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"
27 #include "IOHandler.h"
30 typedef uint32_t socklen_t;
33 #define QSERVER_TIMEOUT 30
34 #define QSERVER_MAXCLIENTS 100
36 #define QSERVER_FLAG_AUTHED 0x01
37 #define QSERVER_FLAG_IN_USE 0x02
39 struct QServerClient {
40 struct IODescriptor *iofd;
43 struct QServerClient *next;
46 static struct IODescriptor *server_iofd = NULL;
47 struct QServerClient *qserver_clients = NULL;
48 static int qserver_clientcount = 0;
50 static IOHANDLER_CALLBACK(qserver_callback);
53 if(get_int_field("QServer.enabled")) {
54 char *host = get_string_field("QServer.host");
57 int port = get_int_field("QServer.port");
60 server_iofd = iohandler_listen(host, port, qserver_callback);
65 struct QServerClient *client, *next;
66 for (client = qserver_clients; client; client = next) {
69 iohandler_close(client->iofd);
72 qserver_clients = NULL;
73 qserver_clientcount = 0;
74 iohandler_close(server_iofd);
78 static int qserver_write(struct QServerClient *client, char* msg, int len) {
79 if (!client || !client->iofd) return 0;
82 iohandler_send(client->iofd, msg, len);
86 static void qserver_put(struct QServerClient *client, const char *text, ...) {
90 if (!client || !client->iofd) return;
92 va_start(arg_list, text);
93 pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
95 if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
97 sendBuf[pos+1] = '\0';
98 qserver_write(client, sendBuf, pos+1);
101 static void qserver_update_lastmsg(struct QServerClient *client) {
102 struct timeval timeout;
103 gettimeofday(&timeout, NULL);
104 timeout.tv_sec += QSERVER_TIMEOUT;
105 iohandler_set_timeout(client->iofd, &timeout);
108 static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
109 if(client->flags & QSERVER_FLAG_AUTHED) {
110 qserver_put(client, "E :Already Authed");
114 qserver_put(client, "E :Missing Parameter");
117 if(strcmp(argv[0], get_string_field("QServer.pass"))) {
118 qserver_put(client, "E :Wrong Password");
121 client->flags |= QSERVER_FLAG_AUTHED;
122 qserver_update_lastmsg(client);
123 qserver_put(client, "A :Logged in");
126 #define QSERVER_COMMAND_HEADER {\
127 if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
128 qserver_put(client, "E :Not Authed");\
131 qserver_update_lastmsg(client);\
134 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
135 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
136 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
137 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
138 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
140 static void qserver_parse(struct QServerClient *client, char *line) {
142 char *argv[MAXNUMPARAMS];
144 //skip leading spaces
148 //the rest is a single parameter
149 argv[argc++] = line + 1;
153 if (argc >= MAXNUMPARAMS)
155 while (*line != ' ' && *line)
158 if(!stricmp(argv[0], "A")) //AUTH
159 qserver_parse_A(client, argv+1, argc-1);
160 else if(!stricmp(argv[0], "U")) //get User
161 qserver_parse_U(client, argv+1, argc-1);
162 else if(!stricmp(argv[0], "C")) //get Channel
163 qserver_parse_C(client, argv+1, argc-1);
164 else if(!stricmp(argv[0], "AC")) //get All Channels
165 qserver_parse_AC(client, argv+1, argc-1);
166 else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
167 qserver_parse_ACU(client, argv+1, argc-1);
168 else if(!stricmp(argv[0], "R")) //RAW
169 qserver_parse_R(client, argv+1, argc-1);
171 qserver_put(client, "E :Unknown Command");
174 static void qserver_accept(int sockfd) {
175 struct IODescriptor *client_iofd = iohandler_add(sockfd, IOTYPE_CLIENT, NULL, qserver_callback);
176 client_iofd->state = IO_CONNECTED;
177 iohandler_update(client_iofd);
178 if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
179 iohandler_printf(client_iofd, "E :Maximum QServer Connections reached");
180 iohandler_close(client_iofd);
183 struct QServerClient *client = malloc(sizeof(*client));
184 client->iofd = client_iofd;
185 client->references = 0;
186 client->next = qserver_clients;
187 qserver_clients = client;
188 qserver_clientcount++;
191 static void qserver_cleanup() {
192 struct QServerClient *client, *next, *prev = NULL;
193 for (client = qserver_clients; client; client = next) {
195 if(client->iofd == NULL && !(client->flags & QSERVER_FLAG_IN_USE)) {
197 prev->next = client->next;
199 qserver_clients = client->next;
200 qserver_clientcount--;
206 static IOHANDLER_CALLBACK(qserver_callback) {
207 struct QServerClient *client = event->iofd->data;
208 switch(event->type) {
209 case IOEVENT_TIMEOUT:
210 qserver_put(client, "E :Timeout");
214 qserver_parse(client, event->data.recv_str);
217 iohandler_close(client->iofd);
221 qserver_accept(event->data.accept_fd);
233 static USERAUTH_CALLBACK(qserver_parse_U_async);
234 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
235 QSERVER_COMMAND_HEADER;
237 qserver_put(client, "E :Missing Parameter");
240 struct UserNode *cuser = getUserByNick(argv[0]);
242 cuser = createTempUser(argv[0]);
244 qserver_put(client, "U 0 :Unknown User");
247 cuser->flags |= USERFLAG_ISTMPUSER;
249 client->references++;
250 client->flags |= QSERVER_FLAG_IN_USE;
251 get_userauth(cuser, 0, qserver_parse_U_async, client);
254 static USERAUTH_CALLBACK(qserver_parse_U_async) {
255 struct QServerClient *qclient = data;
256 qclient->references--;
257 if(!qclient->references)
258 qclient->flags &= ~QSERVER_FLAG_IN_USE;
260 qserver_put(qclient, "U 0 :Unknown User");
263 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);
266 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
267 QSERVER_COMMAND_HEADER;
269 qserver_put(client, "E :Missing Parameter");
272 struct ChanNode *chan = getChanByName(argv[0]);
274 qserver_put(client, "C 0 :Unknown Channel");
278 getModeString(chan->modes, tmpStr);
279 qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
282 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
283 QSERVER_COMMAND_HEADER;
284 struct ChanNode *chan;
286 for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
287 getModeString(chan->modes, tmpStr);
288 qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
290 qserver_put(client, "ACE"); //AllChannelsEnd
293 static USERLIST_CALLBACK(qserver_parse_ACU_async);
294 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
295 QSERVER_COMMAND_HEADER;
297 qserver_put(client, "E :Missing Parameter");
300 struct ChanNode *chan = getChanByName(argv[0]);
302 qserver_put(client, "ACUE 0 :Unknown Channel");
305 if(argc > 1 && !stricmp(argv[1], "1")) {
306 client->references++;
307 client->flags |= QSERVER_FLAG_IN_USE;
308 get_userlist_if_invisible(chan, 0, qserver_parse_ACU_async, client);
313 struct ChanUser *chanuser;
314 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
316 if(chanuser->flags & CHANUSERFLAG_OPPED)
317 tmpStr[tmpStrPos++] = '@';
318 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
319 tmpStr[tmpStrPos++] = '%';
320 if(chanuser->flags & CHANUSERFLAG_VOICED)
321 tmpStr[tmpStrPos++] = '+';
322 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
323 tmpStr[tmpStrPos++] = '<';
324 tmpStr[tmpStrPos] = '\0';
325 qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
327 qserver_put(client, "ACUE 1");
330 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
331 struct QServerClient *qclient = data;
332 qclient->references--;
333 if(!qclient->references)
334 qclient->flags &= ~QSERVER_FLAG_IN_USE;
337 struct ChanUser *chanuser;
338 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
340 if(chanuser->flags & CHANUSERFLAG_OPPED)
341 tmpStr[tmpStrPos++] = '@';
342 if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
343 tmpStr[tmpStrPos++] = '%';
344 if(chanuser->flags & CHANUSERFLAG_VOICED)
345 tmpStr[tmpStrPos++] = '+';
346 if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
347 tmpStr[tmpStrPos++] = '<';
348 tmpStr[tmpStrPos] = '\0';
349 qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
351 qserver_put(qclient, "ACUE 1");
354 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
355 QSERVER_COMMAND_HEADER;
357 qserver_put(client, "E :Missing Parameter");
360 struct ClientSocket *bot;
361 if(!strcmp(argv[0], "1")) {
362 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
363 if(!stricmp(bot->user->nick, argv[1])) break;
366 struct ClientSocket *low_bot;
367 int botid = resolve_botalias(argv[1]);
369 botid = atoi(argv[1]);
370 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
371 if(bot->botid == botid) {
372 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
380 qserver_put(client, "R 0 :Bot not found");
383 putsock(bot, "%s", argv[2]);
384 qserver_put(client, "R 1");