diff --git a/binlog.c b/binlog.c index 7637430..2860157 100644 --- a/binlog.c +++ b/binlog.c @@ -616,6 +616,93 @@ void replay_log_event (void) { C->chat.users_num = *(rptr ++); }; break; + case CODE_binlog_set_chat_admin: + rptr ++; + { + peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + assert (C && (C->flags & FLAG_CREATED)); + C->chat.admin_id = *(rptr ++); + }; + break; + case CODE_binlog_set_chat_participants: + rptr ++; + { + peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + assert (C && (C->flags & FLAG_CREATED)); + C->chat.user_list_version = *(rptr ++); + C->chat.user_list_size = *(rptr ++); + if (C->chat.user_list) { free (C->chat.user_list); } + C->chat.user_list = malloc (12 * C->chat.user_list_size); + memcpy (C->chat.user_list, rptr, 12 * C->chat.user_list_size); + rptr += 3 * C->chat.user_list_size; + }; + break; + case CODE_binlog_chat_full_photo: + in_ptr ++; + { + peer_id_t id = MK_CHAT (fetch_int ()); + peer_t *U = user_chat_get (id); + assert (U && (U->flags & FLAG_CREATED)); + if (U->flags & FLAG_HAS_PHOTO) { + free_photo (&U->chat.photo); + } + fetch_photo (&U->chat.photo); + } + rptr = in_ptr; + break; + case CODE_binlog_add_chat_participant: + rptr ++; + { + peer_id_t id = MK_CHAT (*(rptr ++)); + peer_t *_C = user_chat_get (id); + assert (_C && (_C->flags & FLAG_CREATED)); + struct chat *C = &_C->chat; + + int version = *(rptr ++); + int user = *(rptr ++); + int inviter = *(rptr ++); + int date = *(rptr ++); + assert (C->user_list_version < version); + + int i; + for (i = 0; i < C->user_list_size; i++) { + assert (C->user_list[i].user_id != user); + } + C->user_list_size ++; + C->user_list = realloc (C->user_list, 12 * C->user_list_size); + C->user_list[C->user_list_size - 1].user_id = user; + C->user_list[C->user_list_size - 1].inviter_id = inviter; + C->user_list[C->user_list_size - 1].date = date; + C->user_list_version = version; + } + break; + case CODE_binlog_del_chat_participant: + rptr ++; + { + peer_id_t id = MK_CHAT (*(rptr ++)); + peer_t *_C = user_chat_get (id); + assert (_C && (_C->flags & FLAG_CREATED)); + struct chat *C = &_C->chat; + + int version = *(rptr ++); + int user = *(rptr ++); + assert (C->user_list_version < version); + + int i; + for (i = 0; i < C->user_list_size; i++) { + if (C->user_list[i].user_id == user) { + struct chat_user t; + t = C->user_list[i]; + C->user_list[i] = C->user_list[C->user_list_size - 1]; + C->user_list[C->user_list_size - 1] = t; + } + } + assert (C->user_list[C->user_list_size - 1].user_id == user); + C->user_list_size --; + C->user_list = realloc (C->user_list, 12 * C->user_list_size); + C->user_list_version = version; + } + break; case CODE_update_user_photo: case CODE_update_user_name: work_update_binlog (); @@ -1120,3 +1207,54 @@ void bl_do_set_chat_version (struct chat *C, int version, int user_num) { ev[3] = user_num; add_log_event (ev, 16); } + +void bl_do_set_chat_admin (struct chat *C, int admin) { + if (C->admin_id == admin) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_chat_admin; + ev[1] = get_peer_id (C->id); + ev[2] = admin; + add_log_event (ev, 12); +} + +void bl_do_set_chat_participants (struct chat *C, int version, int user_num, struct chat_user *users) { + if (C->user_list_version >= version) { return; } + int *ev = alloc_log_event (12 * user_num + 16); + ev[0] = CODE_binlog_set_chat_participants; + ev[1] = get_peer_id (C->id); + ev[2] = version; + ev[3] = user_num; + memcpy (ev + 4, users, 12 * user_num); + add_log_event (ev, 12 * user_num + 16); +} + +void bl_do_set_chat_full_photo (struct chat *U, const int *start, int len) { + if (U->photo.id == *(long long *)(start + 1)) { return; } + int *ev = alloc_log_event (len + 8); + ev[0] = CODE_binlog_chat_full_photo; + ev[1] = get_peer_id (U->id); + memcpy (ev + 2, start, len); + add_log_event (ev, len + 8); +} + +void bl_do_chat_add_user (struct chat *C, int version, int user, int inviter, int date) { + if (C->user_list_version >= version || !C->user_list_version) { return; } + int *ev = alloc_log_event (24); + ev[0] = CODE_binlog_add_chat_participant; + ev[1] = get_peer_id (C->id); + ev[2] = version; + ev[3] = user; + ev[4] = inviter; + ev[5] = date; + add_log_event (ev, 24); +} + +void bl_do_chat_del_user (struct chat *C, int version, int user) { + if (C->user_list_version >= version || !C->user_list_version) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_add_chat_participant; + ev[1] = get_peer_id (C->id); + ev[2] = version; + ev[3] = user; + add_log_event (ev, 16); +} diff --git a/binlog.h b/binlog.h index b6e3cf3..02c7af5 100644 --- a/binlog.h +++ b/binlog.h @@ -46,7 +46,11 @@ #define CODE_binlog_set_chat_photo 0xb4ea1fd2 #define CODE_binlog_set_chat_date 0x78d1114e #define CODE_binlog_set_chat_version 0xa5d3504f - +#define CODE_binlog_set_chat_admin 0x1e7cea04 +#define CODE_binlog_set_chat_participants 0x3a29d335 +#define CODE_binlog_chat_full_photo 0x6cca6629 +#define CODE_binlog_add_chat_participant 0x63345108 +#define CODE_binlog_del_chat_participant 0x82d1f0ee void *alloc_log_event (int l); void replay_log (void); @@ -93,4 +97,9 @@ void bl_do_set_chat_photo (struct chat *C, struct file_location *big, struct fil void bl_do_set_chat_date (struct chat *C, int date); void bl_do_set_chat_set_in_chat (struct chat *C, int on); void bl_do_set_chat_version (struct chat *C, int version, int user_num); +void bl_do_set_chat_admin (struct chat *C, int admin); +void bl_do_set_chat_participants (struct chat *C, int version, int user_num, struct chat_user *users); +void bl_do_set_chat_full_photo (struct chat *U, const int *start, int len); +void bl_do_chat_add_user (struct chat *C, int version, int user, int inviter, int date); +void bl_do_chat_del_user (struct chat *C, int version, int user); #endif diff --git a/mtproto-client.c b/mtproto-client.c index fb7a40f..8e29dbb 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -701,7 +701,7 @@ void fetch_seq (void) { int x = fetch_int (); if (x > seq + 1) { logprintf ("Hole in seq: seq = %d, x = %d\n", seq, x); - //do_get_difference (); + do_get_difference (); //seq = x; } else if (x == seq + 1) { seq = x; @@ -879,19 +879,18 @@ void work_update (struct connection *c UU, long long msg_id UU) { { peer_id_t user_id = MK_USER (fetch_int ()); peer_t *UC = user_chat_get (user_id); - if (UC) { + if (UC && (UC->flags & FLAG_CREATED)) { + int l1 = prefetch_strlen (); + char *f = fetch_str (l1); + int l2 = prefetch_strlen (); + char *l = fetch_str (l2); struct user *U = &UC->user; + bl_do_set_user_name (U, f, l1, l, l2); print_start (); push_color (COLOR_YELLOW); print_date (time (0)); printf (" User "); print_user_name (user_id, UC); - if (U->first_name) { free (U->first_name); } - if (U->last_name) { free (U->last_name); } - if (U->print_name) { free (U->print_name); } - U->first_name = fetch_str_dup (); - U->last_name = fetch_str_dup (); - U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); printf (" changed name to "); print_user_name (user_id, UC); printf ("\n"); @@ -911,8 +910,25 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_id_t user_id = MK_USER (fetch_int ()); peer_t *UC = user_chat_get (user_id); fetch_date (); - if (UC) { + if (UC && (UC->flags & FLAG_CREATED)) { struct user *U = &UC->user; + unsigned y = fetch_int (); + long long photo_id; + struct file_location big; + struct file_location small; + memset (&big, 0, sizeof (big)); + memset (&small, 0, sizeof (small)); + if (y == CODE_user_profile_photo_empty) { + photo_id = 0; + big.dc = -2; + small.dc = -2; + } else { + assert (y == CODE_user_profile_photo); + photo_id = fetch_long (); + fetch_file_location (&small); + fetch_file_location (&big); + } + bl_do_set_user_profile_photo (U, photo_id, &big, &small); print_start (); push_color (COLOR_YELLOW); @@ -922,17 +938,6 @@ void work_update (struct connection *c UU, long long msg_id UU) { printf (" updated profile photo\n"); pop_color (); print_end (); - unsigned y = fetch_int (); - if (y == CODE_user_profile_photo_empty) { - U->photo_id = 0; - U->photo_big.dc = -2; - U->photo_small.dc = -2; - } else { - assert (y == CODE_user_profile_photo); - U->photo_id = fetch_long (); - fetch_file_location (&U->photo_small); - fetch_file_location (&U->photo_big); - } } else { struct file_location t; unsigned y = fetch_int (); @@ -981,14 +986,32 @@ void work_update (struct connection *c UU, long long msg_id UU) { assert (x == CODE_chat_participants || x == CODE_chat_participants_forbidden); peer_id_t chat_id = MK_CHAT (fetch_int ()); int n = 0; - if (x == CODE_chat_participants) { - fetch_int (); // admin_id - assert (fetch_int () == CODE_vector); - int n = fetch_int (); - fetch_skip (n * 4); - fetch_int (); // version - } peer_t *C = user_chat_get (chat_id); + if (C && (C->flags & FLAG_CREATED)) { + if (x == CODE_chat_participants) { + bl_do_set_chat_admin (&C->chat, fetch_int ()); + assert (fetch_int () == CODE_vector); + n = fetch_int (); + struct chat_user *users = malloc (12 * n); + int i; + for (i = 0; i < n; i++) { + assert (fetch_int () == (int)CODE_chat_participant); + users[i].user_id = fetch_int (); + users[i].inviter_id = fetch_int (); + users[i].date = fetch_int (); + } + int version = fetch_int (); + bl_do_set_chat_participants (&C->chat, version, n, users); + } + } else { + if (x == CODE_chat_participants) { + fetch_int (); // admin_id + assert (fetch_int () == CODE_vector); + n = fetch_int (); + fetch_skip (n * 4); + fetch_int (); // version + } + } print_start (); push_color (COLOR_YELLOW); print_date (time (0)); @@ -1187,7 +1210,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_id_t chat_id = MK_CHAT (fetch_int ()); peer_id_t user_id = MK_USER (fetch_int ()); peer_id_t inviter_id = MK_USER (fetch_int ()); - fetch_int (); // version + int version = fetch_int (); + + peer_t *C = user_chat_get (chat_id); + if (C && (C->flags & FLAG_CREATED)) { + bl_do_chat_add_user (&C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); + } print_start (); push_color (COLOR_YELLOW); @@ -1207,7 +1235,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { { peer_id_t chat_id = MK_CHAT (fetch_int ()); peer_id_t user_id = MK_USER (fetch_int ()); - fetch_int (); // version + int version = fetch_int (); + + peer_t *C = user_chat_get (chat_id); + if (C && (C->flags & FLAG_CREATED)) { + bl_do_chat_del_user (&C->chat, version, get_peer_id (user_id)); + } print_start (); push_color (COLOR_YELLOW); diff --git a/queries.c b/queries.c index 5c72769..695cb25 100644 --- a/queries.c +++ b/queries.c @@ -1618,14 +1618,14 @@ int chat_info_on_answer (struct query *q UU) { print_chat_name (U->id, U); printf (" members:\n"); int i; - for (i = 0; i < C->users_num; i++) { + for (i = 0; i < C->user_list_size; i++) { printf ("\t\t"); - print_user_name (MK_USER (C->users[i].user_id), user_chat_get (MK_USER (C->users[i].user_id))); + print_user_name (MK_USER (C->user_list[i].user_id), user_chat_get (MK_USER (C->user_list[i].user_id))); printf (" invited by "); - print_user_name (MK_USER (C->users[i].inviter_id), user_chat_get (MK_USER (C->users[i].inviter_id))); + print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (MK_USER (C->user_list[i].inviter_id))); printf (" at "); - print_date_full (C->users[i].date); - if (C->users[i].user_id == C->admin_id) { + print_date_full (C->user_list[i].date); + if (C->user_list[i].user_id == C->admin_id) { printf (" admin"); } printf ("\n"); @@ -2424,8 +2424,8 @@ int get_difference_on_answer (struct query *q UU) { get_difference_active = 0; unsigned x = fetch_int (); if (x == CODE_updates_difference_empty) { - fetch_date (); - fetch_seq (); + bl_do_set_date (fetch_int ()); + bl_do_set_seq (fetch_int ()); difference_got = 1; } else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) { int n, i; diff --git a/structures.c b/structures.c index 4f7f064..a3cba31 100644 --- a/structures.c +++ b/structures.c @@ -34,14 +34,33 @@ #define sha1 SHA1 +static int id_cmp (struct message *M1, struct message *M2); +#define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) +DEFINE_TREE(peer,peer_t *,peer_cmp,0) +DEFINE_TREE(message,struct message *,id_cmp,0) + + +struct message message_list = { + .next_use = &message_list, + .prev_use = &message_list +}; + +struct tree_peer *peer_tree; +struct tree_message *message_tree; + +int users_allocated; +int chats_allocated; +int messages_allocated; + +int our_id; int verbosity; peer_t *Peers[MAX_USER_NUM]; - int peer_num; int encr_chats_allocated; int geo_chats_allocated; - extern int binlog_enabled; + + void fetch_skip_photo (void); #define code_assert(x) if (!(x)) { logprintf ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } @@ -98,8 +117,6 @@ int fetch_user_status (struct user_status *S) { return 0; } -int our_id; - char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) { const char *d[4]; d[0] = a1; d[1] = a2; d[2] = a3; d[3] = a4; @@ -516,35 +533,32 @@ void fetch_chat_full (struct chat *C) { assert (x == CODE_messages_chat_full); assert (fetch_int () == CODE_chat_full); C->id = MK_CHAT (fetch_int ()); - C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); - C->flags |= FLAG_CREATED; + //C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); + //C->flags |= FLAG_CREATED; x = fetch_int (); + int version = 0; + struct chat_user *users = 0; + int users_num = 0; + int admin_id = 0; + if (x == CODE_chat_participants) { assert (fetch_int () == get_peer_id (C->id)); - C->admin_id = fetch_int (); + admin_id = fetch_int (); assert (fetch_int () == CODE_vector); - if (C->users) { - free (C->users); - } - C->users_num = fetch_int (); - C->users = malloc (sizeof (struct chat_user) * C->users_num); + users_num = fetch_int (); + users = malloc (sizeof (struct chat_user) * users_num); int i; for (i = 0; i < C->users_num; i++) { assert (fetch_int () == (int)CODE_chat_participant); - C->users[i].user_id = fetch_int (); - C->users[i].inviter_id = fetch_int (); - C->users[i].date = fetch_int (); + users[i].user_id = fetch_int (); + users[i].inviter_id = fetch_int (); + users[i].date = fetch_int (); } - C->version = fetch_int (); - } else { - C->flags |= FLAG_FORBIDDEN; - assert (x == CODE_chat_participants_forbidden); + version = fetch_int (); } - if (C->flags & FLAG_HAS_PHOTO) { - free_photo (&C->photo); - } - fetch_photo (&C->photo); - C->flags |= FLAG_HAS_PHOTO; + int *start = in_ptr; + fetch_skip_photo (); + int *end = in_ptr; fetch_notify_settings (); int n, i; @@ -558,6 +572,14 @@ void fetch_chat_full (struct chat *C) { for (i = 0; i < n; i++) { fetch_alloc_user (); } + if (admin_id) { + bl_do_set_chat_admin (C, admin_id); + } + if (version > 0) { + bl_do_set_chat_participants (C, version, users_num, users); + free (users); + } + bl_do_set_chat_full_photo (C, start, 4 * (end - start)); } void fetch_photo_size (struct photo_size *S) { @@ -1019,8 +1041,8 @@ void fetch_geo_message (struct message *M) { } } -int *decr_ptr; -int *decr_end; +static int *decr_ptr; +static int *decr_end; int decrypt_encrypted_message (struct secret_chat *E) { int *msg_key = decr_ptr; @@ -1180,22 +1202,6 @@ static int id_cmp (struct message *M1, struct message *M2) { else { return 0; } } -#define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) - -DEFINE_TREE(peer,peer_t *,peer_cmp,0) -DEFINE_TREE(message,struct message *,id_cmp,0) -struct tree_peer *peer_tree; -struct tree_message *message_tree; - -int users_allocated; -int chats_allocated; -int messages_allocated; - -struct message message_list = { - .next_use = &message_list, - .prev_use = &message_list -}; - struct user *fetch_alloc_user (void) { int data[2]; prefetch_data (data, 8); diff --git a/structures.h b/structures.h index 415eea0..dc33ee2 100644 --- a/structures.h +++ b/structures.h @@ -172,7 +172,9 @@ struct chat { struct photo photo; char *title; int users_num; - struct chat_user *users; + int user_list_size; + int user_list_version; + struct chat_user *user_list; int date; int version; int admin_id;