diff --git a/mtproto-common.h b/mtproto-common.h index 0c1012f..dc61b3d 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -334,6 +334,10 @@ static inline int prefetch_int (void) { return *(in_ptr); } +static inline void prefetch_data (void *data, int size) { + memcpy (data, in_ptr, size); +} + static inline long long fetch_long (void) { long long r = *(long long *)in_ptr; in_ptr += 2; diff --git a/queries.c b/queries.c index f044fe1..15a137d 100644 --- a/queries.c +++ b/queries.c @@ -103,8 +103,8 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth void query_ack (long long id) { struct query *q = query_get (id); if (q && !(q->flags & QUERY_ACK_RECEIVED)) { - remove_event_timer (&q->ev); q->flags |= QUERY_ACK_RECEIVED; + remove_event_timer (&q->ev); } } @@ -863,37 +863,22 @@ void do_send_photo (int type, int to_id, char *file_name) { } int chat_info_on_answer (struct query *q UU) { - assert (fetch_int () == (int)CODE_messages_chat_full); - - assert (fetch_int () == (int)CODE_chat_full); - int id = fetch_int (); // id - - assert (fetch_int () == (int)CODE_chat_participants); - assert (id == fetch_int ()); // id - - int admin_id = fetch_int (); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); - assert (n <= 100); - int i; - static int a[300]; - for (i = 0; i < n; i ++) { - assert (fetch_int () == (int)CODE_chat_participant); - a[3 * i + 0] = fetch_int (); - a[3 * i + 1] = fetch_int (); - a[3 * i + 2] = fetch_int (); - } - fetch_int (); // version - + struct chat *C = fetch_alloc_chat_full (); + union user_chat *U = (void *)C; print_start (); push_color (COLOR_YELLOW); printf ("Chat "); - print_chat_name (-id, user_chat_get (-id)); + print_chat_name (U->id, U); printf (" members:\n"); - for (i = 0; i < n; i++) { + int i; + for (i = 0; i < C->users_num; i++) { printf ("\t\t"); - print_user_name (a[3 * i], user_chat_get (a[3 * i])); - if (a[3 * i] == admin_id) { + print_user_name (C->users[i].user_id, user_chat_get (C->users[i].user_id)); + printf (" invited by "); + print_user_name (C->users[i].inviter_id, user_chat_get (C->users[i].inviter_id)); + printf (" at "); + print_date_full (C->users[i].date); + if (C->users[i].user_id == C->admin_id) { printf (" admin"); } printf ("\n"); diff --git a/structures.c b/structures.c index 74ead3f..fb9bbca 100644 --- a/structures.c +++ b/structures.c @@ -61,12 +61,12 @@ void fetch_user_status (struct user_status *S) { int our_id; void fetch_user (struct user *U) { - memset (U, 0, sizeof (*U)); unsigned x = fetch_int (); assert (x == CODE_user_empty || x == CODE_user_self || x == CODE_user_contact || x == CODE_user_request || x == CODE_user_foreign || x == CODE_user_deleted); U->id = fetch_int (); + U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT); if (x == CODE_user_empty) { - U->flags = FLAG_EMPTY; + U->flags |= FLAG_EMPTY; return; } if (x == CODE_user_self) { @@ -76,6 +76,9 @@ void fetch_user (struct user *U) { write_auth_file (); } } + 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 (); if (!strlen (U->first_name)) { @@ -98,17 +101,18 @@ void fetch_user (struct user *U) { s++; } if (x == CODE_user_deleted) { - U->flags = FLAG_DELETED; + U->flags |= FLAG_DELETED; return; } if (x == CODE_user_self) { - U->flags = FLAG_USER_SELF; + U->flags |= FLAG_USER_SELF; } else { U->access_hash = fetch_long (); } if (x == CODE_user_foreign) { U->flags |= FLAG_USER_FOREIGN; } else { + if (U->phone) { free (U->phone); } U->phone = fetch_str_dup (); } unsigned y = fetch_int (); @@ -130,17 +134,19 @@ void fetch_user (struct user *U) { } void fetch_chat (struct chat *C) { - memset (C, 0, sizeof (*C)); unsigned x = fetch_int (); assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); C->id = -fetch_int (); + C->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); if (x == CODE_chat_empty) { - C->flags = FLAG_EMPTY; + C->flags |= FLAG_EMPTY; return; } if (x == CODE_chat_forbidden) { C->flags |= FLAG_FORBIDDEN; } + if (C->title) { free (C->title); } + if (C->print_title) { free (C->print_title); } C->title = fetch_str_dup (); C->print_title = strdup (C->title); char *s = C->print_title; @@ -158,7 +164,7 @@ void fetch_chat (struct chat *C) { fetch_file_location (&C->photo_small); fetch_file_location (&C->photo_big); } - C->user_num = fetch_int (); + C->users_num = fetch_int (); C->date = fetch_int (); if (fetch_int () == (int)CODE_bool_true) { C->flags |= FLAG_CHAT_IN_CHAT; @@ -167,12 +173,72 @@ void fetch_chat (struct chat *C) { } else { C->photo_small.dc = -2; C->photo_big.dc = -2; - C->user_num = -1; + C->users_num = -1; C->date = fetch_int (); C->version = -1; } } +void fetch_notify_settings (void) { + unsigned x = fetch_int (); + assert (x == CODE_peer_notify_settings || x == CODE_peer_notify_settings_empty); + if (x == CODE_peer_notify_settings) { + fetch_int (); // mute_until + int l = prefetch_strlen (); + fetch_str (l); + fetch_bool (); // show_previews + fetch_int (); // peer notify events + } +} + +void fetch_chat_full (struct chat *C) { + unsigned x = fetch_int (); + assert (x == CODE_messages_chat_full); + assert (fetch_int () == CODE_chat_full); + C->id = -fetch_int (); + C->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); + x = fetch_int (); + if (x == CODE_chat_participants) { + assert (fetch_int () == -C->id); + C->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); + 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 (); + } + C->version = fetch_int (); + } else { + C->flags |= FLAG_FORBIDDEN; + assert (x == CODE_chat_participants_forbidden); + } + if (C->flags & FLAG_HAS_PHOTO) { + free_photo (&C->photo); + } + fetch_photo (&C->photo); + C->flags |= FLAG_HAS_PHOTO; + fetch_notify_settings (); + + int n, i; + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_chat (); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_user (); + } +} + void fetch_photo_size (struct photo_size *S) { memset (S, 0, sizeof (*S)); unsigned x = fetch_int (); @@ -205,6 +271,7 @@ void fetch_geo (struct geo *G) { void fetch_photo (struct photo *P) { memset (P, 0, sizeof (*P)); unsigned x = fetch_int (); + assert (x == CODE_photo_empty || x == CODE_photo); P->id = fetch_long (); if (x == CODE_photo_empty) { return; } P->access_hash = fetch_long (); @@ -384,17 +451,17 @@ struct message message_list = { }; struct user *fetch_alloc_user (void) { - union user_chat *U = malloc (sizeof (*U)); - fetch_user (&U->user); - users_allocated ++; - union user_chat *U1 = tree_lookup_peer (peer_tree, U); - if (U1) { - free_user (&U1->user); - memcpy (U1, U, sizeof (*U)); - free (U); - users_allocated --; - return &U1->user; + int data[2]; + prefetch_data (data, 8); + union user_chat *U = user_chat_get (data[1]); + if (U) { + fetch_user (&U->user); + return &U->user; } else { + users_allocated ++; + U = malloc (sizeof (*U)); + memset (U, 0, sizeof (*U)); + fetch_user (&U->user); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[chat_num + (user_num ++)] = U; return &U->user; @@ -568,23 +635,42 @@ struct message *fetch_alloc_message_short_chat (void) { } struct chat *fetch_alloc_chat (void) { - union user_chat *U = malloc (sizeof (*U)); - fetch_chat (&U->chat); - chats_allocated ++; - union user_chat *U1 = tree_lookup_peer (peer_tree, U); - if (U1) { - free_chat (&U1->chat); - *U1 = *U; - free (U); - chats_allocated --; - return &U1->chat; + int data[2]; + prefetch_data (data, 8); + union user_chat *U = user_chat_get (-data[1]); + if (U) { + fetch_chat (&U->chat); + return &U->chat; } else { + chats_allocated ++; + U = malloc (sizeof (*U)); + memset (U, 0, sizeof (*U)); + fetch_chat (&U->chat); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[(chat_num ++) + user_num] = U; return &U->chat; } } +struct chat *fetch_alloc_chat_full (void) { + int data[3]; + prefetch_data (data, 12); + union user_chat *U = user_chat_get (-data[2]); + if (U) { + fetch_chat_full (&U->chat); + return &U->chat; + } else { + chats_allocated ++; + U = malloc (sizeof (*U)); + memset (U, 0, sizeof (*U)); + U->id = -data[2]; + peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + fetch_chat_full (&U->chat); + Peers[(chat_num ++) + user_num] = U; + return &U->chat; + } +} + void free_chat (struct chat *U) { if (U->title) { free (U->title); } if (U->print_title) { free (U->print_title); } diff --git a/structures.h b/structures.h index c700a6a..6178c75 100644 --- a/structures.h +++ b/structures.h @@ -22,7 +22,7 @@ #define FLAG_EMPTY 1 #define FLAG_DELETED 2 #define FLAG_FORBIDDEN 4 - +#define FLAG_HAS_PHOTO 8 #define FLAG_USER_SELF 128 #define FLAG_USER_FOREIGN 256 @@ -37,49 +37,6 @@ struct file_location { long long secret; }; -struct user_status { - int online; - int when; -}; - -struct user { - int id; - int flags; - char *print_name; - struct file_location photo_big; - struct file_location photo_small; - char *first_name; - char *last_name; - char *phone; - long long access_hash; - struct user_status status; -}; - -struct chat { - int id; - int flags; - char *print_title; - struct file_location photo_big; - struct file_location photo_small; - char *title; - int user_num; - int date; - int version; - int admin_id; -}; - -union user_chat { - struct { - int id; - int flags; - char *print_name; - struct file_location photo_big; - struct file_location photo_small; - }; - struct user user; - struct chat chat; -}; - struct photo_size { char *type; struct file_location loc; @@ -105,6 +62,59 @@ struct photo { struct photo_size *sizes; }; +struct user_status { + int online; + int when; +}; + +struct user { + int id; + int flags; + char *print_name; + struct file_location photo_big; + struct file_location photo_small; + struct photo photo; + char *first_name; + char *last_name; + char *phone; + long long access_hash; + struct user_status status; +}; + +struct chat_user { + int user_id; + int inviter_id; + int date; +}; + +struct chat { + int id; + int flags; + char *print_title; + struct file_location photo_big; + struct file_location photo_small; + struct photo photo; + char *title; + int users_num; + struct chat_user *users; + int date; + int version; + int admin_id; +}; + +union user_chat { + struct { + int id; + int flags; + char *print_name; + struct file_location photo_big; + struct file_location photo_small; + struct photo photo; + }; + struct user user; + struct chat chat; +}; + struct video { long long id; long long access_hash; @@ -179,6 +189,7 @@ struct chat *fetch_alloc_chat (void); struct message *fetch_alloc_message (void); struct message *fetch_alloc_message_short (void); struct message *fetch_alloc_message_short_chat (void); +struct chat *fetch_alloc_chat_full (void); int fetch_peer_id (void); void free_user (struct user *U); @@ -189,4 +200,6 @@ union user_chat *user_chat_get (int id); struct message *message_get (int id); void update_message_id (struct message *M, int id); void message_insert (struct message *M); +void free_photo (struct photo *P); +void fetch_photo (struct photo *P); #endif