| |
1 /** |
| |
2 * @file sslconn.c SSL API |
| |
3 * @ingroup core |
| |
4 * |
| |
5 * purple |
| |
6 * |
| |
7 * Purple is the legal property of its developers, whose names are too numerous |
| |
8 * to list here. Please refer to the COPYRIGHT file distributed with this |
| |
9 * source distribution. |
| |
10 * |
| |
11 * This program is free software; you can redistribute it and/or modify |
| |
12 * it under the terms of the GNU General Public License as published by |
| |
13 * the Free Software Foundation; either version 2 of the License, or |
| |
14 * (at your option) any later version. |
| |
15 * |
| |
16 * This program is distributed in the hope that it will be useful, |
| |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
19 * GNU General Public License for more details. |
| |
20 * |
| |
21 * You should have received a copy of the GNU General Public License |
| |
22 * along with this program; if not, write to the Free Software |
| |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
24 */ |
| |
25 #include "internal.h" |
| |
26 |
| |
27 #include "debug.h" |
| |
28 #include "sslconn.h" |
| |
29 |
| |
30 static gboolean _ssl_initialized = FALSE; |
| |
31 static PurpleSslOps *_ssl_ops = NULL; |
| |
32 |
| |
33 static gboolean |
| |
34 ssl_init(void) |
| |
35 { |
| |
36 PurplePlugin *plugin; |
| |
37 PurpleSslOps *ops; |
| |
38 |
| |
39 if (_ssl_initialized) |
| |
40 return FALSE; |
| |
41 |
| |
42 plugin = purple_plugins_find_with_id("core-ssl"); |
| |
43 |
| |
44 if (plugin != NULL && !purple_plugin_is_loaded(plugin)) |
| |
45 purple_plugin_load(plugin); |
| |
46 |
| |
47 ops = purple_ssl_get_ops(); |
| |
48 if ((ops == NULL) || (ops->init == NULL) || (ops->uninit == NULL) || |
| |
49 (ops->connectfunc == NULL) || (ops->close == NULL) || |
| |
50 (ops->read == NULL) || (ops->write == NULL)) |
| |
51 { |
| |
52 return FALSE; |
| |
53 } |
| |
54 |
| |
55 return ops->init(); |
| |
56 } |
| |
57 |
| |
58 gboolean |
| |
59 purple_ssl_is_supported(void) |
| |
60 { |
| |
61 #ifdef HAVE_SSL |
| |
62 ssl_init(); |
| |
63 return (purple_ssl_get_ops() != NULL); |
| |
64 #else |
| |
65 return FALSE; |
| |
66 #endif |
| |
67 } |
| |
68 |
| |
69 static void |
| |
70 purple_ssl_connect_cb(gpointer data, gint source, const gchar *error_message) |
| |
71 { |
| |
72 PurpleSslConnection *gsc; |
| |
73 PurpleSslOps *ops; |
| |
74 |
| |
75 gsc = data; |
| |
76 gsc->connect_data = NULL; |
| |
77 |
| |
78 if (source < 0) |
| |
79 { |
| |
80 if (gsc->error_cb != NULL) |
| |
81 gsc->error_cb(gsc, PURPLE_SSL_CONNECT_FAILED, gsc->connect_cb_data); |
| |
82 |
| |
83 purple_ssl_close(gsc); |
| |
84 return; |
| |
85 } |
| |
86 |
| |
87 gsc->fd = source; |
| |
88 |
| |
89 ops = purple_ssl_get_ops(); |
| |
90 ops->connectfunc(gsc); |
| |
91 } |
| |
92 |
| |
93 PurpleSslConnection * |
| |
94 purple_ssl_connect(PurpleAccount *account, const char *host, int port, |
| |
95 PurpleSslInputFunction func, PurpleSslErrorFunction error_func, |
| |
96 void *data) |
| |
97 { |
| |
98 PurpleSslConnection *gsc; |
| |
99 |
| |
100 g_return_val_if_fail(host != NULL, NULL); |
| |
101 g_return_val_if_fail(port != 0 && port != -1, NULL); |
| |
102 g_return_val_if_fail(func != NULL, NULL); |
| |
103 g_return_val_if_fail(purple_ssl_is_supported(), NULL); |
| |
104 |
| |
105 if (!_ssl_initialized) |
| |
106 { |
| |
107 if (!ssl_init()) |
| |
108 return NULL; |
| |
109 } |
| |
110 |
| |
111 gsc = g_new0(PurpleSslConnection, 1); |
| |
112 |
| |
113 gsc->fd = -1; |
| |
114 gsc->host = g_strdup(host); |
| |
115 gsc->port = port; |
| |
116 gsc->connect_cb_data = data; |
| |
117 gsc->connect_cb = func; |
| |
118 gsc->error_cb = error_func; |
| |
119 |
| |
120 gsc->connect_data = purple_proxy_connect(NULL, account, host, port, purple_ssl_connect_cb, gsc); |
| |
121 |
| |
122 if (gsc->connect_data == NULL) |
| |
123 { |
| |
124 g_free(gsc->host); |
| |
125 g_free(gsc); |
| |
126 |
| |
127 return NULL; |
| |
128 } |
| |
129 |
| |
130 return (PurpleSslConnection *)gsc; |
| |
131 } |
| |
132 |
| |
133 static void |
| |
134 recv_cb(gpointer data, gint source, PurpleInputCondition cond) |
| |
135 { |
| |
136 PurpleSslConnection *gsc = data; |
| |
137 |
| |
138 gsc->recv_cb(gsc->recv_cb_data, gsc, cond); |
| |
139 } |
| |
140 |
| |
141 void |
| |
142 purple_ssl_input_add(PurpleSslConnection *gsc, PurpleSslInputFunction func, |
| |
143 void *data) |
| |
144 { |
| |
145 g_return_if_fail(func != NULL); |
| |
146 g_return_if_fail(purple_ssl_is_supported()); |
| |
147 |
| |
148 gsc->recv_cb_data = data; |
| |
149 gsc->recv_cb = func; |
| |
150 |
| |
151 gsc->inpa = purple_input_add(gsc->fd, PURPLE_INPUT_READ, recv_cb, gsc); |
| |
152 } |
| |
153 |
| |
154 PurpleSslConnection * |
| |
155 purple_ssl_connect_fd(PurpleAccount *account, int fd, |
| |
156 PurpleSslInputFunction func, |
| |
157 PurpleSslErrorFunction error_func, void *data) |
| |
158 { |
| |
159 PurpleSslConnection *gsc; |
| |
160 PurpleSslOps *ops; |
| |
161 |
| |
162 g_return_val_if_fail(fd != -1, NULL); |
| |
163 g_return_val_if_fail(func != NULL, NULL); |
| |
164 g_return_val_if_fail(purple_ssl_is_supported(), NULL); |
| |
165 |
| |
166 if (!_ssl_initialized) |
| |
167 { |
| |
168 if (!ssl_init()) |
| |
169 return NULL; |
| |
170 } |
| |
171 |
| |
172 gsc = g_new0(PurpleSslConnection, 1); |
| |
173 |
| |
174 gsc->connect_cb_data = data; |
| |
175 gsc->connect_cb = func; |
| |
176 gsc->error_cb = error_func; |
| |
177 gsc->fd = fd; |
| |
178 |
| |
179 ops = purple_ssl_get_ops(); |
| |
180 ops->connectfunc(gsc); |
| |
181 |
| |
182 return (PurpleSslConnection *)gsc; |
| |
183 } |
| |
184 |
| |
185 void |
| |
186 purple_ssl_close(PurpleSslConnection *gsc) |
| |
187 { |
| |
188 PurpleSslOps *ops; |
| |
189 |
| |
190 g_return_if_fail(gsc != NULL); |
| |
191 |
| |
192 ops = purple_ssl_get_ops(); |
| |
193 (ops->close)(gsc); |
| |
194 |
| |
195 if (gsc->connect_data != NULL) |
| |
196 purple_proxy_connect_cancel(gsc->connect_data); |
| |
197 |
| |
198 if (gsc->inpa > 0) |
| |
199 purple_input_remove(gsc->inpa); |
| |
200 |
| |
201 if (gsc->fd >= 0) |
| |
202 close(gsc->fd); |
| |
203 |
| |
204 g_free(gsc->host); |
| |
205 g_free(gsc); |
| |
206 } |
| |
207 |
| |
208 size_t |
| |
209 purple_ssl_read(PurpleSslConnection *gsc, void *data, size_t len) |
| |
210 { |
| |
211 PurpleSslOps *ops; |
| |
212 |
| |
213 g_return_val_if_fail(gsc != NULL, 0); |
| |
214 g_return_val_if_fail(data != NULL, 0); |
| |
215 g_return_val_if_fail(len > 0, 0); |
| |
216 |
| |
217 ops = purple_ssl_get_ops(); |
| |
218 return (ops->read)(gsc, data, len); |
| |
219 } |
| |
220 |
| |
221 size_t |
| |
222 purple_ssl_write(PurpleSslConnection *gsc, const void *data, size_t len) |
| |
223 { |
| |
224 PurpleSslOps *ops; |
| |
225 |
| |
226 g_return_val_if_fail(gsc != NULL, 0); |
| |
227 g_return_val_if_fail(data != NULL, 0); |
| |
228 g_return_val_if_fail(len > 0, 0); |
| |
229 |
| |
230 ops = purple_ssl_get_ops(); |
| |
231 return (ops->write)(gsc, data, len); |
| |
232 } |
| |
233 |
| |
234 void |
| |
235 purple_ssl_set_ops(PurpleSslOps *ops) |
| |
236 { |
| |
237 _ssl_ops = ops; |
| |
238 } |
| |
239 |
| |
240 PurpleSslOps * |
| |
241 purple_ssl_get_ops(void) |
| |
242 { |
| |
243 return _ssl_ops; |
| |
244 } |
| |
245 |
| |
246 void |
| |
247 purple_ssl_init(void) |
| |
248 { |
| |
249 } |
| |
250 |
| |
251 void |
| |
252 purple_ssl_uninit(void) |
| |
253 { |
| |
254 PurpleSslOps *ops; |
| |
255 |
| |
256 if (!_ssl_initialized) |
| |
257 return; |
| |
258 |
| |
259 ops = purple_ssl_get_ops(); |
| |
260 ops->uninit(); |
| |
261 |
| |
262 _ssl_initialized = FALSE; |
| |
263 } |