Support file transfers
This commit is contained in:
parent
8fec18e8c4
commit
c9aab9c8eb
10 changed files with 324 additions and 23 deletions
|
@ -15,7 +15,7 @@ OBJ=objs
|
|||
LIB=libs
|
||||
DIR_LIST=${DEP} ${AUTO} ${EXE} ${OBJ} ${LIB} ${DEP}/auto ${OBJ}/auto ${DEP}/lodepng ${OBJ}/lodepng
|
||||
|
||||
PLUGIN_OBJECTS=${OBJ}/tgp-net.o ${OBJ}/tgp-timers.o ${OBJ}/msglog.o ${OBJ}/telegram-base.o ${OBJ}/telegram-purple.o ${OBJ}/tgp-2prpl.o ${OBJ}/tgp-structs.o ${OBJ}/tgp-utils.o ${OBJ}/tgp-chat.o ${OBJ}/lodepng/lodepng.o
|
||||
PLUGIN_OBJECTS=${OBJ}/tgp-net.o ${OBJ}/tgp-timers.o ${OBJ}/msglog.o ${OBJ}/telegram-base.o ${OBJ}/telegram-purple.o ${OBJ}/tgp-2prpl.o ${OBJ}/tgp-structs.o ${OBJ}/tgp-utils.o ${OBJ}/tgp-chat.o ${OBJ}/tgp-ft.o ${OBJ}/lodepng/lodepng.o
|
||||
ALL_OBJS=${PLUGIN_OBJECTS}
|
||||
|
||||
.SUFFIXES:
|
||||
|
|
|
@ -116,6 +116,8 @@ Acknowledgements
|
|||
|
||||
This software is based on the library [Libtgl](https://github.com/vysheng/tgl), which was written by Vitaly Valtman <mail@vysheng.ru> and others, see (http://github.com/vysheng/tgl)
|
||||
|
||||
For PNG rendering, it includes the [lodepng library](http://lodev.org/lodepng/).
|
||||
|
||||
This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)
|
||||
|
||||
This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "msglog.h"
|
||||
#include "tgp-utils.h"
|
||||
#include "tgp-chat.h"
|
||||
#include "tgp-ft.h"
|
||||
|
||||
#define _(m) m
|
||||
|
||||
|
@ -255,10 +256,56 @@ static char *format_message (struct tgl_message *M) {
|
|||
}
|
||||
}
|
||||
|
||||
static void picture_message_done (struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M) {
|
||||
if (success) {
|
||||
debug ("send photo sucess!");
|
||||
} else {
|
||||
debug ("send photo fail!");
|
||||
}
|
||||
}
|
||||
|
||||
static void tgl_do_send_unescape_message (struct tgl_state *TLS, const char *message, tgl_peer_id_t to) {
|
||||
gchar *raw = purple_unescape_html(message);
|
||||
|
||||
debug (message);
|
||||
|
||||
// search for outgoing embedded image tags and send them
|
||||
gchar *img = NULL;
|
||||
if ((img = g_strrstr (message, "<IMG")) || (img = g_strrstr (message, "<img"))) {
|
||||
debug ("img found: %s", img);
|
||||
|
||||
gchar *id;
|
||||
if ((id = g_strrstr (img, "ID=\"")) || (id = g_strrstr (img, "id=\""))) {
|
||||
id += 4;
|
||||
debug ("id found: %s", id);
|
||||
int imgid = atoi (id);
|
||||
|
||||
if (imgid > 0) {
|
||||
PurpleStoredImage *psi = purple_imgstore_find_by_id (imgid);
|
||||
|
||||
gchar *tmp = g_build_filename(g_get_tmp_dir(), purple_imgstore_get_filename (psi), NULL) ;
|
||||
|
||||
GError *err = NULL;
|
||||
gconstpointer data = purple_imgstore_get_data (psi);
|
||||
g_file_set_contents (tmp, data, purple_imgstore_get_size (psi), &err);
|
||||
if (! err) {
|
||||
tgl_do_send_document (TLS, -2, to, tmp, picture_message_done, NULL);
|
||||
} else {
|
||||
failure ("Cannot store image, temp directory not available: %s\n", err->message);
|
||||
g_error_free (err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove all remaining html elements that would mess up the message
|
||||
gchar *stripped = purple_markup_strip_html (message);
|
||||
|
||||
// unescape all escaped html markup, so that we don't see any escape symbols in the message
|
||||
gchar *raw = purple_unescape_html (stripped);
|
||||
tgl_do_send_message (TLS, to, raw, (int)strlen (raw), 0, 0);
|
||||
g_free(raw);
|
||||
g_free (raw);
|
||||
|
||||
g_free (stripped);
|
||||
}
|
||||
|
||||
static void start_secret_chat (PurpleBlistNode *node, gpointer data) {
|
||||
|
@ -354,6 +401,15 @@ static void update_message_received (struct tgl_state *TLS, struct tgl_message *
|
|||
tgl_do_load_photo (TLS, &M->media.photo, on_message_load_photo, M);
|
||||
return;
|
||||
}
|
||||
|
||||
if (M->media.type == tgl_message_media_document) {
|
||||
char *who = g_strdup_printf("%d", tgl_get_peer_id(M->from_id));
|
||||
|
||||
tgprpl_recv_file (conn->gc, who, &M->media.document);
|
||||
|
||||
g_free (who);
|
||||
return;
|
||||
}
|
||||
|
||||
char *text = format_message (M);
|
||||
switch (tgl_get_peer_type (M->to_id)) {
|
||||
|
@ -666,7 +722,7 @@ static GList *tgprpl_status_types (PurpleAccount * acct) {
|
|||
}
|
||||
|
||||
static GList* tgprpl_blist_node_menu (PurpleBlistNode *node) {
|
||||
purple_debug_info (PLUGIN_ID, "tgprpl_blist_node_menu()");
|
||||
debug ("tgprpl_blist_node_menu()");
|
||||
|
||||
GList* menu = NULL;
|
||||
if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
||||
|
@ -880,15 +936,6 @@ static char *tgprpl_get_chat_name (GHashTable * data) {
|
|||
return g_strdup(g_hash_table_lookup(data, "subject"));
|
||||
}
|
||||
|
||||
static PurpleXfer *tgprpl_new_xfer (PurpleConnection * gc, const char *who) {
|
||||
debug ("tgprpl_new_xfer()");
|
||||
return (PurpleXfer *)NULL;
|
||||
}
|
||||
|
||||
static void tgprpl_send_file (PurpleConnection * gc, const char *who, const char *file) {
|
||||
debug ("tgprpl_send_file()");
|
||||
}
|
||||
|
||||
static GHashTable *tgprpl_chat_info_deflt (PurpleConnection * gc, const char *chat_name) {
|
||||
debug ("tgprpl_chat_info_defaults()");
|
||||
return NULL;
|
||||
|
@ -947,16 +994,11 @@ static void tgprpl_set_buddy_icon (PurpleConnection * gc, PurpleStoredImage * im
|
|||
|
||||
static gboolean tgprpl_can_receive_file (PurpleConnection * gc, const char *who) {
|
||||
debug ("tgprpl_can_receive_file()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean tgprpl_offline_message (const PurpleBuddy * buddy) {
|
||||
debug ("tgprpl_offline_message()");
|
||||
return 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PurplePluginProtocolInfo prpl_info = {
|
||||
OPT_PROTO_NO_PASSWORD,
|
||||
OPT_PROTO_NO_PASSWORD | OPT_PROTO_IM_IMAGE,
|
||||
NULL, // user_splits, initialized in tgprpl_init()
|
||||
NULL, // protocol_options, initialized in tgprpl_init()
|
||||
{
|
||||
|
@ -1022,7 +1064,7 @@ static PurplePluginProtocolInfo prpl_info = {
|
|||
tgprpl_can_receive_file,
|
||||
tgprpl_send_file,
|
||||
tgprpl_new_xfer,
|
||||
tgprpl_offline_message,
|
||||
NULL, // offline_message
|
||||
NULL, // whiteboard_prpl_ops
|
||||
NULL, // send_raw
|
||||
NULL, // roomlist_room_serialize
|
||||
|
|
|
@ -42,5 +42,6 @@ extern const char *pk_path;
|
|||
extern const char *config_dir;
|
||||
extern PurplePlugin *_telegram_protocol;
|
||||
char *format_user_status (struct tgl_user_status *status);
|
||||
char *p2tgl_peer_strdup_id (tgl_peer_id_t user);
|
||||
|
||||
#endif
|
||||
|
|
10
tgp-2prpl.c
10
tgp-2prpl.c
|
@ -37,7 +37,7 @@ PurpleConnection *tg_get_conn (struct tgl_state *TLS) {
|
|||
return (PurpleConnection *) ((connection_data *)TLS->ev_base)->gc;
|
||||
}
|
||||
|
||||
static char *p2tgl_peer_strdup_id (tgl_peer_id_t user) {
|
||||
char *p2tgl_peer_strdup_id (tgl_peer_id_t user) {
|
||||
return g_strdup_printf("%d", tgl_get_peer_id(user));
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,11 @@ int p2tgl_status_is_present (PurpleStatus *status)
|
|||
return !(strcmp (name, "unavailable") == 0 || strcmp (name, "away") == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Disclaimer: I stole this function from davidgfnet's whatsapp plugin, all
|
||||
credit for it goes to him
|
||||
@see: https://github.com/davidgfnet/whatsapp-purple
|
||||
*/
|
||||
static PurpleChat *blist_find_chat_by_hasht_cond (PurpleConnection *gc,
|
||||
int (*fn)(GHashTable *hasht, void *data), void *data) {
|
||||
PurpleAccount *account = purple_connection_get_account(gc);
|
||||
|
@ -261,7 +266,8 @@ PurpleChat *p2tgl_chat_new (struct tgl_state *TLS, struct tgl_chat *chat) {
|
|||
g_hash_table_insert(ht, g_strdup("id"), name);
|
||||
g_hash_table_insert(ht, g_strdup("owner"), admin);
|
||||
|
||||
return purple_chat_new(tg_get_acc(TLS), chat->title, ht);
|
||||
PurpleChat *C = purple_chat_new(tg_get_acc(TLS), chat->title, ht);
|
||||
return C;
|
||||
}
|
||||
|
||||
PurpleChat *p2tgl_chat_find (struct tgl_state *TLS, tgl_peer_id_t id) {
|
||||
|
|
|
@ -34,6 +34,7 @@ PurpleAccount *tg_get_acc (struct tgl_state *TLS);
|
|||
PurpleConnection *tg_get_conn (struct tgl_state *TLS);
|
||||
tgl_peer_t *p2tgl_get_peer (tgl_peer_id_t peer);
|
||||
tgl_peer_t *p2tgl_get_peer_by_id (int id);
|
||||
char *p2tgl_peer_strdup_id (tgl_peer_id_t user);
|
||||
char *p2tgl_strdup_alias(tgl_peer_t *user);
|
||||
|
||||
int p2tgl_status_is_present (PurpleStatus *status);
|
||||
|
|
204
tgp-ft.c
Normal file
204
tgp-ft.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
static void tgprpl_xfer_recv_on_finished (struct tgl_state *TLS, void *_data, int success, char *filename) {
|
||||
debug ("tgprpl_xfer_recv_on_finished()");
|
||||
struct tgp_xfer_send_data *data = _data;
|
||||
|
||||
if (success) {
|
||||
if (!data->done) {
|
||||
purple_xfer_set_completed (data->xfer, TRUE);
|
||||
}
|
||||
|
||||
g_unlink (purple_xfer_get_local_filename (data->xfer));
|
||||
g_rename (filename, purple_xfer_get_local_filename(data->xfer));
|
||||
|
||||
} else {
|
||||
failure ("ERROR xfer failed");
|
||||
}
|
||||
|
||||
if (data->timer) { purple_timeout_remove(data->timer); }
|
||||
data->timer = 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
purple_xfer_set_completed (data->xfer, TRUE);
|
||||
}
|
||||
} else {
|
||||
failure ("ERROR xfer failed");
|
||||
}
|
||||
|
||||
if (data->timer) { purple_timeout_remove(data->timer); }
|
||||
data->timer = 0;
|
||||
}
|
||||
|
||||
static void tgprpl_xfer_canceled (PurpleXfer *X) {
|
||||
struct tgp_xfer_send_data *data = X->data;
|
||||
data->done = TRUE;
|
||||
|
||||
if (data->timer) { purple_timeout_remove (data->timer); }
|
||||
data->timer = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (conn->TLS->cur_uploaded_bytes == conn->TLS->cur_uploading_bytes) {
|
||||
data->timer = 0;
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case PURPLE_XFER_RECEIVE:
|
||||
debug ("PURPLE_XFER_RECEIVER progress ...");
|
||||
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_RECEIVER progress %d", conn->TLS->cur_downloaded_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);
|
||||
debug ("who: %s", who);
|
||||
tgl_peer_t *P = find_peer_by_name (data->conn->TLS, who);
|
||||
|
||||
if (P) {
|
||||
tgl_do_load_document (data->conn->TLS, data->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) {
|
||||
tgl_do_send_document (data->conn->TLS, -2, P->id, (char*)localfile, tgprpl_xfer_on_finished, data);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!X->data) {
|
||||
// TODO: free this somewhere
|
||||
struct tgp_xfer_send_data *data = g_malloc0 (sizeof (struct tgp_xfer_send_data));
|
||||
data->xfer = X;
|
||||
data->conn = conn;
|
||||
data->document = D;
|
||||
X->data = data;
|
||||
conn->transfers = g_list_append (conn->transfers, data);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return (PurpleXfer *)X;
|
||||
}
|
||||
|
||||
void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_document *D) {
|
||||
debug ("tgprpl_recv_file()");
|
||||
connection_data *conn = purple_connection_get_protocol_data (gc);
|
||||
|
||||
PurpleXfer *X = purple_xfer_new (conn->pa, PURPLE_XFER_RECEIVE, who);
|
||||
|
||||
purple_xfer_set_filename (X, D->caption);
|
||||
purple_xfer_set_init_fnc (X, tgprpl_xfer_recv_init);
|
||||
purple_xfer_set_cancel_recv_fnc (X, tgprpl_xfer_canceled);
|
||||
|
||||
tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), 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);
|
||||
purple_xfer_set_init_fnc (X, tgprpl_xfer_send_init);
|
||||
purple_xfer_set_cancel_send_fnc (X, tgprpl_xfer_canceled);
|
||||
|
||||
if (file) {
|
||||
purple_xfer_request_accepted (X, file);
|
||||
debug ("starting xfer...");
|
||||
} else {
|
||||
purple_xfer_request (X);
|
||||
}
|
||||
|
||||
tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), NULL);
|
||||
}
|
||||
|
29
tgp-ft.h
Normal file
29
tgp-ft.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef __telegram_adium__tgp_ft__
|
||||
#define __telegram_adium__tgp_ft__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
PurpleXfer *tgprpl_new_xfer (PurpleConnection * gc, const char *who);
|
||||
void tgprpl_send_file (PurpleConnection * gc, const char *who, const char *file);
|
||||
void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_document *D);
|
||||
#endif
|
|
@ -93,6 +93,12 @@ connection_data *connection_data_init (struct tgl_state *TLS, PurpleConnection *
|
|||
return conn;
|
||||
}
|
||||
|
||||
static void tgp_xfer_send_data_free (gpointer _data) {
|
||||
struct tgp_xfer_send_data *data = _data;
|
||||
if (data->timer) { purple_timeout_remove(data->timer); }
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
void *connection_data_free (connection_data *conn) {
|
||||
if (conn->write_timer) { purple_timeout_remove (conn->write_timer); }
|
||||
if (conn->login_timer) { purple_timeout_remove (conn->login_timer); }
|
||||
|
@ -100,6 +106,7 @@ void *connection_data_free (connection_data *conn) {
|
|||
tgp_g_queue_free_full (conn->pending_reads, pending_reads_free_cb);
|
||||
tgp_g_queue_free_full (conn->new_messages, message_text_free);
|
||||
g_list_free_full (conn->used_images, used_image_free);
|
||||
g_list_free_full (conn->transfers, tgp_xfer_send_data_free);
|
||||
tgl_free_all (conn->TLS);
|
||||
free (conn->TLS);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ typedef struct {
|
|||
GList *used_images;
|
||||
guint write_timer;
|
||||
guint login_timer;
|
||||
GList *transfers;
|
||||
int in_fallback_chat;
|
||||
} connection_data;
|
||||
|
||||
|
@ -45,6 +46,14 @@ typedef struct {
|
|||
tgl_peer_id_t peer;
|
||||
} get_user_info_data;
|
||||
|
||||
struct tgp_xfer_send_data {
|
||||
int timer;
|
||||
int done;
|
||||
PurpleXfer *xfer;
|
||||
connection_data *conn;
|
||||
struct tgl_document *document;
|
||||
};
|
||||
|
||||
struct download_desc {
|
||||
get_user_info_data *get_user_info_data;
|
||||
void *data;
|
||||
|
|
Loading…
Add table
Reference in a new issue