Support secret chats
Load and store secret chats in a file, handle secret chat updates, visualize fingerprint in settings
This commit is contained in:
parent
0c718206d7
commit
1dda956166
5 changed files with 262 additions and 88 deletions
139
telegram-base.c
139
telegram-base.c
|
@ -31,13 +31,15 @@
|
|||
|
||||
#include <glib.h>
|
||||
#include <request.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <telegram-purple.h>
|
||||
#include <msglog.h>
|
||||
#include <tgp-2prpl.h>
|
||||
#include "telegram-purple.h"
|
||||
#include "msglog.h"
|
||||
#include "tgp-2prpl.h"
|
||||
#include "tgp-structs.h"
|
||||
#include "lodepng/lodepng.h"
|
||||
|
||||
|
||||
#define DC_SERIALIZED_MAGIC 0x868aa81d
|
||||
#define STATE_FILE_MAGIC 0x28949a93
|
||||
#define SECRET_CHAT_FILE_MAGIC 0x37a1988a
|
||||
|
@ -234,6 +236,136 @@ void read_auth_file (struct tgl_state *TLS) {
|
|||
close (auth_file_fd);
|
||||
}
|
||||
|
||||
|
||||
void write_secret_chat (tgl_peer_t *_P, void *extra) {
|
||||
struct tgl_secret_chat *P = (void *)_P;
|
||||
if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { return; }
|
||||
if (P->state != sc_ok) { return; }
|
||||
int *a = extra;
|
||||
int fd = a[0];
|
||||
a[1] ++;
|
||||
|
||||
int id = tgl_get_peer_id (P->id);
|
||||
assert (write (fd, &id, 4) == 4);
|
||||
//assert (write (fd, &P->flags, 4) == 4);
|
||||
int l = strlen (P->print_name);
|
||||
assert (write (fd, &l, 4) == 4);
|
||||
assert (write (fd, P->print_name, l) == l);
|
||||
assert (write (fd, &P->user_id, 4) == 4);
|
||||
assert (write (fd, &P->admin_id, 4) == 4);
|
||||
assert (write (fd, &P->date, 4) == 4);
|
||||
assert (write (fd, &P->ttl, 4) == 4);
|
||||
assert (write (fd, &P->layer, 4) == 4);
|
||||
assert (write (fd, &P->access_hash, 8) == 8);
|
||||
assert (write (fd, &P->state, 4) == 4);
|
||||
assert (write (fd, &P->key_fingerprint, 8) == 8);
|
||||
assert (write (fd, &P->key, 256) == 256);
|
||||
assert (write (fd, &P->first_key_sha, 20) == 20);
|
||||
assert (write (fd, &P->in_seq_no, 4) == 4);
|
||||
assert (write (fd, &P->last_in_seq_no, 4) == 4);
|
||||
assert (write (fd, &P->out_seq_no, 4) == 4);
|
||||
}
|
||||
|
||||
void write_secret_chat_file (struct tgl_state *TLS) {
|
||||
char *name = 0;
|
||||
if (asprintf (&name, "%s/%s", TLS->base_path, "secret") < 0) {
|
||||
return;
|
||||
}
|
||||
int secret_chat_fd = open (name, O_CREAT | O_RDWR, 0600);
|
||||
free (name);
|
||||
assert (secret_chat_fd >= 0);
|
||||
int x = SECRET_CHAT_FILE_MAGIC;
|
||||
assert (write (secret_chat_fd, &x, 4) == 4);
|
||||
x = 2;
|
||||
assert (write (secret_chat_fd, &x, 4) == 4); // version
|
||||
assert (write (secret_chat_fd, &x, 4) == 4); // num
|
||||
|
||||
int y[2];
|
||||
y[0] = secret_chat_fd;
|
||||
y[1] = 0;
|
||||
|
||||
tgl_peer_iterator_ex (TLS, write_secret_chat, y);
|
||||
|
||||
lseek (secret_chat_fd, 8, SEEK_SET);
|
||||
assert (write (secret_chat_fd, &y[1], 4) == 4);
|
||||
close (secret_chat_fd);
|
||||
}
|
||||
|
||||
void read_secret_chat (struct tgl_state *TLS, int fd, int v) {
|
||||
int id, l, user_id, admin_id, date, ttl, layer, state;
|
||||
long long access_hash, key_fingerprint;
|
||||
static char s[1000];
|
||||
static unsigned char key[256];
|
||||
static unsigned char sha[20];
|
||||
assert (read (fd, &id, 4) == 4);
|
||||
//assert (read (fd, &flags, 4) == 4);
|
||||
assert (read (fd, &l, 4) == 4);
|
||||
assert (l > 0 && l < 1000);
|
||||
assert (read (fd, s, l) == l);
|
||||
assert (read (fd, &user_id, 4) == 4);
|
||||
assert (read (fd, &admin_id, 4) == 4);
|
||||
assert (read (fd, &date, 4) == 4);
|
||||
assert (read (fd, &ttl, 4) == 4);
|
||||
assert (read (fd, &layer, 4) == 4);
|
||||
assert (read (fd, &access_hash, 8) == 8);
|
||||
assert (read (fd, &state, 4) == 4);
|
||||
assert (read (fd, &key_fingerprint, 8) == 8);
|
||||
assert (read (fd, &key, 256) == 256);
|
||||
if (v >= 2) {
|
||||
assert (read (fd, sha, 20) == 20);
|
||||
}
|
||||
int in_seq_no = 0, out_seq_no = 0, last_in_seq_no = 0;
|
||||
if (v >= 1) {
|
||||
assert (read (fd, &in_seq_no, 4) == 4);
|
||||
assert (read (fd, &last_in_seq_no, 4) == 4);
|
||||
assert (read (fd, &out_seq_no, 4) == 4);
|
||||
}
|
||||
|
||||
bl_do_encr_chat_create (TLS, id, user_id, admin_id, s, l);
|
||||
struct tgl_secret_chat *P = (void *)tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (id));
|
||||
assert (P && (P->flags & FLAG_CREATED));
|
||||
bl_do_encr_chat_set_date (TLS, P, date);
|
||||
bl_do_encr_chat_set_ttl (TLS, P, ttl);
|
||||
bl_do_encr_chat_set_layer (TLS ,P, layer);
|
||||
bl_do_encr_chat_set_state (TLS, P, state);
|
||||
bl_do_encr_chat_set_key (TLS, P, key, key_fingerprint);
|
||||
if (v >= 2) {
|
||||
bl_do_encr_chat_set_sha (TLS, P, sha);
|
||||
} else {
|
||||
SHA1 ((void *)key, 256, sha);
|
||||
bl_do_encr_chat_set_sha (TLS, P, sha);
|
||||
}
|
||||
if (v >= 1) {
|
||||
bl_do_encr_chat_set_seq (TLS, P, in_seq_no, last_in_seq_no, out_seq_no);
|
||||
}
|
||||
bl_do_encr_chat_set_access_hash (TLS, P, access_hash);
|
||||
}
|
||||
|
||||
void read_secret_chat_file (struct tgl_state *TLS) {
|
||||
char *name = 0;
|
||||
if (asprintf (&name, "%s/%s", TLS->base_path, "secret") < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int secret_chat_fd = open (name, O_RDWR, 0600);
|
||||
free (name);
|
||||
|
||||
if (secret_chat_fd < 0) { return; }
|
||||
|
||||
int x;
|
||||
if (read (secret_chat_fd, &x, 4) < 4) { close (secret_chat_fd); return; }
|
||||
if (x != SECRET_CHAT_FILE_MAGIC) { close (secret_chat_fd); return; }
|
||||
int v = 0;
|
||||
assert (read (secret_chat_fd, &v, 4) == 4);
|
||||
assert (v == 0 || v == 1 || v == 2); // version
|
||||
assert (read (secret_chat_fd, &x, 4) == 4);
|
||||
assert (x >= 0);
|
||||
while (x -- > 0) {
|
||||
read_secret_chat (TLS, secret_chat_fd, v);
|
||||
}
|
||||
close (secret_chat_fd);
|
||||
}
|
||||
|
||||
void telegram_export_authorization (struct tgl_state *TLS);
|
||||
void export_auth_callback (struct tgl_state *TLS, void *extra, int success) {
|
||||
if (!error_if_val_false(TLS, success, "Authentication Export failed.")) {
|
||||
|
@ -397,6 +529,7 @@ static int check_all_authorized (gpointer arg) {
|
|||
void telegram_login (struct tgl_state *TLS) {
|
||||
read_auth_file (TLS);
|
||||
read_state_file (TLS);
|
||||
read_secret_chat_file (TLS);
|
||||
if (all_authorized (TLS)) {
|
||||
telegram_send_sms (TLS);
|
||||
return;
|
||||
|
|
|
@ -26,6 +26,8 @@ void read_state_file (struct tgl_state *TLS);
|
|||
void read_auth_file (struct tgl_state *TLS);
|
||||
void write_auth_file (struct tgl_state *TLS);
|
||||
void write_state_file (struct tgl_state *TLS);
|
||||
void read_secret_chat_file (struct tgl_state *TLS);
|
||||
void write_secret_chat_file (struct tgl_state *TLS);
|
||||
|
||||
void telegram_login (struct tgl_state *TLS);
|
||||
PurpleConversation *chat_show (PurpleConnection *gc, int id);
|
||||
|
|
|
@ -153,7 +153,6 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M)
|
|||
case tgl_message_action_notify_layer:
|
||||
txt_action = g_strdup_printf ("updated layer to %d", M->action.layer);
|
||||
break;
|
||||
/*
|
||||
case tgl_message_action_request_key:
|
||||
txt_action = g_strdup_printf ("Request rekey #%016llx\n", M->action.exchange_id);
|
||||
break;
|
||||
|
@ -166,7 +165,6 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M)
|
|||
case tgl_message_action_abort_key:
|
||||
txt_action = g_strdup_printf ("Abort rekey #%016llx\n", M->action.exchange_id);
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
txt_action = NULL;
|
||||
break;
|
||||
|
@ -180,6 +178,13 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M)
|
|||
return txt;
|
||||
}
|
||||
|
||||
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);
|
||||
tgl_do_send_message (TLS, to, raw, (int)strlen (raw), 0, 0);
|
||||
g_free(raw);
|
||||
}
|
||||
|
||||
static int our_msg (struct tgl_state *TLS, struct tgl_message *M) {
|
||||
//return tgl_get_peer_id(M->from_id) == TLS->our_id;
|
||||
//return M->out;
|
||||
|
@ -201,6 +206,19 @@ static gboolean queries_timerfunc (gpointer data) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void created_secret_chat (struct tgl_state *TLS, void *data, int success, struct tgl_secret_chat *chat) {
|
||||
debug ("created_secret_chat: success=%d\n", success);
|
||||
}
|
||||
|
||||
static void start_secret_chat (PurpleBlistNode *node, gpointer data) {
|
||||
PurpleBuddy *buddy = data;
|
||||
connection_data *conn = purple_connection_get_protocol_data (
|
||||
purple_account_get_connection (purple_buddy_get_account(buddy)));
|
||||
|
||||
tgl_do_create_secret_chat(conn->TLS, TGL_MK_USER(atoi (purple_buddy_get_name (buddy))),
|
||||
created_secret_chat, buddy);
|
||||
}
|
||||
|
||||
static void on_update_user_name (struct tgl_state *TLS, tgl_peer_t *user) __attribute__ ((unused));
|
||||
static void on_update_user_name (struct tgl_state *TLS, tgl_peer_t *user) {
|
||||
p2tgl_got_alias(TLS, user->id, p2tgl_strdup_alias(user));
|
||||
|
@ -264,13 +282,6 @@ void on_message_load_photo (struct tgl_state *TLS, void *extra, int success, cha
|
|||
}
|
||||
break;
|
||||
|
||||
case TGL_PEER_ENCR_CHAT:
|
||||
debug ("PEER_ENCR_CHAT\n");
|
||||
if (our_msg(TLS, M)) {
|
||||
//encr_chat_add_message(...)
|
||||
}
|
||||
break;
|
||||
|
||||
case TGL_PEER_GEO_CHAT:
|
||||
break;
|
||||
}
|
||||
|
@ -330,6 +341,17 @@ static void update_message_received (struct tgl_state *TLS, struct tgl_message *
|
|||
}
|
||||
break;
|
||||
|
||||
case TGL_PEER_ENCR_CHAT:
|
||||
if (!our_msg(TLS, M)) {
|
||||
p2tgl_got_im (TLS, M->to_id, text, PURPLE_MESSAGE_RECV, M->date);
|
||||
|
||||
pending_reads_add (conn->pending_reads, M->to_id);
|
||||
if (p2tgl_status_is_present (purple_account_get_active_status(conn->pa))) {
|
||||
pending_reads_send_all (conn->pending_reads, conn->TLS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TGL_PEER_USER:
|
||||
debug ("PEER_USER\n");
|
||||
|
||||
|
@ -342,20 +364,13 @@ static void update_message_received (struct tgl_state *TLS, struct tgl_message *
|
|||
p2tgl_got_im (TLS, M->from_id, text, PURPLE_MESSAGE_RECV, M->date);
|
||||
|
||||
pending_reads_add (conn->pending_reads, M->from_id);
|
||||
if (p2tgl_status_is_present(purple_account_get_active_status(conn->pa))) {
|
||||
if (p2tgl_status_is_present (purple_account_get_active_status(conn->pa))) {
|
||||
pending_reads_send_all (conn->pending_reads, conn->TLS);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TGL_PEER_ENCR_CHAT:
|
||||
debug ("PEER_ENCR_CHAT\n");
|
||||
if (! our_msg(TLS, M)) {
|
||||
//encr_chat_add_message(...)
|
||||
}
|
||||
break;
|
||||
|
||||
case TGL_PEER_GEO_CHAT:
|
||||
break;
|
||||
}
|
||||
|
@ -389,15 +404,51 @@ static void update_user_handler (struct tgl_state *TLS, struct tgl_user *user, u
|
|||
}
|
||||
}
|
||||
|
||||
static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret_chat *C, unsigned flags) {
|
||||
//tgl_do_get_chat_info (TLS, chat->id, 0, on_chat_get_info, 0);
|
||||
PurpleBuddy *buddy = p2tgl_buddy_find (TLS, C->id);
|
||||
static void write_secret_chat_cb (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E) {
|
||||
debug ("update_secret_chat_handle success=%d", success);
|
||||
write_secret_chat_file (TLS);
|
||||
}
|
||||
|
||||
static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret_chat *U, unsigned flags) {
|
||||
if (U->state == sc_none) { return; }
|
||||
debug ("secret-chat-state: %d", U->state);
|
||||
|
||||
PurpleBuddy *buddy = p2tgl_buddy_find (TLS, U->id);
|
||||
if (!buddy) {
|
||||
buddy = p2tgl_buddy_new (TLS, (tgl_peer_t *)U);
|
||||
purple_blist_add_buddy (buddy, NULL, tggroup, NULL);
|
||||
purple_blist_alias_buddy (buddy, U->print_name);
|
||||
}
|
||||
|
||||
if (U->first_key_sha[0]) {
|
||||
// display secret key
|
||||
PurpleNotifyUserInfo *info = purple_notify_user_info_new();
|
||||
int sha1key_store_id = generate_ident_icon (TLS, U->first_key_sha);
|
||||
if (sha1key_store_id != -1) {
|
||||
char *ident_icon = format_img_full (sha1key_store_id);
|
||||
purple_notify_user_info_add_pair (info, "Secret Key", ident_icon);
|
||||
g_free(ident_icon);
|
||||
}
|
||||
connection_data *conn = TLS->ev_base;
|
||||
char *id = g_strdup_printf ("%d", tgl_get_peer_id (U->id));
|
||||
purple_notify_userinfo (conn->gc, id, info, NULL, NULL);
|
||||
g_free (id);
|
||||
}
|
||||
|
||||
p2tgl_prpl_got_set_status_mobile (TLS, U->id);
|
||||
|
||||
if ((flags & TGL_UPDATE_WORKING) || (flags & TGL_UPDATE_DELETED)) {
|
||||
write_secret_chat_file (TLS);
|
||||
}
|
||||
|
||||
if ((flags & TGL_UPDATE_REQUESTED)) {
|
||||
// TODO: autoaccept setting, otherwise prompt for ok
|
||||
tgl_do_accept_encr_chat_request (TLS, U, write_secret_chat_cb, 0);
|
||||
}
|
||||
|
||||
if (flags & TGL_UPDATE_CREATED) {
|
||||
if (!buddy) {
|
||||
buddy = p2tgl_buddy_new (TLS, (tgl_peer_t *)C);
|
||||
purple_blist_add_buddy (buddy, NULL, tggroup, NULL);
|
||||
}
|
||||
purple_buddy_set_protocol_data (buddy, (gpointer)U);
|
||||
p2tgl_buddy_update (TLS, (tgl_peer_t *)U, flags);
|
||||
}
|
||||
if (flags & (TGL_UPDATE_NAME | TGL_UPDATE_REAL_NAME | TGL_UPDATE_USERNAME) && buddy) {
|
||||
}
|
||||
|
@ -486,16 +537,6 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success,
|
|||
PurpleNotifyUserInfo *info = create_user_notify_info(U);
|
||||
char *profile_image = profile_image = format_img_full(imgStoreId);
|
||||
purple_notify_user_info_add_pair (info, "Profile image", profile_image);
|
||||
//TODO: get the sha1key from the secret chat
|
||||
unsigned char sha1_key[20] = {129, 236, 235, 161, 62, 139, 244, 162, 120, 99, 99, 26, 171, 224, 25, 125};
|
||||
int sha1key_store_id = generate_ident_icon(TLS, sha1_key);
|
||||
if(sha1key_store_id != -1)
|
||||
{
|
||||
char *ident_icon = g_strdup_printf("<br><img id=\"%u\">", sha1key_store_id);
|
||||
purple_notify_user_info_add_pair(info, "Identification icon", ident_icon);
|
||||
g_free(ident_icon);
|
||||
}
|
||||
|
||||
purple_notify_userinfo (conn->gc, who, info, NULL, NULL);
|
||||
g_free (profile_image);
|
||||
}
|
||||
|
@ -505,7 +546,10 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success,
|
|||
|
||||
void on_user_get_info (struct tgl_state *TLS, void *show_info, int success, struct tgl_user *U)
|
||||
{
|
||||
assert (success);
|
||||
if (! success) {
|
||||
warning ("on_user_get_info not successfull, aborting...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (U->photo.sizes_num == 0) {
|
||||
if (show_info) {
|
||||
|
@ -558,7 +602,7 @@ void on_ready (struct tgl_state *TLS) {
|
|||
purple_connection_set_state(conn->gc, PURPLE_CONNECTED);
|
||||
purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa));
|
||||
purple_blist_add_account(conn->pa);
|
||||
tggroup = purple_find_group("Telegram");
|
||||
tggroup = purple_find_group ("Telegram");
|
||||
if (tggroup == NULL) {
|
||||
debug ("PurpleGroup = NULL, creating");
|
||||
tggroup = purple_group_new ("Telegram");
|
||||
|
@ -621,6 +665,20 @@ static GList *tgprpl_status_types (PurpleAccount * acct) {
|
|||
return g_list_reverse (types);
|
||||
}
|
||||
|
||||
static GList* tgprpl_blist_node_menu (PurpleBlistNode *node) {
|
||||
purple_debug_info (PLUGIN_ID, "tgprpl_blist_node_menu()\n");
|
||||
|
||||
GList* menu = NULL;
|
||||
if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
|
||||
// Add encrypted chat option to the right click menu of all buddies
|
||||
PurpleBuddy* buddy = (PurpleBuddy*)node;
|
||||
PurpleMenuAction* menu_action = purple_menu_action_new("Start Secret Chat",
|
||||
PURPLE_CALLBACK(start_secret_chat), buddy, NULL);
|
||||
menu = g_list_append(menu, (gpointer)menu_action);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
static GList *tgprpl_chat_join_info (PurpleConnection * gc) {
|
||||
debug ("tgprpl_chat_join_info()\n");
|
||||
struct proto_chat_entry *pce;
|
||||
|
@ -702,15 +760,24 @@ static int tgprpl_send_im (PurpleConnection * gc, const char *who, const char *m
|
|||
return -1;
|
||||
}
|
||||
|
||||
tgl_peer_t *peer = tgl_peer_get(conn->TLS, TGL_MK_USER(atoi (who)));
|
||||
if (!peer) {
|
||||
warning ("Protocol data tgl_peer_t for %s not found, cannot send IM\n", who);
|
||||
return -1;
|
||||
/*
|
||||
Make sure that we only send messages to an existing peer by
|
||||
searching it in the peer tree. This allows us to give immediate feedback
|
||||
by returning an error-code in case the peer doesn't exist
|
||||
*/
|
||||
tgl_peer_t *peer = tgl_peer_get (conn->TLS, TGL_MK_USER(atoi (who)));
|
||||
if (peer) {
|
||||
tgl_do_send_unescape_message (conn->TLS, message, peer->id);
|
||||
return 1;
|
||||
}
|
||||
gchar *raw = purple_unescape_html(message);
|
||||
tgl_do_send_message (conn->TLS, peer->id, raw, (int)strlen (raw), 0, 0);
|
||||
g_free(raw);
|
||||
return 1;
|
||||
peer = tgl_peer_get (conn->TLS, TGL_MK_ENCR_CHAT(atoi(who)));
|
||||
if (peer) {
|
||||
tgl_do_send_unescape_message (conn->TLS, message, peer->id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// peer not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned int tgprpl_send_typing (PurpleConnection * gc, const char *who, PurpleTypingState typing) {
|
||||
|
@ -829,10 +896,7 @@ static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *messa
|
|||
static int tgprpl_send_chat (PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) {
|
||||
debug ("tgprpl_send_chat()\n");
|
||||
connection_data *conn = purple_connection_get_protocol_data (gc);
|
||||
|
||||
gchar *raw = purple_unescape_html(message);
|
||||
tgl_do_send_message (conn->TLS, TGL_MK_CHAT(id), raw, (int)strlen (raw), 0, 0);
|
||||
g_free (raw);
|
||||
tgl_do_send_unescape_message (conn->TLS, message, TGL_MK_CHAT(id));
|
||||
|
||||
/* Pidgin won't display the written message if we don't call this, Adium will display it twice
|
||||
if we call it, so we don't do it for the adium Plugin.
|
||||
|
@ -881,25 +945,6 @@ static gboolean tgprpl_offline_message (const PurpleBuddy * buddy) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void start_encrypted_chat ( PurpleBlistNode *node, gpointer data )
|
||||
{
|
||||
debug("start_encrypted_chat()\n");
|
||||
}
|
||||
|
||||
//Add encrypted chat option to the rightclick menue of all buddies
|
||||
static GList* tgprpl_blist_node_menu(PurpleBlistNode *node)
|
||||
{
|
||||
purple_debug_info (PLUGIN_ID, "tgprpl_blist_node_menu()\n");
|
||||
GList* menu = NULL;
|
||||
if (PURPLE_BLIST_NODE_IS_BUDDY(node))
|
||||
{
|
||||
PurpleBuddy* buddy = (PurpleBuddy*)node;
|
||||
PurpleMenuAction* menu_action = purple_menu_action_new("Start encrypted chat...", PURPLE_CALLBACK(start_encrypted_chat), buddy, NULL);
|
||||
menu = g_list_append(menu, (gpointer)menu_action);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
static PurplePluginProtocolInfo prpl_info = {
|
||||
OPT_PROTO_NO_PASSWORD,
|
||||
NULL, // user_splits, initialized in tgprpl_init()
|
||||
|
|
28
tgp-2prpl.c
28
tgp-2prpl.c
|
@ -68,26 +68,12 @@ PurpleConnection *tg_get_conn (struct tgl_state *TLS) {
|
|||
return (PurpleConnection *) ((connection_data *)TLS->ev_base)->gc;
|
||||
}
|
||||
|
||||
static char *peer_strdup_id(tgl_peer_id_t user) {
|
||||
static char *p2tgl_peer_strdup_id (tgl_peer_id_t user) {
|
||||
return g_strdup_printf("%d", tgl_get_peer_id(user));
|
||||
}
|
||||
|
||||
char *p2tgl_strdup_alias(tgl_peer_t *user) {
|
||||
char *alias = malloc(64);
|
||||
|
||||
// snprintf returs number of bytes it wanted to write
|
||||
// negative return points on write error
|
||||
// should never happen
|
||||
int r = user_get_alias(user, alias, 64);
|
||||
if (r >= 64) {
|
||||
warning ("user name too long");
|
||||
alias[63] = 0;
|
||||
}
|
||||
assert (r >= 0);
|
||||
|
||||
gchar *g_alias = g_strdup(alias);
|
||||
free (alias);
|
||||
return g_alias;
|
||||
gchar *p2tgl_strdup_alias (tgl_peer_t *user) {
|
||||
return g_strdup (user->print_name);
|
||||
}
|
||||
|
||||
int p2tgl_status_is_present (PurpleStatus *status)
|
||||
|
@ -205,6 +191,14 @@ PurpleBuddy *p2tgl_buddy_update (struct tgl_state *TLS, tgl_peer_t *user, unsign
|
|||
return b;
|
||||
}
|
||||
|
||||
void p2tgl_prpl_got_set_status_mobile (struct tgl_state *TLS, tgl_peer_id_t user) {
|
||||
char *name = peer_strdup_id (user);
|
||||
|
||||
purple_prpl_got_user_status (tg_get_acc(TLS), name, "mobile", NULL);
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
void p2tgl_prpl_got_user_status (struct tgl_state *TLS, tgl_peer_id_t user, struct tgl_user_status *status) {
|
||||
|
||||
if (status->online == 1) {
|
||||
|
|
|
@ -53,7 +53,7 @@ PurpleBuddy *p2tgl_buddy_new (struct tgl_state *TLS, tgl_peer_t *user);
|
|||
PurpleBuddy *p2tgl_buddy_update (struct tgl_state *TLS, tgl_peer_t *user, unsigned flags);
|
||||
void p2tgl_buddy_add_data (struct tgl_state *TLS, tgl_peer_id_t user, void *data);
|
||||
void p2tgl_prpl_got_user_status (struct tgl_state *TLS, tgl_peer_id_t user, struct tgl_user_status *status);
|
||||
|
||||
void p2tgl_prpl_got_set_status_mobile (struct tgl_state *TLS, tgl_peer_id_t user);
|
||||
|
||||
void p2tgl_connection_set_display_name(struct tgl_state *TLS, tgl_peer_t *user);
|
||||
void p2tgl_conv_del_user (PurpleConversation *conv, tgl_peer_id_t user);
|
||||
|
|
Loading…
Add table
Reference in a new issue