Improve group chat management
Load full chat info lazily, prevents useless network request and should fix issues with delays through flood errors when handling big amounts of user chats. Handle chat participant deletions and additions correctly and only touch the user list when it is actually updated, this should fix some issues with printing annoying messages in Finch and users not showing up in the buddy list in certain situations. Only add chats to buddy list that are actively joined or receive incoming message, which should help keeping the buddy list more tidy when using much chats.
This commit is contained in:
parent
592b31e8c8
commit
888cffffc1
11 changed files with 279 additions and 209 deletions
|
@ -37,10 +37,12 @@
|
|||
|
||||
@implementation TelegramJoinChatViewController
|
||||
|
||||
static void tgl_peer_iterator_cb (tgl_peer_t *peer, void *extra) {
|
||||
static void tgl_chat_iterator_cb (tgl_peer_t *peer, void *extra) {
|
||||
NSMutableArray *A = (__bridge NSMutableArray *)(extra);
|
||||
if (tgl_get_peer_type (peer->id) == TGL_PEER_CHAT) {
|
||||
[A addObject: [NSValue valueWithPointer: peer]];
|
||||
|
||||
// chats with 0 participants were deleted or left by the user
|
||||
if (tgl_get_peer_type (peer->id) == TGL_PEER_CHAT && peer->chat.users_num > 0) {
|
||||
[A addObject: [NSString stringWithUTF8String: peer->print_name]];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,33 +55,12 @@ static void tgl_peer_iterator_cb (tgl_peer_t *peer, void *extra) {
|
|||
if (gc && PURPLE_CONNECTION_IS_CONNECTED(gc)) {
|
||||
connection_data *conn = purple_connection_get_protocol_data (gc);
|
||||
|
||||
// fetch all active chats and put them into the select box
|
||||
[popupButton_existingChat removeAllItems];
|
||||
|
||||
NSMutableArray *a = [NSMutableArray new];
|
||||
tgl_peer_iterator_ex (conn->TLS, tgl_peer_iterator_cb, (__bridge void *)(a));
|
||||
|
||||
NSMutableArray *chats = [NSMutableArray new];
|
||||
NSMutableArray *leftChats = [NSMutableArray new];
|
||||
for (NSValue *V in a) {
|
||||
tgl_peer_t *P = [V pointerValue];
|
||||
NSString *name = [[NSString alloc] initWithUTF8String:P->print_name];
|
||||
if (chat_is_member (conn->TLS->our_id, &P->chat)) {
|
||||
[chats addObject: name];
|
||||
}
|
||||
else {
|
||||
[leftChats addObject: name];
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *sortedChats = [chats sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
|
||||
return [(NSString*)a
|
||||
compare:b
|
||||
options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch];
|
||||
}];
|
||||
[popupButton_existingChat addItemsWithTitles: sortedChats];
|
||||
// TODO: Display left chats with a grey font to indicate that those are no
|
||||
// longer, but still allow the user to view the history
|
||||
// [popupButton_existingChat addItemsWithTitles: leftChats];
|
||||
tgl_peer_iterator_ex (conn->TLS, tgl_chat_iterator_cb, (__bridge void *)(chats));
|
||||
[popupButton_existingChat
|
||||
addItemsWithTitles: [chats sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]];
|
||||
|
||||
// provide the current TLS instance for access by the autocompletion
|
||||
TelegramAutocompletionDelegate *D = [tokenField_createChatUsers delegate];
|
||||
|
|
|
@ -620,10 +620,9 @@ void request_accept_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat *
|
|||
|
||||
void create_group_chat_done_cb (struct tgl_state *TLS, void *title, int success) {
|
||||
if (success) {
|
||||
tgl_peer_t *t = tgl_peer_get_by_name(TLS, title);
|
||||
if (t) {
|
||||
connection_data *conn = TLS->ev_base;
|
||||
chat_show (conn->gc, tgl_get_peer_id(t->id));
|
||||
tgl_peer_t *P = tgl_peer_get_by_name (TLS, title);
|
||||
if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) {
|
||||
tgp_chat_show (TLS, &P->chat);
|
||||
}
|
||||
}
|
||||
tgp_notify_on_error_gw (TLS, NULL, success);
|
||||
|
@ -645,7 +644,7 @@ void tgp_create_group_chat_by_usernames (struct tgl_state *TLS, const char *titl
|
|||
if (P && tgl_get_peer_id (P->id) != TLS->our_id) {
|
||||
ids[j++] = P->id;
|
||||
} else {
|
||||
debug("User %s not found in peer list", users[j]);
|
||||
debug ("User %s not found in peer list", users[j]);
|
||||
}
|
||||
}
|
||||
if (i > 0) {
|
||||
|
@ -662,9 +661,9 @@ static void create_group_chat_cb (void *_data, PurpleRequestFields* fields) {
|
|||
debug ("create_group_chat_cb()");
|
||||
struct accept_create_chat_data *data = _data;
|
||||
const char *users[3] = {
|
||||
purple_request_fields_get_string(fields, "user1"),
|
||||
purple_request_fields_get_string(fields, "user2"),
|
||||
purple_request_fields_get_string(fields, "user3")
|
||||
purple_request_fields_get_string (fields, "user1"),
|
||||
purple_request_fields_get_string (fields, "user2"),
|
||||
purple_request_fields_get_string (fields, "user3")
|
||||
};
|
||||
|
||||
tgp_create_group_chat_by_usernames (data->TLS, data->title, users, 3, FALSE);
|
||||
|
|
|
@ -83,7 +83,6 @@ static void update_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum
|
|||
static void update_marked_read (struct tgl_state *TLS, int num, struct tgl_message *list[]);
|
||||
static char *format_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4);
|
||||
void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, struct tgl_user *U);
|
||||
void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C);
|
||||
|
||||
PurpleGroup *tggroup;
|
||||
const char *config_dir = "telegram-purple";
|
||||
|
@ -141,12 +140,6 @@ static void update_user_handler (struct tgl_state *TLS, struct tgl_user *user, u
|
|||
static void update_message_handler (struct tgl_state *TLS, struct tgl_message *M) {
|
||||
write_files_schedule (TLS);
|
||||
tgp_msg_recv (TLS, M);
|
||||
|
||||
if (M->flags & TGLMF_SERVICE &&
|
||||
(M->action.type == tgl_message_action_chat_add_user ||
|
||||
M->action.type == tgl_message_action_chat_delete_user)) {
|
||||
tgl_do_get_chat_info (TLS, M->to_id, FALSE, on_chat_get_info, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_user_status_handler (struct tgl_state *TLS, struct tgl_user *U) {
|
||||
|
@ -191,15 +184,17 @@ static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret
|
|||
}
|
||||
|
||||
static void update_chat_handler (struct tgl_state *TLS, struct tgl_chat *chat, unsigned flags) {
|
||||
PurpleChat *ch = p2tgl_chat_find (TLS, chat->id);
|
||||
|
||||
if (! (flags & TGL_UPDATE_CREATED)) {
|
||||
PurpleChat *ch = p2tgl_chat_find (TLS, chat->id);
|
||||
|
||||
if (flags & TGL_UPDATE_TITLE && ch) {
|
||||
purple_blist_alias_chat (ch, chat->print_title);
|
||||
}
|
||||
/*
|
||||
if (flags & (TGL_UPDATE_MEMBERS | TGL_UPDATE_ADMIN) && ch) {
|
||||
chat_users_update (TLS, chat);
|
||||
tgp_chat_users_update (TLS, chat);
|
||||
}
|
||||
*/
|
||||
if (flags & TGL_UPDATE_DELETED && ch) {
|
||||
purple_blist_remove_chat (ch);
|
||||
}
|
||||
|
@ -325,33 +320,26 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success,
|
|||
free (dld);
|
||||
}
|
||||
|
||||
static void on_get_dialog_list_done (struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) {
|
||||
int i;
|
||||
for (i = size - 1; i >= 0; i--) {
|
||||
tgl_peer_t *UC;
|
||||
switch (tgl_get_peer_type (peers[i])) {
|
||||
|
||||
case TGL_PEER_USER: {
|
||||
PurpleBuddy *buddy = p2tgl_buddy_find (TLS, peers[i]);
|
||||
UC = tgl_peer_get (TLS, peers[i]);
|
||||
if (tgl_get_peer_id (peers[i]) != TLS->our_id) {
|
||||
if (! buddy) {
|
||||
buddy = p2tgl_buddy_new (TLS, UC);
|
||||
purple_blist_add_buddy (buddy, NULL, tggroup, NULL);
|
||||
tgl_do_get_user_info (TLS, UC->id, 0, on_user_get_info, get_user_info_data_new (0, UC->id));
|
||||
}
|
||||
p2tgl_prpl_got_user_status (TLS, UC->id, &UC->user.status);
|
||||
p2tgl_prpl_got_set_status_mobile (TLS, UC->id);
|
||||
} else {
|
||||
p2tgl_connection_set_display_name (TLS, UC);
|
||||
}
|
||||
break;
|
||||
static void on_get_dialog_list_done (struct tgl_state *TLS, void *callback_extra, int success, int size,
|
||||
tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) {
|
||||
int i = size - 1;
|
||||
for (; i >= 0; i--) if (tgl_get_peer_type (peers[i]) == TGL_PEER_USER) {
|
||||
tgl_peer_t *UC = tgl_peer_get (TLS, peers[i]);
|
||||
|
||||
if (tgl_get_peer_id (peers[i]) != TLS->our_id) {
|
||||
PurpleBuddy *buddy = p2tgl_buddy_find (TLS, peers[i]);
|
||||
if (! buddy) {
|
||||
buddy = p2tgl_buddy_new (TLS, UC);
|
||||
purple_blist_add_buddy (buddy, NULL, tggroup, NULL);
|
||||
tgl_do_get_user_info (TLS, UC->id, 0, on_user_get_info, get_user_info_data_new (0, UC->id));
|
||||
}
|
||||
|
||||
case TGL_PEER_CHAT:
|
||||
tgl_do_get_chat_info (TLS, peers[i], FALSE, on_chat_get_info, NULL);
|
||||
break;
|
||||
|
||||
p2tgl_prpl_got_user_status (TLS, UC->id, &UC->user.status);
|
||||
p2tgl_prpl_got_set_status_mobile (TLS, UC->id);
|
||||
} else {
|
||||
p2tgl_connection_set_display_name (TLS, UC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,21 +367,6 @@ void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, stru
|
|||
}
|
||||
}
|
||||
|
||||
void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C) {
|
||||
if (!success) {
|
||||
failure ("chat_get_info FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
PurpleChat *PC = p2tgl_chat_find (TLS, C->id);
|
||||
if (!PC) {
|
||||
PC = p2tgl_chat_new (TLS, C);
|
||||
purple_blist_add_chat (PC, NULL, NULL);
|
||||
}
|
||||
|
||||
chat_users_update (TLS, C);
|
||||
}
|
||||
|
||||
void on_ready (struct tgl_state *TLS) {
|
||||
debug ("on_ready().");
|
||||
connection_data *conn = TLS->ev_base;
|
||||
|
@ -479,8 +452,10 @@ static void create_chat_link_done (struct tgl_state *TLS, void *extra, int succe
|
|||
tgl_peer_t *C = extra;
|
||||
|
||||
if (success) {
|
||||
chat_show (conn->gc, tgl_get_peer_id (C->id));
|
||||
char *msg = g_strdup_printf("Invite link: %s", url);
|
||||
assert (tgl_get_peer_type (C->id) == TGL_PEER_CHAT);
|
||||
tgp_chat_show (TLS, &C->chat);
|
||||
|
||||
char *msg = g_strdup_printf ("Invite link: %s", url);
|
||||
serv_got_chat_in (conn->gc, tgl_get_peer_id(C->id), "WebPage", PURPLE_MESSAGE_SYSTEM,
|
||||
msg, time(NULL));
|
||||
g_free (msg);
|
||||
|
@ -561,23 +536,6 @@ static GList* tgprpl_blist_node_menu (PurpleBlistNode *node) {
|
|||
return menu;
|
||||
}
|
||||
|
||||
static GList *tgprpl_chat_join_info (PurpleConnection * gc) {
|
||||
debug ("tgprpl_chat_join_info()");
|
||||
|
||||
struct proto_chat_entry *pce;
|
||||
pce = g_new0(struct proto_chat_entry, 1);
|
||||
pce->label = "_Subject:";
|
||||
pce->identifier = "subject";
|
||||
pce->required = FALSE;
|
||||
GList *info = g_list_append (NULL, pce);
|
||||
|
||||
pce = g_new0(struct proto_chat_entry, 1);
|
||||
pce->label = "_Join by Link:";
|
||||
pce->identifier = "link";
|
||||
pce->required = FALSE;
|
||||
return g_list_append (info, pce);
|
||||
}
|
||||
|
||||
static void tgprpl_login (PurpleAccount * acct) {
|
||||
debug ("tgprpl_login()");
|
||||
|
||||
|
@ -741,50 +699,6 @@ static void tgprpl_remove_buddy (PurpleConnection * gc, PurpleBuddy * buddy, Pur
|
|||
}
|
||||
}
|
||||
|
||||
static void tgprpl_chat_join (PurpleConnection * gc, GHashTable * data) {
|
||||
debug ("tgprpl_chat_join()");
|
||||
const char *subject = NULL, *link = NULL;
|
||||
gpointer value;
|
||||
connection_data *conn = purple_connection_get_protocol_data (gc);
|
||||
|
||||
value = g_hash_table_lookup (data, "id");
|
||||
if (value && atoi (value)) {
|
||||
chat_show (conn->gc, atoi (value));
|
||||
return;
|
||||
}
|
||||
|
||||
link = g_hash_table_lookup(data, "link");
|
||||
if (str_not_empty (link)) {
|
||||
tgl_do_import_chat_link (conn->TLS, link, (int)strlen (link), tgp_notify_on_error_gw, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
subject = g_hash_table_lookup (data, "subject");
|
||||
if (str_not_empty (subject)) {
|
||||
tgl_peer_t *P = tgl_peer_get_by_name (conn->TLS, subject);
|
||||
if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) {
|
||||
chat_show (conn->gc, tgl_get_peer_id (P->id));
|
||||
return;
|
||||
}
|
||||
request_create_chat (conn->TLS, subject);
|
||||
}
|
||||
}
|
||||
|
||||
static char *tgprpl_get_chat_name (GHashTable * data) {
|
||||
return g_strdup(g_hash_table_lookup(data, "subject"));
|
||||
}
|
||||
|
||||
static void add_user_to_chat_done_cb (struct tgl_state *TLS, void *callback_extra, int success) {
|
||||
tgl_peer_t *C = callback_extra;
|
||||
|
||||
if (success) {
|
||||
// update users
|
||||
tgl_do_get_chat_info (TLS, C->id, FALSE, on_chat_get_info, NULL);
|
||||
} else {
|
||||
tgp_notify_on_error_gw (TLS, NULL, success);
|
||||
}
|
||||
}
|
||||
|
||||
static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *message, const char *name) {
|
||||
debug ("tgprpl_chat_invite()");
|
||||
|
||||
|
@ -797,7 +711,7 @@ static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *messa
|
|||
return;
|
||||
}
|
||||
|
||||
tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, add_user_to_chat_done_cb, chat);
|
||||
tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, tgp_notify_on_error_gw, chat);
|
||||
}
|
||||
|
||||
static int tgprpl_send_chat (PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) {
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
#define TGP_DEFAULT_SEND_READ_NOTIFICATIONS TRUE
|
||||
#define TGP_KEY_SEND_READ_NOTIFICATIONS "send-read-notifications"
|
||||
|
||||
void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C);
|
||||
void on_ready (struct tgl_state *TLS);
|
||||
extern const char *pk_path;
|
||||
extern const char *config_dir;
|
||||
|
|
24
tgp-2prpl.c
24
tgp-2prpl.c
|
@ -294,6 +294,14 @@ PurpleChat *p2tgl_chat_new (struct tgl_state *TLS, struct tgl_chat *chat) {
|
|||
return C;
|
||||
}
|
||||
|
||||
void p2tgl_chat_update (PurpleChat *chat, tgl_peer_id_t id, int admin_id, const char *subject) {
|
||||
GHashTable *ht = purple_chat_get_components (chat);
|
||||
|
||||
g_hash_table_replace (ht, g_strdup ("id"), g_strdup_printf ("%d", tgl_get_peer_id (id)));
|
||||
g_hash_table_replace (ht, g_strdup ("owner"), g_strdup_printf ("%d", admin_id));
|
||||
g_hash_table_replace (ht, g_strdup ("subject"), g_strdup (subject));
|
||||
}
|
||||
|
||||
tgl_chat_id_t p2tgl_chat_get_id (PurpleChat *PC) {
|
||||
char *name = g_hash_table_lookup (purple_chat_get_components (PC), "id");
|
||||
if (! atoi (name)) {
|
||||
|
@ -310,17 +318,17 @@ PurpleChat *p2tgl_chat_find (struct tgl_state *TLS, tgl_peer_id_t id) {
|
|||
}
|
||||
|
||||
void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv,
|
||||
struct tgl_chat_user user, char *message, int flags, int new_arrival) {
|
||||
int user, char *message, int flags, int new_arrival) {
|
||||
PurpleConvChat *cdata = purple_conversation_get_chat_data(conv);
|
||||
char *name = g_strdup_printf("%d", user.user_id);
|
||||
char *name = g_strdup_printf ("%d", user);
|
||||
purple_conv_chat_add_user (cdata, name, message, flags, new_arrival);
|
||||
|
||||
// inject print_name into chat buddies to display a human-readable name
|
||||
// for buddies not in the buddy list instead of the user id
|
||||
tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER(user.user_id));
|
||||
tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER(user));
|
||||
if (U) {
|
||||
PurpleConvChatBuddy *cbuddy = purple_conv_chat_cb_find (PURPLE_CONV_CHAT(conv), name);
|
||||
PurpleConversationUiOps *uiops = purple_conversation_get_ui_ops (conv);;
|
||||
PurpleConversationUiOps *uiops = purple_conversation_get_ui_ops (conv);
|
||||
if (cbuddy && cbuddy->alias) {
|
||||
g_free (cbuddy->alias);
|
||||
cbuddy->alias = g_strdup (U->print_name);
|
||||
|
@ -337,6 +345,14 @@ void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv,
|
|||
g_free(name);
|
||||
}
|
||||
|
||||
void p2tgl_conv_del_user (struct tgl_state *TLS, PurpleConversation *conv, const char *message, int userid) {
|
||||
char *name = g_strdup_printf("%d", userid);
|
||||
|
||||
purple_conv_chat_remove_user (purple_conversation_get_chat_data (conv), name, message);
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
void p2tgl_connection_set_display_name(struct tgl_state *TLS, tgl_peer_t *user) {
|
||||
char *name = p2tgl_strdup_alias (user);
|
||||
purple_connection_set_display_name (tg_get_conn(TLS), name);
|
||||
|
|
|
@ -60,14 +60,15 @@ void p2tgl_prpl_got_set_status_mobile (struct tgl_state *TLS, tgl_peer_id_t user
|
|||
void p2tgl_prpl_got_set_status_offline (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);
|
||||
void p2tgl_conv_del_user (struct tgl_state *TLS, PurpleConversation *conv, const char *message, int userid);
|
||||
void p2tgl_conv_add_users (PurpleConversation *conv, struct tgl_chat_user *list);
|
||||
void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, struct tgl_chat_user user, char *message, int flags, int new_arrival);
|
||||
void p2tgl_conv_add_user (struct tgl_state *TLS, PurpleConversation *conv, int user, char *message, int flags, int new_arrival);
|
||||
PurpleConversation *p2tgl_find_conversation_with_account (struct tgl_state *TLS, tgl_peer_id_t peer);
|
||||
void p2tgl_conversation_write (PurpleConversation *conv, tgl_peer_id_t who, const char *message, int flags, int date);
|
||||
PurpleConversation *p2tgl_conversation_new (struct tgl_state *TLS, tgl_peer_id_t who);
|
||||
|
||||
PurpleChat *p2tgl_chat_new (struct tgl_state *TLS, struct tgl_chat *chat);
|
||||
void p2tgl_chat_update (PurpleChat *chat, tgl_peer_id_t id, int admin_id, const char *subject);
|
||||
PurpleChat *p2tgl_chat_find (struct tgl_state *TLS, tgl_peer_id_t chat);
|
||||
|
||||
void *p2tgl_notify_userinfo(struct tgl_state *TLS, tgl_peer_id_t user, PurpleNotifyUserInfo *user_info, PurpleNotifyCloseCallback cb, gpointer user_data);
|
||||
|
|
138
tgp-chat.c
138
tgp-chat.c
|
@ -20,45 +20,125 @@
|
|||
|
||||
#include "tgp-chat.h"
|
||||
#include "msglog.h"
|
||||
#include "tgp-utils.h"
|
||||
#include "telegram-base.h"
|
||||
|
||||
void chat_add_all_users (struct tgl_state *TLS, PurpleConversation *pc, struct tgl_chat *chat) {
|
||||
int i;
|
||||
for (i = 0; i < chat->user_list_size; i++) {
|
||||
struct tgl_chat_user *uid = (chat->user_list + i);
|
||||
int flags = (chat->admin_id == uid->user_id ? PURPLE_CBFLAGS_FOUNDER : PURPLE_CBFLAGS_NONE);
|
||||
p2tgl_conv_add_user (TLS, pc, *uid, NULL, flags, FALSE);
|
||||
#include <tgl.h>
|
||||
#include <assert.h>
|
||||
|
||||
void tgp_chat_on_loaded_chat_full (struct tgl_state *TLS, struct tgl_chat *C) {
|
||||
PurpleChat *PC = p2tgl_chat_find (TLS, C->id);
|
||||
if (!PC) {
|
||||
PC = p2tgl_chat_new (TLS, C);
|
||||
purple_blist_add_chat (PC, NULL, NULL);
|
||||
}
|
||||
p2tgl_chat_update (PC, C->id, C->admin_id, C->print_title);
|
||||
}
|
||||
|
||||
void chat_users_update (struct tgl_state *TLS, struct tgl_chat *chat) {
|
||||
PurpleConversation *pc = purple_find_chat(tg_get_conn(TLS), tgl_get_peer_id(chat->id));
|
||||
if (pc) {
|
||||
purple_conv_chat_clear_users (purple_conversation_get_chat_data(pc));
|
||||
chat_add_all_users (TLS, pc, chat);
|
||||
static void tgp_chat_on_loaded_chat_full_joining (struct tgl_state *TLS, void *_,
|
||||
int success, struct tgl_chat *C) {
|
||||
if (! success) {
|
||||
tgp_notify_on_error_gw (TLS, NULL, success);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PurpleConversation *chat_show (PurpleConnection *gc, int id) {
|
||||
connection_data *conn = purple_connection_get_protocol_data(gc);
|
||||
PurpleConversation *convo = purple_find_chat (gc, id);
|
||||
PurpleConvChat *chat = purple_conversation_get_chat_data (convo);
|
||||
tgl_peer_t *P = tgl_peer_get (conn->TLS, TGL_MK_CHAT(id));
|
||||
|
||||
if (! P) {
|
||||
warning ("Chat %d not existing, not showing...", id);
|
||||
return NULL;
|
||||
tgp_chat_on_loaded_chat_full (TLS, C);
|
||||
tgp_chat_show (TLS, C);
|
||||
|
||||
// Check if the users attempts to join an empty chat
|
||||
if (! C->user_list_size) {
|
||||
p2tgl_got_chat_in (TLS, C->id, C->id, "You have already left this chat.",
|
||||
PURPLE_MESSAGE_SYSTEM, time (NULL));
|
||||
}
|
||||
}
|
||||
|
||||
static void tgp_chat_add_all_users (struct tgl_state *TLS, PurpleConversation *pc, struct tgl_chat *C) {
|
||||
int i = 0;
|
||||
for (; i < C->user_list_size; i++) {
|
||||
struct tgl_chat_user *uid = (C->user_list + i);
|
||||
int flags = (C->admin_id == uid->user_id ? PURPLE_CBFLAGS_FOUNDER : PURPLE_CBFLAGS_NONE);
|
||||
p2tgl_conv_add_user (TLS, pc, uid->user_id, NULL, flags, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void tgp_chat_users_update (struct tgl_state *TLS, struct tgl_chat *C) {
|
||||
PurpleConversation *pc = purple_find_chat (tg_get_conn (TLS), tgl_get_peer_id (C->id));
|
||||
if (pc) {
|
||||
purple_conv_chat_clear_users (purple_conversation_get_chat_data (pc));
|
||||
tgp_chat_add_all_users (TLS, pc, C);
|
||||
}
|
||||
}
|
||||
|
||||
PurpleConversation *tgp_chat_show (struct tgl_state *TLS, struct tgl_chat *C) {
|
||||
connection_data *conn = TLS->ev_base;
|
||||
|
||||
PurpleConversation *convo = purple_find_chat (conn->gc, tgl_get_peer_id (C->id));
|
||||
PurpleConvChat *chat = purple_conversation_get_chat_data (convo);
|
||||
|
||||
if (! convo || (chat && purple_conv_chat_has_left (chat))) {
|
||||
convo = p2tgl_got_joined_chat (conn->TLS, &P->chat);
|
||||
chat_users_update (conn->TLS, &P->chat);
|
||||
convo = p2tgl_got_joined_chat (conn->TLS, C);
|
||||
tgp_chat_users_update (conn->TLS, C);
|
||||
}
|
||||
return convo;
|
||||
}
|
||||
|
||||
int chat_is_member (int who, struct tgl_chat *chat) {
|
||||
int i;
|
||||
for (i = 0; i < chat->user_list_size; i++) if ((chat->user_list + i)->user_id == who) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
GList *tgprpl_chat_join_info (PurpleConnection * gc) {
|
||||
struct proto_chat_entry *pce;
|
||||
pce = g_new0 (struct proto_chat_entry, 1);
|
||||
pce->label = "_Subject:";
|
||||
pce->identifier = "subject";
|
||||
pce->required = FALSE;
|
||||
GList *info = g_list_append (NULL, pce);
|
||||
|
||||
pce = g_new0 (struct proto_chat_entry, 1);
|
||||
pce->label = "_Join by Link:";
|
||||
pce->identifier = "link";
|
||||
pce->required = FALSE;
|
||||
return g_list_append (info, pce);
|
||||
}
|
||||
|
||||
void tgprpl_chat_join (PurpleConnection * gc, GHashTable * data) {
|
||||
debug ("tgprpl_chat_join()");
|
||||
connection_data *conn = purple_connection_get_protocol_data (gc);
|
||||
|
||||
// join existing chat by id when the user clicks on a chat in the buddy list
|
||||
void *value = g_hash_table_lookup (data, "id");
|
||||
if (value && atoi (value)) {
|
||||
tgl_peer_id_t cid = TGL_MK_CHAT(atoi (value));
|
||||
tgl_peer_t *P = tgl_peer_get (conn->TLS, cid);
|
||||
if (P) {
|
||||
tgl_do_get_chat_info (conn->TLS, cid, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL);
|
||||
} else {
|
||||
warning ("Cannot join chat %d, peer not found...", tgl_get_peer_id (cid));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// join chat by invite link provided in the chat join window
|
||||
const char *link = g_hash_table_lookup (data, "link");
|
||||
if (str_not_empty (link)) {
|
||||
tgl_do_import_chat_link (conn->TLS, link, (int)strlen (link), tgp_notify_on_error_gw, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// if a chat with this name doesn't exist yet, prompt to create one
|
||||
const char *subject = g_hash_table_lookup (data, "subject");
|
||||
if (str_not_empty (subject)) {
|
||||
tgl_peer_t *P = tgl_peer_get_by_name (conn->TLS, subject);
|
||||
|
||||
// handle joining chats by print_names as used by the Adium plugin
|
||||
if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) {
|
||||
tgl_do_get_chat_info (conn->TLS, P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL);
|
||||
return;
|
||||
} else {
|
||||
warning ("Cannot join chat %s, peer not found...", subject);
|
||||
}
|
||||
|
||||
// user creates a new chat by providing its subject the chat join window
|
||||
request_create_chat (conn->TLS, subject);
|
||||
}
|
||||
}
|
||||
|
||||
char *tgprpl_get_chat_name (GHashTable * data) {
|
||||
return g_strdup (g_hash_table_lookup (data, "subject"));
|
||||
}
|
||||
|
|
10
tgp-chat.h
10
tgp-chat.h
|
@ -26,9 +26,13 @@
|
|||
#include "tgp-2prpl.h"
|
||||
#include <purple.h>
|
||||
|
||||
PurpleConversation *chat_show (PurpleConnection *gc, int id);
|
||||
void chat_users_update (struct tgl_state *TLS, struct tgl_chat *chat);
|
||||
void tgp_chat_on_loaded_chat_full (struct tgl_state *TLS, struct tgl_chat *C);
|
||||
PurpleConversation *tgp_chat_show (struct tgl_state *TLS, struct tgl_chat *C);
|
||||
void tgp_chat_users_update (struct tgl_state *TLS, struct tgl_chat *C);
|
||||
int chat_add_message (struct tgl_state *TLS, struct tgl_message *M, char *text);
|
||||
int chat_is_member (int who, struct tgl_chat *chat);
|
||||
|
||||
char *tgprpl_get_chat_name (GHashTable *data);
|
||||
void tgprpl_chat_join (PurpleConnection *gc, GHashTable *data);
|
||||
GList *tgprpl_chat_join_info (PurpleConnection *gc);
|
||||
|
||||
#endif
|
||||
|
|
108
tgp-msg.c
108
tgp-msg.c
|
@ -43,6 +43,7 @@ static void tgp_msg_err_out (struct tgl_state *TLS, const char *error, tgl_peer_
|
|||
|
||||
static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) {
|
||||
assert (M && M->flags & TGLMF_SERVICE);
|
||||
connection_data *conn = TLS->ev_base;
|
||||
char *txt_user = NULL;
|
||||
char *txt_action = NULL;
|
||||
char *txt = NULL;
|
||||
|
@ -52,6 +53,7 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) {
|
|||
return NULL;
|
||||
}
|
||||
txt_user = p2tgl_strdup_alias (peer);
|
||||
|
||||
switch (M->action.type) {
|
||||
case tgl_message_action_chat_create:
|
||||
txt_action = g_strdup_printf ("created chat %s", M->action.title);
|
||||
|
@ -65,20 +67,65 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) {
|
|||
case tgl_message_action_chat_delete_photo:
|
||||
txt_action = g_strdup ("deleted photo");
|
||||
break;
|
||||
case tgl_message_action_chat_add_user:
|
||||
{
|
||||
case tgl_message_action_chat_add_user_by_link: {
|
||||
tgl_peer_t *actionPeer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user));
|
||||
if (actionPeer) {
|
||||
char *alias = p2tgl_strdup_alias (actionPeer);
|
||||
|
||||
PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id));
|
||||
txt_action = g_strdup_printf ("%s added user %s by link.", alias, txt_user);
|
||||
if (conv) {
|
||||
p2tgl_conv_add_user (TLS, conv, tgl_get_peer_id (peer->id), NULL, 0, FALSE);
|
||||
}
|
||||
|
||||
g_free (alias);
|
||||
g_free (txt_user);
|
||||
return txt_action;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tgl_message_action_chat_add_user: {
|
||||
tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user));
|
||||
if (peer) {
|
||||
char *alias = p2tgl_strdup_alias (peer);
|
||||
txt_action = g_strdup_printf ("added user %s", alias);
|
||||
|
||||
PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id));
|
||||
if (conv) {
|
||||
p2tgl_conv_add_user (TLS, conv, M->action.user, NULL, 0, FALSE);
|
||||
}
|
||||
g_free (alias);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tgl_message_action_chat_delete_user:
|
||||
{
|
||||
case tgl_message_action_chat_delete_user: {
|
||||
tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user));
|
||||
if (peer) {
|
||||
|
||||
tgl_peer_t *chatPeer = tgl_peer_get (TLS, M->to_id);
|
||||
assert (tgl_get_peer_type(chatPeer->id) == TGL_PEER_CHAT);
|
||||
|
||||
// make sure that the chat is showing before deleting the user, otherwise the
|
||||
// chat will be initialised after removing the chat and the chat will still contain
|
||||
// the deleted user
|
||||
PurpleConversation *conv = tgp_chat_show (TLS, &chatPeer->chat);
|
||||
if (conv) {
|
||||
char *alias = p2tgl_strdup_alias (peer);
|
||||
txt_action = g_strdup_printf ("%s deleted user %s.", txt_user, alias);
|
||||
g_free (alias);
|
||||
|
||||
p2tgl_conv_del_user (TLS, conv, txt_action, M->action.user);
|
||||
if (M->action.user == TLS->our_id) {
|
||||
purple_conv_chat_left (purple_conversation_get_chat_data (conv));
|
||||
}
|
||||
|
||||
// conv_del_user already printed a message, prevent a redundant message
|
||||
// from being printed by returning NULL
|
||||
g_free (txt_user);
|
||||
g_free (txt_action);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *alias = p2tgl_strdup_alias (peer);
|
||||
txt_action = g_strdup_printf ("deleted user %s", alias);
|
||||
g_free (alias);
|
||||
|
@ -117,7 +164,6 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) {
|
|||
break;
|
||||
}
|
||||
if (txt_action) {
|
||||
debug ("SERVICE MESSAGE: %s", txt_action);
|
||||
txt = g_strdup_printf ("%s %s.", txt_user, txt_action);
|
||||
g_free (txt_action);
|
||||
}
|
||||
|
@ -454,15 +500,17 @@ static void tgp_msg_display (struct tgl_state *TLS, struct tgp_msg_loading *C) {
|
|||
flags |= PURPLE_MESSAGE_DELAYED;
|
||||
}
|
||||
|
||||
// some service messages (like removing/adding users from chats) might print the message
|
||||
// text through other means and leave the text empty
|
||||
if (! str_not_empty (text)) {
|
||||
warning ("No text to display");
|
||||
return;
|
||||
}
|
||||
|
||||
// display the message to the user
|
||||
switch (tgl_get_peer_type (M->to_id)) {
|
||||
case TGL_PEER_CHAT: {
|
||||
if (chat_show (conn->gc, tgl_get_peer_id (M->to_id))) {
|
||||
tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
|
||||
if (tgp_chat_show (TLS, &P->chat)) {
|
||||
p2tgl_got_chat_in (TLS, M->to_id, M->from_id, text, flags, M->date);
|
||||
}
|
||||
pending_reads_add (conn->pending_reads, M->to_id);
|
||||
|
@ -505,7 +553,7 @@ static void tgp_msg_process_in_ready (struct tgl_state *TLS) {
|
|||
struct tgp_msg_loading *C;
|
||||
|
||||
while ((C = g_queue_peek_head (conn->new_messages))) {
|
||||
if (! C->done) {
|
||||
if (C->pending) {
|
||||
break;
|
||||
}
|
||||
g_queue_pop_head (conn->new_messages);
|
||||
|
@ -518,10 +566,23 @@ static void tgp_msg_process_in_ready (struct tgl_state *TLS) {
|
|||
}
|
||||
|
||||
static void tgp_msg_on_loaded_document (struct tgl_state *TLS, void *extra, int success, const char *filename) {
|
||||
debug ("tgp_msg_on_loaded_document()");
|
||||
assert (success);
|
||||
|
||||
struct tgp_msg_loading *C = extra;
|
||||
C->data = (void *) g_strdup (filename);
|
||||
C->done = TRUE;
|
||||
-- C->pending;
|
||||
tgp_msg_process_in_ready (TLS);
|
||||
}
|
||||
|
||||
static void tgp_msg_on_loaded_chat_full (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *chat) {
|
||||
debug ("tgp_msg_on_loaded_chat()");
|
||||
assert (success);
|
||||
|
||||
tgp_chat_on_loaded_chat_full (TLS, chat);
|
||||
|
||||
struct tgp_msg_loading *C = extra;
|
||||
-- C->pending;
|
||||
tgp_msg_process_in_ready (TLS);
|
||||
}
|
||||
|
||||
|
@ -538,29 +599,31 @@ void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct tgp_msg_loading *C = tgp_msg_loading_init (TRUE, M);
|
||||
struct tgp_msg_loading *C = tgp_msg_loading_init (M);
|
||||
|
||||
if (! (M->flags & TGLMF_SERVICE)) {
|
||||
|
||||
// handle all messages that need to load content before they can be displayed
|
||||
if (M->media.type != tgl_message_media_none) {
|
||||
switch (M->media.type) {
|
||||
case tgl_message_media_photo:
|
||||
C->done = FALSE;
|
||||
++ C->pending;
|
||||
tgl_do_load_photo (TLS, M->media.photo, tgp_msg_on_loaded_document, C);
|
||||
break;
|
||||
|
||||
// documents that are stickers or images will be displayed just like regular photo messages
|
||||
// and need to be lodaed beforehand
|
||||
// documents that are stickers or images will be displayed just like regular photo messages
|
||||
// and need to be lodaed beforehand
|
||||
case tgl_message_media_document:
|
||||
case tgl_message_media_video:
|
||||
case tgl_message_media_audio:
|
||||
if (M->media.document->flags & TGLDF_STICKER || M->media.document->flags & TGLDF_IMAGE) {
|
||||
C->done = FALSE;
|
||||
++ C->pending;
|
||||
tgl_do_load_document (TLS, M->media.document, tgp_msg_on_loaded_document, C);
|
||||
}
|
||||
break;
|
||||
case tgl_message_media_document_encr:
|
||||
if (M->media.encr_document->flags & TGLDF_STICKER || M->media.encr_document->flags & TGLDF_IMAGE) {
|
||||
C->done = FALSE;
|
||||
++ C->pending;
|
||||
tgl_do_load_encr_document (TLS, M->media.encr_document, tgp_msg_on_loaded_document, C);
|
||||
}
|
||||
break;
|
||||
|
@ -569,12 +632,25 @@ void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M) {
|
|||
// TODO: load geo thumbnail
|
||||
break;
|
||||
|
||||
default:
|
||||
default: // prevent Clang warnings ...
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) {
|
||||
|
||||
tgl_peer_t *peer = tgl_peer_get (TLS, M->to_id);
|
||||
assert (peer);
|
||||
|
||||
if (! peer->chat.user_list_size) {
|
||||
// we receive messages even though the user list is empty, this means that we still
|
||||
// haven't fetched the full chat information
|
||||
++ C->pending;
|
||||
tgl_do_get_chat_info (TLS, M->to_id, FALSE, tgp_msg_on_loaded_chat_full, C);
|
||||
}
|
||||
}
|
||||
|
||||
g_queue_push_tail (conn->new_messages, C);
|
||||
tgp_msg_process_in_ready (TLS);
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@ void tgp_msg_loading_free (gpointer data) {
|
|||
free (C);
|
||||
}
|
||||
|
||||
struct tgp_msg_loading *tgp_msg_loading_init (int done, struct tgl_message *M) {
|
||||
struct tgp_msg_loading *tgp_msg_loading_init (struct tgl_message *M) {
|
||||
struct tgp_msg_loading *C = malloc (sizeof (struct tgp_msg_loading));
|
||||
C->done = done;
|
||||
C->pending = 0;
|
||||
C->msg = M;
|
||||
C->data = NULL;
|
||||
return C;
|
||||
|
|
|
@ -62,7 +62,7 @@ struct download_desc {
|
|||
};
|
||||
|
||||
struct tgp_msg_loading {
|
||||
int done;
|
||||
int pending;
|
||||
struct tgl_message *msg;
|
||||
void *data;
|
||||
};
|
||||
|
@ -91,7 +91,7 @@ void used_images_add (connection_data *data, gint imgid);
|
|||
void *connection_data_free (connection_data *conn);
|
||||
connection_data *connection_data_init (struct tgl_state *TLS, PurpleConnection *gc, PurpleAccount *pa);
|
||||
get_user_info_data* get_user_info_data_new (int show_info, tgl_peer_id_t peer);
|
||||
struct tgp_msg_loading *tgp_msg_loading_init (int done, struct tgl_message *M);
|
||||
struct tgp_msg_loading *tgp_msg_loading_init (struct tgl_message *M);
|
||||
struct tgp_msg_sending *tgp_msg_sending_init (struct tgl_state *TLS, char *M, tgl_peer_id_t to);
|
||||
void tgp_msg_loading_free (gpointer data);
|
||||
void tgp_msg_sending_free (gpointer data);
|
||||
|
|
Loading…
Add table
Reference in a new issue