added SSL backend for IOMultiplexer
[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         if(client->user)
60             usersession_client_close(client->user);
61     } else {
62         struct UserLogin *login = client->user;
63         if(client->flags & USERCLIENT_LOGIN_PROCESSING) {
64             usersession_login_abort(login);
65         }
66         if(login->username)
67             free(login->username);
68         if(login->realname)
69             free(login->realname);
70         if(login->password)
71             free(login->password);
72         if(login->nick)
73             free(login->nick);
74         if(login->reject_reason)
75             free(login->reject_reason);
76         if(login->session_class)
77             free(login->session_class);
78         if(login->bind_address)
79             free(login->bind_address);
80         if(login->server_address)
81             free(login->server_address);
82         free(login);
83     }
84     iohandler_close(client->iofd);
85     client->server->clientcount--;
86     if(client->prev)
87         client->prev->next = client->next;
88     else
89         userclients = client->next;
90     if(client->next)
91         client->next->prev = client->prev;
92     
93     free(client);
94 }
95
96 void userclient_close_server(struct ServerSocket *server, int keep_clients) {
97     struct UserClient *client, *next_client;
98     for(client = userclients; client; client = next_client) {
99         next_client = client->next;
100         if(client->server == server) {
101             if(keep_clients)
102                 client->server = NULL;
103             else
104                 userclient_close(client);
105         }
106     }
107 }
108
109 static void userclient_recv(struct UserClient *client, char *line) {
110     if(!stricmplen(line, "TRANSIRC ", 9)) {
111         /*
112         char *argv[MAXNUMPARAMS];
113         int argc = parse_line(line, argv, 1);
114         */
115         
116         return;
117     } else if(!(client->flags & USERCLIENT_LOGGED_IN)) {
118         struct UserLogin *login = client->user;
119         char *argv[MAXNUMPARAMS];
120         int argc = parse_line(line, argv, 1);
121         if(argc < 3) return;
122         if(!stricmp(argv[1], "PASS")) {
123             char *delimiter = strchr(argv[2], ':');
124             if(login->password)
125                 free(login->password);
126             if(delimiter) {
127                 *delimiter = '\0';
128                 delimiter++;
129                 if(login->username)
130                     free(login->username);
131                 login->username = strdup(argv[2]);
132                 login->password = strdup(delimiter);
133             } else 
134                 login->password = strdup(argv[2]);
135         } else if(!stricmp(argv[1], "USER") && argc >= 6) {
136             if(!login->username)
137                 login->username = strdup(argv[2]);
138             login->realname = strdup(argv[5]);
139         } else if(!stricmp(argv[1], "NICK")) {
140             if(login->nick)
141                 free(login->nick);
142             login->nick = strdup(argv[2]);
143             if(!login->password) {
144                 iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] You need to send your LOC data. Try /quote PASS <username>:<password>");
145             }
146         }
147         if(login->username && login->password && login->nick && login->realname && !(client->flags & USERCLIENT_LOGIN_PROCESSING)) {
148             //try to login
149             iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Checking login...");
150             usersession_login(login);
151         }
152     } else {
153         struct UserSession *session = client->user;
154         if(!stricmplen(line, "QUIT", 4))
155             return;
156         
157         if(session->irc)
158             ircclient_send(session->irc, line);
159     }
160 }
161
162 void userclient_login_failed(struct UserLogin *login, char *reason) {
163     iohandler_printf(login->client->iofd, "NOTICE AUTH :*** [TransparentIRC] Login rejected");
164     userclient_close(login->client);
165 }
166
167 void userclient_login_successful(struct UserLogin *login, struct UserSession *session, int recover) {
168     struct UserClient *client = login->client;
169     iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Login accepted.");
170     if(login->username)
171         free(login->username);
172     if(login->password)
173         free(login->password);
174     if(login->nick)
175         free(login->nick);
176     free(login);
177     client->user = session;
178     client->flags |= USERCLIENT_LOGGED_IN;
179     if(recover) {
180         iohandler_printf(client->iofd, "NOTICE AUTH :*** [TransparentIRC] Recovering previous link (Nick: %s).", session->nick);
181         ircclient_recover_session(session);
182     }
183 }
184
185 static void userclient_callback(struct IOEvent *event) {
186     struct UserClient *client = event->iofd->data;
187     switch(event->type) {
188         case IOEVENT_RECV:
189             userclient_recv(client, event->data.recv_str);
190             break;
191         case IOEVENT_CLOSED:
192             userclient_close(client);
193             break;
194         default:
195             break;
196     }
197 }