telegram-purple/tgp-ft.c
mjentsch 82b36060b8 Fix progress of receiving file transfers in Adium
Set the xfer before requesting the xfer from the user, as this is the only time when Adium sets the xfer size in its controller class.
2015-05-24 14:55:26 +02:00

289 lines
9.1 KiB
C

/*
This file is part of telegram-purple
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
Copyright Matthias Jentsch 2014-2015
*/
#include "tgp-utils.h"
#include "tgp-ft.h"
#include "tgp-structs.h"
#include "msglog.h"
#include <purple.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "telegram-purple.h"
static void tgprpl_xfer_free_data (struct tgp_xfer_send_data *data);
static char *tgp_strdup_determine_filename (const char *mime, const char *caption,
int flags, long long hash) {
if (caption) {
return g_strdup (caption);
}
const char *type = NULL;
if (mime) {
type = tgp_mime_to_filetype (mime);
}
if (!type) {
if (flags & TGLDF_IMAGE) {
type = "png";
} else if (flags & TGLDF_AUDIO) {
type = "ogg";
} else if (flags & TGLDF_VIDEO) {
type = "mp4";
} else if (flags & TGLDF_STICKER) {
type = "webp";
} else {
type = "bin";
}
}
return g_strdup_printf ("%lld.%s", ABS(hash), type);
}
static void tgprpl_xfer_recv_on_finished (struct tgl_state *TLS, void *_data, int success, const char *filename) {
debug ("tgprpl_xfer_recv_on_finished()");
struct tgp_xfer_send_data *data = _data;
if (success) {
if (!data->done) {
debug ("purple_xfer_set_completed");
purple_xfer_set_bytes_sent (data->xfer, purple_xfer_get_size (data->xfer));
purple_xfer_set_completed (data->xfer, TRUE);
purple_xfer_end (data->xfer);
}
g_unlink (purple_xfer_get_local_filename (data->xfer));
g_rename (filename, purple_xfer_get_local_filename (data->xfer));
} else {
failure ("ERROR xfer failed");
}
data->xfer->data = NULL;
tgprpl_xfer_free_data (data);
}
static void tgprpl_xfer_on_finished (struct tgl_state *TLS, void *_data, int success, struct tgl_message *M) {
debug ("tgprpl_xfer_on_finished()");
struct tgp_xfer_send_data *data = _data;
if (success) {
if (!data->done) {
debug ("purple_xfer_set_completed");
purple_xfer_set_bytes_sent (data->xfer, purple_xfer_get_size (data->xfer));
purple_xfer_set_completed (data->xfer, TRUE);
purple_xfer_end(data->xfer);
}
} else {
failure ("ERROR xfer failed");
}
data->xfer->data = NULL;
tgprpl_xfer_free_data (data);
}
static void tgprpl_xfer_canceled (PurpleXfer *X) {
struct tgp_xfer_send_data *data = X->data;
tgprpl_xfer_free_data (data);
}
static gboolean tgprpl_xfer_upload_progress (gpointer _data) {
PurpleXfer *X = _data;
struct tgp_xfer_send_data *data = X->data;
connection_data *conn = data->conn;
PurpleXferType type = purple_xfer_get_type(X);
switch (type) {
case PURPLE_XFER_SEND:
purple_xfer_set_size (X, conn->TLS->cur_uploading_bytes);
purple_xfer_set_bytes_sent (X, conn->TLS->cur_uploaded_bytes);
purple_xfer_update_progress (X);
debug ("PURPLE_XFER_SEND progress %d / %d", conn->TLS->cur_uploaded_bytes, conn->TLS->cur_uploading_bytes);
if (conn->TLS->cur_uploaded_bytes == conn->TLS->cur_uploading_bytes) {
data->timer = 0;
return FALSE;
}
break;
case PURPLE_XFER_RECEIVE:
purple_xfer_set_size (X, conn->TLS->cur_downloading_bytes);
purple_xfer_set_bytes_sent (X, conn->TLS->cur_downloaded_bytes);
purple_xfer_update_progress (X);
debug ("PURPLE_XFER_RECEIVE progress %d / %d", conn->TLS->cur_downloaded_bytes, conn->TLS->cur_downloading_bytes);
if (conn->TLS->cur_downloading_bytes == conn->TLS->cur_downloaded_bytes) {
data->timer = 0;
return FALSE;
}
break;
default:
case PURPLE_XFER_UNKNOWN:
failure ("ERROR: tgprpl_xfer_upload_progress xfer type PURPLE_XFER_UNKNOWN.");
return FALSE;
break;
}
return TRUE;
}
static void tgprpl_xfer_recv_init (PurpleXfer *X) {
debug ("tgprpl_xfer_recv_init");
struct tgp_xfer_send_data *data = X->data;
purple_xfer_start (X, -1, NULL, 0);
const char *who = purple_xfer_get_remote_user (X);
tgl_peer_t *P = find_peer_by_name (data->conn->TLS, who);
if (P) {
if (data->document) {
tgl_do_load_document (data->conn->TLS, data->document, tgprpl_xfer_recv_on_finished, data);
}
else if (data->encr_document) {
tgl_do_load_encr_document (data->conn->TLS, data->encr_document,
tgprpl_xfer_recv_on_finished, data);
}
} else {
warning ("User not found, not downloading...");
}
data->timer = purple_timeout_add (100, tgprpl_xfer_upload_progress, X);
}
static void tgprpl_xfer_send_init (PurpleXfer *X) {
struct tgp_xfer_send_data *data = X->data;
purple_xfer_start (X, -1, NULL, 0);
const char *file = purple_xfer_get_filename (X);
const char *localfile = purple_xfer_get_local_filename (X);
const char *who = purple_xfer_get_remote_user (X);
debug ("xfer_on_init (file=%s, local=%s, who=%s)", file, localfile, who);
tgl_peer_t *P = find_peer_by_name (data->conn->TLS, who);
if (P) {
if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) {
tgl_do_send_document (data->conn->TLS, P->id, (char*) localfile, NULL,
0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, tgprpl_xfer_on_finished, data);
}
else {
purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, "Not supported",
"Sorry, sending documents to encrypted chats not yet supported.",
NULL, NULL, NULL);
}
}
data->timer = purple_timeout_add (100, tgprpl_xfer_upload_progress, X);
}
static void tgprpl_xfer_init_data (PurpleXfer *X, connection_data *conn, struct tgl_document *D, struct tgl_encr_document *ED) {
if (!X->data) {
struct tgp_xfer_send_data *data = g_malloc0 (sizeof (struct tgp_xfer_send_data));
data->xfer = X;
data->conn = conn;
data->document = D;
data->encr_document = ED;
X->data = data;
}
}
static void tgprpl_xfer_free_data (struct tgp_xfer_send_data *data) {
if (data->timer) { purple_input_remove(data->timer); }
data->timer = 0;
g_free (data);
}
void tgprpl_xfer_free_all (connection_data *conn) {
GList *xfers = purple_xfers_get_all();
while (xfers) {
PurpleXfer *xfer = xfers->data;
struct tgp_xfer_send_data *data = xfer->data;
if (data) {
purple_xfer_cancel_local (xfer);
}
xfers = g_list_next(xfers);
}
}
PurpleXfer *tgprpl_new_xfer (PurpleConnection * gc, const char *who) {
debug ("tgprpl_new_xfer()");
connection_data *conn = purple_connection_get_protocol_data (gc);
PurpleXfer *X = purple_xfer_new (conn->pa, PURPLE_XFER_SEND, who);
if (X) {
purple_xfer_set_init_fnc (X, tgprpl_xfer_send_init);
purple_xfer_set_cancel_send_fnc (X, tgprpl_xfer_canceled);
tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), NULL, NULL);
}
return (PurpleXfer *)X;
}
static PurpleXfer *tgprpl_new_xfer_recv (PurpleConnection * gc, const char *who) {
connection_data *conn = purple_connection_get_protocol_data (gc);
PurpleXfer *X = purple_xfer_new (conn->pa, PURPLE_XFER_RECEIVE, who);
purple_xfer_set_init_fnc (X, tgprpl_xfer_recv_init);
purple_xfer_set_cancel_recv_fnc (X, tgprpl_xfer_canceled);
return X;
}
void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_document *D) {
debug ("tgprpl_recv_file()");
PurpleXfer *X = tgprpl_new_xfer_recv (gc, who);
char *filename = tgp_strdup_determine_filename (D->mime_type, D->caption, D->flags,
D->access_hash);
purple_xfer_set_filename (X, filename);
g_free (filename);
purple_xfer_set_size (X, D->size);
tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), D, NULL);
purple_xfer_request (X);
}
void tgprpl_recv_encr_file (PurpleConnection * gc, const char *who, struct tgl_encr_document *D) {
debug ("tgprpl_recv_encr_file()");
PurpleXfer *X = tgprpl_new_xfer_recv (gc, who);
char *filename = tgp_strdup_determine_filename (D->mime_type, D->caption, D->flags,
D->access_hash);
purple_xfer_set_filename (X, filename);
g_free (filename);
purple_xfer_set_size (X, D->size);
tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), NULL, D);
purple_xfer_request (X);
}
void tgprpl_send_file (PurpleConnection * gc, const char *who, const char *file) {
debug ("tgprpl_send_file()");
PurpleXfer *X = tgprpl_new_xfer (gc, who);
if (file) {
purple_xfer_request_accepted (X, file);
debug ("starting xfer...");
} else {
purple_xfer_request (X);
}
}