1 /* QServer.c - NeonServ v5.5
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
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.
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.
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/>.
23 #include "ClientSocket.h"
24 #include "WHOHandler.h"
25 #include "ConfigParser.h"
29 typedef uint32_t socklen_t;
32 #define QSERVER_TIMEOUT 30
33 #define QSERVER_MAXCLIENTS 100
35 #define QSERVER_FLAG_DISCONNECT 0x01
36 #define QSERVER_FLAG_AUTHED 0x02
37 #define QSERVER_FLAG_IN_USE 0x04
39 struct QServerClient {
46 struct QServerClient *next;
49 static int server_sockfd = 0;
50 struct QServerClient *qserver_clients = NULL;
51 static int qserver_clientcount = 0;
54 if(get_int_field("QServer.enabled")) {
55 server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
56 if (server_sockfd < 0)
58 struct sockaddr_in serv_addr;
59 memset(&serv_addr, 0, sizeof(serv_addr));
60 int portno = get_int_field("QServer.port");
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)
68 listen(server_sockfd,5);
72 static int qserver_write(struct QServerClient *client, char* msg, int len) {
73 if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return 0;
78 ret = send(client->sock, msg, len, 0);
80 ret = write(client->sock, msg, len);
85 static void qserver_put(struct QServerClient *client, const char *text, ...) {
89 if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return;
91 va_start(arg_list, text);
92 pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
94 if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
96 sendBuf[pos+1] = '\0';
97 qserver_write(client, sendBuf, pos+1);
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");
106 qserver_put(client, "E :Missing Parameter");
109 if(strcmp(argv[0], get_string_field("QServer.pass"))) {
110 qserver_put(client, "E :Wrong Password");
113 client->flags |= QSERVER_FLAG_AUTHED;
114 client->lastmsg = time(0);
115 qserver_put(client, "A :Logged in");
118 #define QSERVER_COMMAND_HEADER {\
119 if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
120 qserver_put(client, "E :Not Authed");\
123 client->lastmsg = time(0);\
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);
132 static void qserver_parse(struct QServerClient *client, char *line, int len) {
134 char *argv[MAXNUMPARAMS];
136 //skip leading spaces
140 //the rest is a single parameter
141 argv[argc++] = line + 1;
145 if (argc >= MAXNUMPARAMS)
147 while (*line != ' ' && *line)
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);
163 qserver_put(client, "E :Unknown Command");
166 void qserver_loop() {
167 if(!get_int_field("QServer.enabled"))
170 struct QServerClient *client, *next, *prev = NULL;
172 time_t now = time(0);
178 FD_SET(server_sockfd, &fds);
179 for (client = qserver_clients; client; client = next) {
181 if((client->flags & (QSERVER_FLAG_DISCONNECT | QSERVER_FLAG_IN_USE)) == QSERVER_FLAG_DISCONNECT) {
184 prev->next = client->next;
186 qserver_clients = client->next;
187 qserver_clientcount--;
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;
198 FD_SET(client->sock, &fds);
199 if(client->sock > ret)
202 ret = select(ret + 1, &fds, NULL, NULL, &tv);
206 if(FD_ISSET(server_sockfd, &fds)) {
208 struct sockaddr_in cli_addr;
214 client = malloc(sizeof(*client));
215 clilen = sizeof(cli_addr);
216 client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
218 if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
219 qserver_put(client, "E :Maximum QServer Connections reached");
223 client->lastmsg = now;
224 client->bufferpos = 0;
225 client->references = 0;
226 client->next = qserver_clients;
227 qserver_clients = client;
228 qserver_clientcount++;
233 for (client = qserver_clients; client; client = next) {
235 if(FD_ISSET(client->sock, &fds)) {
237 bytes = recv(client->sock, buffer, sizeof(buffer), 0);
239 bytes = read(client->sock, buffer, sizeof(buffer));
242 client->flags |= QSERVER_FLAG_DISCONNECT;
245 for(i = 0; i < bytes; i++) {
246 if(client->bufferpos == MAXLEN-1) {
248 qserver_put(client, "E :Buffer Overflow");
249 client->flags |= QSERVER_FLAG_DISCONNECT;
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;
258 client->buffer[client->bufferpos++] = buffer[i];
265 void qserver_free() {
266 struct QServerClient *client, *next;
267 for (client = qserver_clients; client; client = next) {
272 qserver_clients = NULL;
273 qserver_clientcount = 0;
274 close(server_sockfd);
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;
285 qserver_put(client, "E :Missing Parameter");
288 struct UserNode *cuser = getUserByNick(argv[0]);
290 cuser = createTempUser(argv[0]);
292 qserver_put(client, "U 0 :Unknown User");
295 cuser->flags |= USERFLAG_ISTMPUSER;
297 client->references++;
298 client->flags |= QSERVER_FLAG_IN_USE;
299 get_userauth(cuser, 0, qserver_parse_U_async, client);
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;
308 qserver_put(qclient, "U 0 :Unknown User");
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);
314 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
315 QSERVER_COMMAND_HEADER;
317 qserver_put(client, "E :Missing Parameter");
320 struct ChanNode *chan = getChanByName(argv[0]);
322 qserver_put(client, "C 0 :Unknown Channel");
326 getModeString(chan->modes, tmpStr);
327 qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
330 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
331 QSERVER_COMMAND_HEADER;
332 struct ChanNode *chan;
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);
338 qserver_put(client, "ACE"); //AllChannelsEnd
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;
345 qserver_put(client, "E :Missing Parameter");
348 struct ChanNode *chan = getChanByName(argv[0]);
350 qserver_put(client, "ACUE 0 :Unknown Channel");
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);
361 struct ChanUser *chanuser;
362 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
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);
375 qserver_put(client, "ACUE 1");
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;
385 struct ChanUser *chanuser;
386 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
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);
399 qserver_put(qclient, "ACUE 1");
402 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
403 QSERVER_COMMAND_HEADER;
405 qserver_put(client, "E :Missing Parameter");
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;
414 struct ClientSocket *low_bot;
415 int botid = resolve_botalias(argv[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;
428 qserver_put(client, "R 0 :Bot not found");
431 putsock(bot, "%s", argv[2]);
432 qserver_put(client, "R 1");