Mercurial > pidgin.yaz
annotate src/protocols/silc/ft.c @ 12312:1c8ea8f3b84e
[gaim-migrate @ 14616]
forgot a line, and infamy
committer: Tailor Script <tailor@pidgin.im>
author | Christopher O'Brien <siege@pidgin.im> |
---|---|
date | Sun, 04 Dec 2005 05:04:39 +0000 |
parents | 4e46eeec4ace |
children | fd606401a8d2 |
rev | line source |
---|---|
8849 | 1 /* |
2 | |
3 silcgaim_ft.c | |
4 | |
5 Author: Pekka Riikonen <priikone@silcnet.org> | |
6 | |
7 Copyright (C) 2004 Pekka Riikonen | |
8 | |
9 This program is free software; you can redistribute it and/or modify | |
10 it under the terms of the GNU General Public License as published by | |
11 the Free Software Foundation; version 2 of the License. | |
12 | |
13 This program is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU General Public License for more details. | |
17 | |
18 */ | |
19 | |
20 #include "silcincludes.h" | |
21 #include "silcclient.h" | |
22 #include "silcgaim.h" | |
23 | |
24 /****************************** File Transfer ********************************/ | |
25 | |
26 /* This implements the secure file transfer protocol (SFTP) using the SILC | |
27 SFTP library implementation. The API we use from the SILC Toolkit is the | |
28 SILC Client file transfer API, as it provides a simple file transfer we | |
29 need in this case. We could use the SILC SFTP API directly, but it would | |
30 be an overkill since we'd effectively re-implement the file transfer what | |
31 the SILC Client's file transfer API already provides. | |
32 | |
33 From Gaim we do NOT use the FT API to do the transfer as it is very limiting. | |
34 In fact it does not suite to file transfers like SFTP at all. For example, | |
35 it assumes that read operations are synchronous what they are not in SFTP. | |
36 It also assumes that the file transfer socket is to be handled by the Gaim | |
37 eventloop, and this naturally is something we don't want to do in case of | |
38 SILC Toolkit. The FT API suites well to purely stream based file transfers | |
39 like HTTP GET and similar. | |
40 | |
41 For this reason, we directly access the Gaim GKT FT API and hack the FT | |
42 API to merely provide the user interface experience and all the magic | |
43 is done in the SILC Toolkit. Ie. we update the statistics information in | |
44 the FT API for user interface, and that's it. A bit dirty but until the | |
45 FT API gets better this is the way to go. Good thing that FT API allowed | |
46 us to do this. */ | |
47 | |
48 typedef struct { | |
49 SilcGaim sg; | |
50 SilcClientEntry client_entry; | |
51 SilcUInt32 session_id; | |
52 char *hostname; | |
53 SilcUInt16 port; | |
54 GaimXfer *xfer; | |
55 | |
56 SilcClientFileName completion; | |
57 void *completion_context; | |
58 } *SilcGaimXfer; | |
59 | |
60 static void | |
61 silcgaim_ftp_monitor(SilcClient client, | |
62 SilcClientConnection conn, | |
63 SilcClientMonitorStatus status, | |
64 SilcClientFileError error, | |
65 SilcUInt64 offset, | |
66 SilcUInt64 filesize, | |
67 SilcClientEntry client_entry, | |
68 SilcUInt32 session_id, | |
69 const char *filepath, | |
70 void *context) | |
71 { | |
72 SilcGaimXfer xfer = context; | |
73 GaimConnection *gc = xfer->sg->gc; | |
74 char tmp[256]; | |
75 | |
76 if (status == SILC_CLIENT_FILE_MONITOR_CLOSED) { | |
77 gaim_xfer_unref(xfer->xfer); | |
78 silc_free(xfer); | |
79 return; | |
80 } | |
81 | |
82 if (status == SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT) | |
83 return; | |
84 | |
85 if (status == SILC_CLIENT_FILE_MONITOR_ERROR) { | |
86 if (error == SILC_CLIENT_FILE_NO_SUCH_FILE) { | |
87 g_snprintf(tmp, sizeof(tmp), "No such file %s", | |
88 filepath ? filepath : "[N/A]"); | |
89 gaim_notify_error(gc, _("Secure File Transfer"), | |
90 _("Error during file transfer"), tmp); | |
91 } else if (error == SILC_CLIENT_FILE_PERMISSION_DENIED) { | |
92 gaim_notify_error(gc, _("Secure File Transfer"), | |
93 _("Error during file transfer"), | |
94 _("Permission denied")); | |
95 } else if (error == SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED) { | |
96 gaim_notify_error(gc, _("Secure File Transfer"), | |
97 _("Error during file transfer"), | |
98 _("Key agreement failed")); | |
99 } else if (error == SILC_CLIENT_FILE_UNKNOWN_SESSION) { | |
100 gaim_notify_error(gc, _("Secure File Transfer"), | |
101 _("Error during file transfer"), | |
10254 | 102 _("File transfer session does not exist")); |
8849 | 103 } else { |
104 gaim_notify_error(gc, _("Secure File Transfer"), | |
105 _("Error during file transfer"), NULL); | |
106 } | |
107 silc_client_file_close(client, conn, session_id); | |
108 gaim_xfer_unref(xfer->xfer); | |
109 silc_free(xfer); | |
110 return; | |
111 } | |
112 | |
113 /* Update file transfer UI */ | |
114 if (!offset && filesize) | |
115 gaim_xfer_set_size(xfer->xfer, filesize); | |
116 if (offset && filesize) { | |
117 xfer->xfer->bytes_sent = offset; | |
118 xfer->xfer->bytes_remaining = filesize - offset; | |
119 } | |
120 gaim_xfer_update_progress(xfer->xfer); | |
121 | |
122 if (status == SILC_CLIENT_FILE_MONITOR_SEND || | |
123 status == SILC_CLIENT_FILE_MONITOR_RECEIVE) { | |
124 if (offset == filesize) { | |
125 /* Download finished */ | |
126 gaim_xfer_set_completed(xfer->xfer, TRUE); | |
127 silc_client_file_close(client, conn, session_id); | |
128 } | |
129 } | |
130 } | |
131 | |
132 static void | |
133 silcgaim_ftp_cancel(GaimXfer *x) | |
134 { | |
135 SilcGaimXfer xfer = x->data; | |
136 xfer->xfer->status = GAIM_XFER_STATUS_CANCEL_LOCAL; | |
137 gaim_xfer_update_progress(xfer->xfer); | |
138 silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); | |
139 } | |
140 | |
141 static void | |
142 silcgaim_ftp_ask_name_cancel(GaimXfer *x) | |
143 { | |
144 SilcGaimXfer xfer = x->data; | |
145 | |
146 /* Cancel the transmission */ | |
147 xfer->completion(NULL, xfer->completion_context); | |
148 silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); | |
149 } | |
150 | |
151 static void | |
152 silcgaim_ftp_ask_name_ok(GaimXfer *x) | |
153 { | |
154 SilcGaimXfer xfer = x->data; | |
155 const char *name; | |
156 | |
157 name = gaim_xfer_get_local_filename(x); | |
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10254
diff
changeset
|
158 g_unlink(name); |
8849 | 159 xfer->completion(name, xfer->completion_context); |
160 } | |
161 | |
162 static void | |
163 silcgaim_ftp_ask_name(SilcClient client, | |
164 SilcClientConnection conn, | |
165 SilcUInt32 session_id, | |
166 const char *remote_filename, | |
167 SilcClientFileName completion, | |
168 void *completion_context, | |
169 void *context) | |
170 { | |
171 SilcGaimXfer xfer = context; | |
172 | |
173 xfer->completion = completion; | |
174 xfer->completion_context = completion_context; | |
175 | |
176 gaim_xfer_set_init_fnc(xfer->xfer, silcgaim_ftp_ask_name_ok); | |
177 gaim_xfer_set_request_denied_fnc(xfer->xfer, silcgaim_ftp_ask_name_cancel); | |
178 | |
179 /* Request to save the file */ | |
180 gaim_xfer_set_filename(xfer->xfer, remote_filename); | |
181 gaim_xfer_request(xfer->xfer); | |
182 } | |
183 | |
184 static void | |
185 silcgaim_ftp_request_result(GaimXfer *x) | |
186 { | |
187 SilcGaimXfer xfer = x->data; | |
188 SilcClientFileError status; | |
189 GaimConnection *gc = xfer->sg->gc; | |
190 | |
191 if (gaim_xfer_get_status(x) != GAIM_XFER_STATUS_ACCEPTED) | |
192 return; | |
193 | |
194 /* Start the file transfer */ | |
195 status = silc_client_file_receive(xfer->sg->client, xfer->sg->conn, | |
196 silcgaim_ftp_monitor, xfer, | |
197 NULL, xfer->session_id, | |
198 silcgaim_ftp_ask_name, xfer); | |
199 switch (status) { | |
200 case SILC_CLIENT_FILE_OK: | |
201 return; | |
202 break; | |
203 | |
204 case SILC_CLIENT_FILE_UNKNOWN_SESSION: | |
205 gaim_notify_error(gc, _("Secure File Transfer"), | |
206 _("No file transfer session active"), NULL); | |
207 break; | |
208 | |
209 case SILC_CLIENT_FILE_ALREADY_STARTED: | |
210 gaim_notify_error(gc, _("Secure File Transfer"), | |
211 _("File transfer already started"), NULL); | |
212 break; | |
213 | |
214 case SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED: | |
215 gaim_notify_error(gc, _("Secure File Transfer"), | |
216 _("Could not perform key agreement for file transfer"), | |
217 NULL); | |
218 break; | |
219 | |
220 default: | |
221 gaim_notify_error(gc, _("Secure File Transfer"), | |
222 _("Could not start the file transfer"), NULL); | |
223 break; | |
224 } | |
225 | |
226 /* Error */ | |
227 gaim_xfer_unref(xfer->xfer); | |
228 g_free(xfer->hostname); | |
229 silc_free(xfer); | |
230 } | |
231 | |
232 static void | |
233 silcgaim_ftp_request_denied(GaimXfer *x) | |
234 { | |
235 | |
236 } | |
237 | |
238 void silcgaim_ftp_request(SilcClient client, SilcClientConnection conn, | |
239 SilcClientEntry client_entry, SilcUInt32 session_id, | |
240 const char *hostname, SilcUInt16 port) | |
241 { | |
242 GaimConnection *gc = client->application; | |
243 SilcGaim sg = gc->proto_data; | |
244 SilcGaimXfer xfer; | |
245 | |
246 xfer = silc_calloc(1, sizeof(*xfer)); | |
247 if (!xfer) { | |
248 silc_client_file_close(sg->client, sg->conn, xfer->session_id); | |
249 return; | |
250 } | |
251 | |
252 xfer->sg = sg; | |
253 xfer->client_entry = client_entry; | |
254 xfer->session_id = session_id; | |
255 xfer->hostname = g_strdup(hostname); | |
256 xfer->port = port; | |
257 xfer->xfer = gaim_xfer_new(xfer->sg->account, GAIM_XFER_RECEIVE, | |
258 xfer->client_entry->nickname); | |
259 if (!xfer->xfer) { | |
260 silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); | |
261 g_free(xfer->hostname); | |
262 silc_free(xfer); | |
263 return; | |
264 } | |
265 gaim_xfer_set_init_fnc(xfer->xfer, silcgaim_ftp_request_result); | |
266 gaim_xfer_set_request_denied_fnc(xfer->xfer, silcgaim_ftp_request_denied); | |
267 gaim_xfer_set_cancel_recv_fnc(xfer->xfer, silcgaim_ftp_cancel); | |
268 xfer->xfer->remote_ip = g_strdup(hostname); | |
269 xfer->xfer->remote_port = port; | |
270 xfer->xfer->data = xfer; | |
271 | |
272 /* File transfer request */ | |
273 gaim_xfer_request(xfer->xfer); | |
274 } | |
275 | |
276 static void | |
277 silcgaim_ftp_send_cancel(GaimXfer *x) | |
278 { | |
279 SilcGaimXfer xfer = x->data; | |
280 silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); | |
281 gaim_xfer_unref(xfer->xfer); | |
282 g_free(xfer->hostname); | |
283 silc_free(xfer); | |
284 } | |
285 | |
286 static void | |
287 silcgaim_ftp_send(GaimXfer *x) | |
288 { | |
289 SilcGaimXfer xfer = x->data; | |
290 const char *name; | |
8910 | 291 char *local_ip = NULL, *remote_ip = NULL; |
8849 | 292 gboolean local = TRUE; |
293 | |
294 name = gaim_xfer_get_local_filename(x); | |
295 | |
296 /* Do the same magic what we do with key agreement (see silcgaim_buddy.c) | |
297 to see if we are behind NAT. */ | |
298 if (silc_net_check_local_by_sock(xfer->sg->conn->sock->sock, | |
299 NULL, &local_ip)) { | |
300 /* Check if the IP is private */ | |
301 if (silcgaim_ip_is_private(local_ip)) { | |
302 local = FALSE; | |
303 /* Local IP is private, resolve the remote server IP to see whether | |
304 we are talking to Internet or just on LAN. */ | |
305 if (silc_net_check_host_by_sock(xfer->sg->conn->sock->sock, NULL, | |
306 &remote_ip)) | |
307 if (silcgaim_ip_is_private(remote_ip)) | |
308 /* We assume we are in LAN. Let's provide the connection point. */ | |
309 local = TRUE; | |
310 } | |
311 } | |
312 | |
313 if (local && !local_ip) | |
314 local_ip = silc_net_localip(); | |
315 | |
316 /* Send the file */ | |
317 silc_client_file_send(xfer->sg->client, xfer->sg->conn, | |
318 silcgaim_ftp_monitor, xfer, | |
319 local_ip, 0, !local, xfer->client_entry, | |
320 name, &xfer->session_id); | |
321 | |
322 silc_free(local_ip); | |
323 silc_free(remote_ip); | |
324 } | |
325 | |
326 static void | |
327 silcgaim_ftp_send_file_resolved(SilcClient client, | |
328 SilcClientConnection conn, | |
329 SilcClientEntry *clients, | |
330 SilcUInt32 clients_count, | |
331 void *context) | |
332 { | |
333 GaimConnection *gc = client->application; | |
334 char tmp[256]; | |
335 | |
336 if (!clients) { | |
337 g_snprintf(tmp, sizeof(tmp), | |
338 _("User %s is not present in the network"), | |
339 (const char *)context); | |
340 gaim_notify_error(gc, _("Secure File Transfer"), | |
341 _("Cannot send file"), tmp); | |
342 silc_free(context); | |
343 return; | |
344 } | |
345 | |
9466 | 346 silcgaim_ftp_send_file(client->application, (const char *)context, NULL); |
8849 | 347 silc_free(context); |
348 } | |
349 | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
350 GaimXfer *silcgaim_ftp_new_xfer(GaimConnection *gc, const char *name) |
8849 | 351 { |
352 SilcGaim sg = gc->proto_data; | |
353 SilcClient client = sg->client; | |
354 SilcClientConnection conn = sg->conn; | |
355 SilcClientEntry *clients; | |
356 SilcUInt32 clients_count; | |
357 SilcGaimXfer xfer; | |
358 char *nickname; | |
359 | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
360 g_return_val_if_fail(name != NULL, NULL); |
8849 | 361 |
362 if (!silc_parse_userfqdn(name, &nickname, NULL)) | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
363 return NULL; |
8849 | 364 |
365 /* Find client entry */ | |
366 clients = silc_client_get_clients_local(client, conn, nickname, name, | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
367 &clients_count); |
8849 | 368 if (!clients) { |
369 silc_client_get_clients(client, conn, nickname, NULL, | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
370 silcgaim_ftp_send_file_resolved, |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
371 strdup(name)); |
8849 | 372 silc_free(nickname); |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
373 return NULL; |
8849 | 374 } |
375 | |
376 xfer = silc_calloc(1, sizeof(*xfer)); | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
377 |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
378 g_return_val_if_fail(xfer != NULL, NULL); |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
379 |
8849 | 380 xfer->sg = sg; |
381 xfer->client_entry = clients[0]; | |
382 xfer->xfer = gaim_xfer_new(xfer->sg->account, GAIM_XFER_SEND, | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
383 xfer->client_entry->nickname); |
8849 | 384 if (!xfer->xfer) { |
385 silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); | |
386 g_free(xfer->hostname); | |
387 silc_free(xfer); | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
388 return NULL; |
8849 | 389 } |
390 gaim_xfer_set_init_fnc(xfer->xfer, silcgaim_ftp_send); | |
391 gaim_xfer_set_request_denied_fnc(xfer->xfer, silcgaim_ftp_request_denied); | |
392 gaim_xfer_set_cancel_send_fnc(xfer->xfer, silcgaim_ftp_send_cancel); | |
393 xfer->xfer->data = xfer; | |
394 | |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
395 silc_free(clients); |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
396 silc_free(nickname); |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
397 |
12149
4e46eeec4ace
[gaim-migrate @ 14450]
Richard Laager <rlaager@wiktel.com>
parents:
12143
diff
changeset
|
398 return xfer->xfer; |
12143
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
399 } |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
400 |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
401 void silcgaim_ftp_send_file(GaimConnection *gc, const char *name, const char *file) |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
402 { |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
403 GaimXfer *xfer = silcgaim_ftp_new_xfer(gc, name); |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
404 |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
405 g_return_if_fail(xfer != NULL); |
cbebda5f019c
[gaim-migrate @ 14444]
Richard Laager <rlaager@wiktel.com>
parents:
11015
diff
changeset
|
406 |
8849 | 407 /* Choose file to send */ |
9466 | 408 if (file) |
12149
4e46eeec4ace
[gaim-migrate @ 14450]
Richard Laager <rlaager@wiktel.com>
parents:
12143
diff
changeset
|
409 gaim_xfer_request_accepted(xfer, file); |
9466 | 410 else |
12149
4e46eeec4ace
[gaim-migrate @ 14450]
Richard Laager <rlaager@wiktel.com>
parents:
12143
diff
changeset
|
411 gaim_xfer_request(xfer); |
8849 | 412 } |