ucs: fix Persona key extraction
[siplcs.git] / src / miranda / miranda-ft.c
blob2d444a209b281bde6cd6b07fb889993c4d77c0c3
1 /**
2 * @file miranda-ft.c
4 * pidgin-sipe
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
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 sipe_core_ft_deallocate(ft);
160 xfer->ft = NULL;
164 static void
165 cancel_remote(struct sipe_backend_file_transfer *xfer)
167 struct sipe_file_transfer *ft = xfer->ft;
168 gchar *msg;
169 FT_SIPE_DEBUG_INFO_NOFORMAT("");
171 if (!xfer) return;
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);
178 g_free(msg);
180 free_xfer_struct(xfer);
182 if (xfer->watcher != 0) {
183 sipe_miranda_input_remove(xfer->watcher);
184 xfer->watcher = 0;
187 if (xfer->fd)
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)
209 cancel_remote(xfer);
214 gssize sipe_backend_ft_read(struct sipe_file_transfer *ft,
215 guchar *data,
216 gsize size)
218 gssize bytes_read;
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");
226 return -2;
227 } else if (bytes_read == SOCKET_ERROR) {
228 int err = WSAGetLastError();
229 if (err == WSAEWOULDBLOCK) {
230 return 0;
231 } else {
232 FT_SIPE_DEBUG_INFO("Error reading <%d>", err);
233 return -1;
236 FT_SIPE_DEBUG_INFO("read <%d> bytes [%02x:%c]", bytes_read, *data, *data);
237 return bytes_read;
240 gssize sipe_backend_ft_write(struct sipe_file_transfer *ft,
241 const guchar *data,
242 gsize size)
244 int bytes_written;
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) {
250 return 0;
251 } else {
252 FT_SIPE_DEBUG_INFO("Error writing <%u>", err);
253 return -1;
256 FT_SIPE_DEBUG_INFO("wrote <%d> bytes", bytes_written);
257 return bytes_written;
260 static void
261 cancel_local(struct sipe_backend_file_transfer *xfer)
263 struct sipe_file_transfer *ft = xfer->ft;
264 gchar *msg;
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);
272 g_free(msg);
274 free_xfer_struct(xfer);
276 if (xfer->watcher != 0) {
277 sipe_miranda_input_remove(xfer->watcher);
278 xfer->watcher = 0;
281 if (xfer->fd)
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);
292 g_free(xfer);
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,
308 HANDLE hContact)
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);
314 xfer->ft = ft;
315 xfer->hContact = hContact;
316 xfer->pr = pr;
318 xfer->st.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
319 xfer->st.hContact = hContact;
321 return xfer;
324 void sipe_backend_ft_incoming(struct sipe_core_public *sipe_public,
325 struct sipe_file_transfer *ft,
326 const gchar *who,
327 const gchar *file_name,
328 gsize file_size)
330 SIPPROTO *pr = sipe_public->backend_private;
331 PROTORECVFILET pre = {0};
332 CCSDATA ccs;
333 HANDLE hContact;
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 );
337 if (!hContact)
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);
356 pre.fileCount = 1;
357 pre.ptszFiles = &pre.tszDescription;
358 pre.lParam = (LPARAM)ft;
360 ccs.szProtoService = PSR_FILE;
361 ccs.hContact = hContact;
362 ccs.wParam = 0;
363 ccs.lParam = (LPARAM)&pre;
364 CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
368 gboolean
369 sipe_backend_ft_incoming_accept(struct sipe_file_transfer *ft,
370 const gchar *ip,
371 unsigned short port_min,
372 unsigned short port_max)
374 _NIF();
375 return FALSE;
378 static void
379 set_completed(struct sipe_backend_file_transfer *xfer, gboolean completed)
381 if (completed == TRUE) {
382 char *msg = NULL;
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",
393 local, filename);
394 g_free(local);
396 else
397 msg = g_strdup_printf("Transfer of file %s complete",
398 filename);
399 g_free(filename);
401 else
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);
407 g_free(msg);
410 update_progress(xfer);
413 static void
414 do_transfer(struct sipe_backend_file_transfer *xfer)
417 guchar *buffer = NULL;
418 gssize r = 0;
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);
426 if (r > 0) {
427 size_t wc;
428 wc = fwrite(buffer, 1, r, xfer->dest_fp);
430 if (wc != r) {
431 SIPE_DEBUG_ERROR("Unable to write whole buffer.");
432 cancel_local(xfer);
433 g_free(buffer);
434 return;
437 if ((xfer->file_size > 0) && ((xfer->bytes_sent+r) >= xfer->file_size))
438 set_completed(xfer, TRUE);
440 } else if(r < 0) {
441 cancel_remote(xfer);
442 g_free(buffer);
443 return;
445 } else {
446 size_t result = 0;
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. */
453 if (s == 0) {
454 if (xfer->watcher) {
455 sipe_miranda_input_remove(xfer->watcher);
456 xfer->watcher = 0;
458 return;
461 if (xfer->buffer) {
462 if (xfer->buffer->len < s) {
463 s -= xfer->buffer->len;
464 read = TRUE;
465 } else {
466 read = FALSE;
470 if (read) {
471 buffer = g_malloc(s);
472 result = fread(buffer, 1, s, xfer->dest_fp);
473 if (result != s) {
474 FT_SIPE_DEBUG_INFO_NOFORMAT("Unable to read whole buffer.");
475 cancel_local(xfer);
476 g_free(buffer);
477 return;
481 if (xfer->buffer) {
482 g_byte_array_append(xfer->buffer, buffer, result);
483 g_free(buffer);
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);
497 if (r == -1) {
498 cancel_remote(xfer);
500 if (!xfer->buffer)
501 /* We don't free buffer if priv->buffer is set, because in
502 that case buffer doesn't belong to us. */
503 g_free(buffer);
504 return;
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
509 * bigger.
511 increase_buffer_size(xfer);
514 if (xfer->buffer) {
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.
520 buffer = NULL;
521 g_byte_array_remove_range(xfer->buffer, 0, r);
525 FT_SIPE_DEBUG_INFO_NOFORMAT("back to common code");
526 if (r > 0) {
527 if (xfer->file_size > 0)
528 xfer->bytes_remaining -= r;
530 xfer->bytes_sent += r;
532 g_free(buffer);
533 update_progress(xfer);
536 if (xfer->status == SIPE_MIRANDA_XFER_STATUS_DONE)
538 xfer->end_time = time(NULL);
539 if (xfer->incoming)
541 if (sipe_core_tftp_incoming_stop(xfer->ft)) {
542 /* We're done with this transfer */
543 free_xfer_struct(xfer);
544 } else {
545 _unlink(xfer->local_filename);
547 } else {
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);
556 xfer->watcher = 0;
559 if (xfer->fd)
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);
568 g_free(xfer);
572 static void
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("");
577 do_transfer(xfer);
580 static void
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) {
588 int err = errno;
589 gchar *msg;
590 if (xfer->incoming)
592 msg = g_strdup_printf("Error reading %s: \n%s.\n", xfer->local_filename, g_strerror(err));
593 } else {
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);
597 g_free(msg);
598 FT_SIPE_DEBUG_INFO("error opening local file: %s", g_strerror(errno));
599 cancel_local(xfer);
600 return;
603 fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET);
605 xfer->start_time = time(NULL);
607 LOCK;
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);
611 else {
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);
624 UNLOCK;
626 if (xfer->fd)
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);
632 static void
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;
639 if (!fd)
641 cancel_local(xfer);
642 } else {
643 ft->backend_private->fd = fd;
644 begin_transfer(ft);
649 void
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;
655 if (ip && port)
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);
659 return;
662 FT_SIPE_DEBUG_INFO("Should use incoming fd <%08x>", fd);
663 ft->backend_private->fd = fd;
664 begin_transfer(ft);
667 gboolean
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;
674 HANDLE
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);
678 DBVARIANT dbv;
680 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
681 int result;
682 struct __stat64 buf;
684 LOCK;
685 ft->backend_private = new_xfer(pr, ft, hContact);
686 ft->backend_private->incoming = FALSE;
687 result = _tstat64( ppszFiles[0], &buf );
688 if (result != 0)
690 FT_SIPE_DEBUG_INFO("Could not stat file, error<%d>", result);
691 ft->backend_private->file_size = 0;
693 else
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);
705 UNLOCK;
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);
720 HANDLE
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);
739 return 0;
744 Local Variables:
745 mode: c
746 c-file-style: "bsd"
747 indent-tabs-mode: t
748 tab-width: 8
749 End: