1 /* QServer.c - NeonServ v5.3
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;
77 send(client->sock, msg, len, 0);
79 write(client->sock, msg, len);
84 static void qserver_put(struct QServerClient *client, const char *text, ...) {
88 if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return;
90 va_start(arg_list, text);
91 pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
93 if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
95 sendBuf[pos+1] = '\0';
96 qserver_write(client, sendBuf, pos+1);
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");
105 qserver_put(client, "E :Missing Parameter");
108 if(strcmp(argv[0], get_string_field("QServer.pass"))) {
109 qserver_put(client, "E :Wrong Password");
112 client->flags |= QSERVER_FLAG_AUTHED;
113 client->lastmsg = time(0);
114 qserver_put(client, "A :Logged in");
117 #define QSERVER_COMMAND_HEADER {\
118 if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
119 qserver_put(client, "E :Not Authed");\
122 client->lastmsg = time(0);\
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);
131 static void qserver_parse(struct QServerClient *client, char *line, int len) {
133 char *argv[MAXNUMPARAMS];
135 //skip leading spaces
139 //the rest is a single parameter
140 argv[argc++] = line + 1;
144 if (argc >= MAXNUMPARAMS)
146 while (*line != ' ' && *line)
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);
162 qserver_put(client, "E :Unknown Command");
165 void qserver_loop() {
166 if(!get_int_field("QServer.enabled"))
169 struct QServerClient *client, *next, *prev = NULL;
171 time_t now = time(0);
177 FD_SET(server_sockfd, &fds);
178 for (client = qserver_clients; client; client = next) {
180 if((client->flags & (QSERVER_FLAG_DISCONNECT | QSERVER_FLAG_IN_USE)) == QSERVER_FLAG_DISCONNECT) {
183 prev->next = client->next;
185 qserver_clients = client->next;
186 qserver_clientcount--;
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;
197 FD_SET(client->sock, &fds);
198 if(client->sock > ret)
201 ret = select(ret + 1, &fds, NULL, NULL, &tv);
205 if(FD_ISSET(server_sockfd, &fds)) {
207 struct sockaddr_in cli_addr;
213 client = malloc(sizeof(*client));
214 clilen = sizeof(cli_addr);
215 client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
217 if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
218 qserver_put(client, "E :Maximum QServer Connections reached");
222 client->lastmsg = now;
223 client->bufferpos = 0;
224 client->references = 0;
225 client->next = qserver_clients;
226 qserver_clients = client;
227 qserver_clientcount++;
232 for (client = qserver_clients; client; client = next) {
234 if(FD_ISSET(client->sock, &fds)) {
236 bytes = recv(client->sock, buffer, sizeof(buffer), 0);
238 bytes = read(client->sock, buffer, sizeof(buffer));
241 client->flags |= QSERVER_FLAG_DISCONNECT;
244 for(i = 0; i < bytes; i++) {
245 if(client->bufferpos == MAXLEN-1) {
247 qserver_put(client, "E :Buffer Overflow");
248 client->flags |= QSERVER_FLAG_DISCONNECT;
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;
257 client->buffer[client->bufferpos++] = buffer[i];
264 void qserver_free() {
265 struct QServerClient *client, *next;
266 for (client = qserver_clients; client; client = next) {
271 qserver_clients = NULL;
272 qserver_clientcount = 0;
273 close(server_sockfd);
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;
284 qserver_put(client, "E :Missing Parameter");
287 struct UserNode *cuser = getUserByNick(argv[0]);
289 cuser = createTempUser(argv[0]);
291 qserver_put(client, "U 0 :Unknown User");
294 cuser->flags |= USERFLAG_ISTMPUSER;
296 client->references++;
297 client->flags |= QSERVER_FLAG_IN_USE;
298 get_userauth(cuser, 0, qserver_parse_U_async, client);
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;
307 qserver_put(qclient, "U 0 :Unknown User");
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);
313 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
314 QSERVER_COMMAND_HEADER;
316 qserver_put(client, "E :Missing Parameter");
319 struct ChanNode *chan = getChanByName(argv[0]);
321 qserver_put(client, "C 0 :Unknown Channel");
325 getModeString(chan->modes, tmpStr);
326 qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
329 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
330 QSERVER_COMMAND_HEADER;
331 struct ChanNode *chan;
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);
337 qserver_put(client, "ACE"); //AllChannelsEnd
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;
344 qserver_put(client, "E :Missing Parameter");
347 struct ChanNode *chan = getChanByName(argv[0]);
349 qserver_put(client, "ACUE 0 :Unknown Channel");
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);
360 struct ChanUser *chanuser;
361 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
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);
374 qserver_put(client, "ACUE 1");
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;
384 struct ChanUser *chanuser;
385 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
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);
398 qserver_put(qclient, "ACUE 1");
401 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
402 QSERVER_COMMAND_HEADER;
404 qserver_put(client, "E :Missing Parameter");
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;
413 struct ClientSocket *low_bot;
414 int botid = resolve_botalias(argv[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;
427 qserver_put(client, "R 0 :Bot not found");
430 putsock(bot, "%s", argv[2]);
431 qserver_put(client, "R 1");