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:
mjentsch 2015-09-06 17:33:30 +02:00
parent 592b31e8c8
commit 888cffffc1
11 changed files with 279 additions and 209 deletions

View file

@ -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];

View file

@ -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);

View file

@ -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) {

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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"));
}

View file

@ -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
View file

@ -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);
}

View file

@ -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;

View file

@ -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);