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