6 * Copyright (C) 2010 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2010 Jakub Adam <jakub.adam@tieto.com>
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 #include "connection.h"
37 #include "eventloop.h"
44 #include "win32/libc_interface.h"
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #ifdef HAVE_SYS_SOCKIO_H
53 #include <sys/sockio.h> /* SIOCGIFCONF for Solaris */
57 #include "sipe-common.h"
58 #include "sipe-backend.h"
59 #include "sipe-core.h"
62 #include "purple-private.h"
64 struct sipe_backend_file_transfer
{
66 PurpleNetworkListenData
*listener
;
69 #define PURPLE_XFER_TO_SIPE_FILE_TRANSFER ((struct sipe_file_transfer *) xfer->data)
70 #define PURPLE_XFER_TO_SIPE_CORE_PUBLIC ((struct sipe_core_public *) xfer->account->gc->proto_data)
72 void sipe_backend_ft_error(struct sipe_file_transfer
*ft
,
75 PurpleXfer
*xfer
= ft
->backend_private
->xfer
;
76 purple_xfer_error(purple_xfer_get_type(xfer
),
77 xfer
->account
, xfer
->who
,
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 struct sipe_backend_file_transfer
*backend_ft
= ft
->backend_private
;
89 PurpleXfer
*xfer
= backend_ft
->xfer
;
90 PurpleXferStatusType status
= purple_xfer_get_status(xfer
);
92 if (backend_ft
->listenfd
>= 0) {
93 SIPE_DEBUG_INFO("sipe_ft_free_xfer_struct: closing listening socket %d",
94 backend_ft
->listenfd
);
95 close(backend_ft
->listenfd
);
97 if (backend_ft
->listener
)
98 purple_network_listen_cancel(backend_ft
->listener
);
100 // If file transfer is not finished, cancel it
101 if ( status
!= PURPLE_XFER_STATUS_DONE
102 && status
!= PURPLE_XFER_STATUS_CANCEL_LOCAL
103 && status
!= PURPLE_XFER_STATUS_CANCEL_REMOTE
) {
104 purple_xfer_set_cancel_recv_fnc(xfer
, NULL
);
105 purple_xfer_set_cancel_send_fnc(xfer
, NULL
);
106 purple_xfer_cancel_remote(xfer
);
112 gssize
sipe_backend_ft_read(struct sipe_file_transfer
*ft
,
116 gssize bytes_read
= read(ft
->backend_private
->xfer
->fd
, data
, size
);
117 if (bytes_read
== 0) {
118 /* Sender canceled transfer before it was finished */
120 } else if (bytes_read
== -1) {
129 gssize
sipe_backend_ft_write(struct sipe_file_transfer
*ft
,
133 gssize bytes_written
= write(ft
->backend_private
->xfer
->fd
,
135 if (bytes_written
== -1) {
141 return bytes_written
;
144 void sipe_backend_ft_cancel_local(struct sipe_file_transfer
*ft
)
146 purple_xfer_cancel_local(ft
->backend_private
->xfer
);
149 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer
*ft
)
151 purple_xfer_cancel_remote(ft
->backend_private
->xfer
);
155 sipe_ft_free_xfer_struct(PurpleXfer
*xfer
)
157 struct sipe_file_transfer
*ft
= PURPLE_XFER_TO_SIPE_FILE_TRANSFER
;
161 purple_input_remove(xfer
->watcher
);
164 sipe_core_ft_deallocate(ft
);
170 sipe_ft_request_denied(PurpleXfer
*xfer
)
172 if (xfer
->type
== PURPLE_XFER_RECEIVE
)
173 sipe_core_ft_cancel(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
);
174 sipe_ft_free_xfer_struct(xfer
);
178 sipe_ft_incoming_init(PurpleXfer
*xfer
)
180 sipe_core_ft_incoming_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
);
184 sipe_ft_incoming_start(PurpleXfer
*xfer
)
186 sipe_core_ft_incoming_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
,
191 sipe_ft_incoming_stop(PurpleXfer
*xfer
)
193 if (sipe_core_ft_incoming_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
)) {
194 /* We're done with this transfer */
195 sipe_ft_free_xfer_struct(xfer
);
197 unlink(xfer
->local_filename
);
202 sipe_ft_read(guchar
**buffer
, PurpleXfer
*xfer
)
204 return sipe_core_ft_read(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
,
206 purple_xfer_get_bytes_remaining(xfer
),
207 xfer
->current_buffer_size
);
211 sipe_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
),
220 sipe_ft_outgoing_start(PurpleXfer
*xfer
)
222 /* Set socket to non-blocking mode */
223 int flags
= fcntl(xfer
->fd
, F_GETFL
, 0);
226 fcntl(xfer
->fd
, F_SETFL
, flags
| O_NONBLOCK
);
228 sipe_core_ft_outgoing_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
,
233 sipe_ft_outgoing_stop(PurpleXfer
*xfer
)
235 if (sipe_core_ft_outgoing_stop(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
)) {
236 /* We're done with this transfer */
237 sipe_ft_free_xfer_struct(xfer
);
242 sipe_ft_write(const guchar
*buffer
, size_t size
, PurpleXfer
*xfer
)
244 gssize bytes_written
= sipe_core_ft_write(PURPLE_XFER_TO_SIPE_FILE_TRANSFER
,
248 if ((xfer
->bytes_remaining
- bytes_written
) == 0)
249 purple_xfer_set_completed(xfer
, TRUE
);
251 return bytes_written
;
254 //******************************************************************************
256 static void sipe_backend_private_init(struct sipe_file_transfer
*ft
,
259 struct sipe_backend_file_transfer
*backend_ft
= g_new0(struct sipe_backend_file_transfer
, 1);
261 ft
->backend_private
= backend_ft
;
262 backend_ft
->xfer
= xfer
;
263 backend_ft
->listenfd
= -1;
268 void sipe_backend_ft_incoming(struct sipe_core_public
*sipe_public
,
269 struct sipe_file_transfer
*ft
,
271 const gchar
*file_name
,
274 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
277 xfer
= purple_xfer_new(purple_private
->account
,
282 sipe_backend_private_init(ft
, xfer
);
284 purple_xfer_set_filename(xfer
, file_name
);
285 purple_xfer_set_size(xfer
, file_size
);
287 purple_xfer_set_init_fnc(xfer
, sipe_ft_incoming_init
);
288 purple_xfer_set_start_fnc(xfer
, sipe_ft_incoming_start
);
289 purple_xfer_set_end_fnc(xfer
, sipe_ft_incoming_stop
);
290 purple_xfer_set_request_denied_fnc(xfer
, sipe_ft_request_denied
);
291 purple_xfer_set_read_fnc(xfer
, sipe_ft_read
);
292 purple_xfer_set_cancel_send_fnc(xfer
, sipe_ft_free_xfer_struct
);
293 purple_xfer_set_cancel_recv_fnc(xfer
, sipe_ft_free_xfer_struct
);
295 purple_xfer_request(xfer
);
300 void sipe_ft_client_connected(gpointer data
, gint listenfd
,
301 SIPE_UNUSED_PARAMETER PurpleInputCondition cond
)
303 struct sipe_file_transfer
*ft
= data
;
304 struct sipe_backend_file_transfer
*backend_ft
= ft
->backend_private
;
305 PurpleXfer
*xfer
= backend_ft
->xfer
;
306 struct sockaddr_in saddr
;
307 socklen_t slen
= sizeof (saddr
);
309 int fd
= accept(listenfd
, (struct sockaddr
*)&saddr
, &slen
);
311 purple_input_remove(xfer
->watcher
);
314 backend_ft
->listenfd
= -1;
317 sipe_backend_ft_error(ft
, _("Socket read failed"));
318 sipe_backend_ft_cancel_local(ft
);
320 purple_xfer_start(xfer
, fd
, NULL
, 0);
325 void sipe_ft_listen_socket_created(int listenfd
, gpointer data
)
327 struct sipe_file_transfer
*ft
= data
;
328 struct sipe_backend_file_transfer
*backend_ft
= ft
->backend_private
;
329 struct sockaddr_in addr
;
330 socklen_t socklen
= sizeof (addr
);
332 backend_ft
->listener
= NULL
;
333 backend_ft
->listenfd
= listenfd
;
335 getsockname(listenfd
, (struct sockaddr
*)&addr
, &socklen
);
337 backend_ft
->xfer
->watcher
= purple_input_add(listenfd
,
339 sipe_ft_client_connected
,
342 sipe_core_ft_incoming_accept(ft
,
343 backend_ft
->xfer
->who
,
345 ntohs(addr
.sin_port
));
348 gboolean
sipe_backend_ft_incoming_accept(struct sipe_file_transfer
*ft
,
350 unsigned short port_min
,
351 unsigned short port_max
)
353 struct sipe_backend_file_transfer
*backend_ft
= ft
->backend_private
;
355 if (ip
&& (port_min
== port_max
)) {
356 purple_xfer_start(backend_ft
->xfer
, -1, ip
, port_min
);
358 backend_ft
->listener
= purple_network_listen_range(port_min
,
361 sipe_ft_listen_socket_created
,
363 if (!backend_ft
->listener
)
369 void sipe_ft_send_file(PurpleConnection
*gc
, const char *who
, const char *file
)
371 PurpleXfer
*xfer
= sipe_ft_new_xfer(gc
, who
);
375 purple_xfer_request_accepted(xfer
, file
);
377 purple_xfer_request(xfer
);
381 PurpleXfer
*sipe_ft_new_xfer(PurpleConnection
*gc
, const char *who
)
383 PurpleXfer
*xfer
= NULL
;
385 if (PURPLE_CONNECTION_IS_VALID(gc
)) {
386 xfer
= purple_xfer_new(purple_connection_get_account(gc
),
387 PURPLE_XFER_SEND
, who
);
390 struct sipe_file_transfer
*ft
= sipe_core_ft_allocate(PURPLE_GC_TO_SIPE_CORE_PUBLIC
);
392 sipe_backend_private_init(ft
, xfer
);
394 purple_xfer_set_init_fnc(xfer
, sipe_ft_outgoing_init
);
395 purple_xfer_set_start_fnc(xfer
, sipe_ft_outgoing_start
);
396 purple_xfer_set_end_fnc(xfer
, sipe_ft_outgoing_stop
);
397 purple_xfer_set_request_denied_fnc(xfer
, sipe_ft_request_denied
);
398 purple_xfer_set_write_fnc(xfer
, sipe_ft_write
);
399 purple_xfer_set_cancel_send_fnc(xfer
, sipe_ft_free_xfer_struct
);
400 purple_xfer_set_cancel_recv_fnc(xfer
, sipe_ft_free_xfer_struct
);