diff --git a/gen_constants_h.awk b/gen_constants_h.awk new file mode 100644 index 0000000..5088914 --- /dev/null +++ b/gen_constants_h.awk @@ -0,0 +1,19 @@ +BEGIN { + print "#ifndef CONSTANTS_H"; + print "#define CONSTANTS_H"; +} +// { + if (split ($1, a, "#") == 2) { + gsub (/[A-Z]/, "_&", a[1]); + gsub (/[.]/, "_", a[1]); + if (a[2] in h) { + print "ERROR: Duplicate magic " a[2] " for define " a[1] " and " h[a[2]] >"/dev/stderr/" + exit 1; + } + h[a[2]] = a[1]; + print "#define", "CODE_" tolower(a[1]), "0x" a[2]; + } +} +END { + print "#endif"; +} diff --git a/interface.c b/interface.c index 9ad1643..e20f90f 100644 --- a/interface.c +++ b/interface.c @@ -104,14 +104,28 @@ int get_complete_mode (void) { } extern int user_num; -extern struct user *Users[]; +extern int chat_num; +extern union user_chat *Peers[]; int complete_user_list (int index, const char *text, int len, char **R) { index ++; - while (index < user_num && (!Users[index]->print_name || strncmp (Users[index]->print_name, text, len))) { + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id < 0)) { index ++; } - if (index < user_num) { - *R = strdup (Users[index]->print_name); + if (index < user_num + chat_num) { + *R = strdup (Peers[index]->print_name); + return index; + } else { + return -1; + } +} + +int complete_user_chat_list (int index, const char *text, int len, char **R) { + index ++; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num) { + *R = strdup (Peers[index]->print_name); return index; } else { return -1; @@ -161,7 +175,7 @@ char *command_generator (const char *text, int state) { index = complete_user_list (index, text, len, &R); return R; case 2: - index = complete_string_list (chat_list, index, text, len, &R); + index = complete_user_chat_list (index, text, len, &R); return R; case 3: return rl_filename_completion_function(text,state); diff --git a/mtproto-common.h b/mtproto-common.h index 6c7f156..b0357c6 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -270,7 +270,10 @@ static inline char *fetch_str (int len) { static inline char *fetch_str_dup (void) { int l = prefetch_strlen (); - return strndup (fetch_str (l), l); + char *s = malloc (l + 1); + memcpy (s, fetch_str (l), l); + s[l] = 0; + return s; } static __inline__ unsigned long long rdtsc(void) { @@ -299,6 +302,17 @@ static inline long long fetch_long (void) { return r; } +static inline double fetch_double (void) { + double r = *(double *)in_ptr; + in_ptr += 2; + return r; +} + +static inline void fetch_ints (void *data, int count) { + memcpy (data, in_ptr, 4 * count); + in_ptr += count; +} + int get_random_bytes (void *buf, int n); int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E); diff --git a/structures.c b/structures.c index 0bed6f8..87d81fa 100644 --- a/structures.c +++ b/structures.c @@ -105,7 +105,7 @@ 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->id = -fetch_int (); if (x == CODE_chat_empty) { C->flags = 1; return; @@ -130,34 +130,200 @@ void fetch_chat (struct chat *C) { fetch_file_location (&C->photo_small); fetch_file_location (&C->photo_big); } + C->user_num = fetch_int (); + C->date = fetch_int (); + if (fetch_int () == (int)CODE_bool_true) { + C->flags |= 16; + } + C->version = fetch_int (); + } else { + C->photo_small.dc = -2; + C->photo_big.dc = -2; + C->user_num = -1; + C->date = fetch_int (); + C->version = -1; + } +} + +void fetch_photo_size (struct photo_size *S) { + unsigned x = fetch_int (); + assert (x == CODE_photo_size || x == CODE_photo_cached_size); + S->type = fetch_str_dup (); + fetch_file_location (&S->loc); + S->w = fetch_int (); + S->h = fetch_int (); + if (x == CODE_photo_size) { + S->size = fetch_int (); + } else { + S->data = fetch_str_dup (); + } +} + +void fetch_geo (struct geo *G) { + assert (fetch_int () == CODE_geo_point); + G->longitude = fetch_double (); + G->latitude = fetch_double (); +} + +void fetch_photo (struct photo *P) { + memset (P, 0, sizeof (*P)); + unsigned x = fetch_int (); + P->id = fetch_long (); + if (x == CODE_photo_empty) { return; } + P->access_hash = fetch_long (); + P->user_id = fetch_int (); + P->date = fetch_int (); + P->caption = fetch_str_dup (); + fetch_geo (&P->geo); + assert (fetch_int () == CODE_vector); + P->sizes_num = fetch_int (); + P->sizes = malloc (sizeof (struct photo_size) * P->sizes_num); + int i; + for (i = 0; i < P->sizes_num; i++) { + fetch_photo_size (&P->sizes[i]); + } +} + +void fetch_video (struct video *V) { + memset (V, 0, sizeof (*V)); + unsigned x = fetch_int (); + V->id = fetch_long (); + if (x == CODE_video_empty) { return; } + V->access_hash = fetch_long (); + V->user_id = fetch_int (); + V->date = fetch_int (); + V->caption = fetch_str_dup (); + V->duration = fetch_int (); + V->size = fetch_int (); + fetch_photo_size (&V->thumb); + V->dc_id = fetch_int (); + V->w = fetch_int (); + V->h = fetch_int (); +} + +void fetch_message_action (struct message_action *M) { + memset (M, 0, sizeof (*M)); + unsigned x = fetch_int (); + M->type = x; + switch (x) { + case CODE_message_action_empty: + break; + case CODE_message_action_chat_create: + M->title = fetch_str_dup (); + assert (fetch_int () == (int)CODE_vector); + M->user_num = fetch_int (); + M->users = malloc (M->user_num * 4); + fetch_ints (M->users, M->user_num); + break; + case CODE_message_action_chat_edit_title: + M->new_title = fetch_str_dup (); + break; + case CODE_message_action_chat_edit_photo: + fetch_photo (&M->photo); + break; + case CODE_message_action_chat_delete_photo: + break; + case CODE_message_action_chat_add_user: + M->user = fetch_int (); + break; + case CODE_message_action_chat_delete_user: + M->user = fetch_int (); + break; + default: + assert (0); + } +} + +void fetch_message_media (struct message_media *M) { + memset (M, 0, sizeof (*M)); + M->type = fetch_int (); + switch (M->type) { + case CODE_message_media_empty: + break; + case CODE_message_media_photo: + fetch_photo (&M->photo); + break; + case CODE_message_media_video: + fetch_video (&M->video); + break; + case CODE_message_media_geo: + fetch_geo (&M->geo); + break; + case CODE_message_media_contact: + M->phone = fetch_str_dup (); + M->first_name = fetch_str_dup (); + M->last_name = fetch_str_dup (); + M->user_id = fetch_int (); + break; + case CODE_message_media_unsupported: + M->data = fetch_str_dup (); + break; + default: + assert (0); + } +} + +void fetch_message (struct message *M) { + memset (M, 0, sizeof (*M)); + unsigned x = fetch_int (); + assert (x == CODE_message_empty || x == CODE_message || x == CODE_message_forwarded || x == CODE_message_service); + M->id = fetch_int (); + if (x == CODE_message_empty) { + M->flags |= 1; + return; + } + if (x == CODE_message_forwarded) { + M->fwd_from_id = fetch_int (); + M->fwd_date = fetch_int (); + } + M->from_id = fetch_int (); + M->to_id = fetch_int (); + M->out = (fetch_int () == (int)CODE_bool_true); + M->unread = (fetch_int () == (int)CODE_bool_true); + M->date = fetch_int (); + if (x == CODE_message_service) { + M->service = 1; + fetch_message_action (&M->action); + } else { + M->message = fetch_str_dup (); + fetch_message_media (&M->media); } - } #define user_cmp(a,b) ((a)->id - (b)->id) -DEFINE_TREE(user,struct user *,user_cmp,0) -struct tree_user *user_tree; +DEFINE_TREE(peer,union user_chat *,user_cmp,0) +DEFINE_TREE(message,struct message *,user_cmp,0) +struct tree_peer *peer_tree; +struct tree_message *message_tree; +int chat_num; int user_num; -struct user *Users[MAX_USER_NUM]; int users_allocated; +int chats_allocated; +int messages_allocated; +union user_chat *Peers[MAX_USER_NUM]; + +struct message message_list = { + .next_use = &message_list, + .prev_use = &message_list +}; struct user *fetch_alloc_user (void) { - struct user *U = malloc (sizeof (*U)); - fetch_user (U); + union user_chat *U = malloc (sizeof (*U)); + fetch_user (&U->user); users_allocated ++; - struct user *U1 = tree_lookup_user (user_tree, U); + union user_chat *U1 = tree_lookup_peer (peer_tree, U); if (U1) { - free_user (U1); + free_user (&U1->user); memcpy (U1, U, sizeof (*U)); free (U); users_allocated --; - return U1; + return &U1->user; } else { - user_tree = tree_insert_user (user_tree, U, lrand48 ()); - Users[user_num ++] = U; - return U; + peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + Peers[chat_num + (user_num ++)] = U; + return &U->user; } } @@ -168,10 +334,144 @@ void free_user (struct user *U) { if (U->phone) { free (U->phone); } } +void free_photo_size (struct photo_size *S) { + free (S->type); + free (S->data); +} + +void free_photo (struct photo *P) { + free (P->caption); + int i; + for (i = 0; i < P->sizes_num; i++) { + free_photo_size (&P->sizes[i]); + } + free (P->sizes); +} + +void free_video (struct video *V) { + free (V->caption); + free (&V->thumb); +} + +void free_message_media (struct message_media *M) { + switch (M->type) { + case CODE_message_media_empty: + return; + case CODE_message_media_photo: + free_photo (&M->photo); + return; + case CODE_message_media_video: + free_video (&M->video); + return; + case CODE_message_media_contact: + free (M->phone); + free (M->first_name); + free (M->last_name); + return; + case CODE_message_media_unsupported: + free (M->data); + return; + default: + assert (0); + } +} + +void free_message_action (struct message_action *M) { + switch (M->type) { + case CODE_message_action_empty: + break; + case CODE_message_action_chat_create: + free (M->title); + free (M->users); + break; + case CODE_message_action_chat_edit_title: + free (M->new_title); + break; + case CODE_message_action_chat_edit_photo: + free_photo (&M->photo); + break; + case CODE_message_action_chat_delete_photo: + break; + case CODE_message_action_chat_add_user: + break; + case CODE_message_action_chat_delete_user: + break; + default: + assert (0); + } +} + +void free_message (struct message *M) { + if (!M->service) { + if (M->message) { free (M->message); } + free_message_media (&M->media); + } else { + free_message_action (&M->action); + } +} + +void message_del_use (struct message *M) { + M->next_use->prev_use = M->prev_use; + M->prev_use->next_use = M->next_use; +} + +void message_add_use (struct message *M) { + M->next_use = message_list.next_use; + M->prev_use = &message_list; + M->next_use->prev_use = M; + M->prev_use->next_use = M; +} + +struct message *fetch_alloc_message (void) { + struct message *M = malloc (sizeof (*M)); + fetch_message (M); + struct message *M1 = tree_lookup_message (message_tree, M); + messages_allocated ++; + if (M1) { + message_del_use (M1); + free_message (M1); + memcpy (M1, M, sizeof (*M)); + free (M); + message_add_use (M1); + messages_allocated --; + return M1; + } else { + message_add_use (M); + message_tree = tree_insert_message (message_tree, M, lrand48 ()); + return M; + } +} + +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; + } else { + peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + 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); } +} + int print_stat (char *s, int len) { return snprintf (s, len, - "user_num\t%d\n" - "users_allocated\t%d\n", - user_num, - users_allocated); + "users_allocated\t%d\n" + "chats_allocated\t%d\n" + "messages_allocated\t%d\n", + users_allocated, + chats_allocated, + messages_allocated + ); } diff --git a/structures.h b/structures.h index 717a5aa..df89632 100644 --- a/structures.h +++ b/structures.h @@ -17,33 +17,137 @@ struct user_status { 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; - char *print_name; long long access_hash; - struct file_location photo_big; - struct file_location photo_small; struct user_status status; }; struct chat { int id; int flags; - char *title; char *print_title; + struct file_location photo_big; + struct file_location photo_small; + char *title; int user_num; int date; int version; - struct file_location photo_big; - struct file_location photo_small; +}; + +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; + int w; + int h; + int size; + char *data; +}; + +struct geo { + double longitude; + double latitude; +}; + +struct photo { + long long id; + long long access_hash; + int user_id; + int date; + char *caption; + struct geo geo; + int sizes_num; + struct photo_size *sizes; +}; + +struct video { + long long id; + long long access_hash; + int user_id; + int date; + char *caption; + int duration; + int size; + struct photo_size thumb; + int dc_id; + int w; + int h; +}; + +struct message_action { + int type; + union { + struct { + char *title; + int user_num; + int *users; + }; + char *new_title; + struct photo photo; + int user; + }; +}; + +struct message_media { + int type; + union { + struct photo photo; + struct video video; + struct geo geo; + struct { + char *phone; + char *first_name; + char *last_name; + int user_id; + }; + void *data; + }; +}; + +struct message { + struct message *next_use, *prev_use; + int id; + int flags; + int fwd_from_id; + int fwd_date; + int from_id; + int to_id; + int out; + int unread; + int date; + int service; + union { + struct message_action action; + struct { + char *message; + struct message_media media; + }; + }; }; void fetch_file_location (struct file_location *loc); void fetch_user (struct user *U); struct user *fetch_alloc_user (void); +struct chat *fetch_alloc_chat (void); void free_user (struct user *U); +void free_chat (struct chat *U); int print_stat (char *s, int len); #endif diff --git a/telegram.h b/telegram.h index 30d8f40..d285b5c 100644 --- a/telegram.h +++ b/telegram.h @@ -1,2 +1,3 @@ #define MAX_DC_NUM 9 #define MAX_USER_NUM 1000 +#define MAX_CHAT_NUM 1000 diff --git a/tg.pub b/tg.pub new file mode 100644 index 0000000..4e006b4 --- /dev/null +++ b/tg.pub @@ -0,0 +1,9 @@ +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 +lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS +an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw +Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ +8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n +Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB +-----END RSA PUBLIC KEY----- +