Merge branch 'mob' of git+ssh://repo.or.cz/srv/git/siplcs into mob
[siplcs.git] / src / purple / purple-ft.c
blobb26c3ff520f92680cf80e3a00afff0ae9099755c
1 /**
2 * @file purple-ft.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2013 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2010 Jakub Adam <jakub.adam@ktknet.cz>
8 * Copyright (C) 2010 Tomáš Hrabčík <tomas.hrabcik@tieto.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 #include <string.h>
30 #include <fcntl.h>
31 #include <errno.h>
33 #include <glib.h>
35 #include "version.h"
36 #if PURPLE_VERSION_CHECK(3,0,0)
37 #include "xfer.h"
38 #define PURPLE_XFER_TO_SIPE_CORE_PUBLIC ((struct sipe_core_public *) purple_connection_get_protocol_data(purple_account_get_connection(purple_xfer_get_account(xfer))))
39 #else
40 #include "ft.h"
41 #define PurpleXferStatus PurpleXferStatusType
42 #define PURPLE_XFER_TO_SIPE_CORE_PUBLIC ((struct sipe_core_public *) purple_account_get_connection(xfer->account)->proto_data)
43 #define PURPLE_XFER_TYPE_RECEIVE PURPLE_XFER_RECEIVE
44 #define PURPLE_XFER_TYPE_SEND PURPLE_XFER_SEND
45 #define purple_xfer_get_fd(xfer) xfer->fd
46 #define purple_xfer_get_protocol_data(xfer) xfer->data
47 #define purple_xfer_get_status(xfer) purple_xfer_get_status(xfer)
48 #define purple_xfer_get_xfer_type(xfer) purple_xfer_get_type(xfer)
49 #define purple_xfer_get_watcher(xfer) xfer->watcher
50 #define purple_xfer_set_protocol_data(xfer, d) xfer->data = d
51 #define purple_xfer_set_watcher(xfer, w) xfer->watcher = w
52 #endif
54 #ifdef _WIN32
55 /* wrappers for write() & friends for socket handling */
56 #include "win32/win32dep.h"
57 #endif
59 #include "sipe-common.h"
60 #include "sipe-backend.h"
61 #include "sipe-core.h"
63 #include "purple-private.h"
65 #define FT_TO_PURPLE_XFER ((PurpleXfer *) ft->backend_private)
66 #define PURPLE_XFER_TO_SIPE_FILE_TRANSFER ((struct sipe_file_transfer *) purple_xfer_get_protocol_data(xfer))
68 void sipe_backend_ft_error(struct sipe_file_transfer *ft,
69 const char *errmsg)
71 PurpleXfer *xfer = FT_TO_PURPLE_XFER;
72 purple_xfer_error(purple_xfer_get_xfer_type(xfer),
73 purple_xfer_get_account(xfer),
74 purple_xfer_get_remote_user(xfer),
75 errmsg);
78 const gchar *sipe_backend_ft_get_error(SIPE_UNUSED_PARAMETER struct sipe_file_transfer *ft)
80 return strerror(errno);
83 void sipe_backend_ft_deallocate(struct sipe_file_transfer *ft)
85 PurpleXfer *xfer = FT_TO_PURPLE_XFER;
86 PurpleXferStatus status = purple_xfer_get_status(xfer);
88 // If file transfer is not finished, cancel it
89 if ( status != PURPLE_XFER_STATUS_DONE
90 && status != PURPLE_XFER_STATUS_CANCEL_LOCAL
91 && status != PURPLE_XFER_STATUS_CANCEL_REMOTE) {
92 purple_xfer_set_cancel_recv_fnc(xfer, NULL);
93 purple_xfer_set_cancel_send_fnc(xfer, NULL);
94 purple_xfer_cancel_remote(xfer);
98 gssize sipe_backend_ft_read(struct sipe_file_transfer *ft,
99 guchar *data,
100 gsize size)
102 gssize bytes_read = read(purple_xfer_get_fd(FT_TO_PURPLE_XFER),
103 data,
104 size);
105 if (bytes_read == 0) {
106 /* Sender canceled transfer before it was finished */
107 return -2;
108 } else if (bytes_read == -1) {
109 if (errno == EAGAIN)
110 return 0;
111 else
112 return -1;
114 return bytes_read;
117 gssize sipe_backend_ft_write(struct sipe_file_transfer *ft,
118 const guchar *data,
119 gsize size)
121 gssize bytes_written = write(purple_xfer_get_fd(FT_TO_PURPLE_XFER),
122 data,
123 size);
124 if (bytes_written == -1) {
125 if (errno == EAGAIN)
126 return 0;
127 else
128 return -1;
130 return bytes_written;
133 void sipe_backend_ft_cancel_local(struct sipe_file_transfer *ft)
135 purple_xfer_cancel_local(FT_TO_PURPLE_XFER);
138 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer *ft)
140 purple_xfer_cancel_remote(FT_TO_PURPLE_XFER);
143 static void
144 ft_free_xfer_struct(PurpleXfer *xfer)
146 struct sipe_file_transfer *ft = PURPLE_XFER_TO_SIPE_FILE_TRANSFER;
148 if (ft) {
149 if (purple_xfer_get_watcher(xfer)) {
150 purple_input_remove(purple_xfer_get_watcher(xfer));
151 purple_xfer_set_watcher(xfer, 0);
153 sipe_core_ft_deallocate(ft);
154 purple_xfer_set_protocol_data(xfer, NULL);
158 static void
159 ft_request_denied(PurpleXfer *xfer)
161 if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE)
162 sipe_core_ft_cancel(PURPLE_XFER_TO_SIPE_FILE_TRANSFER);
163 ft_free_xfer_struct(xfer);
166 static void
167 ft_incoming_init(PurpleXfer *xfer)
169 sipe_core_ft_incoming_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER);
172 static void
173 tftp_incoming_start(PurpleXfer *xfer)
175 sipe_core_tftp_incoming_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
176 purple_xfer_get_size(xfer));
179 static void
180 tftp_incoming_stop(PurpleXfer *xfer)
182 if (sipe_core_tftp_incoming_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER)) {
183 /* We're done with this transfer */
184 ft_free_xfer_struct(xfer);
185 } else {
186 unlink(purple_xfer_get_local_filename(xfer));
190 static gssize tftp_read(guchar **buffer,
191 #if PURPLE_VERSION_CHECK(3,0,0)
192 size_t buffer_size,
193 #endif
194 PurpleXfer *xfer)
196 return sipe_core_tftp_read(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
197 buffer,
198 purple_xfer_get_bytes_remaining(xfer),
199 #if PURPLE_VERSION_CHECK(3,0,0)
200 buffer_size
201 #else
202 xfer->current_buffer_size
203 #endif
207 static void
208 ft_outgoing_init(PurpleXfer *xfer)
210 sipe_core_ft_outgoing_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
211 purple_xfer_get_filename(xfer),
212 purple_xfer_get_size(xfer),
213 purple_xfer_get_remote_user(xfer));
216 static void
217 tftp_outgoing_start(PurpleXfer *xfer)
219 /* Set socket to non-blocking mode */
220 int flags = fcntl(purple_xfer_get_fd(xfer), F_GETFL, 0);
221 if (flags == -1)
222 flags = 0;
223 /* @TODO: ignoring potential error return - how to handle? */
224 (void) fcntl(purple_xfer_get_fd(xfer), F_SETFL, flags | O_NONBLOCK);
226 sipe_core_tftp_outgoing_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
227 purple_xfer_get_size(xfer));
230 static void
231 tftp_outgoing_stop(PurpleXfer *xfer)
233 if (sipe_core_tftp_outgoing_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER)) {
234 /* We're done with this transfer */
235 ft_free_xfer_struct(xfer);
239 static gssize
240 tftp_write(const guchar *buffer, size_t size, PurpleXfer *xfer)
242 gssize bytes_written = sipe_core_tftp_write(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
243 buffer, size);
245 if ((purple_xfer_get_bytes_remaining(xfer) - bytes_written) == 0)
246 purple_xfer_set_completed(xfer, TRUE);
248 return bytes_written;
251 //******************************************************************************
253 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
254 struct sipe_file_transfer *ft,
255 const gchar *who,
256 const gchar *file_name,
257 gsize file_size)
259 struct sipe_backend_private *purple_private = sipe_public->backend_private;
260 PurpleXfer *xfer;
262 xfer = purple_xfer_new(purple_private->account,
263 PURPLE_XFER_TYPE_RECEIVE,
264 who);
266 if (xfer) {
267 ft->backend_private = (struct sipe_backend_file_transfer *)xfer;
268 purple_xfer_set_protocol_data(xfer, ft);
270 purple_xfer_set_filename(xfer, file_name);
271 purple_xfer_set_size(xfer, file_size);
273 purple_xfer_set_init_fnc(xfer, ft_incoming_init);
274 purple_xfer_set_request_denied_fnc(xfer, ft_request_denied);
275 purple_xfer_set_cancel_send_fnc(xfer, ft_free_xfer_struct);
276 purple_xfer_set_cancel_recv_fnc(xfer, ft_free_xfer_struct);
277 purple_xfer_set_start_fnc(xfer, tftp_incoming_start);
278 purple_xfer_set_end_fnc(xfer, tftp_incoming_stop);
279 purple_xfer_set_read_fnc(xfer, tftp_read);
281 purple_xfer_request(xfer);
285 static void
286 connect_cb(gpointer data, gint fd, SIPE_UNUSED_PARAMETER const gchar *error_message)
288 struct sipe_file_transfer *ft = data;
290 if (fd < 0) {
291 purple_xfer_cancel_local(FT_TO_PURPLE_XFER);
292 return;
295 purple_xfer_start(FT_TO_PURPLE_XFER, fd, NULL, 0);
298 void
299 sipe_backend_ft_start(struct sipe_file_transfer *ft, struct sipe_backend_fd *fd,
300 const char* ip, unsigned port)
302 if (ip && port && !sipe_backend_ft_is_incoming(ft)) {
303 /* Purple accepts ip & port only for incoming file transfers.
304 * If we want to send file with Sender-Connect = TRUE negotiated,
305 * we have to open the connection ourselves and pass the file
306 * descriptor to purple_xfer_start. */
307 purple_proxy_connect(NULL,
308 purple_xfer_get_account(FT_TO_PURPLE_XFER),
310 port,
311 connect_cb,
312 ft);
313 return;
316 purple_xfer_start(FT_TO_PURPLE_XFER, fd ? fd->fd : -1, ip, port);
319 void sipe_purple_ft_send_file(PurpleConnection *gc,
320 const char *who,
321 const char *file)
323 PurpleXfer *xfer = sipe_purple_ft_new_xfer(gc, who);
325 if (xfer) {
326 if (file != NULL)
327 purple_xfer_request_accepted(xfer, file);
328 else
329 purple_xfer_request(xfer);
333 PurpleXfer *sipe_purple_ft_new_xfer(PurpleConnection *gc, const char *who)
335 PurpleXfer *xfer = NULL;
337 #if !PURPLE_VERSION_CHECK(3,0,0)
338 if (!PURPLE_CONNECTION_IS_VALID(gc)) {
339 return NULL;
341 #endif
343 xfer = purple_xfer_new(purple_connection_get_account(gc),
344 PURPLE_XFER_TYPE_SEND,
345 who);
347 if (xfer) {
348 struct sipe_file_transfer *ft = sipe_core_ft_allocate(PURPLE_GC_TO_SIPE_CORE_PUBLIC);
350 ft->backend_private = (struct sipe_backend_file_transfer *)xfer;
351 purple_xfer_set_protocol_data(xfer, ft);
353 purple_xfer_set_init_fnc(xfer, ft_outgoing_init);
354 purple_xfer_set_request_denied_fnc(xfer, ft_request_denied);
355 purple_xfer_set_cancel_send_fnc(xfer, ft_free_xfer_struct);
356 purple_xfer_set_cancel_recv_fnc(xfer, ft_free_xfer_struct);
357 purple_xfer_set_start_fnc(xfer, tftp_outgoing_start);
358 purple_xfer_set_end_fnc(xfer, tftp_outgoing_stop);
359 purple_xfer_set_write_fnc(xfer, tftp_write);
362 return xfer;
365 gboolean
366 sipe_backend_ft_is_incoming(struct sipe_file_transfer *ft)
368 return(purple_xfer_get_xfer_type(FT_TO_PURPLE_XFER) == PURPLE_XFER_TYPE_RECEIVE);
372 Local Variables:
373 mode: c
374 c-file-style: "bsd"
375 indent-tabs-mode: t
376 tab-width: 8
377 End: