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