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