Release 1.25.0 -- Buddy Idle Time, RTF
[siplcs.git] / src / miranda / miranda-ft.c
blob0db018ae70a1844c699a4ba347af16d4dfb941cf
1 /**
2 * @file miranda-ft.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2018 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 "miranda-private.h"
47 #define FT_SIPE_DEBUG_INFO(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_INFO, "[FT:%08x] %s: " fmt, ft, __func__, __VA_ARGS__)
48 #define FT_SIPE_DEBUG_INFO_NOFORMAT(msg) sipe_backend_debug(SIPE_DEBUG_LEVEL_INFO, "[FT:%08x] %s: %s", ft, __func__, msg)
50 #define FT_INITIAL_BUFFER_SIZE 4096
51 #define FT_MAX_BUFFER_SIZE 65535
53 typedef enum
55 SIPE_MIRANDA_XFER_STATUS_UNKNOWN = 0, /**< Unknown, the xfer may be null. */
56 // SIPE_MIRANDA_XFER_STATUS_NOT_STARTED, /**< It hasn't started yet. */
57 // SIPE_MIRANDA_XFER_STATUS_ACCEPTED, /**< Receive accepted, but destination file not selected yet */
58 SIPE_MIRANDA_XFER_STATUS_STARTED, /**< purple_xfer_start has been called. */
59 SIPE_MIRANDA_XFER_STATUS_DONE, /**< The xfer completed successfully. */
60 SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL, /**< The xfer was cancelled by us. */
61 SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE /**< The xfer was cancelled by the other end, or we couldn't connect. */
62 } sipe_miranda_xfer_status;
64 struct sipe_backend_file_transfer {
65 gboolean incoming;
66 HANDLE fd;
67 SIPPROTO *pr;
68 struct sipe_file_transfer *ft;
69 gsize file_size;
70 size_t bytes_sent;
71 size_t bytes_remaining;
72 size_t current_buffer_size;
73 struct sipe_miranda_sel_entry *watcher;
74 gchar *filename;
75 gchar *local_filename;
76 FILE *dest_fp;
77 HANDLE hContact;
78 time_t start_time;
79 time_t end_time;
80 GByteArray *buffer;
81 PROTOFILETRANSFERSTATUS st;
82 sipe_miranda_xfer_status status;
85 static void
86 update_progress(struct sipe_backend_file_transfer *xfer)
88 #if 0
89 ZeroMemory(pfts, sizeof(PROTOFILETRANSFERSTATUS));
90 pfts->flags = PFTS_UTF | (ft->sending ? PFTS_SENDING : PFTS_RECEIVING); /* Standard FT is Ansi only */
91 if (ft->sending)
92 pfts->pszFiles = ft->pszFiles;
93 else
94 pfts->pszFiles = NULL; /* FIXME */
95 pfts->currentFileTime = ft->dwThisFileDate;
97 #endif
98 xfer->st.flags = (xfer->incoming ? PFTS_RECEIVING : PFTS_SENDING);
99 xfer->st.szWorkingDir = "none";
100 xfer->st.szCurrentFile = xfer->filename;
101 xfer->st.totalFiles = 1;
102 xfer->st.totalBytes = xfer->file_size;
103 xfer->st.totalProgress = xfer->bytes_sent;
104 xfer->st.currentFileNumber = 1;
105 xfer->st.currentFileSize = xfer->file_size;
106 xfer->st.currentFileProgress = xfer->bytes_sent;
108 ProtoBroadcastAck(xfer->pr->proto.m_szModuleName,
109 xfer->hContact,
110 ACKTYPE_FILE,
111 ACKRESULT_DATA,
112 (HANDLE)xfer,
113 (LPARAM)&xfer->st);
116 static void
117 increase_buffer_size(struct sipe_backend_file_transfer *xfer)
119 xfer->current_buffer_size = MIN(xfer->current_buffer_size * 1.5,
120 FT_MAX_BUFFER_SIZE);
123 void sipe_backend_ft_error(struct sipe_file_transfer *ft,
124 const gchar *errmsg)
126 gchar *msg;
128 FT_SIPE_DEBUG_INFO("file transfer error: <%s>", errmsg);
130 if (ft->backend_private->incoming)
132 msg = g_strdup_printf("Incoming file transfer failed");
133 } else {
134 msg = g_strdup_printf("Outgoing file transfer failed");
137 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
138 g_free(msg);
142 const gchar *sipe_backend_ft_get_error(SIPE_UNUSED_PARAMETER struct sipe_file_transfer *ft)
144 _NIF();
145 return strerror(errno); /* FIXME: Only valid for the file side i think */
148 static void
149 free_xfer_struct(struct sipe_backend_file_transfer *xfer)
151 struct sipe_file_transfer *ft = xfer->ft;
153 if (ft) {
154 if (xfer->watcher) {
155 sipe_miranda_input_remove(xfer->watcher);
156 xfer->watcher = 0;
158 if (ft->deallocate) {
159 ft->deallocate(ft);
161 xfer->ft = NULL;
165 static void
166 cancel_remote(struct sipe_backend_file_transfer *xfer)
168 struct sipe_file_transfer *ft = xfer->ft;
169 gchar *msg;
170 FT_SIPE_DEBUG_INFO_NOFORMAT("");
172 if (!xfer) return;
174 xfer->status = SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE;
175 xfer->end_time = time(NULL);
177 msg = g_strdup_printf("File transfer cancelled by peer");
178 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
179 g_free(msg);
181 free_xfer_struct(xfer);
183 if (xfer->watcher != 0) {
184 sipe_miranda_input_remove(xfer->watcher);
185 xfer->watcher = 0;
188 if (xfer->fd)
189 Netlib_CloseHandle(xfer->fd);
191 if (xfer->dest_fp != NULL) {
192 fclose(xfer->dest_fp);
193 xfer->dest_fp = NULL;
196 xfer->bytes_remaining = 0;
197 g_free(xfer->filename);
198 /* g_free(xfer); FIXME: needs refcounting like purple i guess */
201 void sipe_backend_ft_deallocate(struct sipe_file_transfer *ft)
203 struct sipe_backend_file_transfer *xfer = ft->backend_private;
205 /* If file transfer is not finished, cancel it */
206 if (xfer->status != SIPE_MIRANDA_XFER_STATUS_DONE
207 && xfer->status != SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL
208 && xfer->status != SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE)
210 cancel_remote(xfer);
215 gssize sipe_backend_ft_read(struct sipe_file_transfer *ft,
216 guchar *data,
217 gsize size)
219 gssize bytes_read;
221 FT_SIPE_DEBUG_INFO("reading up to <%d> bytes", size);
222 bytes_read = Netlib_Recv(ft->backend_private->fd, data, size, MSG_NODUMP);
223 FT_SIPE_DEBUG_INFO("came back from read <%d>", bytes_read);
224 if (bytes_read == 0) {
225 /* Sender canceled transfer before it was finished */
226 FT_SIPE_DEBUG_INFO_NOFORMAT("no read cause sender cancelled");
227 return -2;
228 } else if (bytes_read == SOCKET_ERROR) {
229 int err = WSAGetLastError();
230 if (err == WSAEWOULDBLOCK) {
231 return 0;
232 } else {
233 FT_SIPE_DEBUG_INFO("Error reading <%d>", err);
234 return -1;
237 FT_SIPE_DEBUG_INFO("read <%d> bytes [%02x:%c]", bytes_read, *data, *data);
238 return bytes_read;
241 gssize sipe_backend_ft_write(struct sipe_file_transfer *ft,
242 const guchar *data,
243 gsize size)
245 int bytes_written;
246 FT_SIPE_DEBUG_INFO("writing <%d> bytes", size);
247 bytes_written = Netlib_Send(ft->backend_private->fd, data, size, MSG_NODUMP );
248 if (bytes_written == SOCKET_ERROR) {
249 int err = WSAGetLastError();
250 if (err == WSAEWOULDBLOCK) {
251 return 0;
252 } else {
253 FT_SIPE_DEBUG_INFO("Error writing <%u>", err);
254 return -1;
257 FT_SIPE_DEBUG_INFO("wrote <%d> bytes", bytes_written);
258 return bytes_written;
261 static void
262 cancel_local(struct sipe_backend_file_transfer *xfer)
264 struct sipe_file_transfer *ft = xfer->ft;
265 gchar *msg;
266 FT_SIPE_DEBUG_INFO_NOFORMAT("");
268 xfer->status = SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL;
269 xfer->end_time = time(NULL);
271 msg = g_strdup_printf("File transfer cancelled");
272 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
273 g_free(msg);
275 free_xfer_struct(xfer);
277 if (xfer->watcher != 0) {
278 sipe_miranda_input_remove(xfer->watcher);
279 xfer->watcher = 0;
282 if (xfer->fd)
283 Netlib_CloseHandle(xfer->fd);
285 if (xfer->dest_fp != NULL) {
286 fclose(xfer->dest_fp);
287 xfer->dest_fp = NULL;
290 xfer->bytes_remaining = 0;
292 g_free(xfer->filename);
293 g_free(xfer);
296 void sipe_backend_ft_set_completed(struct sipe_file_transfer *ft)
298 _NIF();
301 void sipe_backend_ft_cancel_local(struct sipe_file_transfer *ft)
303 cancel_local(ft->backend_private);
306 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer *ft)
308 cancel_remote(ft->backend_private);
311 static struct sipe_backend_file_transfer *
312 new_xfer(SIPPROTO *pr,
313 struct sipe_file_transfer *ft,
314 HANDLE hContact)
316 struct sipe_backend_file_transfer *xfer = g_new0(struct sipe_backend_file_transfer, 1);
318 xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
319 xfer->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE);
320 xfer->ft = ft;
321 xfer->hContact = hContact;
322 xfer->pr = pr;
324 xfer->st.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
325 xfer->st.hContact = hContact;
327 return xfer;
330 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
331 struct sipe_file_transfer *ft,
332 const gchar *who,
333 const gchar *file_name,
334 gsize file_size)
336 SIPPROTO *pr = sipe_public->backend_private;
337 PROTORECVFILET pre = {0};
338 CCSDATA ccs;
339 HANDLE hContact;
341 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> from <%s> file <%s> size <%d>", ft, who, file_name, file_size);
342 hContact = sipe_backend_buddy_find( sipe_public, who, NULL );
343 if (!hContact)
345 FT_SIPE_DEBUG_INFO("Adding miranda contact for incoming transfer from <%s>", who);
346 hContact = ( HANDLE )CallService( MS_DB_CONTACT_ADD, 0, 0 );
347 CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact,( LPARAM )pr->proto.m_szModuleName );
348 DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
349 sipe_miranda_setContactString( pr, hContact, SIP_UNIQUEID, who ); // name
352 ft->backend_private = new_xfer(pr, ft, hContact);
353 ft->backend_private->incoming = TRUE;
354 ft->backend_private->file_size = file_size;
355 ft->backend_private->bytes_remaining = file_size;
356 ft->backend_private->bytes_sent = 0;
357 ft->backend_private->filename = g_strdup(file_name);
359 pre.flags = PREF_TCHAR;
360 pre.timestamp = time(NULL);
361 pre.tszDescription = mir_a2t(file_name);
362 pre.fileCount = 1;
363 pre.ptszFiles = &pre.tszDescription;
364 pre.lParam = (LPARAM)ft;
366 ccs.szProtoService = PSR_FILE;
367 ccs.hContact = hContact;
368 ccs.wParam = 0;
369 ccs.lParam = (LPARAM)&pre;
370 CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
374 void
375 sipe_backend_ft_outgoing(struct sipe_core_public *sipe_public,
376 struct sipe_file_transfer *ft,
377 const gchar *who,
378 const gchar *file_name)
380 SIPPROTO *pr = sipe_public->backend_private;
381 HANDLE hContact;
382 int result;
383 struct __stat64 buf;
385 LOCK;
386 hContact = sipe_backend_buddy_find( sipe_public, who, NULL );
387 ft->backend_private = new_xfer(pr, ft, hContact);
388 ft->backend_private->incoming = FALSE;
389 result = _tstat64( file_name, &buf );
390 if (result != 0)
392 FT_SIPE_DEBUG_INFO("Could not stat file, error<%d>", result);
393 ft->backend_private->file_size = 0;
395 else
397 ft->backend_private->file_size = buf.st_size;
398 ft->backend_private->bytes_remaining = ft->backend_private->file_size;
399 ft->backend_private->bytes_sent = 0;
401 ft->backend_private->local_filename = g_strdup(file_name);
402 ft->backend_private->filename = g_path_get_basename(ft->backend_private->local_filename);
403 FT_SIPE_DEBUG_INFO("set filename to <%s>", ft->backend_private->filename);
404 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, who);
405 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
406 UNLOCK;
409 gboolean
410 sipe_backend_ft_incoming_accept(struct sipe_file_transfer *ft,
411 const gchar *ip,
412 unsigned short port_min,
413 unsigned short port_max)
415 _NIF();
416 return FALSE;
419 static void
420 set_completed(struct sipe_backend_file_transfer *xfer, gboolean completed)
422 if (completed == TRUE) {
423 char *msg = NULL;
425 xfer->status = SIPE_MIRANDA_XFER_STATUS_DONE;
427 if (xfer->filename != NULL)
429 char *filename = g_markup_escape_text(xfer->filename, -1);
430 if (xfer->local_filename && xfer->incoming)
432 char *local = g_markup_escape_text(xfer->local_filename, -1);
433 msg = g_strdup_printf("Transfer of file <A HREF=\"file://%s\">%s</A> complete",
434 local, filename);
435 g_free(local);
437 else
438 msg = g_strdup_printf("Transfer of file %s complete",
439 filename);
440 g_free(filename);
442 else
443 msg = g_strdup("File transfer complete");
445 sipe_miranda_AddEvent(xfer->pr, xfer->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
446 sipe_miranda_SendBroadcast(xfer->pr, xfer->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)xfer, 0);
448 g_free(msg);
451 update_progress(xfer);
454 static void
455 do_transfer(struct sipe_backend_file_transfer *xfer)
458 guchar *buffer = NULL;
459 gssize r = 0;
460 struct sipe_file_transfer *ft = xfer->ft;
462 FT_SIPE_DEBUG_INFO("incoming <%d>", xfer->incoming);
463 if (xfer->incoming) {
464 FT_SIPE_DEBUG_INFO_NOFORMAT("incoming branch");
465 r = ft->read(xfer->ft, &buffer, xfer->bytes_remaining,
466 xfer->current_buffer_size);
467 if (r > 0) {
468 size_t wc;
469 wc = fwrite(buffer, 1, r, xfer->dest_fp);
471 if (wc != r) {
472 SIPE_DEBUG_ERROR("Unable to write whole buffer.");
473 cancel_local(xfer);
474 g_free(buffer);
475 return;
478 if ((xfer->file_size > 0) && ((xfer->bytes_sent+r) >= xfer->file_size))
479 set_completed(xfer, TRUE);
481 } else if(r < 0) {
482 cancel_remote(xfer);
483 g_free(buffer);
484 return;
486 } else {
487 size_t result = 0;
488 size_t s = MIN(xfer->bytes_remaining, xfer->current_buffer_size);
489 gboolean read = TRUE;
490 FT_SIPE_DEBUG_INFO("outgoing branch, size <%u>", s);
492 /* this is so the prpl can keep the connection open
493 if it needs to for some odd reason. */
494 if (s == 0) {
495 if (xfer->watcher) {
496 sipe_miranda_input_remove(xfer->watcher);
497 xfer->watcher = 0;
499 return;
502 if (xfer->buffer) {
503 if (xfer->buffer->len < s) {
504 s -= xfer->buffer->len;
505 read = TRUE;
506 } else {
507 read = FALSE;
511 if (read) {
512 buffer = g_malloc(s);
513 result = fread(buffer, 1, s, xfer->dest_fp);
514 if (result != s) {
515 FT_SIPE_DEBUG_INFO_NOFORMAT("Unable to read whole buffer.");
516 cancel_local(xfer);
517 g_free(buffer);
518 return;
522 if (xfer->buffer) {
523 g_byte_array_append(xfer->buffer, buffer, result);
524 g_free(buffer);
525 buffer = xfer->buffer->data;
526 result = xfer->buffer->len;
529 s = MIN(xfer->bytes_remaining, result);
530 r = ft->write(ft, buffer, s);
532 if ((xfer->bytes_remaining - r) == 0)
533 set_completed(xfer, TRUE);
535 if (r >= 0 && (xfer->bytes_sent+r) >= xfer->file_size && xfer->status != SIPE_MIRANDA_XFER_STATUS_DONE)
536 set_completed(xfer, TRUE);
538 if (r == -1) {
539 cancel_remote(xfer);
541 if (!xfer->buffer)
542 /* We don't free buffer if priv->buffer is set, because in
543 that case buffer doesn't belong to us. */
544 g_free(buffer);
545 return;
546 } else if (r == result) {
548 * We managed to write the entire buffer. This means our
549 * network is fast and our buffer is too small, so make it
550 * bigger.
552 increase_buffer_size(xfer);
555 if (xfer->buffer) {
557 * Remove what we wrote
558 * If we wrote the whole buffer the byte array will be empty
559 * Otherwise we'll keep what wasn't sent for next time.
561 buffer = NULL;
562 g_byte_array_remove_range(xfer->buffer, 0, r);
566 FT_SIPE_DEBUG_INFO_NOFORMAT("back to common code");
567 if (r > 0) {
568 if (xfer->file_size > 0)
569 xfer->bytes_remaining -= r;
571 xfer->bytes_sent += r;
573 g_free(buffer);
574 update_progress(xfer);
577 if (xfer->status == SIPE_MIRANDA_XFER_STATUS_DONE)
579 xfer->end_time = time(NULL);
580 if (xfer->ft->end && xfer->ft->end(xfer->ft)) {
581 /* We're done with this transfer */
582 free_xfer_struct(xfer);
583 } else if (xfer->incoming) {
584 _unlink(xfer->local_filename);
587 if (xfer->watcher != 0) {
588 sipe_miranda_input_remove(xfer->watcher);
589 xfer->watcher = 0;
592 if (xfer->fd)
593 Netlib_CloseHandle(xfer->fd);
595 if (xfer->dest_fp != NULL) {
596 fclose(xfer->dest_fp);
597 xfer->dest_fp = NULL;
600 g_free(xfer->filename);
601 g_free(xfer);
605 static void
606 transfer_cb(gpointer data, gint source, sipe_miranda_input_condition condition)
608 struct sipe_backend_file_transfer *xfer = data;
609 SIPE_DEBUG_INFO_NOFORMAT("");
610 do_transfer(xfer);
613 static void
614 begin_transfer(struct sipe_file_transfer *ft)
616 struct sipe_backend_file_transfer *xfer = ft->backend_private;
617 SIPPROTO *pr = xfer->pr;
619 xfer->dest_fp = fopen(xfer->local_filename, xfer->incoming ? "wb" : "rb");
620 if (xfer->dest_fp == NULL) {
621 int err = errno;
622 gchar *msg;
623 if (xfer->incoming)
625 msg = g_strdup_printf("Error reading %s: \n%s.\n", xfer->local_filename, g_strerror(err));
626 } else {
627 msg = g_strdup_printf("Error writing %s: \n%s.\n", xfer->local_filename, g_strerror(err));
629 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
630 g_free(msg);
631 FT_SIPE_DEBUG_INFO("error opening local file: %s", g_strerror(errno));
632 cancel_local(xfer);
633 return;
636 fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
638 xfer->start_time = time(NULL);
640 LOCK;
641 FT_SIPE_DEBUG_INFO("incoming <%d> size <%d>", ft->backend_private->incoming, ft->backend_private->file_size);
642 if (!ft->backend_private->incoming) {
643 /* Set socket to nonblocking */
644 SOCKET sock = CallService(MS_NETLIB_GETSOCKET, (WPARAM)xfer->fd, (LPARAM)0);
645 unsigned long parm = 1;
647 if (ioctlsocket(sock, FIONBIO, &parm) == SOCKET_ERROR)
649 FT_SIPE_DEBUG_INFO("Error ioctlsocket <%d>", WSAGetLastError());
652 FT_SIPE_DEBUG_INFO("outgoing ft <%08x> size <%d>", ft, ft->backend_private->file_size);
654 if (ft->start) {
655 ft->start(ft, ft->backend_private->file_size);
657 UNLOCK;
659 if (xfer->fd)
660 xfer->watcher = sipe_miranda_input_add(xfer->fd, xfer->incoming?SIPE_MIRANDA_INPUT_READ:SIPE_MIRANDA_INPUT_WRITE, transfer_cb, xfer);
662 FT_SIPE_DEBUG_INFO("watcher [%08x]", xfer->watcher);
665 static void
666 ft_connected_callback(HANDLE fd, void* data, const gchar *reason)
668 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)data;
669 struct sipe_backend_file_transfer *xfer = ft->backend_private;
670 SIPPROTO *pr = ft->backend_private->pr;
672 if (!fd)
674 cancel_local(xfer);
675 } else {
676 ft->backend_private->fd = fd;
677 begin_transfer(ft);
682 void
683 sipe_backend_ft_start(struct sipe_file_transfer *ft, struct sipe_backend_fd *fd,
684 const char* ip, unsigned port)
686 ft->backend_private->status = SIPE_MIRANDA_XFER_STATUS_STARTED;
688 if (ip && port)
690 FT_SIPE_DEBUG_INFO("Should connect to <%s:%d>", ip, port);
691 sipe_miranda_connect(ft->backend_private->pr, ip, port, FALSE, 5, ft_connected_callback, ft);
692 return;
695 FT_SIPE_DEBUG_INFO("Should use incoming fd <%08x>", fd);
696 ft->backend_private->fd = fd;
697 begin_transfer(ft);
700 gboolean
701 sipe_backend_ft_is_incoming(struct sipe_file_transfer *ft)
703 FT_SIPE_DEBUG_INFO("ft <%08x> incoming <%d>", ft, ft->backend_private->incoming);
704 return ft->backend_private->incoming;
707 HANDLE
708 sipe_miranda_SendFile( SIPPROTO *pr, HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles )
710 DBVARIANT dbv;
712 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
713 struct sipe_file_transfer *ft;
715 ft = sipe_core_ft_create_outgoing(pr->sip, dbv.pszVal, TCHAR2CHAR(ppszFiles[0]));
717 FT_SIPE_DEBUG_INFO("SendFile: desc <%ls> name <%s> size <%d> to <%s>", szDescription, TCHAR2CHAR(ppszFiles[0]), ft->backend_private->file_size, dbv.pszVal);
719 DBFreeVariant( &dbv );
721 return ft->backend_private;
724 return NULL;
728 sipe_miranda_RecvFile( SIPPROTO *pr, HANDLE hContact, PROTOFILEEVENT* evt )
730 CCSDATA ccs = { hContact, PSR_FILE, 0, (LPARAM)evt };
731 return CallService(MS_PROTO_RECVFILET, 0, (LPARAM)&ccs);
734 HANDLE
735 sipe_miranda_FileAllow( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath )
737 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
738 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> allowed", ft);
739 ft->backend_private->local_filename = g_strdup_printf("%s%s", TCHAR2CHAR(szPath), ft->backend_private->filename);
740 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
741 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, NULL);
742 return ft->backend_private;
746 sipe_miranda_FileDeny( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason )
748 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
749 FT_SIPE_DEBUG_INFO("FileDeny: reason <%s>", szReason);
750 if (ft->backend_private->incoming && ft->request_denied)
751 ft->request_denied(ft);
752 free_xfer_struct(ft->backend_private);
753 return 0;
758 Local Variables:
759 mode: c
760 c-file-style: "bsd"
761 indent-tabs-mode: t
762 tab-width: 8
763 End: