adium: allow build without building Adium
[siplcs.git] / src / miranda / miranda-ft.c
blob0b7a0ef2f843db1cdf99cf19a5146ac3b9d5955a
1 /**
2 * @file miranda-ft.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2016 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 #include <winsock2.h>
26 #include <windows.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
31 #include <glib.h>
32 #include <glib/gstdio.h>
34 #include "miranda-version.h"
35 #include "newpluginapi.h"
36 #include "m_protosvc.h"
37 #include "m_protoint.h"
38 #include "m_database.h"
39 #include "m_protomod.h"
40 #include "m_netlib.h"
42 #include "sipe-common.h"
43 #include "sipe-backend.h"
44 #include "sipe-core.h"
45 #include "sipe-nls.h"
46 #include "miranda-private.h"
48 #define FT_SIPE_DEBUG_INFO(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_INFO, "[FT:%08x] %s: " fmt, ft, __func__, __VA_ARGS__)
49 #define FT_SIPE_DEBUG_INFO_NOFORMAT(msg) sipe_backend_debug(SIPE_DEBUG_LEVEL_INFO, "[FT:%08x] %s: %s", ft, __func__, msg)
51 #define FT_INITIAL_BUFFER_SIZE 4096
52 #define FT_MAX_BUFFER_SIZE 65535
54 typedef enum
56 SIPE_MIRANDA_XFER_STATUS_UNKNOWN = 0, /**< Unknown, the xfer may be null. */
57 // SIPE_MIRANDA_XFER_STATUS_NOT_STARTED, /**< It hasn't started yet. */
58 // SIPE_MIRANDA_XFER_STATUS_ACCEPTED, /**< Receive accepted, but destination file not selected yet */
59 SIPE_MIRANDA_XFER_STATUS_STARTED, /**< purple_xfer_start has been called. */
60 SIPE_MIRANDA_XFER_STATUS_DONE, /**< The xfer completed successfully. */
61 SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL, /**< The xfer was cancelled by us. */
62 SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE /**< The xfer was cancelled by the other end, or we couldn't connect. */
63 } sipe_miranda_xfer_status;
65 struct sipe_backend_file_transfer {
66 gboolean incoming;
67 HANDLE fd;
68 SIPPROTO *pr;
69 struct sipe_file_transfer *ft;
70 gsize file_size;
71 size_t bytes_sent;
72 size_t bytes_remaining;
73 size_t current_buffer_size;
74 struct sipe_miranda_sel_entry *watcher;
75 gchar *filename;
76 gchar *local_filename;
77 FILE *dest_fp;
78 HANDLE hContact;
79 time_t start_time;
80 time_t end_time;
81 GByteArray *buffer;
82 PROTOFILETRANSFERSTATUS st;
83 sipe_miranda_xfer_status status;
86 static void
87 update_progress(struct sipe_backend_file_transfer *xfer)
89 #if 0
90 ZeroMemory(pfts, sizeof(PROTOFILETRANSFERSTATUS));
91 pfts->flags = PFTS_UTF | (ft->sending ? PFTS_SENDING : PFTS_RECEIVING); /* Standard FT is Ansi only */
92 if (ft->sending)
93 pfts->pszFiles = ft->pszFiles;
94 else
95 pfts->pszFiles = NULL; /* FIXME */
96 pfts->currentFileTime = ft->dwThisFileDate;
98 #endif
99 xfer->st.flags = (xfer->incoming ? PFTS_RECEIVING : PFTS_SENDING);
100 xfer->st.szWorkingDir = "none";
101 xfer->st.szCurrentFile = xfer->filename;
102 xfer->st.totalFiles = 1;
103 xfer->st.totalBytes = xfer->file_size;
104 xfer->st.totalProgress = xfer->bytes_sent;
105 xfer->st.currentFileNumber = 1;
106 xfer->st.currentFileSize = xfer->file_size;
107 xfer->st.currentFileProgress = xfer->bytes_sent;
109 ProtoBroadcastAck(xfer->pr->proto.m_szModuleName,
110 xfer->hContact,
111 ACKTYPE_FILE,
112 ACKRESULT_DATA,
113 (HANDLE)xfer,
114 (LPARAM)&xfer->st);
117 static void
118 increase_buffer_size(struct sipe_backend_file_transfer *xfer)
120 xfer->current_buffer_size = MIN(xfer->current_buffer_size * 1.5,
121 FT_MAX_BUFFER_SIZE);
124 void sipe_backend_ft_error(struct sipe_file_transfer *ft,
125 const gchar *errmsg)
127 gchar *msg;
129 FT_SIPE_DEBUG_INFO("file transfer error: <%s>", errmsg);
131 if (ft->backend_private->incoming)
133 msg = g_strdup_printf("Incoming file transfer failed");
134 } else {
135 msg = g_strdup_printf("Outgoing file transfer failed");
138 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
139 g_free(msg);
143 const gchar *sipe_backend_ft_get_error(SIPE_UNUSED_PARAMETER struct sipe_file_transfer *ft)
145 _NIF();
146 return strerror(errno); /* FIXME: Only valid for the file side i think */
149 static void
150 free_xfer_struct(struct sipe_backend_file_transfer *xfer)
152 struct sipe_file_transfer *ft = xfer->ft;
154 if (ft) {
155 if (xfer->watcher) {
156 sipe_miranda_input_remove(xfer->watcher);
157 xfer->watcher = 0;
159 if (ft->deallocate) {
160 ft->deallocate(ft);
162 xfer->ft = NULL;
166 static void
167 cancel_remote(struct sipe_backend_file_transfer *xfer)
169 struct sipe_file_transfer *ft = xfer->ft;
170 gchar *msg;
171 FT_SIPE_DEBUG_INFO_NOFORMAT("");
173 if (!xfer) return;
175 xfer->status = SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE;
176 xfer->end_time = time(NULL);
178 msg = g_strdup_printf("File transfer cancelled by peer");
179 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
180 g_free(msg);
182 free_xfer_struct(xfer);
184 if (xfer->watcher != 0) {
185 sipe_miranda_input_remove(xfer->watcher);
186 xfer->watcher = 0;
189 if (xfer->fd)
190 Netlib_CloseHandle(xfer->fd);
192 if (xfer->dest_fp != NULL) {
193 fclose(xfer->dest_fp);
194 xfer->dest_fp = NULL;
197 xfer->bytes_remaining = 0;
198 g_free(xfer->filename);
199 /* g_free(xfer); FIXME: needs refcounting like purple i guess */
202 void sipe_backend_ft_deallocate(struct sipe_file_transfer *ft)
204 struct sipe_backend_file_transfer *xfer = ft->backend_private;
206 /* If file transfer is not finished, cancel it */
207 if (xfer->status != SIPE_MIRANDA_XFER_STATUS_DONE
208 && xfer->status != SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL
209 && xfer->status != SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE)
211 cancel_remote(xfer);
216 gssize sipe_backend_ft_read(struct sipe_file_transfer *ft,
217 guchar *data,
218 gsize size)
220 gssize bytes_read;
222 FT_SIPE_DEBUG_INFO("reading up to <%d> bytes", size);
223 bytes_read = Netlib_Recv(ft->backend_private->fd, data, size, MSG_NODUMP);
224 FT_SIPE_DEBUG_INFO("came back from read <%d>", bytes_read);
225 if (bytes_read == 0) {
226 /* Sender canceled transfer before it was finished */
227 FT_SIPE_DEBUG_INFO_NOFORMAT("no read cause sender cancelled");
228 return -2;
229 } else if (bytes_read == SOCKET_ERROR) {
230 int err = WSAGetLastError();
231 if (err == WSAEWOULDBLOCK) {
232 return 0;
233 } else {
234 FT_SIPE_DEBUG_INFO("Error reading <%d>", err);
235 return -1;
238 FT_SIPE_DEBUG_INFO("read <%d> bytes [%02x:%c]", bytes_read, *data, *data);
239 return bytes_read;
242 gssize sipe_backend_ft_write(struct sipe_file_transfer *ft,
243 const guchar *data,
244 gsize size)
246 int bytes_written;
247 FT_SIPE_DEBUG_INFO("writing <%d> bytes", size);
248 bytes_written = Netlib_Send(ft->backend_private->fd, data, size, MSG_NODUMP );
249 if (bytes_written == SOCKET_ERROR) {
250 int err = WSAGetLastError();
251 if (err == WSAEWOULDBLOCK) {
252 return 0;
253 } else {
254 FT_SIPE_DEBUG_INFO("Error writing <%u>", err);
255 return -1;
258 FT_SIPE_DEBUG_INFO("wrote <%d> bytes", bytes_written);
259 return bytes_written;
262 static void
263 cancel_local(struct sipe_backend_file_transfer *xfer)
265 struct sipe_file_transfer *ft = xfer->ft;
266 gchar *msg;
267 FT_SIPE_DEBUG_INFO_NOFORMAT("");
269 xfer->status = SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL;
270 xfer->end_time = time(NULL);
272 msg = g_strdup_printf("File transfer cancelled");
273 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
274 g_free(msg);
276 free_xfer_struct(xfer);
278 if (xfer->watcher != 0) {
279 sipe_miranda_input_remove(xfer->watcher);
280 xfer->watcher = 0;
283 if (xfer->fd)
284 Netlib_CloseHandle(xfer->fd);
286 if (xfer->dest_fp != NULL) {
287 fclose(xfer->dest_fp);
288 xfer->dest_fp = NULL;
291 xfer->bytes_remaining = 0;
293 g_free(xfer->filename);
294 g_free(xfer);
297 void sipe_backend_ft_set_completed(struct sipe_file_transfer *ft)
299 _NIF();
302 void sipe_backend_ft_cancel_local(struct sipe_file_transfer *ft)
304 cancel_local(ft->backend_private);
307 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer *ft)
309 cancel_remote(ft->backend_private);
312 static struct sipe_backend_file_transfer *
313 new_xfer(SIPPROTO *pr,
314 struct sipe_file_transfer *ft,
315 HANDLE hContact)
317 struct sipe_backend_file_transfer *xfer = g_new0(struct sipe_backend_file_transfer, 1);
319 xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
320 xfer->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE);
321 xfer->ft = ft;
322 xfer->hContact = hContact;
323 xfer->pr = pr;
325 xfer->st.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
326 xfer->st.hContact = hContact;
328 return xfer;
331 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
332 struct sipe_file_transfer *ft,
333 const gchar *who,
334 const gchar *file_name,
335 gsize file_size)
337 SIPPROTO *pr = sipe_public->backend_private;
338 PROTORECVFILET pre = {0};
339 CCSDATA ccs;
340 HANDLE hContact;
342 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> from <%s> file <%s> size <%d>", ft, who, file_name, file_size);
343 hContact = sipe_backend_buddy_find( sipe_public, who, NULL );
344 if (!hContact)
346 FT_SIPE_DEBUG_INFO("Adding miranda contact for incoming transfer from <%s>", who);
347 hContact = ( HANDLE )CallService( MS_DB_CONTACT_ADD, 0, 0 );
348 CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact,( LPARAM )pr->proto.m_szModuleName );
349 DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
350 sipe_miranda_setContactString( pr, hContact, SIP_UNIQUEID, who ); // name
353 ft->backend_private = new_xfer(pr, ft, hContact);
354 ft->backend_private->incoming = TRUE;
355 ft->backend_private->file_size = file_size;
356 ft->backend_private->bytes_remaining = file_size;
357 ft->backend_private->bytes_sent = 0;
358 ft->backend_private->filename = g_strdup(file_name);
360 pre.flags = PREF_TCHAR;
361 pre.timestamp = time(NULL);
362 pre.tszDescription = mir_a2t(file_name);
363 pre.fileCount = 1;
364 pre.ptszFiles = &pre.tszDescription;
365 pre.lParam = (LPARAM)ft;
367 ccs.szProtoService = PSR_FILE;
368 ccs.hContact = hContact;
369 ccs.wParam = 0;
370 ccs.lParam = (LPARAM)&pre;
371 CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
375 void
376 sipe_backend_ft_outgoing(struct sipe_core_public *sipe_public,
377 struct sipe_file_transfer *ft,
378 const gchar *who,
379 const gchar *file_name)
381 SIPPROTO *pr = sipe_public->backend_private;
382 HANDLE hContact;
383 int result;
384 struct __stat64 buf;
386 LOCK;
387 hContact = sipe_backend_buddy_find( sipe_public, who, NULL );
388 ft->backend_private = new_xfer(pr, ft, hContact);
389 ft->backend_private->incoming = FALSE;
390 result = _tstat64( file_name, &buf );
391 if (result != 0)
393 FT_SIPE_DEBUG_INFO("Could not stat file, error<%d>", result);
394 ft->backend_private->file_size = 0;
396 else
398 ft->backend_private->file_size = buf.st_size;
399 ft->backend_private->bytes_remaining = ft->backend_private->file_size;
400 ft->backend_private->bytes_sent = 0;
402 ft->backend_private->local_filename = g_strdup(file_name);
403 ft->backend_private->filename = g_path_get_basename(ft->backend_private->local_filename);
404 FT_SIPE_DEBUG_INFO("set filename to <%s>", ft->backend_private->filename);
405 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, who);
406 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
407 UNLOCK;
410 gboolean
411 sipe_backend_ft_incoming_accept(struct sipe_file_transfer *ft,
412 const gchar *ip,
413 unsigned short port_min,
414 unsigned short port_max)
416 _NIF();
417 return FALSE;
420 static void
421 set_completed(struct sipe_backend_file_transfer *xfer, gboolean completed)
423 if (completed == TRUE) {
424 char *msg = NULL;
426 xfer->status = SIPE_MIRANDA_XFER_STATUS_DONE;
428 if (xfer->filename != NULL)
430 char *filename = g_markup_escape_text(xfer->filename, -1);
431 if (xfer->local_filename && xfer->incoming)
433 char *local = g_markup_escape_text(xfer->local_filename, -1);
434 msg = g_strdup_printf("Transfer of file <A HREF=\"file://%s\">%s</A> complete",
435 local, filename);
436 g_free(local);
438 else
439 msg = g_strdup_printf("Transfer of file %s complete",
440 filename);
441 g_free(filename);
443 else
444 msg = g_strdup("File transfer complete");
446 sipe_miranda_AddEvent(xfer->pr, xfer->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
447 sipe_miranda_SendBroadcast(xfer->pr, xfer->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)xfer, 0);
449 g_free(msg);
452 update_progress(xfer);
455 static void
456 do_transfer(struct sipe_backend_file_transfer *xfer)
459 guchar *buffer = NULL;
460 gssize r = 0;
461 struct sipe_file_transfer *ft = xfer->ft;
463 FT_SIPE_DEBUG_INFO("incoming <%d>", xfer->incoming);
464 if (xfer->incoming) {
465 FT_SIPE_DEBUG_INFO_NOFORMAT("incoming branch");
466 r = ft->read(xfer->ft, &buffer, xfer->bytes_remaining,
467 xfer->current_buffer_size);
468 if (r > 0) {
469 size_t wc;
470 wc = fwrite(buffer, 1, r, xfer->dest_fp);
472 if (wc != r) {
473 SIPE_DEBUG_ERROR("Unable to write whole buffer.");
474 cancel_local(xfer);
475 g_free(buffer);
476 return;
479 if ((xfer->file_size > 0) && ((xfer->bytes_sent+r) >= xfer->file_size))
480 set_completed(xfer, TRUE);
482 } else if(r < 0) {
483 cancel_remote(xfer);
484 g_free(buffer);
485 return;
487 } else {
488 size_t result = 0;
489 size_t s = MIN(xfer->bytes_remaining, xfer->current_buffer_size);
490 gboolean read = TRUE;
491 FT_SIPE_DEBUG_INFO("outgoing branch, size <%u>", s);
493 /* this is so the prpl can keep the connection open
494 if it needs to for some odd reason. */
495 if (s == 0) {
496 if (xfer->watcher) {
497 sipe_miranda_input_remove(xfer->watcher);
498 xfer->watcher = 0;
500 return;
503 if (xfer->buffer) {
504 if (xfer->buffer->len < s) {
505 s -= xfer->buffer->len;
506 read = TRUE;
507 } else {
508 read = FALSE;
512 if (read) {
513 buffer = g_malloc(s);
514 result = fread(buffer, 1, s, xfer->dest_fp);
515 if (result != s) {
516 FT_SIPE_DEBUG_INFO_NOFORMAT("Unable to read whole buffer.");
517 cancel_local(xfer);
518 g_free(buffer);
519 return;
523 if (xfer->buffer) {
524 g_byte_array_append(xfer->buffer, buffer, result);
525 g_free(buffer);
526 buffer = xfer->buffer->data;
527 result = xfer->buffer->len;
530 s = MIN(xfer->bytes_remaining, result);
531 r = ft->write(ft, buffer, s);
533 if ((xfer->bytes_remaining - r) == 0)
534 set_completed(xfer, TRUE);
536 if (r >= 0 && (xfer->bytes_sent+r) >= xfer->file_size && xfer->status != SIPE_MIRANDA_XFER_STATUS_DONE)
537 set_completed(xfer, TRUE);
539 if (r == -1) {
540 cancel_remote(xfer);
542 if (!xfer->buffer)
543 /* We don't free buffer if priv->buffer is set, because in
544 that case buffer doesn't belong to us. */
545 g_free(buffer);
546 return;
547 } else if (r == result) {
549 * We managed to write the entire buffer. This means our
550 * network is fast and our buffer is too small, so make it
551 * bigger.
553 increase_buffer_size(xfer);
556 if (xfer->buffer) {
558 * Remove what we wrote
559 * If we wrote the whole buffer the byte array will be empty
560 * Otherwise we'll keep what wasn't sent for next time.
562 buffer = NULL;
563 g_byte_array_remove_range(xfer->buffer, 0, r);
567 FT_SIPE_DEBUG_INFO_NOFORMAT("back to common code");
568 if (r > 0) {
569 if (xfer->file_size > 0)
570 xfer->bytes_remaining -= r;
572 xfer->bytes_sent += r;
574 g_free(buffer);
575 update_progress(xfer);
578 if (xfer->status == SIPE_MIRANDA_XFER_STATUS_DONE)
580 xfer->end_time = time(NULL);
581 if (xfer->ft->end && xfer->ft->end(xfer->ft)) {
582 /* We're done with this transfer */
583 free_xfer_struct(xfer);
584 } else if (xfer->incoming) {
585 _unlink(xfer->local_filename);
588 if (xfer->watcher != 0) {
589 sipe_miranda_input_remove(xfer->watcher);
590 xfer->watcher = 0;
593 if (xfer->fd)
594 Netlib_CloseHandle(xfer->fd);
596 if (xfer->dest_fp != NULL) {
597 fclose(xfer->dest_fp);
598 xfer->dest_fp = NULL;
601 g_free(xfer->filename);
602 g_free(xfer);
606 static void
607 transfer_cb(gpointer data, gint source, sipe_miranda_input_condition condition)
609 struct sipe_backend_file_transfer *xfer = data;
610 SIPE_DEBUG_INFO_NOFORMAT("");
611 do_transfer(xfer);
614 static void
615 begin_transfer(struct sipe_file_transfer *ft)
617 struct sipe_backend_file_transfer *xfer = ft->backend_private;
618 SIPPROTO *pr = xfer->pr;
620 xfer->dest_fp = fopen(xfer->local_filename, xfer->incoming ? "wb" : "rb");
621 if (xfer->dest_fp == NULL) {
622 int err = errno;
623 gchar *msg;
624 if (xfer->incoming)
626 msg = g_strdup_printf("Error reading %s: \n%s.\n", xfer->local_filename, g_strerror(err));
627 } else {
628 msg = g_strdup_printf("Error writing %s: \n%s.\n", xfer->local_filename, g_strerror(err));
630 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
631 g_free(msg);
632 FT_SIPE_DEBUG_INFO("error opening local file: %s", g_strerror(errno));
633 cancel_local(xfer);
634 return;
637 fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
639 xfer->start_time = time(NULL);
641 LOCK;
642 FT_SIPE_DEBUG_INFO("incoming <%d> size <%d>", ft->backend_private->incoming, ft->backend_private->file_size);
643 if (!ft->backend_private->incoming) {
644 /* Set socket to nonblocking */
645 SOCKET sock = CallService(MS_NETLIB_GETSOCKET, (WPARAM)xfer->fd, (LPARAM)0);
646 unsigned long parm = 1;
648 if (ioctlsocket(sock, FIONBIO, &parm) == SOCKET_ERROR)
650 FT_SIPE_DEBUG_INFO("Error ioctlsocket <%d>", WSAGetLastError());
653 FT_SIPE_DEBUG_INFO("outgoing ft <%08x> size <%d>", ft, ft->backend_private->file_size);
655 if (ft->start) {
656 ft->start(ft, ft->backend_private->file_size);
658 UNLOCK;
660 if (xfer->fd)
661 xfer->watcher = sipe_miranda_input_add(xfer->fd, xfer->incoming?SIPE_MIRANDA_INPUT_READ:SIPE_MIRANDA_INPUT_WRITE, transfer_cb, xfer);
663 FT_SIPE_DEBUG_INFO("watcher [%08x]", xfer->watcher);
666 static void
667 ft_connected_callback(HANDLE fd, void* data, const gchar *reason)
669 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)data;
670 struct sipe_backend_file_transfer *xfer = ft->backend_private;
671 SIPPROTO *pr = ft->backend_private->pr;
673 if (!fd)
675 cancel_local(xfer);
676 } else {
677 ft->backend_private->fd = fd;
678 begin_transfer(ft);
683 void
684 sipe_backend_ft_start(struct sipe_file_transfer *ft, struct sipe_backend_fd *fd,
685 const char* ip, unsigned port)
687 ft->backend_private->status = SIPE_MIRANDA_XFER_STATUS_STARTED;
689 if (ip && port)
691 FT_SIPE_DEBUG_INFO("Should connect to <%s:%d>", ip, port);
692 sipe_miranda_connect(ft->backend_private->pr, ip, port, FALSE, 5, ft_connected_callback, ft);
693 return;
696 FT_SIPE_DEBUG_INFO("Should use incoming fd <%08x>", fd);
697 ft->backend_private->fd = fd;
698 begin_transfer(ft);
701 gboolean
702 sipe_backend_ft_is_incoming(struct sipe_file_transfer *ft)
704 FT_SIPE_DEBUG_INFO("ft <%08x> incoming <%d>", ft, ft->backend_private->incoming);
705 return ft->backend_private->incoming;
708 HANDLE
709 sipe_miranda_SendFile( SIPPROTO *pr, HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles )
711 DBVARIANT dbv;
713 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
714 struct sipe_file_transfer *ft;
716 ft = sipe_core_ft_create_outgoing(pr->sip, dbv.pszVal, TCHAR2CHAR(ppszFiles[0]));
718 FT_SIPE_DEBUG_INFO("SendFile: desc <%ls> name <%s> size <%d> to <%s>", szDescription, TCHAR2CHAR(ppszFiles[0]), ft->backend_private->file_size, dbv.pszVal);
720 DBFreeVariant( &dbv );
722 return ft->backend_private;
725 return NULL;
729 sipe_miranda_RecvFile( SIPPROTO *pr, HANDLE hContact, PROTOFILEEVENT* evt )
731 CCSDATA ccs = { hContact, PSR_FILE, 0, (LPARAM)evt };
732 return CallService(MS_PROTO_RECVFILET, 0, (LPARAM)&ccs);
735 HANDLE
736 sipe_miranda_FileAllow( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath )
738 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
739 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> allowed", ft);
740 ft->backend_private->local_filename = g_strdup_printf("%s%s", TCHAR2CHAR(szPath), ft->backend_private->filename);
741 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
742 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, NULL);
743 return ft->backend_private;
747 sipe_miranda_FileDeny( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason )
749 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
750 FT_SIPE_DEBUG_INFO("FileDeny: reason <%s>", szReason);
751 if (ft->backend_private->incoming && ft->request_denied)
752 ft->request_denied(ft);
753 free_xfer_struct(ft->backend_private);
754 return 0;
759 Local Variables:
760 mode: c
761 c-file-style: "bsd"
762 indent-tabs-mode: t
763 tab-width: 8
764 End: