media: do not set "controlling-mode" parameter
[siplcs.git] / src / purple / purple-ft.c
blob6685815e88fba1122f0746c68dea95b5a5365f42
1 /**
2 * @file purple-ft.c
4 * pidgin-sipe
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
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 #include <string.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <time.h>
34 #include <glib.h>
36 #include "connection.h"
37 #include "eventloop.h"
38 #include "ft.h"
39 #include "network.h"
40 #include "request.h"
42 #ifdef _WIN32
43 /* for network */
44 #include "win32/libc_interface.h"
45 #include <nspapi.h>
46 #else
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <net/if.h>
51 #include <arpa/inet.h>
52 #ifdef HAVE_SYS_SOCKIO_H
53 #include <sys/sockio.h> /* SIOCGIFCONF for Solaris */
54 #endif
55 #endif
57 #include "sipe-common.h"
58 #include "sipe-backend.h"
59 #include "sipe-core.h"
60 #include "sipe-nls.h"
62 #include "purple-private.h"
64 struct sipe_backend_file_transfer {
65 PurpleXfer *xfer;
66 PurpleNetworkListenData *listener;
67 int listenfd;
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,
73 const char *errmsg)
75 PurpleXfer *xfer = ft->backend_private->xfer;
76 purple_xfer_error(purple_xfer_get_type(xfer),
77 xfer->account, xfer->who,
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 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);
109 g_free(backend_ft);
112 gssize sipe_backend_ft_read(struct sipe_file_transfer *ft,
113 guchar *data,
114 gsize size)
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 */
119 return -2;
120 } else if (bytes_read == -1) {
121 if (errno == EAGAIN)
122 return 0;
123 else
124 return -1;
126 return bytes_read;
129 gssize sipe_backend_ft_write(struct sipe_file_transfer *ft,
130 const guchar *data,
131 gsize size)
133 gssize bytes_written = write(ft->backend_private->xfer->fd,
134 data, size);
135 if (bytes_written == -1) {
136 if (errno == EAGAIN)
137 return 0;
138 else
139 return -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);
154 static void
155 sipe_ft_free_xfer_struct(PurpleXfer *xfer)
157 struct sipe_file_transfer *ft = PURPLE_XFER_TO_SIPE_FILE_TRANSFER;
159 if (ft) {
160 if (xfer->watcher) {
161 purple_input_remove(xfer->watcher);
162 xfer->watcher = 0;
164 sipe_core_ft_deallocate(ft);
165 xfer->data = NULL;
169 static void
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);
177 static void
178 sipe_ft_incoming_init(PurpleXfer *xfer)
180 sipe_core_ft_incoming_init(PURPLE_XFER_TO_SIPE_FILE_TRANSFER);
183 static void
184 sipe_ft_incoming_start(PurpleXfer *xfer)
186 sipe_core_ft_incoming_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
187 xfer->size);
190 static void
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);
196 } else {
197 unlink(xfer->local_filename);
201 static gssize
202 sipe_ft_read(guchar **buffer, PurpleXfer *xfer)
204 return sipe_core_ft_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 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),
216 xfer->who);
219 static void
220 sipe_ft_outgoing_start(PurpleXfer *xfer)
222 /* Set socket to non-blocking mode */
223 int flags = fcntl(xfer->fd, F_GETFL, 0);
224 if (flags == -1)
225 flags = 0;
226 fcntl(xfer->fd, F_SETFL, flags | O_NONBLOCK);
228 sipe_core_ft_outgoing_start(PURPLE_XFER_TO_SIPE_FILE_TRANSFER,
229 xfer->size);
232 static void
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);
241 static gssize
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,
245 buffer,
246 size);
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,
257 PurpleXfer *xfer)
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;
265 xfer->data = ft;
268 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
269 struct sipe_file_transfer *ft,
270 const gchar *who,
271 const gchar *file_name,
272 gsize file_size)
274 struct sipe_backend_private *purple_private = sipe_public->backend_private;
275 PurpleXfer *xfer;
277 xfer = purple_xfer_new(purple_private->account,
278 PURPLE_XFER_RECEIVE,
279 who);
281 if (xfer) {
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);
299 static
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);
312 xfer->watcher = 0;
313 close(listenfd);
314 backend_ft->listenfd = -1;
316 if (fd < 0) {
317 sipe_backend_ft_error(ft, _("Socket read failed"));
318 sipe_backend_ft_cancel_local(ft);
319 } else {
320 purple_xfer_start(xfer, fd, NULL, 0);
324 static
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,
338 PURPLE_INPUT_READ,
339 sipe_ft_client_connected,
340 ft);
342 sipe_core_ft_incoming_accept(ft,
343 backend_ft->xfer->who,
344 listenfd,
345 ntohs(addr.sin_port));
348 gboolean sipe_backend_ft_incoming_accept(struct sipe_file_transfer *ft,
349 const gchar *ip,
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);
357 } else {
358 backend_ft->listener = purple_network_listen_range(port_min,
359 port_max,
360 SOCK_STREAM,
361 sipe_ft_listen_socket_created,
362 ft);
363 if (!backend_ft->listener)
364 return FALSE;
366 return(TRUE);
369 void sipe_ft_send_file(PurpleConnection *gc, const char *who, const char *file)
371 PurpleXfer *xfer = sipe_ft_new_xfer(gc, who);
373 if (xfer) {
374 if (file != NULL)
375 purple_xfer_request_accepted(xfer, file);
376 else
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);
389 if (xfer) {
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);
404 return xfer;
408 Local Variables:
409 mode: c
410 c-file-style: "bsd"
411 indent-tabs-mode: t
412 tab-width: 8
413 End: