diff --git a/binlog.c b/binlog.c index 30cc8a2..7637430 100644 --- a/binlog.c +++ b/binlog.c @@ -543,6 +543,79 @@ void replay_log_event (void) { rptr ++; seq = *(rptr ++); break; + case CODE_binlog_chat_create: + in_ptr ++; + { + peer_id_t id = MK_CHAT (fetch_int ()); + peer_t *_C = user_chat_get (id); + if (!_C) { + _C = malloc (sizeof (*_C)); + memset (_C, 0, sizeof (*_C)); + _C->id = id; + insert_chat (_C); + } else { + assert (!(_C->flags & FLAG_CREATED)); + } + struct chat *C = &_C->chat; + C->flags = FLAG_CREATED | fetch_int (); + C->title = fetch_str_dup (); + C->print_title = create_print_name (id, C->title, 0, 0, 0); + C->users_num = fetch_int (); + C->date = fetch_int (); + C->version = fetch_int (); + fetch_data (&C->photo_big, sizeof (struct file_location)); + fetch_data (&C->photo_small, sizeof (struct file_location)); + }; + rptr = in_ptr; + break; + case CODE_binlog_chat_change_flags: + rptr ++; + { + peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + assert (C && (C->flags & FLAG_CREATED)); + C->flags |= *(rptr ++); + C->flags &= ~*(rptr ++); + }; + break; + case CODE_binlog_set_chat_title: + in_ptr ++; + { + peer_t *_C = user_chat_get (MK_CHAT (fetch_int ())); + assert (_C && (_C->flags & FLAG_CREATED)); + struct chat *C = &_C->chat; + if (C->title) { free (C->title); } + C->title = fetch_str_dup (); + C->print_title = create_print_name (C->id, C->title, 0, 0, 0); + }; + rptr = in_ptr; + break; + case CODE_binlog_set_chat_photo: + in_ptr ++; + { + peer_t *C = user_chat_get (MK_CHAT (fetch_int ())); + assert (C && (C->flags & FLAG_CREATED)); + fetch_data (&C->photo_big, sizeof (struct file_location)); + fetch_data (&C->photo_small, sizeof (struct file_location)); + }; + rptr = in_ptr; + break; + case CODE_binlog_set_chat_date: + rptr ++; + { + peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + assert (C && (C->flags & FLAG_CREATED)); + C->chat.date = *(rptr ++); + }; + break; + case CODE_binlog_set_chat_version: + rptr ++; + { + peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + assert (C && (C->flags & FLAG_CREATED)); + C->chat.version = *(rptr ++); + C->chat.users_num = *(rptr ++); + }; + break; case CODE_update_user_photo: case CODE_update_user_name: work_update_binlog (); @@ -954,3 +1027,96 @@ void bl_do_set_seq (int seq) { ev[1] = seq; add_log_event (ev, 8); } + +void bl_do_create_chat (struct chat *C, int y, const char *s, int l, int users_num, int date, int version, struct file_location *big, struct file_location *small) { + clear_packet (); + out_int (CODE_binlog_chat_create); + out_int (get_peer_id (C->id)); + out_int (y); + out_cstring (s, l); + out_int (users_num); + out_int (date); + out_int (version); + out_data (big, sizeof (struct file_location)); + out_data (small, sizeof (struct file_location)); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_chat_forbid (struct chat *C, int on) { + if (on) { + if (C->flags & FLAG_FORBIDDEN) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_chat_change_flags; + ev[1] = get_peer_id (C->id); + ev[2] = FLAG_FORBIDDEN; + ev[3] = 0; + add_log_event (ev, 16); + } else { + if (!(C->flags & FLAG_FORBIDDEN)) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_chat_change_flags; + ev[1] = get_peer_id (C->id); + ev[2] = 0; + ev[3] = FLAG_FORBIDDEN; + add_log_event (ev, 16); + } +} + +void bl_do_set_chat_title (struct chat *C, const char *s, int l) { + if (C->title && (int)strlen (C->title) == l && !strncmp (C->title, s, l)) { return; } + clear_packet (); + out_int (CODE_binlog_set_chat_title); + out_int (get_peer_id (C->id)); + out_cstring (s, l); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_chat_photo (struct chat *C, struct file_location *big, struct file_location *small) { + if (!memcmp (&C->photo_small, small, sizeof (struct file_location)) && + !memcmp (&C->photo_big, big, sizeof (struct file_location))) { return; } + clear_packet (); + out_int (CODE_binlog_set_chat_photo); + out_int (get_peer_id (C->id)); + out_data (big, sizeof (struct file_location)); + out_data (small, sizeof (struct file_location)); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_chat_date (struct chat *C, int date) { + if (C->date == date) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_chat_date; + ev[1] = get_peer_id (C->id); + ev[2] = date; + add_log_event (ev, 12); +} + +void bl_do_set_chat_set_in_chat (struct chat *C, int on) { + if (on) { + if (C->flags & FLAG_CHAT_IN_CHAT) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_chat_change_flags; + ev[1] = get_peer_id (C->id); + ev[2] = FLAG_CHAT_IN_CHAT; + ev[3] = 0; + add_log_event (ev, 16); + } else { + if (!(C->flags & FLAG_CHAT_IN_CHAT)) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_chat_change_flags; + ev[1] = get_peer_id (C->id); + ev[2] = 0; + ev[3] = FLAG_CHAT_IN_CHAT; + add_log_event (ev, 16); + } +} + +void bl_do_set_chat_version (struct chat *C, int version, int user_num) { + if (C->version >= version) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_set_chat_version; + ev[1] = get_peer_id (C->id); + ev[2] = version; + ev[3] = user_num; + add_log_event (ev, 16); +} diff --git a/binlog.h b/binlog.h index bf15775..b6e3cf3 100644 --- a/binlog.h +++ b/binlog.h @@ -40,6 +40,13 @@ #define CODE_binlog_set_qts 0x3cf22b79 #define CODE_binlog_set_date 0x33dfe392 #define CODE_binlog_set_seq 0xb9294837 +#define CODE_binlog_chat_create 0xbaa75791 +#define CODE_binlog_chat_change_flags 0x1e494031 +#define CODE_binlog_set_chat_title 0x7dd9bea8 +#define CODE_binlog_set_chat_photo 0xb4ea1fd2 +#define CODE_binlog_set_chat_date 0x78d1114e +#define CODE_binlog_set_chat_version 0xa5d3504f + void *alloc_log_event (int l); void replay_log (void); @@ -78,4 +85,12 @@ void bl_do_set_pts (int pts); void bl_do_set_qts (int qts); void bl_do_set_seq (int seq); void bl_do_set_date (int date); + +void bl_do_create_chat (struct chat *C, int y, const char *s, int l, int users_num, int date, int version, struct file_location *big, struct file_location *small); +void bl_do_chat_forbid (struct chat *C, int on); +void bl_do_set_chat_title (struct chat *C, const char *s, int l); +void bl_do_set_chat_photo (struct chat *C, struct file_location *big, struct file_location *small); +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); #endif diff --git a/interface.c b/interface.c index db23e73..db43a1b 100644 --- a/interface.c +++ b/interface.c @@ -1237,6 +1237,12 @@ void print_service_message (struct message *M) { case CODE_message_action_empty: printf ("\n"); break; + case CODE_message_action_geo_chat_create: + printf ("Created geo chat\n"); + break; + case CODE_message_action_geo_chat_checkin: + printf ("Checkin in geochat\n"); + break; case CODE_message_action_chat_create: printf (" created chat %s. %d users\n", M->action.title, M->action.user_num); break; diff --git a/mtproto-common.c b/mtproto-common.c index ab3614e..07d073c 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -221,7 +221,7 @@ void out_cstring_careful (const char *str, long len) { } -void out_data (const char *data, long len) { +void out_data (const void *data, long len) { assert (len >= 0 && len < (1 << 24) && !(len & 3)); assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); memcpy (packet_ptr, data, len); diff --git a/mtproto-common.h b/mtproto-common.h index 9aec485..d119cec 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -249,7 +249,7 @@ static inline void clear_packet (void) { void out_cstring (const char *str, long len); void out_cstring_careful (const char *str, long len); -void out_data (const char *data, long len); +void out_data (const void *data, long len); static inline void out_string (const char *str) { out_cstring (str, strlen (str)); @@ -394,6 +394,12 @@ static inline void prefetch_data (void *data, int size) { memcpy (data, in_ptr, size); } +static inline void fetch_data (void *data, int size) { + memcpy (data, in_ptr, size); + assert (!(size & 3)); + in_ptr += (size >> 2); +} + static inline long long fetch_long (void) { long long r = *(long long *)in_ptr; in_ptr += 2; diff --git a/structures.c b/structures.c index 4f3d452..4f7f064 100644 --- a/structures.c +++ b/structures.c @@ -414,37 +414,81 @@ void fetch_chat (struct chat *C) { if (x == CODE_chat_empty) { return; } - C->flags |= FLAG_CREATED; - C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); - 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 = create_print_name (C->id, C->title, 0, 0, 0); - if (x == CODE_chat) { - unsigned y = fetch_int (); - if (y == CODE_chat_photo_empty) { - C->photo_small.dc = -2; - C->photo_big.dc = -2; + int new = !(C->flags & FLAG_CREATED); + if (new) { + int y = 0; + if (x == CODE_chat_forbidden) { + y |= FLAG_FORBIDDEN; + } + int l = prefetch_strlen (); + char *s = fetch_str (l); + + struct file_location small; + struct file_location big; + memset (&small, 0, sizeof (small)); + memset (&big, 0, sizeof (big)); + int users_num = -1; + int date = 0; + int version = -1; + + if (x == CODE_chat) { + unsigned y = fetch_int (); + if (y == CODE_chat_photo_empty) { + small.dc = -2; + big.dc = -2; + } else { + assert (y == CODE_chat_photo); + fetch_file_location (&small); + fetch_file_location (&big); + } + users_num = fetch_int (); + date = fetch_int (); + if (fetch_bool ()) { + y |= FLAG_CHAT_IN_CHAT; + } + version = fetch_int (); } else { - assert (y == CODE_chat_photo); - fetch_file_location (&C->photo_small); - fetch_file_location (&C->photo_big); + small.dc = -2; + big.dc = -2; + users_num = -1; + date = fetch_int (); + version = -1; } - C->users_num = fetch_int (); - C->date = fetch_int (); - if (fetch_int () == (int)CODE_bool_true) { - C->flags |= FLAG_CHAT_IN_CHAT; - } - C->version = fetch_int (); + + bl_do_create_chat (C, y, s, l, users_num, date, version, &big, &small); } else { - C->photo_small.dc = -2; - C->photo_big.dc = -2; - C->users_num = -1; - C->date = fetch_int (); - C->version = -1; + if (x == CODE_chat_forbidden) { + bl_do_chat_forbid (C, 1); + } else { + bl_do_chat_forbid (C, 0); + } + int l = prefetch_strlen (); + char *s = fetch_str (l); + bl_do_set_chat_title (C, s, l); + + struct file_location small; + struct file_location big; + memset (&small, 0, sizeof (small)); + memset (&big, 0, sizeof (big)); + + if (x == CODE_chat) { + unsigned y = fetch_int (); + if (y == CODE_chat_photo_empty) { + small.dc = -2; + big.dc = -2; + } else { + assert (y == CODE_chat_photo); + fetch_file_location (&small); + fetch_file_location (&big); + } + bl_do_set_chat_photo (C, &big, &small); + int users_num = fetch_int (); + bl_do_set_chat_date (C, fetch_int ()); + bl_do_set_chat_set_in_chat (C, fetch_bool ()); + bl_do_set_chat_version (C, users_num, fetch_int ()); + } else { + bl_do_set_chat_date (C, fetch_int ()); + } } } @@ -663,6 +707,17 @@ void fetch_message_action (struct message_action *M) { switch (x) { case CODE_message_action_empty: break; + case CODE_message_action_geo_chat_create: + { + int l = prefetch_strlen (); // title + char *s = fetch_str (l); + int l2 = prefetch_strlen (); // checkin + char *s2 = fetch_str (l2); + logprintf ("Message action: Created geochat %.*s in address %.*s\n", l, s, l2, s2); + } + break; + case CODE_message_action_geo_chat_checkin: + break; case CODE_message_action_chat_create: M->title = fetch_str_dup (); assert (fetch_int () == (int)CODE_vector); @@ -1185,6 +1240,12 @@ void insert_user (peer_t *P) { Peers[peer_num ++] = P; } +void insert_chat (peer_t *P) { + chats_allocated ++; + peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); + Peers[peer_num ++] = P; +} + struct user *fetch_alloc_user_full (void) { int data[3]; prefetch_data (data, 12); @@ -1505,18 +1566,16 @@ struct chat *fetch_alloc_chat (void) { int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_CHAT (data[1])); - if (U) { - fetch_chat (&U->chat); - return &U->chat; - } else { + if (!U) { chats_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - fetch_chat (&U->chat); + U->id = MK_CHAT (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[peer_num ++] = U; - return &U->chat; } + fetch_chat (&U->chat); + return &U->chat; } struct chat *fetch_alloc_chat_full (void) { diff --git a/structures.h b/structures.h index 6852ffb..415eea0 100644 --- a/structures.h +++ b/structures.h @@ -351,6 +351,7 @@ void free_photo (struct photo *P); void fetch_photo (struct photo *P); void insert_encrypted_chat (peer_t *P); void insert_user (peer_t *P); +void insert_chat (peer_t *P); void fetch_photo (struct photo *P); void free_photo (struct photo *P);