purple: update purple-ft for 3.x.x API
[siplcs.git] / src / purple / purple-ft.c
blobeaad7a8709621a7a7d33980d669d1232071d8fcc
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 #else
39 #include "ft.h"
40 #endif
42 #ifdef _WIN32
43 /* wrappers for write() & friends for socket handling */
44 #include "win32/win32dep.h"
45 #endif
47 #include "sipe-common.h"
48 #include "sipe-backend.h"
49 #include "sipe-core.h"
51 #include "purple-private.h"
53 #define FT_TO_PURPLE_XFER ((PurpleXfer *) ft->backend_private)
54 #if PURPLE_VERSION_CHECK(3,0,0)
55 #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))))
56 #else
57 #define purple_xfer_get_protocol_data(xfer) xfer->data
58 #define purple_xfer_set_protocol_data(xfer, d) xfer->data = d
59 #define PURPLE_XFER_TO_SIPE_CORE_PUBLIC ((struct sipe_core_public *) purple_account_get_connection(xfer->account)->proto_data)
60 #define purple_xfer_get_fd(xfer) xfer->fd
61 #define purple_xfer_get_watcher(xfer) xfer->watcher
62 #define purple_xfer_set_watcher(xfer, w) xfer->watcher = w
63 #endif
64 #define PURPLE_XFER_TO_SIPE_FILE_TRANSFER ((struct sipe_file_transfer *) purple_xfer_get_protocol_data(xfer))
66 void sipe_backend_ft_error(struct sipe_file_transfer *ft,
67 const char *errmsg)
69 PurpleXfer *xfer = FT_TO_PURPLE_XFER;
70 purple_xfer_error(
71 #if PURPLE_VERSION_CHECK(3,0,0)
72 purple_xfer_get_xfer_type(xfer),
73 #else
74 purple_xfer_get_type(xfer),
75 #endif
76 purple_xfer_get_account(xfer),
77 purple_xfer_get_remote_user(xfer),
78 errmsg);
81 const gchar *sipe_backend_ft_get_error(SIPE_UNUSED_PARAMETER struct sipe_file_transfer *ft)
83 return strerror(errno);
86 void sipe_backend_ft_deallocate(struct sipe_file_transfer *ft)
88 PurpleXfer *xfer = FT_TO_PURPLE_XFER;
89 #if PURPLE_VERSION_CHECK(3,0,0)
90 PurpleXferStatus status = purple_xfer_get_status(xfer);
91 #else
92 PurpleXferStatusType status = purple_xfer_get_status(xfer);
93 #endif
95 // If file transfer is not finished, cancel it
96 if ( status != PURPLE_XFER_STATUS_DONE
97 && status != PURPLE_XFER_STATUS_CANCEL_LOCAL
98 && status != PURPLE_XFER_STATUS_CANCEL_REMOTE) {
99 purple_xfer_set_cancel_recv_fnc(xfer, NULL);
100 purple_xfer_set_cancel_send_fnc(xfer, NULL);
101 purple_xfer_cancel_remote(xfer);
105 gssize sipe_backend_ft_read(struct sipe_file_transfer *ft,
106 guchar *data,
107 gsize size)
109 gssize bytes_read = read(purple_xfer_get_fd(FT_TO_PURPLE_XFER),
110 data,
111 size);
112 if (bytes_read == 0) {
113 /* Sender canceled transfer before it was finished */
114 return -2;
115 } else if (bytes_read == -1) {
116 if (errno == EAGAIN)
117 return 0;
118 else
119 return -1;
121 return bytes_read;
124 gssize sipe_backend_ft_write(struct sipe_file_transfer *ft,
125 const guchar *data,
126 gsize size)
128 gssize bytes_written = write(purple_xfer_get_fd(FT_TO_PURPLE_XFER),
129 data,
130 size);
131 if (bytes_written == -1) {
132 if (errno == EAGAIN)
133 return 0;
134 else
135 return -1;
137 return bytes_written;
140 void sipe_backend_ft_cancel_local(struct sipe_file_transfer *ft)
142 purple_xfer_cancel_local(FT_TO_PURPLE_XFER);
145 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer *ft)
147 purple_xfer_cancel_remote(FT_TO_PURPLE_XFER);
150 static void
151 ft_free_xfer_struct(PurpleXfer *xfer)
153 struct sipe_file_transfer *ft = PURPLE_XFER_TO_SIPE_FILE_TRANSFER;
155 if (ft) {
156 if (purple_xfer_get_watcher(xfer)) {
157 purple_input_remove(purple_xfer_get_watcher(xfer));
158 purple_xfer_set_watcher(xfer, 0);
160 sipe_core_ft_deallocate(ft);
161 purple_xfer_set_protocol_data(xfer, NULL);
165 static void
166 ft_request_denied(PurpleXfer *xfer)
168 #if PURPLE_VERSION_CHECK(3,0,0)
169 if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE)
170 #else
171 if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE)
172 #endif
173 sipe_core_ft_cancel(PURPLE_XFER_TO_SIPE_FILE_TRANSFER);
174 ft_free_xfer_struct(xfer);
177 static void
178 ft_incoming_init(PurpleXfer *xfer)
180 sipe_core_ft_incoming_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER);
183 static void
184 tftp_incoming_start(PurpleXfer *xfer)
186 sipe_core_tftp_incoming_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
187 purple_xfer_get_size(xfer));
190 static void
191 tftp_incoming_stop(PurpleXfer *xfer)
193 if (sipe_core_tftp_incoming_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER)) {
194 /* We're done with this transfer */
195 ft_free_xfer_struct(xfer);
196 } else {
197 unlink(purple_xfer_get_local_filename(xfer));
201 static gssize
202 tftp_read(guchar **buffer, PurpleXfer *xfer)
204 return sipe_core_tftp_read(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
205 buffer,
206 purple_xfer_get_bytes_remaining(xfer),
207 xfer->current_buffer_size);
210 static void
211 ft_outgoing_init(PurpleXfer *xfer)
213 sipe_core_ft_outgoing_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
214 purple_xfer_get_filename(xfer),
215 purple_xfer_get_size(xfer),
216 purple_xfer_get_remote_user(xfer));
219 static void
220 tftp_outgoing_start(PurpleXfer *xfer)
222 /* Set socket to non-blocking mode */
223 int flags = fcntl(purple_xfer_get_fd(xfer), F_GETFL, 0);
224 if (flags == -1)
225 flags = 0;
226 /* @TODO: ignoring potential error return - how to handle? */
227 (void) fcntl(purple_xfer_get_fd(xfer), F_SETFL, flags | O_NONBLOCK);
229 sipe_core_tftp_outgoing_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
230 purple_xfer_get_size(xfer));
233 static void
234 tftp_outgoing_stop(PurpleXfer *xfer)
236 if (sipe_core_tftp_outgoing_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER)) {
237 /* We're done with this transfer */
238 ft_free_xfer_struct(xfer);
242 static gssize
243 tftp_write(const guchar *buffer, size_t size, PurpleXfer *xfer)
245 gssize bytes_written = sipe_core_tftp_write(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
246 buffer, size);
248 if ((purple_xfer_get_bytes_remaining(xfer) - bytes_written) == 0)
249 purple_xfer_set_completed(xfer, TRUE);
251 return bytes_written;
254 //******************************************************************************
256 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
257 struct sipe_file_transfer *ft,
258 const gchar *who,
259 const gchar *file_name,
260 gsize file_size)
262 struct sipe_backend_private *purple_private = sipe_public->backend_private;
263 PurpleXfer *xfer;
265 xfer = purple_xfer_new(purple_private->account,
266 #if PURPLE_VERSION_CHECK(3,0,0)
267 PURPLE_XFER_TYPE_RECEIVE,
268 #else
269 PURPLE_XFER_RECEIVE,
270 #endif
271 who);
273 if (xfer) {
274 ft->backend_private = (struct sipe_backend_file_transfer *)xfer;
275 purple_xfer_set_protocol_data(xfer, ft);
277 purple_xfer_set_filename(xfer, file_name);
278 purple_xfer_set_size(xfer, file_size);
280 purple_xfer_set_init_fnc(xfer, ft_incoming_init);
281 purple_xfer_set_request_denied_fnc(xfer, ft_request_denied);
282 purple_xfer_set_cancel_send_fnc(xfer, ft_free_xfer_struct);
283 purple_xfer_set_cancel_recv_fnc(xfer, ft_free_xfer_struct);
284 purple_xfer_set_start_fnc(xfer, tftp_incoming_start);
285 purple_xfer_set_end_fnc(xfer, tftp_incoming_stop);
286 purple_xfer_set_read_fnc(xfer, tftp_read);
288 purple_xfer_request(xfer);
292 static void
293 connect_cb(gpointer data, gint fd, SIPE_UNUSED_PARAMETER const gchar *error_message)
295 struct sipe_file_transfer *ft = data;
297 if (fd < 0) {
298 purple_xfer_cancel_local(FT_TO_PURPLE_XFER);
299 return;
302 purple_xfer_start(FT_TO_PURPLE_XFER, fd, NULL, 0);
305 void
306 sipe_backend_ft_start(struct sipe_file_transfer *ft, struct sipe_backend_fd *fd,
307 const char* ip, unsigned port)
309 if (ip && port && !sipe_backend_ft_is_incoming(ft)) {
310 /* Purple accepts ip & port only for incoming file transfers.
311 * If we want to send file with Sender-Connect = TRUE negotiated,
312 * we have to open the connection ourselves and pass the file
313 * descriptor to purple_xfer_start. */
314 purple_proxy_connect(NULL,
315 purple_xfer_get_account(FT_TO_PURPLE_XFER),
317 port,
318 connect_cb,
319 ft);
320 return;
323 purple_xfer_start(FT_TO_PURPLE_XFER, fd ? fd->fd : -1, ip, port);
326 void sipe_purple_ft_send_file(PurpleConnection *gc,
327 const char *who,
328 const char *file)
330 PurpleXfer *xfer = sipe_purple_ft_new_xfer(gc, who);
332 if (xfer) {
333 if (file != NULL)
334 purple_xfer_request_accepted(xfer, file);
335 else
336 purple_xfer_request(xfer);
340 PurpleXfer *sipe_purple_ft_new_xfer(PurpleConnection *gc, const char *who)
342 PurpleXfer *xfer = NULL;
344 if (PURPLE_CONNECTION_IS_VALID(gc)) {
345 xfer = purple_xfer_new(purple_connection_get_account(gc),
346 #if PURPLE_VERSION_CHECK(3,0,0)
347 PURPLE_XFER_TYPE_SEND,
348 #else
349 PURPLE_XFER_SEND,
350 #endif
351 who);
353 if (xfer) {
354 struct sipe_file_transfer *ft = sipe_core_ft_allocate(PURPLE_GC_TO_SIPE_CORE_PUBLIC);
356 ft->backend_private = (struct sipe_backend_file_transfer *)xfer;
357 purple_xfer_set_protocol_data(xfer, ft);
359 purple_xfer_set_init_fnc(xfer, ft_outgoing_init);
360 purple_xfer_set_request_denied_fnc(xfer, ft_request_denied);
361 purple_xfer_set_cancel_send_fnc(xfer, ft_free_xfer_struct);
362 purple_xfer_set_cancel_recv_fnc(xfer, ft_free_xfer_struct);
363 purple_xfer_set_start_fnc(xfer, tftp_outgoing_start);
364 purple_xfer_set_end_fnc(xfer, tftp_outgoing_stop);
365 purple_xfer_set_write_fnc(xfer, tftp_write);
369 return xfer;
372 gboolean
373 sipe_backend_ft_is_incoming(struct sipe_file_transfer *ft)
375 #if PURPLE_VERSION_CHECK(3,0,0)
376 return(purple_xfer_get_xfer_type(FT_TO_PURPLE_XFER) == PURPLE_XFER_TYPE_RECEIVE);
377 #else
378 return(purple_xfer_get_type(FT_TO_PURPLE_XFER) == PURPLE_XFER_RECEIVE);
379 #endif
383 Local Variables:
384 mode: c
385 c-file-style: "bsd"
386 indent-tabs-mode: t
387 tab-width: 8
388 End: