fixed WIN32 compatibility
[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         #ifdef WIN32
209         int clilen;
210         #else
211         socklen_t clilen;
212         #endif
213         client = malloc(sizeof(*client));
214         clilen = sizeof(cli_addr);
215         client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
216         client->flags = 0;
217         if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
218             qserver_put(client, "E :Maximum QServer Connections reached");
219             close(client->sock);
220             free(client);
221         } else {
222             client->lastmsg = now;
223             client->bufferpos = 0;
224             client->references = 0;
225             client->next = qserver_clients;
226             qserver_clients = client;
227             qserver_clientcount++;
228         }
229     }
230     int bytes, i;
231     char buffer[MAXLEN];
232     for (client = qserver_clients; client; client = next) {
233         next = client->next;
234         if(FD_ISSET(client->sock, &fds)) {
235             #ifdef WIN32
236             bytes = recv(client->sock, buffer, sizeof(buffer), 0);
237             #else
238             bytes = read(client->sock, buffer, sizeof(buffer));
239             #endif
240             if(bytes <= 0) {
241                 client->flags |= QSERVER_FLAG_DISCONNECT;
242                 continue;
243             }
244             for(i = 0; i < bytes; i++) {
245                 if(client->bufferpos == MAXLEN-1) {
246                     //buffer overflow
247                     qserver_put(client, "E :Buffer Overflow");
248                     client->flags |= QSERVER_FLAG_DISCONNECT;
249                     break;
250                 }
251                 if(buffer[i] == '\r') continue;
252                 else if(buffer[i] == '\n') {
253                     client->buffer[client->bufferpos] = '\0';
254                     qserver_parse(client, client->buffer, client->bufferpos);
255                     client->bufferpos = 0;
256                 } else {
257                     client->buffer[client->bufferpos++] = buffer[i];
258                 }
259             }
260         }
261     }
262 }
263
264 void qserver_free() {
265     struct QServerClient *client, *next;
266     for (client = qserver_clients; client; client = next) {
267         next = client->next;
268         close(client->sock);
269         free(client);
270     }
271     qserver_clients = NULL;
272     qserver_clientcount = 0;
273     close(server_sockfd);
274 }
275
276 /* 
277 * Command functions
278 */
279
280 static USERAUTH_CALLBACK(qserver_parse_U_async);
281 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
282     QSERVER_COMMAND_HEADER;
283     if(!argv) {
284         qserver_put(client, "E :Missing Parameter");
285         return;
286     }
287     struct UserNode *cuser = getUserByNick(argv[0]);
288     if(!cuser) {
289         cuser = createTempUser(argv[0]);
290         if(!cuser) {
291             qserver_put(client, "U 0 :Unknown User");
292             return;
293         }
294         cuser->flags |= USERFLAG_ISTMPUSER;
295     }
296     client->references++;
297     client->flags |= QSERVER_FLAG_IN_USE;
298     get_userauth(cuser, 0, qserver_parse_U_async, client);
299 }
300
301 static USERAUTH_CALLBACK(qserver_parse_U_async) {
302     struct QServerClient *qclient = data;
303     qclient->references--;
304     if(!qclient->references)
305         qclient->flags &= ~QSERVER_FLAG_IN_USE;
306     if(!user) {
307         qserver_put(qclient, "U 0 :Unknown User");
308         return;
309     }
310     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);
311 }
312
313 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
314     QSERVER_COMMAND_HEADER;
315     if(!argv) {
316         qserver_put(client, "E :Missing Parameter");
317         return;
318     }
319     struct ChanNode *chan = getChanByName(argv[0]);
320     if(!chan) {
321         qserver_put(client, "C 0 :Unknown Channel");
322         return;
323     }
324     char tmpStr[MAXLEN];
325     getModeString(chan->modes, tmpStr);
326     qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
327 }
328
329 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
330     QSERVER_COMMAND_HEADER;
331     struct ChanNode *chan;
332     char tmpStr[MAXLEN];
333     for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
334         getModeString(chan->modes, tmpStr);
335         qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
336     }
337     qserver_put(client, "ACE"); //AllChannelsEnd
338 }
339
340 static USERLIST_CALLBACK(qserver_parse_ACU_async);
341 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
342     QSERVER_COMMAND_HEADER;
343     if(!argv) {
344         qserver_put(client, "E :Missing Parameter");
345         return;
346     }
347     struct ChanNode *chan = getChanByName(argv[0]);
348     if(!chan) {
349         qserver_put(client, "ACUE 0 :Unknown Channel");
350         return;
351     }
352     if(argc > 1 && !stricmp(argv[1], "1")) {
353         client->references++;
354         client->flags |= QSERVER_FLAG_IN_USE;
355         get_userlist_if_invisible(chan, 0, qserver_parse_ACU_async, client);
356         return;
357     }
358     char tmpStr[6];
359     int tmpStrPos;
360     struct ChanUser *chanuser;
361     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
362         tmpStrPos = 0;
363         if(chanuser->flags & CHANUSERFLAG_OPPED)
364             tmpStr[tmpStrPos++] = '@';
365         if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
366             tmpStr[tmpStrPos++] = '%';
367         if(chanuser->flags & CHANUSERFLAG_VOICED)
368             tmpStr[tmpStrPos++] = '+';
369         if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
370             tmpStr[tmpStrPos++] = '<';
371         tmpStr[tmpStrPos] = '\0';
372         qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
373     }
374     qserver_put(client, "ACUE 1");
375 }
376
377 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
378     struct QServerClient *qclient = data;
379     qclient->references--;
380     if(!qclient->references)
381         qclient->flags &= ~QSERVER_FLAG_IN_USE;
382     char tmpStr[6];
383     int tmpStrPos;
384     struct ChanUser *chanuser;
385     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
386         tmpStrPos = 0;
387         if(chanuser->flags & CHANUSERFLAG_OPPED)
388             tmpStr[tmpStrPos++] = '@';
389         if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
390             tmpStr[tmpStrPos++] = '%';
391         if(chanuser->flags & CHANUSERFLAG_VOICED)
392             tmpStr[tmpStrPos++] = '+';
393         if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
394             tmpStr[tmpStrPos++] = '<';
395         tmpStr[tmpStrPos] = '\0';
396         qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
397     }
398     qserver_put(qclient, "ACUE 1");
399 }
400
401 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
402     QSERVER_COMMAND_HEADER;
403     if(argc < 3) {
404         qserver_put(client, "E :Missing Parameter");
405         return;
406     }
407     struct ClientSocket *bot;
408     if(!strcmp(argv[0], "1")) {
409         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
410             if(!stricmp(bot->user->nick, argv[1])) break;
411         }
412     } else {
413         struct ClientSocket *low_bot;
414         int botid = resolve_botalias(argv[1]);
415         if(botid == -1)
416             botid = atoi(argv[1]);
417         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
418             if(bot->botid == botid) {
419                 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
420                 low_bot = bot;
421             }
422         }
423         if(!bot)
424             bot = low_bot;
425     }
426     if(!bot) {
427         qserver_put(client, "R 0 :Bot not found");
428         return;
429     }
430     putsock(bot, "%s", argv[2]);
431     qserver_put(client, "R 1");
432 }