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"
28 #define QSERVER_TIMEOUT 30
29 #define QSERVER_MAXCLIENTS 100
31 #define QSERVER_FLAG_DISCONNECT 0x01
32 #define QSERVER_FLAG_AUTHED 0x02
33 #define QSERVER_FLAG_IN_USE 0x04
35 struct QServerClient {
42 struct QServerClient *next;
45 static int server_sockfd = 0;
46 struct QServerClient *qserver_clients = NULL;
47 static int qserver_clientcount = 0;
50 if(get_int_field("QServer.enabled")) {
51 server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
52 if (server_sockfd < 0)
54 struct sockaddr_in serv_addr;
55 bzero((char *) &serv_addr, sizeof(serv_addr));
56 int portno = get_int_field("QServer.port");
59 serv_addr.sin_family = AF_INET;
60 serv_addr.sin_addr.s_addr = INADDR_ANY;
61 serv_addr.sin_port = htons(portno);
62 if (bind(server_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
64 listen(server_sockfd,5);
68 static int qserver_write(struct QServerClient *client, char* msg, int len) {
69 if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return 0;
73 send(client->sock, msg, len, 0);
75 write(client->sock, msg, len);
80 static void qserver_put(struct QServerClient *client, const char *text, ...) {
84 if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return;
86 va_start(arg_list, text);
87 pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
89 if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
91 sendBuf[pos+1] = '\0';
92 qserver_write(client, sendBuf, pos+1);
95 static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
96 if(client->flags & QSERVER_FLAG_AUTHED) {
97 qserver_put(client, "E :Already Authed");
101 qserver_put(client, "E :Missing Parameter");
104 if(strcmp(argv[0], get_string_field("QServer.pass"))) {
105 qserver_put(client, "E :Wrong Password");
108 client->flags |= QSERVER_FLAG_AUTHED;
109 client->lastmsg = time(0);
110 qserver_put(client, "A :Logged in");
113 #define QSERVER_COMMAND_HEADER {\
114 if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
115 qserver_put(client, "E :Not Authed");\
118 client->lastmsg = time(0);\
121 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
122 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
123 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
124 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
125 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
127 static void qserver_parse(struct QServerClient *client, char *line, int len) {
129 char *argv[MAXNUMPARAMS];
131 //skip leading spaces
135 //the rest is a single parameter
136 argv[argc++] = line + 1;
140 if (argc >= MAXNUMPARAMS)
142 while (*line != ' ' && *line)
145 if(!stricmp(argv[0], "A")) //AUTH
146 qserver_parse_A(client, argv+1, argc-1);
147 else if(!stricmp(argv[0], "U")) //get User
148 qserver_parse_U(client, argv+1, argc-1);
149 else if(!stricmp(argv[0], "C")) //get Channel
150 qserver_parse_C(client, argv+1, argc-1);
151 else if(!stricmp(argv[0], "AC")) //get All Channels
152 qserver_parse_AC(client, argv+1, argc-1);
153 else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
154 qserver_parse_ACU(client, argv+1, argc-1);
155 else if(!stricmp(argv[0], "R")) //RAW
156 qserver_parse_R(client, argv+1, argc-1);
158 qserver_put(client, "E :Unknown Command");
161 void qserver_loop() {
163 struct QServerClient *client, *next, *prev = NULL;
165 time_t now = time(0);
171 FD_SET(server_sockfd, &fds);
172 for (client = qserver_clients; client; client = next) {
174 if((client->flags & (QSERVER_FLAG_DISCONNECT | QSERVER_FLAG_IN_USE)) == QSERVER_FLAG_DISCONNECT) {
177 prev->next = client->next;
179 qserver_clients = client->next;
180 qserver_clientcount--;
185 if(client->flags & QSERVER_FLAG_DISCONNECT) continue;
186 if(now - client->lastmsg > QSERVER_TIMEOUT) {
187 qserver_put(client, "E :Timeout");
188 client->flags |= QSERVER_FLAG_DISCONNECT;
191 FD_SET(client->sock, &fds);
192 if(client->sock > ret)
195 ret = select(ret + 1, &fds, NULL, NULL, &tv);
199 if(FD_ISSET(server_sockfd, &fds)) {
201 struct sockaddr_in cli_addr;
203 if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
204 qserver_put(client, "E :Maximum QServer Connections reached");
207 client = malloc(sizeof(*client));
208 clilen = sizeof(cli_addr);
209 client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
211 client->lastmsg = now;
212 client->bufferpos = 0;
213 client->references = 0;
214 client->next = qserver_clients;
215 qserver_clients = client;
216 qserver_clientcount++;
221 for (client = qserver_clients; client; client = next) {
223 if(FD_ISSET(client->sock, &fds)) {
225 bytes = recv(client->sock, buffer, sizeof(buffer), 0);
227 bytes = read(client->sock, buffer, sizeof(buffer));
230 client->flags |= QSERVER_FLAG_DISCONNECT;
233 for(i = 0; i < bytes; i++) {
234 if(client->bufferpos == MAXLEN-1) {
236 qserver_put(client, "E :Buffer Overflow");
237 client->flags |= QSERVER_FLAG_DISCONNECT;
240 if(buffer[i] == '\r') continue;
241 else if(buffer[i] == '\n') {
242 client->buffer[client->bufferpos] = '\0';
243 qserver_parse(client, client->buffer, client->bufferpos);
244 client->bufferpos = 0;
246 client->buffer[client->bufferpos++] = buffer[i];
253 void qserver_free() {
254 struct QServerClient *client, *next;
255 for (client = qserver_clients; client; client = next) {
260 qserver_clients = NULL;
261 qserver_clientcount = 0;
262 close(server_sockfd);
269 static USERAUTH_CALLBACK(qserver_parse_U_async);
270 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
271 QSERVER_COMMAND_HEADER;
273 qserver_put(client, "E :Missing Parameter");
276 struct UserNode *cuser = getUserByNick(argv[0]);
278 cuser = createTempUser(argv[0]);
280 qserver_put(client, "U 0 :Unknown User");
283 cuser->flags |= USERFLAG_ISTMPUSER;
285 client->references++;
286 client->flags |= QSERVER_FLAG_IN_USE;
287 get_userauth(cuser, qserver_parse_U_async, client);
290 static USERAUTH_CALLBACK(qserver_parse_U_async) {
291 struct QServerClient *qclient = data;
292 qclient->references--;
293 if(!qclient->references)
294 qclient->flags &= ~QSERVER_FLAG_IN_USE;
296 qserver_put(qclient, "U 0 :Unknown User");
299 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);
302 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
303 QSERVER_COMMAND_HEADER;
305 qserver_put(client, "E :Missing Parameter");
308 struct ChanNode *chan = getChanByName(argv[0]);
310 qserver_put(client, "C 0 :Unknown Channel");
314 getModeString(chan->modes, tmpStr);
315 qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
318 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
319 QSERVER_COMMAND_HEADER;
320 struct ChanNode *chan;
322 for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
323 getModeString(chan->modes, tmpStr);
324 qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
326 qserver_put(client, "ACE"); //AllChannelsEnd
329 static USERLIST_CALLBACK(qserver_parse_ACU_async);
330 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
331 QSERVER_COMMAND_HEADER;
333 qserver_put(client, "E :Missing Parameter");
336 struct ChanNode *chan = getChanByName(argv[0]);
338 qserver_put(client, "ACUE 0 :Unknown Channel");
341 if(argc > 1 && !stricmp(argv[1], "1")) {
342 client->references++;
343 client->flags |= QSERVER_FLAG_IN_USE;
344 get_userlist_if_invisible(chan, qserver_parse_ACU_async, client);
349 struct ChanUser *chanuser;
350 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
352 if(chanuser->flags & CHANUSERFLAG_OPPED)
353 tmpStr[tmpStrPos++] = '@';
354 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
355 tmpStr[tmpStrPos++] = '%';
356 if(chanuser->flags & CHANUSERFLAG_VOICED)
357 tmpStr[tmpStrPos++] = '+';
358 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
359 tmpStr[tmpStrPos++] = '<';
360 tmpStr[tmpStrPos] = '\0';
361 qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
363 qserver_put(client, "ACUE 1");
366 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
367 struct QServerClient *qclient = data;
368 qclient->references--;
369 if(!qclient->references)
370 qclient->flags &= ~QSERVER_FLAG_IN_USE;
373 struct ChanUser *chanuser;
374 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
376 if(chanuser->flags & CHANUSERFLAG_OPPED)
377 tmpStr[tmpStrPos++] = '@';
378 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
379 tmpStr[tmpStrPos++] = '%';
380 if(chanuser->flags & CHANUSERFLAG_VOICED)
381 tmpStr[tmpStrPos++] = '+';
382 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
383 tmpStr[tmpStrPos++] = '<';
384 tmpStr[tmpStrPos] = '\0';
385 qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
387 qserver_put(qclient, "ACUE 1");
390 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
391 QSERVER_COMMAND_HEADER;
393 qserver_put(client, "E :Missing Parameter");
396 struct ClientSocket *bot;
397 if(!strcmp(argv[0], "1")) {
398 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
399 if(!stricmp(bot->user->nick, argv[1])) break;
402 struct ClientSocket *low_bot;
403 int botid = resolve_botalias(argv[1]);
405 botid = atoi(argv[1]);
406 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
407 if(bot->botid == botid) {
408 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
416 qserver_put(client, "R 0 :Bot not found");
419 putsock(bot, "%s", argv[2]);
420 qserver_put(client, "R 1");