6 * Copyright (C) 2010-11 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
28 #include <sys/types.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"
42 #include "sipe-common.h"
43 #include "sipe-backend.h"
44 #include "sipe-core.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
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
{
69 struct sipe_file_transfer
*ft
;
72 size_t bytes_remaining
;
73 size_t current_buffer_size
;
74 struct sipe_miranda_sel_entry
*watcher
;
76 gchar
*local_filename
;
82 PROTOFILETRANSFERSTATUS st
;
83 sipe_miranda_xfer_status status
;
87 update_progress(struct sipe_backend_file_transfer
*xfer
)
90 ZeroMemory(pfts
, sizeof(PROTOFILETRANSFERSTATUS
));
91 pfts
->flags
= PFTS_UTF
| (ft
->sending
? PFTS_SENDING
: PFTS_RECEIVING
); /* Standard FT is Ansi only */
93 pfts
->pszFiles
= ft
->pszFiles
;
95 pfts
->pszFiles
= NULL
; /* FIXME */
96 pfts
->currentFileTime
= ft
->dwThisFileDate
;
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
,
118 increase_buffer_size(struct sipe_backend_file_transfer
*xfer
)
120 xfer
->current_buffer_size
= MIN(xfer
->current_buffer_size
* 1.5,
124 void sipe_backend_ft_error(struct sipe_file_transfer
*ft
,
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");
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
);
143 const gchar
*sipe_backend_ft_get_error(SIPE_UNUSED_PARAMETER
struct sipe_file_transfer
*ft
)
146 return strerror(errno
); /* FIXME: Only valid for the file side i think */
150 free_xfer_struct(struct sipe_backend_file_transfer
*xfer
)
152 struct sipe_file_transfer
*ft
= xfer
->ft
;
156 sipe_miranda_input_remove(xfer
->watcher
);
159 sipe_core_ft_deallocate(ft
);
165 cancel_remote(struct sipe_backend_file_transfer
*xfer
)
167 struct sipe_file_transfer
*ft
= xfer
->ft
;
169 FT_SIPE_DEBUG_INFO_NOFORMAT("");
173 xfer
->status
= SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE
;
174 xfer
->end_time
= time(NULL
);
176 msg
= g_strdup_printf("File transfer cancelled by peer");
177 sipe_miranda_AddEvent(ft
->backend_private
->pr
, ft
->backend_private
->hContact
, SIPE_EVENTTYPE_ERROR_NOTIFY
, time(NULL
), DBEF_UTF
, strlen(msg
), (PBYTE
)msg
);
180 free_xfer_struct(xfer
);
182 if (xfer
->watcher
!= 0) {
183 sipe_miranda_input_remove(xfer
->watcher
);
188 Netlib_CloseHandle(xfer
->fd
);
190 if (xfer
->dest_fp
!= NULL
) {
191 fclose(xfer
->dest_fp
);
192 xfer
->dest_fp
= NULL
;
195 xfer
->bytes_remaining
= 0;
196 g_free(xfer
->filename
);
197 /* g_free(xfer); FIXME: needs refcounting like purple i guess */
200 void sipe_backend_ft_deallocate(struct sipe_file_transfer
*ft
)
202 struct sipe_backend_file_transfer
*xfer
= ft
->backend_private
;
204 /* If file transfer is not finished, cancel it */
205 if (xfer
->status
!= SIPE_MIRANDA_XFER_STATUS_DONE
206 && xfer
->status
!= SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL
207 && xfer
->status
!= SIPE_MIRANDA_XFER_STATUS_CANCEL_REMOTE
)
214 gssize
sipe_backend_ft_read(struct sipe_file_transfer
*ft
,
220 FT_SIPE_DEBUG_INFO("reading up to <%d> bytes", size
);
221 bytes_read
= Netlib_Recv(ft
->backend_private
->fd
, data
, size
, MSG_NODUMP
);
222 FT_SIPE_DEBUG_INFO("came back from read <%d>", bytes_read
);
223 if (bytes_read
== 0) {
224 /* Sender canceled transfer before it was finished */
225 FT_SIPE_DEBUG_INFO_NOFORMAT("no read cause sender cancelled");
227 } else if (bytes_read
== SOCKET_ERROR
) {
228 int err
= WSAGetLastError();
229 if (err
== WSAEWOULDBLOCK
) {
232 FT_SIPE_DEBUG_INFO("Error reading <%d>", err
);
236 FT_SIPE_DEBUG_INFO("read <%d> bytes [%02x:%c]", bytes_read
, *data
, *data
);
240 gssize
sipe_backend_ft_write(struct sipe_file_transfer
*ft
,
245 FT_SIPE_DEBUG_INFO("writing <%d> bytes", size
);
246 bytes_written
= Netlib_Send(ft
->backend_private
->fd
, data
, size
, MSG_NODUMP
);
247 if (bytes_written
== SOCKET_ERROR
) {
248 int err
= WSAGetLastError();
249 if (err
== WSAEWOULDBLOCK
) {
252 FT_SIPE_DEBUG_INFO("Error writing <%u>", err
);
256 FT_SIPE_DEBUG_INFO("wrote <%d> bytes", bytes_written
);
257 return bytes_written
;
261 cancel_local(struct sipe_backend_file_transfer
*xfer
)
263 struct sipe_file_transfer
*ft
= xfer
->ft
;
265 FT_SIPE_DEBUG_INFO_NOFORMAT("");
267 xfer
->status
= SIPE_MIRANDA_XFER_STATUS_CANCEL_LOCAL
;
268 xfer
->end_time
= time(NULL
);
270 msg
= g_strdup_printf("File transfer cancelled");
271 sipe_miranda_AddEvent(ft
->backend_private
->pr
, ft
->backend_private
->hContact
, SIPE_EVENTTYPE_ERROR_NOTIFY
, time(NULL
), DBEF_UTF
, strlen(msg
), (PBYTE
)msg
);
274 free_xfer_struct(xfer
);
276 if (xfer
->watcher
!= 0) {
277 sipe_miranda_input_remove(xfer
->watcher
);
282 Netlib_CloseHandle(xfer
->fd
);
284 if (xfer
->dest_fp
!= NULL
) {
285 fclose(xfer
->dest_fp
);
286 xfer
->dest_fp
= NULL
;
289 xfer
->bytes_remaining
= 0;
291 g_free(xfer
->filename
);
295 void sipe_backend_ft_cancel_local(struct sipe_file_transfer
*ft
)
297 cancel_local(ft
->backend_private
);
300 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer
*ft
)
302 cancel_remote(ft
->backend_private
);
305 static struct sipe_backend_file_transfer
*
306 new_xfer(SIPPROTO
*pr
,
307 struct sipe_file_transfer
*ft
,
310 struct sipe_backend_file_transfer
*xfer
= g_new0(struct sipe_backend_file_transfer
, 1);
312 xfer
->current_buffer_size
= FT_INITIAL_BUFFER_SIZE
;
313 xfer
->buffer
= g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE
);
315 xfer
->hContact
= hContact
;
318 xfer
->st
.cbSize
= sizeof(PROTOFILETRANSFERSTATUS
);
319 xfer
->st
.hContact
= hContact
;
324 void sipe_backend_ft_incoming(struct sipe_core_public
*sipe_public
,
325 struct sipe_file_transfer
*ft
,
327 const gchar
*file_name
,
330 SIPPROTO
*pr
= sipe_public
->backend_private
;
331 PROTORECVFILET pre
= {0};
335 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> from <%s> file <%s> size <%d>", ft
, who
, file_name
, file_size
);
336 hContact
= sipe_backend_buddy_find( sipe_public
, who
, NULL
);
339 FT_SIPE_DEBUG_INFO("Adding miranda contact for incoming transfer from <%s>", who
);
340 hContact
= ( HANDLE
)CallService( MS_DB_CONTACT_ADD
, 0, 0 );
341 CallService( MS_PROTO_ADDTOCONTACT
, ( WPARAM
)hContact
,( LPARAM
)pr
->proto
.m_szModuleName
);
342 DBWriteContactSettingByte( hContact
, "CList", "NotOnList", 1 );
343 sipe_miranda_setContactString( pr
, hContact
, SIP_UNIQUEID
, who
); // name
346 ft
->backend_private
= new_xfer(pr
, ft
, hContact
);
347 ft
->backend_private
->incoming
= TRUE
;
348 ft
->backend_private
->file_size
= file_size
;
349 ft
->backend_private
->bytes_remaining
= file_size
;
350 ft
->backend_private
->bytes_sent
= 0;
351 ft
->backend_private
->filename
= g_strdup(file_name
);
353 pre
.flags
= PREF_TCHAR
;
354 pre
.timestamp
= time(NULL
);
355 pre
.tszDescription
= mir_a2t(file_name
);
357 pre
.ptszFiles
= &pre
.tszDescription
;
358 pre
.lParam
= (LPARAM
)ft
;
360 ccs
.szProtoService
= PSR_FILE
;
361 ccs
.hContact
= hContact
;
363 ccs
.lParam
= (LPARAM
)&pre
;
364 CallService(MS_PROTO_CHAINRECV
, 0, (LPARAM
)&ccs
);
369 sipe_backend_ft_incoming_accept(struct sipe_file_transfer
*ft
,
371 unsigned short port_min
,
372 unsigned short port_max
)
379 set_completed(struct sipe_backend_file_transfer
*xfer
, gboolean completed
)
381 if (completed
== TRUE
) {
384 xfer
->status
= SIPE_MIRANDA_XFER_STATUS_DONE
;
386 if (xfer
->filename
!= NULL
)
388 char *filename
= g_markup_escape_text(xfer
->filename
, -1);
389 if (xfer
->local_filename
&& xfer
->incoming
)
391 char *local
= g_markup_escape_text(xfer
->local_filename
, -1);
392 msg
= g_strdup_printf("Transfer of file <A HREF=\"file://%s\">%s</A> complete",
397 msg
= g_strdup_printf("Transfer of file %s complete",
402 msg
= g_strdup("File transfer complete");
404 sipe_miranda_AddEvent(xfer
->pr
, xfer
->hContact
, SIPE_EVENTTYPE_ERROR_NOTIFY
, time(NULL
), DBEF_UTF
, strlen(msg
), (PBYTE
)msg
);
405 sipe_miranda_SendBroadcast(xfer
->pr
, xfer
->hContact
, ACKTYPE_FILE
, ACKRESULT_SUCCESS
, (HANDLE
)xfer
, 0);
410 update_progress(xfer
);
414 do_transfer(struct sipe_backend_file_transfer
*xfer
)
417 guchar
*buffer
= NULL
;
419 struct sipe_file_transfer
*ft
= xfer
->ft
;
421 FT_SIPE_DEBUG_INFO("incoming <%d>", xfer
->incoming
);
422 if (xfer
->incoming
) {
423 FT_SIPE_DEBUG_INFO_NOFORMAT("incoming branch");
424 r
= sipe_core_tftp_read(xfer
->ft
, &buffer
, xfer
->bytes_remaining
,
425 xfer
->current_buffer_size
);
428 wc
= fwrite(buffer
, 1, r
, xfer
->dest_fp
);
431 SIPE_DEBUG_ERROR("Unable to write whole buffer.");
437 if ((xfer
->file_size
> 0) && ((xfer
->bytes_sent
+r
) >= xfer
->file_size
))
438 set_completed(xfer
, TRUE
);
447 size_t s
= MIN(xfer
->bytes_remaining
, xfer
->current_buffer_size
);
448 gboolean read
= TRUE
;
449 FT_SIPE_DEBUG_INFO("outgoing branch, size <%u>", s
);
451 /* this is so the prpl can keep the connection open
452 if it needs to for some odd reason. */
455 sipe_miranda_input_remove(xfer
->watcher
);
462 if (xfer
->buffer
->len
< s
) {
463 s
-= xfer
->buffer
->len
;
471 buffer
= g_malloc(s
);
472 result
= fread(buffer
, 1, s
, xfer
->dest_fp
);
474 FT_SIPE_DEBUG_INFO_NOFORMAT("Unable to read whole buffer.");
482 g_byte_array_append(xfer
->buffer
, buffer
, result
);
484 buffer
= xfer
->buffer
->data
;
485 result
= xfer
->buffer
->len
;
488 s
= MIN(xfer
->bytes_remaining
, result
);
489 r
= sipe_core_tftp_write(xfer
->ft
, buffer
, s
);
491 if ((xfer
->bytes_remaining
- r
) == 0)
492 set_completed(xfer
, TRUE
);
494 if (r
>= 0 && (xfer
->bytes_sent
+r
) >= xfer
->file_size
&& xfer
->status
!= SIPE_MIRANDA_XFER_STATUS_DONE
)
495 set_completed(xfer
, TRUE
);
501 /* We don't free buffer if priv->buffer is set, because in
502 that case buffer doesn't belong to us. */
505 } else if (r
== result
) {
507 * We managed to write the entire buffer. This means our
508 * network is fast and our buffer is too small, so make it
511 increase_buffer_size(xfer
);
516 * Remove what we wrote
517 * If we wrote the whole buffer the byte array will be empty
518 * Otherwise we'll keep what wasn't sent for next time.
521 g_byte_array_remove_range(xfer
->buffer
, 0, r
);
525 FT_SIPE_DEBUG_INFO_NOFORMAT("back to common code");
527 if (xfer
->file_size
> 0)
528 xfer
->bytes_remaining
-= r
;
530 xfer
->bytes_sent
+= r
;
533 update_progress(xfer
);
536 if (xfer
->status
== SIPE_MIRANDA_XFER_STATUS_DONE
)
538 xfer
->end_time
= time(NULL
);
541 if (sipe_core_tftp_incoming_stop(xfer
->ft
)) {
542 /* We're done with this transfer */
543 free_xfer_struct(xfer
);
545 _unlink(xfer
->local_filename
);
548 if (sipe_core_tftp_outgoing_stop(xfer
->ft
)) {
549 /* We're done with this transfer */
550 free_xfer_struct(xfer
);
554 if (xfer
->watcher
!= 0) {
555 sipe_miranda_input_remove(xfer
->watcher
);
560 Netlib_CloseHandle(xfer
->fd
);
562 if (xfer
->dest_fp
!= NULL
) {
563 fclose(xfer
->dest_fp
);
564 xfer
->dest_fp
= NULL
;
567 g_free(xfer
->filename
);
573 transfer_cb(gpointer data
, gint source
, sipe_miranda_input_condition condition
)
575 struct sipe_backend_file_transfer
*xfer
= data
;
576 SIPE_DEBUG_INFO_NOFORMAT("");
581 begin_transfer(struct sipe_file_transfer
*ft
)
583 struct sipe_backend_file_transfer
*xfer
= ft
->backend_private
;
584 SIPPROTO
*pr
= xfer
->pr
;
586 xfer
->dest_fp
= fopen(xfer
->local_filename
, xfer
->incoming
? "wb" : "rb");
587 if (xfer
->dest_fp
== NULL
) {
592 msg
= g_strdup_printf("Error reading %s: \n%s.\n", xfer
->local_filename
, g_strerror(err
));
594 msg
= g_strdup_printf("Error writing %s: \n%s.\n", xfer
->local_filename
, g_strerror(err
));
596 sipe_miranda_AddEvent(ft
->backend_private
->pr
, ft
->backend_private
->hContact
, SIPE_EVENTTYPE_ERROR_NOTIFY
, time(NULL
), DBEF_UTF
, strlen(msg
), (PBYTE
)msg
);
598 FT_SIPE_DEBUG_INFO("error opening local file: %s", g_strerror(errno
));
603 fseek(xfer
->dest_fp
, xfer
->bytes_sent
, SEEK_SET
);
605 xfer
->start_time
= time(NULL
);
608 FT_SIPE_DEBUG_INFO("incoming <%d> size <%d>", ft
->backend_private
->incoming
, ft
->backend_private
->file_size
);
609 if (ft
->backend_private
->incoming
)
610 sipe_core_tftp_incoming_start(ft
, ft
->backend_private
->file_size
);
612 /* Set socket to nonblocking */
613 SOCKET sock
= CallService(MS_NETLIB_GETSOCKET
, (WPARAM
)xfer
->fd
, (LPARAM
)0);
614 unsigned long parm
= 1;
616 if (ioctlsocket(sock
, FIONBIO
, &parm
) == SOCKET_ERROR
)
618 FT_SIPE_DEBUG_INFO("Error ioctlsocket <%d>", WSAGetLastError());
621 FT_SIPE_DEBUG_INFO("outgoing ft <%08x> size <%d>", ft
, ft
->backend_private
->file_size
);
622 sipe_core_tftp_outgoing_start(ft
, ft
->backend_private
->file_size
);
627 xfer
->watcher
= sipe_miranda_input_add(xfer
->fd
, xfer
->incoming
?SIPE_MIRANDA_INPUT_READ
:SIPE_MIRANDA_INPUT_WRITE
, transfer_cb
, xfer
);
629 FT_SIPE_DEBUG_INFO("watcher [%08x]", xfer
->watcher
);
633 ft_connected_callback(HANDLE fd
, void* data
, const gchar
*reason
)
635 struct sipe_file_transfer
*ft
= (struct sipe_file_transfer
*)data
;
636 struct sipe_backend_file_transfer
*xfer
= ft
->backend_private
;
637 SIPPROTO
*pr
= ft
->backend_private
->pr
;
643 ft
->backend_private
->fd
= fd
;
650 sipe_backend_ft_start(struct sipe_file_transfer
*ft
, struct sipe_backend_fd
*fd
,
651 const char* ip
, unsigned port
)
653 ft
->backend_private
->status
= SIPE_MIRANDA_XFER_STATUS_STARTED
;
657 FT_SIPE_DEBUG_INFO("Should connect to <%s:%d>", ip
, port
);
658 sipe_miranda_connect(ft
->backend_private
->pr
, ip
, port
, FALSE
, 5, ft_connected_callback
, ft
);
662 FT_SIPE_DEBUG_INFO("Should use incoming fd <%08x>", fd
);
663 ft
->backend_private
->fd
= fd
;
668 sipe_backend_ft_is_incoming(struct sipe_file_transfer
*ft
)
670 FT_SIPE_DEBUG_INFO("ft <%08x> incoming <%d>", ft
, ft
->backend_private
->incoming
);
671 return ft
->backend_private
->incoming
;
675 sipe_miranda_SendFile( SIPPROTO
*pr
, HANDLE hContact
, const PROTOCHAR
* szDescription
, PROTOCHAR
** ppszFiles
)
677 struct sipe_file_transfer
*ft
= sipe_core_ft_allocate(pr
->sip
);
680 if ( !DBGetContactSettingString( hContact
, pr
->proto
.m_szModuleName
, SIP_UNIQUEID
, &dbv
)) {
685 ft
->backend_private
= new_xfer(pr
, ft
, hContact
);
686 ft
->backend_private
->incoming
= FALSE
;
687 result
= _tstat64( ppszFiles
[0], &buf
);
690 FT_SIPE_DEBUG_INFO("Could not stat file, error<%d>", result
);
691 ft
->backend_private
->file_size
= 0;
695 ft
->backend_private
->file_size
= buf
.st_size
;
696 ft
->backend_private
->bytes_remaining
= ft
->backend_private
->file_size
;
697 ft
->backend_private
->bytes_sent
= 0;
699 FT_SIPE_DEBUG_INFO("SendFile: desc <%ls> name <%s> size <%d> to <%s>", szDescription
, TCHAR2CHAR(ppszFiles
[0]), ft
->backend_private
->file_size
, dbv
.pszVal
);
700 ft
->backend_private
->local_filename
= g_strdup(TCHAR2CHAR(ppszFiles
[0]));
701 ft
->backend_private
->filename
= g_path_get_basename(ft
->backend_private
->local_filename
);
702 FT_SIPE_DEBUG_INFO("set filename to <%s>", ft
->backend_private
->filename
);
703 sipe_core_ft_outgoing_init(ft
, ft
->backend_private
->filename
, ft
->backend_private
->file_size
, dbv
.pszVal
);
704 sipe_miranda_SendBroadcast(pr
, hContact
, ACKTYPE_FILE
, ACKRESULT_CONNECTING
, (HANDLE
)ft
->backend_private
, 0);
707 DBFreeVariant( &dbv
);
710 return ft
->backend_private
;
714 sipe_miranda_RecvFile( SIPPROTO
*pr
, HANDLE hContact
, PROTOFILEEVENT
* evt
)
716 CCSDATA ccs
= { hContact
, PSR_FILE
, 0, (LPARAM
)evt
};
717 return CallService(MS_PROTO_RECVFILET
, 0, (LPARAM
)&ccs
);
721 sipe_miranda_FileAllow( SIPPROTO
*pr
, HANDLE hContact
, HANDLE hTransfer
, const PROTOCHAR
* szPath
)
723 struct sipe_file_transfer
*ft
= (struct sipe_file_transfer
*)hTransfer
;
724 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> allowed", ft
);
725 ft
->backend_private
->local_filename
= g_strdup_printf("%s%s", TCHAR2CHAR(szPath
), ft
->backend_private
->filename
);
726 sipe_miranda_SendBroadcast(pr
, hContact
, ACKTYPE_FILE
, ACKRESULT_CONNECTING
, (HANDLE
)ft
->backend_private
, 0);
727 sipe_core_ft_incoming_init(ft
);
728 return ft
->backend_private
;
732 sipe_miranda_FileDeny( SIPPROTO
*pr
, HANDLE hContact
, HANDLE hTransfer
, const PROTOCHAR
* szReason
)
734 struct sipe_file_transfer
*ft
= (struct sipe_file_transfer
*)hTransfer
;
735 FT_SIPE_DEBUG_INFO("FileDeny: reason <%s>", szReason
);
736 if (ft
->backend_private
->incoming
)
737 sipe_core_ft_cancel(ft
);
738 free_xfer_struct(ft
->backend_private
);