6 * Copyright (C) 2010-2017 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
40 #if PURPLE_VERSION_CHECK(3,0,0)
42 #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))))
45 #define g_timeout_add(t, f, d) purple_timeout_add(t, f, d)
46 #define PurpleXferStatus PurpleXferStatusType
47 #define PURPLE_XFER_TO_SIPE_CORE_PUBLIC ((struct sipe_core_public *) purple_account_get_connection(xfer->account)->proto_data)
48 #define PURPLE_XFER_TYPE_RECEIVE PURPLE_XFER_RECEIVE
49 #define PURPLE_XFER_TYPE_SEND PURPLE_XFER_SEND
50 #define purple_xfer_get_fd(xfer) xfer->fd
51 #define purple_xfer_get_protocol_data(xfer) xfer->data
52 #define purple_xfer_get_status(xfer) purple_xfer_get_status(xfer)
53 #define purple_xfer_get_xfer_type(xfer) purple_xfer_get_type(xfer)
54 #define purple_xfer_get_watcher(xfer) xfer->watcher
55 #define purple_xfer_set_protocol_data(xfer, d) xfer->data = d
56 #define purple_xfer_set_watcher(xfer, w) xfer->watcher = w
60 /* wrappers for write() & friends for socket handling */
61 #include "win32/win32dep.h"
64 #include "sipe-common.h"
65 #include "sipe-backend.h"
66 #include "sipe-core.h"
68 #include "purple-private.h"
70 #define FT_TO_PURPLE_XFER ((PurpleXfer *) ft->backend_private)
71 #define PURPLE_XFER_TO_SIPE_FILE_TRANSFER ((struct sipe_file_transfer *) purple_xfer_get_protocol_data(xfer))
73 void sipe_backend_ft_error(struct sipe_file_transfer
*ft
,
76 PurpleXfer
*xfer
= FT_TO_PURPLE_XFER
;
77 purple_xfer_error(purple_xfer_get_xfer_type(xfer
),
78 purple_xfer_get_account(xfer
),
79 purple_xfer_get_remote_user(xfer
),
83 const gchar
*sipe_backend_ft_get_error(SIPE_UNUSED_PARAMETER
struct sipe_file_transfer
*ft
)
85 return strerror(errno
);
88 void sipe_backend_ft_deallocate(struct sipe_file_transfer
*ft
)
90 PurpleXfer
*xfer
= FT_TO_PURPLE_XFER
;
91 PurpleXferStatus status
= purple_xfer_get_status(xfer
);
93 // If file transfer is not finished, cancel it
94 if ( status
!= PURPLE_XFER_STATUS_DONE
95 && status
!= PURPLE_XFER_STATUS_CANCEL_LOCAL
96 && status
!= PURPLE_XFER_STATUS_CANCEL_REMOTE
) {
97 purple_xfer_set_cancel_recv_fnc(xfer
, NULL
);
98 purple_xfer_set_cancel_send_fnc(xfer
, NULL
);
99 purple_xfer_cancel_remote(xfer
);
103 gssize
sipe_backend_ft_read(struct sipe_file_transfer
*ft
,
107 gssize bytes_read
= read(purple_xfer_get_fd(FT_TO_PURPLE_XFER
),
110 if (bytes_read
== 0) {
111 /* Sender canceled transfer before it was finished */
113 } else if (bytes_read
== -1) {
122 gssize
sipe_backend_ft_write(struct sipe_file_transfer
*ft
,
126 gssize bytes_written
= write(purple_xfer_get_fd(FT_TO_PURPLE_XFER
),
129 if (bytes_written
== -1) {
135 return bytes_written
;
139 end_transfer_cb(gpointer data
)
141 purple_xfer_end((PurpleXfer
*)data
);
146 sipe_backend_ft_set_completed(struct sipe_file_transfer
*ft
)
148 purple_xfer_set_completed(FT_TO_PURPLE_XFER
, TRUE
);
149 g_timeout_add(0, end_transfer_cb
, FT_TO_PURPLE_XFER
);
152 void sipe_backend_ft_cancel_local(struct sipe_file_transfer
*ft
)
154 purple_xfer_cancel_local(FT_TO_PURPLE_XFER
);
157 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer
*ft
)
159 purple_xfer_cancel_remote(FT_TO_PURPLE_XFER
);
163 ft_free_xfer_struct(PurpleXfer
*xfer
)
165 if (purple_xfer_get_watcher(xfer
)) {
166 purple_input_remove(purple_xfer_get_watcher(xfer
));
167 purple_xfer_set_watcher(xfer
, 0);
170 purple_xfer_set_protocol_data(xfer
, NULL
);
174 ft_request_denied(PurpleXfer
*xfer
)
176 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
177 if (ft
->ft_request_denied
) {
178 ft
->ft_request_denied(ft
);
181 ft_free_xfer_struct(xfer
);
185 ft_cancelled(PurpleXfer
*xfer
)
187 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
189 if (ft
->ft_cancelled
&&
190 purple_xfer_get_status(xfer
) == PURPLE_XFER_STATUS_CANCEL_LOCAL
) {
191 ft
->ft_cancelled(ft
);
194 ft_free_xfer_struct(xfer
);
198 ft_init(PurpleXfer
*xfer
)
200 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
201 g_return_if_fail(ft
->ft_init
);
204 purple_xfer_get_filename(xfer
),
205 purple_xfer_get_size(xfer
),
206 purple_xfer_get_remote_user(xfer
));
210 ft_start(PurpleXfer
*xfer
)
212 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
214 if (purple_xfer_get_xfer_type(xfer
) == PURPLE_XFER_TYPE_RECEIVE
) {
215 /* Set socket to non-blocking mode */
216 int flags
= fcntl(purple_xfer_get_fd(xfer
), F_GETFL
, 0);
220 /* @TODO: ignoring potential error return - how to handle? */
221 (void) fcntl(purple_xfer_get_fd(xfer
), F_SETFL
, flags
| O_NONBLOCK
);
225 ft
->ft_start(ft
, purple_xfer_get_size(xfer
));
230 ft_end(PurpleXfer
*xfer
)
232 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
234 if (!ft
->ft_end
|| ft
->ft_end(ft
)) {
235 /* We're done with this transfer */
236 ft_free_xfer_struct(xfer
);
237 } else if (purple_xfer_get_xfer_type(xfer
) == PURPLE_XFER_TYPE_RECEIVE
) {
238 /* Remove incomplete file from failed transfer. */
239 unlink(purple_xfer_get_local_filename(xfer
));
244 ft_read(guchar
**buffer
,
245 #if PURPLE_VERSION_CHECK(3,0,0)
250 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
251 g_return_val_if_fail(ft
->ft_read
, 0);
252 return ft
->ft_read(ft
, buffer
, purple_xfer_get_bytes_remaining(xfer
),
253 #if PURPLE_VERSION_CHECK(3,0,0)
256 xfer
->current_buffer_size
262 ft_write(const guchar
*buffer
, size_t size
, PurpleXfer
*xfer
)
264 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
265 gssize bytes_written
= 0;
267 g_return_val_if_fail(ft
->ft_write
, 0);
269 bytes_written
= ft
->ft_write(ft
, buffer
, size
);
271 if ((purple_xfer_get_bytes_remaining(xfer
) - bytes_written
) == 0)
272 purple_xfer_set_completed(xfer
, TRUE
);
274 return bytes_written
;
278 create_xfer(PurpleAccount
*account
, PurpleXferType type
, const char *who
,
279 struct sipe_file_transfer
*ft
)
281 PurpleXfer
*xfer
= purple_xfer_new(account
, type
, who
);
283 ft
->backend_private
= (struct sipe_backend_file_transfer
*)xfer
;
285 purple_xfer_set_protocol_data(xfer
, ft
);
286 purple_xfer_set_init_fnc(xfer
, ft_init
);
287 purple_xfer_set_request_denied_fnc(xfer
, ft_request_denied
);
288 purple_xfer_set_cancel_send_fnc(xfer
, ft_cancelled
);
289 purple_xfer_set_cancel_recv_fnc(xfer
, ft_cancelled
);
290 purple_xfer_set_start_fnc(xfer
, ft_start
);
291 purple_xfer_set_end_fnc(xfer
, ft_end
);
297 void sipe_backend_ft_incoming(struct sipe_core_public
*sipe_public
,
298 struct sipe_file_transfer
*ft
,
300 const gchar
*file_name
,
303 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
304 PurpleXfer
*xfer
= create_xfer(purple_private
->account
,
305 PURPLE_XFER_TYPE_RECEIVE
, who
, ft
);
307 purple_xfer_set_filename(xfer
, file_name
);
308 purple_xfer_set_size(xfer
, file_size
);
310 purple_xfer_request(xfer
);
315 sipe_backend_ft_outgoing(struct sipe_core_public
*sipe_public
,
316 struct sipe_file_transfer
*ft
,
318 const gchar
*file_name
)
320 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
321 PurpleXfer
*xfer
= create_xfer(purple_private
->account
,
322 PURPLE_XFER_TYPE_SEND
, who
, ft
);
324 if (file_name
!= NULL
)
325 purple_xfer_request_accepted(xfer
, file_name
);
327 purple_xfer_request(xfer
);
332 connect_cb(gpointer data
, gint fd
, SIPE_UNUSED_PARAMETER
const gchar
*error_message
)
334 struct sipe_file_transfer
*ft
= data
;
337 purple_xfer_cancel_local(FT_TO_PURPLE_XFER
);
341 purple_xfer_start(FT_TO_PURPLE_XFER
, fd
, NULL
, 0);
345 sipe_backend_ft_start(struct sipe_file_transfer
*ft
, struct sipe_backend_fd
*fd
,
346 const char* ip
, unsigned port
)
348 PurpleXferType type
= purple_xfer_get_xfer_type(FT_TO_PURPLE_XFER
);
349 if (type
== PURPLE_XFER_TYPE_SEND
&& ft
->ft_write
) {
350 purple_xfer_set_write_fnc(FT_TO_PURPLE_XFER
, ft_write
);
351 } else if (type
== PURPLE_XFER_TYPE_RECEIVE
&& ft
->ft_read
) {
352 purple_xfer_set_read_fnc(FT_TO_PURPLE_XFER
, ft_read
);
355 if (ip
&& port
&& !sipe_backend_ft_is_incoming(ft
)) {
356 /* Purple accepts ip & port only for incoming file transfers.
357 * If we want to send file with Sender-Connect = TRUE negotiated,
358 * we have to open the connection ourselves and pass the file
359 * descriptor to purple_xfer_start. */
360 purple_proxy_connect(NULL
,
361 purple_xfer_get_account(FT_TO_PURPLE_XFER
),
369 purple_xfer_start(FT_TO_PURPLE_XFER
, fd
? fd
->fd
: -1, ip
, port
);
372 void sipe_purple_ft_send_file(PurpleConnection
*gc
,
376 sipe_core_ft_create_outgoing(PURPLE_GC_TO_SIPE_CORE_PUBLIC
, who
, file
);
380 sipe_backend_ft_is_incoming(struct sipe_file_transfer
*ft
)
382 return(purple_xfer_get_xfer_type(FT_TO_PURPLE_XFER
) == PURPLE_XFER_TYPE_RECEIVE
);