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
36 #if PURPLE_VERSION_CHECK(3,0,0)
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))))
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
55 /* wrappers for write() & friends for socket handling */
56 #include "win32/win32dep.h"
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
,
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
),
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
,
102 gssize bytes_read
= read(purple_xfer_get_fd(FT_TO_PURPLE_XFER
),
105 if (bytes_read
== 0) {
106 /* Sender canceled transfer before it was finished */
108 } else if (bytes_read
== -1) {
117 gssize
sipe_backend_ft_write(struct sipe_file_transfer
*ft
,
121 gssize bytes_written
= write(purple_xfer_get_fd(FT_TO_PURPLE_XFER
),
124 if (bytes_written
== -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
);
144 ft_free_xfer_struct(PurpleXfer
*xfer
)
146 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
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
);
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
);
167 ft_incoming_init(PurpleXfer
*xfer
)
169 sipe_core_ft_incoming_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
);
173 tftp_incoming_start(PurpleXfer
*xfer
)
175 sipe_core_tftp_incoming_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
,
176 purple_xfer_get_size(xfer
));
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
);
186 unlink(purple_xfer_get_local_filename(xfer
));
190 static gssize
tftp_read(guchar
**buffer
,
191 #if PURPLE_VERSION_CHECK(3,0,0)
196 return sipe_core_tftp_read(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
,
198 purple_xfer_get_bytes_remaining(xfer
),
199 #if PURPLE_VERSION_CHECK(3,0,0)
202 xfer
->current_buffer_size
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
));
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);
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
));
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
);
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
,
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
,
256 const gchar
*file_name
,
259 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
262 xfer
= purple_xfer_new(purple_private
->account
,
263 PURPLE_XFER_TYPE_RECEIVE
,
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
);
286 connect_cb(gpointer data
, gint fd
, SIPE_UNUSED_PARAMETER
const gchar
*error_message
)
288 struct sipe_file_transfer
*ft
= data
;
291 purple_xfer_cancel_local(FT_TO_PURPLE_XFER
);
295 purple_xfer_start(FT_TO_PURPLE_XFER
, fd
, NULL
, 0);
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
),
316 purple_xfer_start(FT_TO_PURPLE_XFER
, fd
? fd
->fd
: -1, ip
, port
);
319 void sipe_purple_ft_send_file(PurpleConnection
*gc
,
323 PurpleXfer
*xfer
= sipe_purple_ft_new_xfer(gc
, who
);
327 purple_xfer_request_accepted(xfer
, file
);
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
)) {
343 xfer
= purple_xfer_new(purple_connection_get_account(gc
),
344 PURPLE_XFER_TYPE_SEND
,
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
);
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
);