modified IOMultiplexer (added epoll & kevent support)
[TransparentIRC.git] / src / UserClient.c
1 /* UserClient.c - TransparentIRC 0.1
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 #include "UserClient.h"
18 #include "IOHandler.h"
19 #include "ServerSocket.h"
20 #include "UserSession.h"
21 #include "tools.h"
22 #include "IRCClient.h"
23
24 static void userclient_callback(struct IOEvent *event);
25
26 static struct UserClient *userclients = NULL;
27
28 void userclient_accepted(struct ServerSocket *server, int sockfd) {
29     struct UserClient *client;
30     struct IODescriptor *iofd = iohandler_add(sockfd, IOTYPE_CLIENT, NULL, userclient_callback);
31     if(!iofd) return;
32     iofd->state = IO_CONNECTED;
33     iofd->read_lines = 1;
34     iohandler_update(iofd);
35     client = calloc(1, sizeof(*client));
36     client->iofd = iofd;
37     iofd->data = client;
38     client->server = server;
39     server->clientcount++;
40     
41     struct UserLogin *login = calloc(1, sizeof(*login));
42     client->user = login;
43     login->client = client;
44     
45     
46     //add UserClient to the list
47     client->prev = NULL;
48     client->next = userclients;
49     if(userclients)
50         userclients->prev = client;
51     userclients = client;
52     
53     //let's say hello to the client
54     iohandler_printf(iofd, "NOTICE AUTH :*** [TransparentIRC] TransparentIRC v" TRANSIRC_VERSION " (use /quote transirc for more information)");
55 }
56
57 void userclient_close(struct UserClient *client) {
58     if(client->flags & USERCLIENT_LOGGED_IN) {
59         usersession_client_close(client->user);
60     } else {
61         struct UserLogin *login = client->user;
62         if(client->flags & USERCLIENT_LOGIN_PROCESSING) {
63             usersession_login_abort(login);
64         }
65         if(login->username)
66             free(login->username);
67         if(login->realname)
68             free(login->realname);
69         if(login->password)
70             free(login->password);
71         if(login->nick)
72             free(login->nick);
73         if(login->reject_reason)
74             free(login->reject_reason);
75         if(login->session_class)
76             free(login->session_class);
77         if(login->bind_address)
78             free(login->bind_address);
79         if(login->server_address)
80             free(login->server_address);
81         free(login);
82     }
83     iohandler_close(client->iofd);
84     client->server->clientcount--;
85     if(client->prev)
86         client->prev->next = client->next;
87     else
88         userclients = client->next;
89     if(client->next)
90         client->next->prev = client->prev;
91     
92     free(client);
93 }
94
95 void userclient_close_server(struct ServerSocket *server, int keep_clients) {
96     struct UserClient *client, *next_client;
97     for(client = userclients; client; client = next_client) {
98         next_client = client->next;
99         if(client->server == server) {
100             if(keep_clients)
101                 client->server = NULL;
102             else
103                 userclient_close(client);
104         }
105     }
106 }
107
108 static void userclient_recv(struct UserClient *client, char *line) {
109     if(!stricmplen(line, "TRANSIRC ", 9)) {
110         /*
111         char *argv[MAXNUMPARAMS];
112         int argc = parse_line(line, argv, 1);
113         */
114         
115         return;
116     } else if(!(client->flags & USERCLIENT_LOGGED_IN)) {
117         struct UserLogin *login = client->user;
118         char *argv[MAXNUMPARAMS];
119         int argc = parse_line(line, argv, 1);
120         if(argc < 3) return;
121         if(!stricmp(argv[1], "PASS")) {
122             char *delimiter = strchr(argv[2], ':');
123             if(login->password)
124                 free(login->password);
125             if(delimiter) {
126                 *delimiter = '\0';
127                 delimiter++;
128                 if(login->username)
129                     free(login->username);
130                 login->username = strdup(argv[2]);
131                 login->password = strdup(delimiter);
132             } else 
133                 login->password = strdup(argv[2]);
134         } else if(!stricmp(argv[1], "USER") && argc >= 6) {
135             if(!login->username)
136                 login->username = strdup(argv[2]);
137             login->realname = strdup(argv[5]);
138         } else if(!stricmp(argv[1], "NICK")) {
139             if(login->nick)
140                 free(login->nick);
141             login->nick = strdup(argv[2]);
142             if(!login->password) {
143                 iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] You need to send your LOC data. Try /quote PASS <username>:<password>");
144             }
145         }
146         if(login->username && login->password && login->nick && login->realname && !(client->flags & USERCLIENT_LOGIN_PROCESSING)) {
147             //try to login
148             iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Checking login...");
149             usersession_login(login);
150         }
151     } else {
152         struct UserSession *session = client->user;
153         if(!stricmplen(line, "QUIT", 4))
154             return;
155         
156         if(session->irc)
157             ircclient_send(session->irc, line);
158     }
159 }
160
161 void userclient_login_failed(struct UserLogin *login, char *reason) {
162     iohandler_printf(login->client->iofd, "NOTICE AUTH :*** [TransparentIRC] Login rejected");
163     userclient_close(login->client);
164 }
165
166 void userclient_login_successful(struct UserLogin *login, struct UserSession *session, int recover) {
167     struct UserClient *client = login->client;
168     iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Login accepted.");
169     if(login->username)
170         free(login->username);
171     if(login->password)
172         free(login->password);
173     if(login->nick)
174         free(login->nick);
175     free(login);
176     client->user = session;
177     client->flags |= USERCLIENT_LOGGED_IN;
178     if(recover) {
179         iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Recovering previous link (Nick: %s).", session->nick);
180         ircclient_recover_session(session);
181     }
182 }
183
184 static void userclient_callback(struct IOEvent *event) {
185     struct UserClient *client = event->iofd->data;
186     switch(event->type) {
187         case IOEVENT_RECV:
188             userclient_recv(client, event->data.recv_str);
189             break;
190         case IOEVENT_CLOSED:
191             userclient_close(client);
192             break;
193         default:
194             break;
195     }
196 }