filetransfer: use 'end' callback in sipe_file_transfer
[siplcs.git] / src / miranda / miranda-ft.c
blob90732b2df829985e2484a29eeb3b2c69ccbc22ab
1 /**
2 * @file miranda-ft.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2015 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_cancel_local(struct sipe_file_transfer *ft)
299 cancel_local(ft->backend_private);
302 void sipe_backend_ft_cancel_remote(struct sipe_file_transfer *ft)
304 cancel_remote(ft->backend_private);
307 static struct sipe_backend_file_transfer *
308 new_xfer(SIPPROTO *pr,
309 struct sipe_file_transfer *ft,
310 HANDLE hContact)
312 struct sipe_backend_file_transfer *xfer = g_new0(struct sipe_backend_file_transfer, 1);
314 xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
315 xfer->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE);
316 xfer->ft = ft;
317 xfer->hContact = hContact;
318 xfer->pr = pr;
320 xfer->st.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
321 xfer->st.hContact = hContact;
323 return xfer;
326 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
327 struct sipe_file_transfer *ft,
328 const gchar *who,
329 const gchar *file_name,
330 gsize file_size)
332 SIPPROTO *pr = sipe_public->backend_private;
333 PROTORECVFILET pre = {0};
334 CCSDATA ccs;
335 HANDLE hContact;
337 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> from <%s> file <%s> size <%d>", ft, who, file_name, file_size);
338 hContact = sipe_backend_buddy_find( sipe_public, who, NULL );
339 if (!hContact)
341 FT_SIPE_DEBUG_INFO("Adding miranda contact for incoming transfer from <%s>", who);
342 hContact = ( HANDLE )CallService( MS_DB_CONTACT_ADD, 0, 0 );
343 CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact,( LPARAM )pr->proto.m_szModuleName );
344 DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
345 sipe_miranda_setContactString( pr, hContact, SIP_UNIQUEID, who ); // name
348 ft->backend_private = new_xfer(pr, ft, hContact);
349 ft->backend_private->incoming = TRUE;
350 ft->backend_private->file_size = file_size;
351 ft->backend_private->bytes_remaining = file_size;
352 ft->backend_private->bytes_sent = 0;
353 ft->backend_private->filename = g_strdup(file_name);
355 pre.flags = PREF_TCHAR;
356 pre.timestamp = time(NULL);
357 pre.tszDescription = mir_a2t(file_name);
358 pre.fileCount = 1;
359 pre.ptszFiles = &pre.tszDescription;
360 pre.lParam = (LPARAM)ft;
362 ccs.szProtoService = PSR_FILE;
363 ccs.hContact = hContact;
364 ccs.wParam = 0;
365 ccs.lParam = (LPARAM)&pre;
366 CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
370 gboolean
371 sipe_backend_ft_incoming_accept(struct sipe_file_transfer *ft,
372 const gchar *ip,
373 unsigned short port_min,
374 unsigned short port_max)
376 _NIF();
377 return FALSE;
380 static void
381 set_completed(struct sipe_backend_file_transfer *xfer, gboolean completed)
383 if (completed == TRUE) {
384 char *msg = NULL;
386 xfer->status = SIPE_MIRANDA_XFER_STATUS_DONE;
388 if (xfer->filename != NULL)
390 char *filename = g_markup_escape_text(xfer->filename, -1);
391 if (xfer->local_filename && xfer->incoming)
393 char *local = g_markup_escape_text(xfer->local_filename, -1);
394 msg = g_strdup_printf("Transfer of file <A HREF=\"file://%s\">%s</A> complete",
395 local, filename);
396 g_free(local);
398 else
399 msg = g_strdup_printf("Transfer of file %s complete",
400 filename);
401 g_free(filename);
403 else
404 msg = g_strdup("File transfer complete");
406 sipe_miranda_AddEvent(xfer->pr, xfer->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
407 sipe_miranda_SendBroadcast(xfer->pr, xfer->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)xfer, 0);
409 g_free(msg);
412 update_progress(xfer);
415 static void
416 do_transfer(struct sipe_backend_file_transfer *xfer)
419 guchar *buffer = NULL;
420 gssize r = 0;
421 struct sipe_file_transfer *ft = xfer->ft;
423 FT_SIPE_DEBUG_INFO("incoming <%d>", xfer->incoming);
424 if (xfer->incoming) {
425 FT_SIPE_DEBUG_INFO_NOFORMAT("incoming branch");
426 r = sipe_core_tftp_read(xfer->ft, &buffer, xfer->bytes_remaining,
427 xfer->current_buffer_size);
428 if (r > 0) {
429 size_t wc;
430 wc = fwrite(buffer, 1, r, xfer->dest_fp);
432 if (wc != r) {
433 SIPE_DEBUG_ERROR("Unable to write whole buffer.");
434 cancel_local(xfer);
435 g_free(buffer);
436 return;
439 if ((xfer->file_size > 0) && ((xfer->bytes_sent+r) >= xfer->file_size))
440 set_completed(xfer, TRUE);
442 } else if(r < 0) {
443 cancel_remote(xfer);
444 g_free(buffer);
445 return;
447 } else {
448 size_t result = 0;
449 size_t s = MIN(xfer->bytes_remaining, xfer->current_buffer_size);
450 gboolean read = TRUE;
451 FT_SIPE_DEBUG_INFO("outgoing branch, size <%u>", s);
453 /* this is so the prpl can keep the connection open
454 if it needs to for some odd reason. */
455 if (s == 0) {
456 if (xfer->watcher) {
457 sipe_miranda_input_remove(xfer->watcher);
458 xfer->watcher = 0;
460 return;
463 if (xfer->buffer) {
464 if (xfer->buffer->len < s) {
465 s -= xfer->buffer->len;
466 read = TRUE;
467 } else {
468 read = FALSE;
472 if (read) {
473 buffer = g_malloc(s);
474 result = fread(buffer, 1, s, xfer->dest_fp);
475 if (result != s) {
476 FT_SIPE_DEBUG_INFO_NOFORMAT("Unable to read whole buffer.");
477 cancel_local(xfer);
478 g_free(buffer);
479 return;
483 if (xfer->buffer) {
484 g_byte_array_append(xfer->buffer, buffer, result);
485 g_free(buffer);
486 buffer = xfer->buffer->data;
487 result = xfer->buffer->len;
490 s = MIN(xfer->bytes_remaining, result);
491 r = sipe_core_tftp_write(xfer->ft, buffer, s);
493 if ((xfer->bytes_remaining - r) == 0)
494 set_completed(xfer, TRUE);
496 if (r >= 0 && (xfer->bytes_sent+r) >= xfer->file_size && xfer->status != SIPE_MIRANDA_XFER_STATUS_DONE)
497 set_completed(xfer, TRUE);
499 if (r == -1) {
500 cancel_remote(xfer);
502 if (!xfer->buffer)
503 /* We don't free buffer if priv->buffer is set, because in
504 that case buffer doesn't belong to us. */
505 g_free(buffer);
506 return;
507 } else if (r == result) {
509 * We managed to write the entire buffer. This means our
510 * network is fast and our buffer is too small, so make it
511 * bigger.
513 increase_buffer_size(xfer);
516 if (xfer->buffer) {
518 * Remove what we wrote
519 * If we wrote the whole buffer the byte array will be empty
520 * Otherwise we'll keep what wasn't sent for next time.
522 buffer = NULL;
523 g_byte_array_remove_range(xfer->buffer, 0, r);
527 FT_SIPE_DEBUG_INFO_NOFORMAT("back to common code");
528 if (r > 0) {
529 if (xfer->file_size > 0)
530 xfer->bytes_remaining -= r;
532 xfer->bytes_sent += r;
534 g_free(buffer);
535 update_progress(xfer);
538 if (xfer->status == SIPE_MIRANDA_XFER_STATUS_DONE)
540 xfer->end_time = time(NULL);
541 if (xfer->ft->end && xfer->ft->end(xfer->ft)) {
542 /* We're done with this transfer */
543 free_xfer_struct(xfer);
544 } else if (xfer->incoming) {
545 _unlink(xfer->local_filename);
548 if (xfer->watcher != 0) {
549 sipe_miranda_input_remove(xfer->watcher);
550 xfer->watcher = 0;
553 if (xfer->fd)
554 Netlib_CloseHandle(xfer->fd);
556 if (xfer->dest_fp != NULL) {
557 fclose(xfer->dest_fp);
558 xfer->dest_fp = NULL;
561 g_free(xfer->filename);
562 g_free(xfer);
566 static void
567 transfer_cb(gpointer data, gint source, sipe_miranda_input_condition condition)
569 struct sipe_backend_file_transfer *xfer = data;
570 SIPE_DEBUG_INFO_NOFORMAT("");
571 do_transfer(xfer);
574 static void
575 begin_transfer(struct sipe_file_transfer *ft)
577 struct sipe_backend_file_transfer *xfer = ft->backend_private;
578 SIPPROTO *pr = xfer->pr;
580 xfer->dest_fp = fopen(xfer->local_filename, xfer->incoming ? "wb" : "rb");
581 if (xfer->dest_fp == NULL) {
582 int err = errno;
583 gchar *msg;
584 if (xfer->incoming)
586 msg = g_strdup_printf("Error reading %s: \n%s.\n", xfer->local_filename, g_strerror(err));
587 } else {
588 msg = g_strdup_printf("Error writing %s: \n%s.\n", xfer->local_filename, g_strerror(err));
590 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
591 g_free(msg);
592 FT_SIPE_DEBUG_INFO("error opening local file: %s", g_strerror(errno));
593 cancel_local(xfer);
594 return;
597 fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
599 xfer->start_time = time(NULL);
601 LOCK;
602 FT_SIPE_DEBUG_INFO("incoming <%d> size <%d>", ft->backend_private->incoming, ft->backend_private->file_size);
603 if (!ft->backend_private->incoming) {
604 /* Set socket to nonblocking */
605 SOCKET sock = CallService(MS_NETLIB_GETSOCKET, (WPARAM)xfer->fd, (LPARAM)0);
606 unsigned long parm = 1;
608 if (ioctlsocket(sock, FIONBIO, &parm) == SOCKET_ERROR)
610 FT_SIPE_DEBUG_INFO("Error ioctlsocket <%d>", WSAGetLastError());
613 FT_SIPE_DEBUG_INFO("outgoing ft <%08x> size <%d>", ft, ft->backend_private->file_size);
615 if (ft->start) {
616 ft->start(ft, ft->backend_private->file_size);
618 UNLOCK;
620 if (xfer->fd)
621 xfer->watcher = sipe_miranda_input_add(xfer->fd, xfer->incoming?SIPE_MIRANDA_INPUT_READ:SIPE_MIRANDA_INPUT_WRITE, transfer_cb, xfer);
623 FT_SIPE_DEBUG_INFO("watcher [%08x]", xfer->watcher);
626 static void
627 ft_connected_callback(HANDLE fd, void* data, const gchar *reason)
629 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)data;
630 struct sipe_backend_file_transfer *xfer = ft->backend_private;
631 SIPPROTO *pr = ft->backend_private->pr;
633 if (!fd)
635 cancel_local(xfer);
636 } else {
637 ft->backend_private->fd = fd;
638 begin_transfer(ft);
643 void
644 sipe_backend_ft_start(struct sipe_file_transfer *ft, struct sipe_backend_fd *fd,
645 const char* ip, unsigned port)
647 ft->backend_private->status = SIPE_MIRANDA_XFER_STATUS_STARTED;
649 if (ip && port)
651 FT_SIPE_DEBUG_INFO("Should connect to <%s:%d>", ip, port);
652 sipe_miranda_connect(ft->backend_private->pr, ip, port, FALSE, 5, ft_connected_callback, ft);
653 return;
656 FT_SIPE_DEBUG_INFO("Should use incoming fd <%08x>", fd);
657 ft->backend_private->fd = fd;
658 begin_transfer(ft);
661 gboolean
662 sipe_backend_ft_is_incoming(struct sipe_file_transfer *ft)
664 FT_SIPE_DEBUG_INFO("ft <%08x> incoming <%d>", ft, ft->backend_private->incoming);
665 return ft->backend_private->incoming;
668 HANDLE
669 sipe_miranda_SendFile( SIPPROTO *pr, HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles )
671 struct sipe_file_transfer *ft = sipe_core_ft_allocate(pr->sip);
672 DBVARIANT dbv;
674 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
675 int result;
676 struct __stat64 buf;
678 LOCK;
679 ft->backend_private = new_xfer(pr, ft, hContact);
680 ft->backend_private->incoming = FALSE;
681 result = _tstat64( ppszFiles[0], &buf );
682 if (result != 0)
684 FT_SIPE_DEBUG_INFO("Could not stat file, error<%d>", result);
685 ft->backend_private->file_size = 0;
687 else
689 ft->backend_private->file_size = buf.st_size;
690 ft->backend_private->bytes_remaining = ft->backend_private->file_size;
691 ft->backend_private->bytes_sent = 0;
693 FT_SIPE_DEBUG_INFO("SendFile: desc <%ls> name <%s> size <%d> to <%s>", szDescription, TCHAR2CHAR(ppszFiles[0]), ft->backend_private->file_size, dbv.pszVal);
694 ft->backend_private->local_filename = g_strdup(TCHAR2CHAR(ppszFiles[0]));
695 ft->backend_private->filename = g_path_get_basename(ft->backend_private->local_filename);
696 FT_SIPE_DEBUG_INFO("set filename to <%s>", ft->backend_private->filename);
697 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, dbv.pszVal);
698 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
699 UNLOCK;
701 DBFreeVariant( &dbv );
704 return ft->backend_private;
708 sipe_miranda_RecvFile( SIPPROTO *pr, HANDLE hContact, PROTOFILEEVENT* evt )
710 CCSDATA ccs = { hContact, PSR_FILE, 0, (LPARAM)evt };
711 return CallService(MS_PROTO_RECVFILET, 0, (LPARAM)&ccs);
714 HANDLE
715 sipe_miranda_FileAllow( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath )
717 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
718 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> allowed", ft);
719 ft->backend_private->local_filename = g_strdup_printf("%s%s", TCHAR2CHAR(szPath), ft->backend_private->filename);
720 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
721 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, NULL);
722 return ft->backend_private;
726 sipe_miranda_FileDeny( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason )
728 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
729 FT_SIPE_DEBUG_INFO("FileDeny: reason <%s>", szReason);
730 if (ft->backend_private->incoming && ft->request_denied)
731 ft->request_denied(ft);
732 free_xfer_struct(ft->backend_private);
733 return 0;
738 Local Variables:
739 mode: c
740 c-file-style: "bsd"
741 indent-tabs-mode: t
742 tab-width: 8
743 End: