purple: don't use PurpleXfer.fd
[siplcs.git] / src / purple / purple-ft.c
blobf8eefa630e0cc02267ec14ab042e39b1e223e251
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_DATA purple_xfer_get_protocol_data(xfer)
56 #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))))
57 #else
58 #define PURPLE_XFER_DATA xfer->data
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 #endif
62 #define PURPLE_XFER_TO_SIPE_FILE_TRANSFER ((struct sipe_file_transfer *) PURPLE_XFER_DATA)
64 void sipe_backend_ft_error(struct sipe_file_transfer *ft,
65 const char *errmsg)
67 PurpleXfer *xfer = FT_TO_PURPLE_XFER;
68 purple_xfer_error(purple_xfer_get_type(xfer),
69 purple_xfer_get_account(xfer),
70 purple_xfer_get_remote_user(xfer),
71 errmsg);
74 const gchar *sipe_backend_ft_get_error(SIPE_UNUSED_PARAMETER struct sipe_file_transfer *ft)
76 return strerror(errno);
79 void sipe_backend_ft_deallocate(struct sipe_file_transfer *ft)
81 PurpleXfer *xfer = FT_TO_PURPLE_XFER;
82 PurpleXferStatusType status = purple_xfer_get_status(xfer);
84 // If file transfer is not finished, cancel it
85 if ( status != PURPLE_XFER_STATUS_DONE
86 && status != PURPLE_XFER_STATUS_CANCEL_LOCAL
87 && status != PURPLE_XFER_STATUS_CANCEL_REMOTE) {
88 purple_xfer_set_cancel_recv_fnc(xfer, NULL);
89 purple_xfer_set_cancel_send_fnc(xfer, NULL);
90 purple_xfer_cancel_remote(xfer);
94 gssize sipe_backend_ft_read(struct sipe_file_transfer *ft,
95 guchar *data,
96 gsize size)
98 gssize bytes_read = read(purple_xfer_get_fd(FT_TO_PURPLE_XFER),
99 data,
100 size);
101 if (bytes_read == 0) {
102 /* Sender canceled transfer before it was finished */
103 return -2;
104 } else if (bytes_read == -1) {
105 if (errno == EAGAIN)
106 return 0;
107 else
108 return -1;
110 return bytes_read;
113 gssize sipe_backend_ft_write(struct sipe_file_transfer *ft,
114 const guchar *data,
115 gsize size)
117 gssize bytes_written = write(purple_xfer_get_fd(FT_TO_PURPLE_XFER),
118 data,
119 size);
120 if (bytes_written == -1) {
121 if (errno == EAGAIN)
122 return 0;
123 else
124 return -1;
126 return bytes_written;
129 void sipe_backend_ft_cancel_local(struct sipe_file_transfer *ft)
131 purple_xfer_cancel_local(FT_TO_PURPLE_XFER);
134 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer *ft)
136 purple_xfer_cancel_remote(FT_TO_PURPLE_XFER);
139 static void
140 ft_free_xfer_struct(PurpleXfer *xfer)
142 struct sipe_file_transfer *ft = PURPLE_XFER_TO_SIPE_FILE_TRANSFER;
144 if (ft) {
145 if (xfer->watcher) {
146 purple_input_remove(xfer->watcher);
147 xfer->watcher = 0;
149 sipe_core_ft_deallocate(ft);
150 PURPLE_XFER_DATA = NULL;
154 static void
155 ft_request_denied(PurpleXfer *xfer)
157 if (xfer->type == PURPLE_XFER_RECEIVE)
158 sipe_core_ft_cancel(PURPLE_XFER_TO_SIPE_FILE_TRANSFER);
159 ft_free_xfer_struct(xfer);
162 static void
163 ft_incoming_init(PurpleXfer *xfer)
165 sipe_core_ft_incoming_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER);
168 static void
169 tftp_incoming_start(PurpleXfer *xfer)
171 sipe_core_tftp_incoming_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
172 xfer->size);
175 static void
176 tftp_incoming_stop(PurpleXfer *xfer)
178 if (sipe_core_tftp_incoming_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER)) {
179 /* We're done with this transfer */
180 ft_free_xfer_struct(xfer);
181 } else {
182 unlink(xfer->local_filename);
186 static gssize
187 tftp_read(guchar **buffer, PurpleXfer *xfer)
189 return sipe_core_tftp_read(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
190 buffer,
191 purple_xfer_get_bytes_remaining(xfer),
192 xfer->current_buffer_size);
195 static void
196 ft_outgoing_init(PurpleXfer *xfer)
198 sipe_core_ft_outgoing_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
199 purple_xfer_get_filename(xfer),
200 purple_xfer_get_size(xfer),
201 purple_xfer_get_remote_user(xfer));
204 static void
205 tftp_outgoing_start(PurpleXfer *xfer)
207 /* Set socket to non-blocking mode */
208 int flags = fcntl(purple_xfer_get_fd(xfer), F_GETFL, 0);
209 if (flags == -1)
210 flags = 0;
211 /* @TODO: ignoring potential error return - how to handle? */
212 (void) fcntl(purple_xfer_get_fd(xfer), F_SETFL, flags | O_NONBLOCK);
214 sipe_core_tftp_outgoing_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
215 xfer->size);
218 static void
219 tftp_outgoing_stop(PurpleXfer *xfer)
221 if (sipe_core_tftp_outgoing_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER)) {
222 /* We're done with this transfer */
223 ft_free_xfer_struct(xfer);
227 static gssize
228 tftp_write(const guchar *buffer, size_t size, PurpleXfer *xfer)
230 gssize bytes_written = sipe_core_tftp_write(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
231 buffer, size);
233 if ((xfer->bytes_remaining - bytes_written) == 0)
234 purple_xfer_set_completed(xfer, TRUE);
236 return bytes_written;
239 //******************************************************************************
241 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
242 struct sipe_file_transfer *ft,
243 const gchar *who,
244 const gchar *file_name,
245 gsize file_size)
247 struct sipe_backend_private *purple_private = sipe_public->backend_private;
248 PurpleXfer *xfer;
250 xfer = purple_xfer_new(purple_private->account,
251 PURPLE_XFER_RECEIVE,
252 who);
254 if (xfer) {
255 ft->backend_private = (struct sipe_backend_file_transfer *)xfer;
256 PURPLE_XFER_DATA = ft;
258 purple_xfer_set_filename(xfer, file_name);
259 purple_xfer_set_size(xfer, file_size);
261 purple_xfer_set_init_fnc(xfer, ft_incoming_init);
262 purple_xfer_set_request_denied_fnc(xfer, ft_request_denied);
263 purple_xfer_set_cancel_send_fnc(xfer, ft_free_xfer_struct);
264 purple_xfer_set_cancel_recv_fnc(xfer, ft_free_xfer_struct);
265 purple_xfer_set_start_fnc(xfer, tftp_incoming_start);
266 purple_xfer_set_end_fnc(xfer, tftp_incoming_stop);
267 purple_xfer_set_read_fnc(xfer, tftp_read);
269 purple_xfer_request(xfer);
273 static void
274 connect_cb(gpointer data, gint fd, SIPE_UNUSED_PARAMETER const gchar *error_message)
276 struct sipe_file_transfer *ft = data;
278 if (fd < 0) {
279 purple_xfer_cancel_local(FT_TO_PURPLE_XFER);
280 return;
283 purple_xfer_start(FT_TO_PURPLE_XFER, fd, NULL, 0);
286 void
287 sipe_backend_ft_start(struct sipe_file_transfer *ft, struct sipe_backend_fd *fd,
288 const char* ip, unsigned port)
290 if (ip && port && !sipe_backend_ft_is_incoming(ft)) {
291 /* Purple accepts ip & port only for incoming file transfers.
292 * If we want to send file with Sender-Connect = TRUE negotiated,
293 * we have to open the connection ourselves and pass the file
294 * descriptor to purple_xfer_start. */
295 purple_proxy_connect(NULL,
296 purple_xfer_get_account(FT_TO_PURPLE_XFER),
298 port,
299 connect_cb,
300 ft);
301 return;
304 purple_xfer_start(FT_TO_PURPLE_XFER, fd ? fd->fd : -1, ip, port);
307 void sipe_purple_ft_send_file(PurpleConnection *gc,
308 const char *who,
309 const char *file)
311 PurpleXfer *xfer = sipe_purple_ft_new_xfer(gc, who);
313 if (xfer) {
314 if (file != NULL)
315 purple_xfer_request_accepted(xfer, file);
316 else
317 purple_xfer_request(xfer);
321 PurpleXfer *sipe_purple_ft_new_xfer(PurpleConnection *gc, const char *who)
323 PurpleXfer *xfer = NULL;
325 if (PURPLE_CONNECTION_IS_VALID(gc)) {
326 xfer = purple_xfer_new(purple_connection_get_account(gc),
327 PURPLE_XFER_SEND, who);
329 if (xfer) {
330 struct sipe_file_transfer *ft = sipe_core_ft_allocate(PURPLE_GC_TO_SIPE_CORE_PUBLIC);
332 ft->backend_private = (struct sipe_backend_file_transfer *)xfer;
333 PURPLE_XFER_DATA = ft;
335 purple_xfer_set_init_fnc(xfer, ft_outgoing_init);
336 purple_xfer_set_request_denied_fnc(xfer, ft_request_denied);
337 purple_xfer_set_cancel_send_fnc(xfer, ft_free_xfer_struct);
338 purple_xfer_set_cancel_recv_fnc(xfer, ft_free_xfer_struct);
339 purple_xfer_set_start_fnc(xfer, tftp_outgoing_start);
340 purple_xfer_set_end_fnc(xfer, tftp_outgoing_stop);
341 purple_xfer_set_write_fnc(xfer, tftp_write);
345 return xfer;
348 gboolean
349 sipe_backend_ft_is_incoming(struct sipe_file_transfer *ft)
351 return purple_xfer_get_type(FT_TO_PURPLE_XFER) == PURPLE_XFER_RECEIVE;
355 Local Variables:
356 mode: c
357 c-file-style: "bsd"
358 indent-tabs-mode: t
359 tab-width: 8
360 End: