Revert "media: add sipe_backend_ft_write_file()"
[siplcs.git] / src / miranda / miranda-ft.c
blob4cd6289d0fa2f5cd8d83772ec98271554b4d7bf0
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_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 gboolean
376 sipe_backend_ft_incoming_accept(struct sipe_file_transfer *ft,
377 const gchar *ip,
378 unsigned short port_min,
379 unsigned short port_max)
381 _NIF();
382 return FALSE;
385 static void
386 set_completed(struct sipe_backend_file_transfer *xfer, gboolean completed)
388 if (completed == TRUE) {
389 char *msg = NULL;
391 xfer->status = SIPE_MIRANDA_XFER_STATUS_DONE;
393 if (xfer->filename != NULL)
395 char *filename = g_markup_escape_text(xfer->filename, -1);
396 if (xfer->local_filename && xfer->incoming)
398 char *local = g_markup_escape_text(xfer->local_filename, -1);
399 msg = g_strdup_printf("Transfer of file <A HREF=\"file://%s\">%s</A> complete",
400 local, filename);
401 g_free(local);
403 else
404 msg = g_strdup_printf("Transfer of file %s complete",
405 filename);
406 g_free(filename);
408 else
409 msg = g_strdup("File transfer complete");
411 sipe_miranda_AddEvent(xfer->pr, xfer->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
412 sipe_miranda_SendBroadcast(xfer->pr, xfer->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)xfer, 0);
414 g_free(msg);
417 update_progress(xfer);
420 static void
421 do_transfer(struct sipe_backend_file_transfer *xfer)
424 guchar *buffer = NULL;
425 gssize r = 0;
426 struct sipe_file_transfer *ft = xfer->ft;
428 FT_SIPE_DEBUG_INFO("incoming <%d>", xfer->incoming);
429 if (xfer->incoming) {
430 FT_SIPE_DEBUG_INFO_NOFORMAT("incoming branch");
431 r = ft->read(xfer->ft, &buffer, xfer->bytes_remaining,
432 xfer->current_buffer_size);
433 if (r > 0) {
434 size_t wc;
435 wc = fwrite(buffer, 1, r, xfer->dest_fp);
437 if (wc != r) {
438 SIPE_DEBUG_ERROR("Unable to write whole buffer.");
439 cancel_local(xfer);
440 g_free(buffer);
441 return;
444 if ((xfer->file_size > 0) && ((xfer->bytes_sent+r) >= xfer->file_size))
445 set_completed(xfer, TRUE);
447 } else if(r < 0) {
448 cancel_remote(xfer);
449 g_free(buffer);
450 return;
452 } else {
453 size_t result = 0;
454 size_t s = MIN(xfer->bytes_remaining, xfer->current_buffer_size);
455 gboolean read = TRUE;
456 FT_SIPE_DEBUG_INFO("outgoing branch, size <%u>", s);
458 /* this is so the prpl can keep the connection open
459 if it needs to for some odd reason. */
460 if (s == 0) {
461 if (xfer->watcher) {
462 sipe_miranda_input_remove(xfer->watcher);
463 xfer->watcher = 0;
465 return;
468 if (xfer->buffer) {
469 if (xfer->buffer->len < s) {
470 s -= xfer->buffer->len;
471 read = TRUE;
472 } else {
473 read = FALSE;
477 if (read) {
478 buffer = g_malloc(s);
479 result = fread(buffer, 1, s, xfer->dest_fp);
480 if (result != s) {
481 FT_SIPE_DEBUG_INFO_NOFORMAT("Unable to read whole buffer.");
482 cancel_local(xfer);
483 g_free(buffer);
484 return;
488 if (xfer->buffer) {
489 g_byte_array_append(xfer->buffer, buffer, result);
490 g_free(buffer);
491 buffer = xfer->buffer->data;
492 result = xfer->buffer->len;
495 s = MIN(xfer->bytes_remaining, result);
496 r = ft->write(ft, buffer, s);
498 if ((xfer->bytes_remaining - r) == 0)
499 set_completed(xfer, TRUE);
501 if (r >= 0 && (xfer->bytes_sent+r) >= xfer->file_size && xfer->status != SIPE_MIRANDA_XFER_STATUS_DONE)
502 set_completed(xfer, TRUE);
504 if (r == -1) {
505 cancel_remote(xfer);
507 if (!xfer->buffer)
508 /* We don't free buffer if priv->buffer is set, because in
509 that case buffer doesn't belong to us. */
510 g_free(buffer);
511 return;
512 } else if (r == result) {
514 * We managed to write the entire buffer. This means our
515 * network is fast and our buffer is too small, so make it
516 * bigger.
518 increase_buffer_size(xfer);
521 if (xfer->buffer) {
523 * Remove what we wrote
524 * If we wrote the whole buffer the byte array will be empty
525 * Otherwise we'll keep what wasn't sent for next time.
527 buffer = NULL;
528 g_byte_array_remove_range(xfer->buffer, 0, r);
532 FT_SIPE_DEBUG_INFO_NOFORMAT("back to common code");
533 if (r > 0) {
534 if (xfer->file_size > 0)
535 xfer->bytes_remaining -= r;
537 xfer->bytes_sent += r;
539 g_free(buffer);
540 update_progress(xfer);
543 if (xfer->status == SIPE_MIRANDA_XFER_STATUS_DONE)
545 xfer->end_time = time(NULL);
546 if (xfer->ft->end && xfer->ft->end(xfer->ft)) {
547 /* We're done with this transfer */
548 free_xfer_struct(xfer);
549 } else if (xfer->incoming) {
550 _unlink(xfer->local_filename);
553 if (xfer->watcher != 0) {
554 sipe_miranda_input_remove(xfer->watcher);
555 xfer->watcher = 0;
558 if (xfer->fd)
559 Netlib_CloseHandle(xfer->fd);
561 if (xfer->dest_fp != NULL) {
562 fclose(xfer->dest_fp);
563 xfer->dest_fp = NULL;
566 g_free(xfer->filename);
567 g_free(xfer);
571 static void
572 transfer_cb(gpointer data, gint source, sipe_miranda_input_condition condition)
574 struct sipe_backend_file_transfer *xfer = data;
575 SIPE_DEBUG_INFO_NOFORMAT("");
576 do_transfer(xfer);
579 static void
580 begin_transfer(struct sipe_file_transfer *ft)
582 struct sipe_backend_file_transfer *xfer = ft->backend_private;
583 SIPPROTO *pr = xfer->pr;
585 xfer->dest_fp = fopen(xfer->local_filename, xfer->incoming ? "wb" : "rb");
586 if (xfer->dest_fp == NULL) {
587 int err = errno;
588 gchar *msg;
589 if (xfer->incoming)
591 msg = g_strdup_printf("Error reading %s: \n%s.\n", xfer->local_filename, g_strerror(err));
592 } else {
593 msg = g_strdup_printf("Error writing %s: \n%s.\n", xfer->local_filename, g_strerror(err));
595 sipe_miranda_AddEvent(ft->backend_private->pr, ft->backend_private->hContact, SIPE_EVENTTYPE_ERROR_NOTIFY, time(NULL), DBEF_UTF, strlen(msg), (PBYTE)msg);
596 g_free(msg);
597 FT_SIPE_DEBUG_INFO("error opening local file: %s", g_strerror(errno));
598 cancel_local(xfer);
599 return;
602 fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
604 xfer->start_time = time(NULL);
606 LOCK;
607 FT_SIPE_DEBUG_INFO("incoming <%d> size <%d>", ft->backend_private->incoming, ft->backend_private->file_size);
608 if (!ft->backend_private->incoming) {
609 /* Set socket to nonblocking */
610 SOCKET sock = CallService(MS_NETLIB_GETSOCKET, (WPARAM)xfer->fd, (LPARAM)0);
611 unsigned long parm = 1;
613 if (ioctlsocket(sock, FIONBIO, &parm) == SOCKET_ERROR)
615 FT_SIPE_DEBUG_INFO("Error ioctlsocket <%d>", WSAGetLastError());
618 FT_SIPE_DEBUG_INFO("outgoing ft <%08x> size <%d>", ft, ft->backend_private->file_size);
620 if (ft->start) {
621 ft->start(ft, ft->backend_private->file_size);
623 UNLOCK;
625 if (xfer->fd)
626 xfer->watcher = sipe_miranda_input_add(xfer->fd, xfer->incoming?SIPE_MIRANDA_INPUT_READ:SIPE_MIRANDA_INPUT_WRITE, transfer_cb, xfer);
628 FT_SIPE_DEBUG_INFO("watcher [%08x]", xfer->watcher);
631 static void
632 ft_connected_callback(HANDLE fd, void* data, const gchar *reason)
634 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)data;
635 struct sipe_backend_file_transfer *xfer = ft->backend_private;
636 SIPPROTO *pr = ft->backend_private->pr;
638 if (!fd)
640 cancel_local(xfer);
641 } else {
642 ft->backend_private->fd = fd;
643 begin_transfer(ft);
648 void
649 sipe_backend_ft_start(struct sipe_file_transfer *ft, struct sipe_backend_fd *fd,
650 const char* ip, unsigned port)
652 ft->backend_private->status = SIPE_MIRANDA_XFER_STATUS_STARTED;
654 if (ip && port)
656 FT_SIPE_DEBUG_INFO("Should connect to <%s:%d>", ip, port);
657 sipe_miranda_connect(ft->backend_private->pr, ip, port, FALSE, 5, ft_connected_callback, ft);
658 return;
661 FT_SIPE_DEBUG_INFO("Should use incoming fd <%08x>", fd);
662 ft->backend_private->fd = fd;
663 begin_transfer(ft);
666 gboolean
667 sipe_backend_ft_is_incoming(struct sipe_file_transfer *ft)
669 FT_SIPE_DEBUG_INFO("ft <%08x> incoming <%d>", ft, ft->backend_private->incoming);
670 return ft->backend_private->incoming;
673 HANDLE
674 sipe_miranda_SendFile( SIPPROTO *pr, HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles )
676 struct sipe_file_transfer *ft = sipe_core_ft_create_outgoing(pr->sip);
677 DBVARIANT dbv;
679 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
680 int result;
681 struct __stat64 buf;
683 LOCK;
684 ft->backend_private = new_xfer(pr, ft, hContact);
685 ft->backend_private->incoming = FALSE;
686 result = _tstat64( ppszFiles[0], &buf );
687 if (result != 0)
689 FT_SIPE_DEBUG_INFO("Could not stat file, error<%d>", result);
690 ft->backend_private->file_size = 0;
692 else
694 ft->backend_private->file_size = buf.st_size;
695 ft->backend_private->bytes_remaining = ft->backend_private->file_size;
696 ft->backend_private->bytes_sent = 0;
698 FT_SIPE_DEBUG_INFO("SendFile: desc <%ls> name <%s> size <%d> to <%s>", szDescription, TCHAR2CHAR(ppszFiles[0]), ft->backend_private->file_size, dbv.pszVal);
699 ft->backend_private->local_filename = g_strdup(TCHAR2CHAR(ppszFiles[0]));
700 ft->backend_private->filename = g_path_get_basename(ft->backend_private->local_filename);
701 FT_SIPE_DEBUG_INFO("set filename to <%s>", ft->backend_private->filename);
702 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, dbv.pszVal);
703 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
704 UNLOCK;
706 DBFreeVariant( &dbv );
709 return ft->backend_private;
713 sipe_miranda_RecvFile( SIPPROTO *pr, HANDLE hContact, PROTOFILEEVENT* evt )
715 CCSDATA ccs = { hContact, PSR_FILE, 0, (LPARAM)evt };
716 return CallService(MS_PROTO_RECVFILET, 0, (LPARAM)&ccs);
719 HANDLE
720 sipe_miranda_FileAllow( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath )
722 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
723 FT_SIPE_DEBUG_INFO("Incoming ft <%08x> allowed", ft);
724 ft->backend_private->local_filename = g_strdup_printf("%s%s", TCHAR2CHAR(szPath), ft->backend_private->filename);
725 sipe_miranda_SendBroadcast(pr, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft->backend_private, 0);
726 ft->init(ft, ft->backend_private->filename, ft->backend_private->file_size, NULL);
727 return ft->backend_private;
731 sipe_miranda_FileDeny( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason )
733 struct sipe_file_transfer *ft = (struct sipe_file_transfer *)hTransfer;
734 FT_SIPE_DEBUG_INFO("FileDeny: reason <%s>", szReason);
735 if (ft->backend_private->incoming && ft->request_denied)
736 ft->request_denied(ft);
737 free_xfer_struct(ft->backend_private);
738 return 0;
743 Local Variables:
744 mode: c
745 c-file-style: "bsd"
746 indent-tabs-mode: t
747 tab-width: 8
748 End: