*** VERSION 5.5.0 ***
[NeonServV5.git] / src / QServer.c
1 /* QServer.c - NeonServ v5.5
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
28 #ifdef WIN32
29 typedef uint32_t socklen_t;
30 #endif
31
32 #define QSERVER_TIMEOUT 30
33 #define QSERVER_MAXCLIENTS 100
34
35 #define QSERVER_FLAG_DISCONNECT 0x01
36 #define QSERVER_FLAG_AUTHED     0x02
37 #define QSERVER_FLAG_IN_USE     0x04
38
39 struct QServerClient {
40     int sock;
41     unsigned int flags;
42     time_t lastmsg;
43     char buffer[MAXLEN];
44     int bufferpos;
45     int references;
46     struct QServerClient *next;
47 };
48
49 static int server_sockfd = 0;
50 struct QServerClient *qserver_clients = NULL;
51 static int qserver_clientcount = 0;
52
53 void qserver_init() {
54     if(get_int_field("QServer.enabled")) {
55         server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
56         if (server_sockfd < 0) 
57             return;
58         struct sockaddr_in serv_addr;
59         memset(&serv_addr, 0, sizeof(serv_addr));
60         int portno = get_int_field("QServer.port");
61         if(!portno)
62             portno = 7499;
63         serv_addr.sin_family = AF_INET;
64         serv_addr.sin_addr.s_addr = INADDR_ANY;
65         serv_addr.sin_port = htons(portno);
66         if (bind(server_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
67             return;
68         listen(server_sockfd,5);
69     }
70 }
71
72 static int qserver_write(struct QServerClient *client, char* msg, int len) {
73     if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return 0;
74     if(!len)
75         len = strlen(msg);
76         int ret = 1;
77     #ifdef WIN32
78     ret = send(client->sock, msg, len, 0);
79     #else
80     ret = write(client->sock, msg, len);
81     #endif
82     return ret;
83 }
84
85 static void qserver_put(struct QServerClient *client, const char *text, ...) {
86     va_list arg_list;
87     char sendBuf[MAXLEN];
88     int pos;
89     if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return;
90     sendBuf[0] = '\0';
91     va_start(arg_list, text);
92     pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
93     va_end(arg_list);
94     if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
95     sendBuf[pos] = '\n';
96     sendBuf[pos+1] = '\0';
97     qserver_write(client, sendBuf, pos+1);
98 }
99
100 static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
101     if(client->flags & QSERVER_FLAG_AUTHED) {
102         qserver_put(client, "E :Already Authed");
103         return;
104     }
105     if(!argv) {
106         qserver_put(client, "E :Missing Parameter");
107         return;
108     }
109     if(strcmp(argv[0], get_string_field("QServer.pass"))) {
110         qserver_put(client, "E :Wrong Password");
111         return;
112     }
113     client->flags |= QSERVER_FLAG_AUTHED;
114     client->lastmsg = time(0);
115     qserver_put(client, "A :Logged in");
116 }
117
118 #define QSERVER_COMMAND_HEADER {\
119     if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
120         qserver_put(client, "E :Not Authed");\
121         return;\
122     }\
123     client->lastmsg = time(0);\
124 }
125
126 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
127 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
128 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
129 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
130 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
131
132 static void qserver_parse(struct QServerClient *client, char *line, int len) {
133     int argc = 0;
134     char *argv[MAXNUMPARAMS];
135     while(*line) {
136         //skip leading spaces
137         while (*line == ' ')
138             *line++ = 0;
139         if (*line == ':') {
140            //the rest is a single parameter
141            argv[argc++] = line + 1;
142            break;
143         }
144         argv[argc++] = line;
145         if (argc >= MAXNUMPARAMS)
146             break;
147         while (*line != ' ' && *line)
148             line++;
149     }
150     if(!stricmp(argv[0], "A")) //AUTH
151         qserver_parse_A(client, argv+1, argc-1);
152     else if(!stricmp(argv[0], "U")) //get User
153         qserver_parse_U(client, argv+1, argc-1);
154     else if(!stricmp(argv[0], "C")) //get Channel
155         qserver_parse_C(client, argv+1, argc-1);
156     else if(!stricmp(argv[0], "AC")) //get All Channels
157         qserver_parse_AC(client, argv+1, argc-1);
158     else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
159         qserver_parse_ACU(client, argv+1, argc-1);
160     else if(!stricmp(argv[0], "R")) //RAW
161         qserver_parse_R(client, argv+1, argc-1);
162     else
163         qserver_put(client, "E :Unknown Command");
164 }
165
166 void qserver_loop() {
167     if(!get_int_field("QServer.enabled"))
168         return;
169     struct timeval tv;
170     struct QServerClient *client, *next, *prev = NULL;
171     int ret;
172     time_t now = time(0);
173     fd_set fds;
174     tv.tv_sec = 0;
175     tv.tv_usec = 0;
176     FD_ZERO(&fds);
177     ret = server_sockfd;
178     FD_SET(server_sockfd, &fds);
179     for (client = qserver_clients; client; client = next) {
180         next = client->next;
181         if((client->flags & (QSERVER_FLAG_DISCONNECT | QSERVER_FLAG_IN_USE)) == QSERVER_FLAG_DISCONNECT) {
182             close(client->sock);
183             if(prev) 
184                 prev->next = client->next;
185             else
186                 qserver_clients = client->next;
187             qserver_clientcount--;
188             free(client);
189             continue;
190         }
191         prev = client;
192         if(client->flags & QSERVER_FLAG_DISCONNECT) continue;
193         if(now - client->lastmsg > QSERVER_TIMEOUT) {
194             qserver_put(client, "E :Timeout");
195             client->flags |= QSERVER_FLAG_DISCONNECT;
196             continue;
197         }
198         FD_SET(client->sock, &fds);
199         if(client->sock > ret)
200             ret = client->sock;
201     }
202     ret = select(ret + 1, &fds, NULL, NULL, &tv);
203     if(ret == 0) {
204         return;
205     }
206     if(FD_ISSET(server_sockfd, &fds)) {
207         //new connection
208         struct sockaddr_in cli_addr;
209         #ifdef WIN32
210         int clilen;
211         #else
212         socklen_t clilen;
213         #endif
214         client = malloc(sizeof(*client));
215         clilen = sizeof(cli_addr);
216         client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
217         client->flags = 0;
218         if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
219             qserver_put(client, "E :Maximum QServer Connections reached");
220             close(client->sock);
221             free(client);
222         } else {
223             client->lastmsg = now;
224             client->bufferpos = 0;
225             client->references = 0;
226             client->next = qserver_clients;
227             qserver_clients = client;
228             qserver_clientcount++;
229         }
230     }
231     int bytes, i;
232     char buffer[MAXLEN];
233     for (client = qserver_clients; client; client = next) {
234         next = client->next;
235         if(FD_ISSET(client->sock, &fds)) {
236             #ifdef WIN32
237             bytes = recv(client->sock, buffer, sizeof(buffer), 0);
238             #else
239             bytes = read(client->sock, buffer, sizeof(buffer));
240             #endif
241             if(bytes <= 0) {
242                 client->flags |= QSERVER_FLAG_DISCONNECT;
243                 continue;
244             }
245             for(i = 0; i < bytes; i++) {
246                 if(client->bufferpos == MAXLEN-1) {
247                     //buffer overflow
248                     qserver_put(client, "E :Buffer Overflow");
249                     client->flags |= QSERVER_FLAG_DISCONNECT;
250                     break;
251                 }
252                 if(buffer[i] == '\r') continue;
253                 else if(buffer[i] == '\n') {
254                     client->buffer[client->bufferpos] = '\0';
255                     qserver_parse(client, client->buffer, client->bufferpos);
256                     client->bufferpos = 0;
257                 } else {
258                     client->buffer[client->bufferpos++] = buffer[i];
259                 }
260             }
261         }
262     }
263 }
264
265 void qserver_free() {
266     struct QServerClient *client, *next;
267     for (client = qserver_clients; client; client = next) {
268         next = client->next;
269         close(client->sock);
270         free(client);
271     }
272     qserver_clients = NULL;
273     qserver_clientcount = 0;
274     close(server_sockfd);
275 }
276
277 /* 
278 * Command functions
279 */
280
281 static USERAUTH_CALLBACK(qserver_parse_U_async);
282 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
283     QSERVER_COMMAND_HEADER;
284     if(!argv) {
285         qserver_put(client, "E :Missing Parameter");
286         return;
287     }
288     struct UserNode *cuser = getUserByNick(argv[0]);
289     if(!cuser) {
290         cuser = createTempUser(argv[0]);
291         if(!cuser) {
292             qserver_put(client, "U 0 :Unknown User");
293             return;
294         }
295         cuser->flags |= USERFLAG_ISTMPUSER;
296     }
297     client->references++;
298     client->flags |= QSERVER_FLAG_IN_USE;
299     get_userauth(cuser, 0, qserver_parse_U_async, client);
300 }
301
302 static USERAUTH_CALLBACK(qserver_parse_U_async) {
303     struct QServerClient *qclient = data;
304     qclient->references--;
305     if(!qclient->references)
306         qclient->flags &= ~QSERVER_FLAG_IN_USE;
307     if(!user) {
308         qserver_put(qclient, "U 0 :Unknown User");
309         return;
310     }
311     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);
312 }
313
314 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
315     QSERVER_COMMAND_HEADER;
316     if(!argv) {
317         qserver_put(client, "E :Missing Parameter");
318         return;
319     }
320     struct ChanNode *chan = getChanByName(argv[0]);
321     if(!chan) {
322         qserver_put(client, "C 0 :Unknown Channel");
323         return;
324     }
325     char tmpStr[MAXLEN];
326     getModeString(chan->modes, tmpStr);
327     qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
328 }
329
330 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
331     QSERVER_COMMAND_HEADER;
332     struct ChanNode *chan;
333     char tmpStr[MAXLEN];
334     for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
335         getModeString(chan->modes, tmpStr);
336         qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
337     }
338     qserver_put(client, "ACE"); //AllChannelsEnd
339 }
340
341 static USERLIST_CALLBACK(qserver_parse_ACU_async);
342 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
343     QSERVER_COMMAND_HEADER;
344     if(!argv) {
345         qserver_put(client, "E :Missing Parameter");
346         return;
347     }
348     struct ChanNode *chan = getChanByName(argv[0]);
349     if(!chan) {
350         qserver_put(client, "ACUE 0 :Unknown Channel");
351         return;
352     }
353     if(argc > 1 && !stricmp(argv[1], "1")) {
354         client->references++;
355         client->flags |= QSERVER_FLAG_IN_USE;
356         get_userlist_if_invisible(chan, 0, qserver_parse_ACU_async, client);
357         return;
358     }
359     char tmpStr[6];
360     int tmpStrPos;
361     struct ChanUser *chanuser;
362     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
363         tmpStrPos = 0;
364         if(chanuser->flags & CHANUSERFLAG_OPPED)
365             tmpStr[tmpStrPos++] = '@';
366         if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
367             tmpStr[tmpStrPos++] = '%';
368         if(chanuser->flags & CHANUSERFLAG_VOICED)
369             tmpStr[tmpStrPos++] = '+';
370         if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
371             tmpStr[tmpStrPos++] = '<';
372         tmpStr[tmpStrPos] = '\0';
373         qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
374     }
375     qserver_put(client, "ACUE 1");
376 }
377
378 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
379     struct QServerClient *qclient = data;
380     qclient->references--;
381     if(!qclient->references)
382         qclient->flags &= ~QSERVER_FLAG_IN_USE;
383     char tmpStr[6];
384     int tmpStrPos;
385     struct ChanUser *chanuser;
386     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
387         tmpStrPos = 0;
388         if(chanuser->flags & CHANUSERFLAG_OPPED)
389             tmpStr[tmpStrPos++] = '@';
390         if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
391             tmpStr[tmpStrPos++] = '%';
392         if(chanuser->flags & CHANUSERFLAG_VOICED)
393             tmpStr[tmpStrPos++] = '+';
394         if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
395             tmpStr[tmpStrPos++] = '<';
396         tmpStr[tmpStrPos] = '\0';
397         qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
398     }
399     qserver_put(qclient, "ACUE 1");
400 }
401
402 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
403     QSERVER_COMMAND_HEADER;
404     if(argc < 3) {
405         qserver_put(client, "E :Missing Parameter");
406         return;
407     }
408     struct ClientSocket *bot;
409     if(!strcmp(argv[0], "1")) {
410         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
411             if(!stricmp(bot->user->nick, argv[1])) break;
412         }
413     } else {
414         struct ClientSocket *low_bot;
415         int botid = resolve_botalias(argv[1]);
416         if(botid == -1)
417             botid = atoi(argv[1]);
418         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
419             if(bot->botid == botid) {
420                 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
421                 low_bot = bot;
422             }
423         }
424         if(!bot)
425             bot = low_bot;
426     }
427     if(!bot) {
428         qserver_put(client, "R 0 :Bot not found");
429         return;
430     }
431     putsock(bot, "%s", argv[2]);
432     qserver_put(client, "R 1");
433 }