diff --git a/loop.c b/loop.c index 63a4899..6d6908f 100644 --- a/loop.c +++ b/loop.c @@ -87,6 +87,30 @@ void net_loop (int flags, int (*is_end)(void)) { } } +char **_s; +size_t *_l; +int got_it_ok; + +void got_it (char *line) { + *_s = strdup (line); + *_l = strlen (line); + got_it_ok = 1; +} + +int is_got_it (void) { + return got_it_ok; +} + +int net_getline (char **s, size_t *l) { + got_it_ok = 0; + _s = s; + _l = l; + rl_callback_handler_install (0, got_it); + net_loop (1, is_got_it); + printf ("'%s'\n", *s); + return 0; +} + int ret1 (void) { return 0; } int main_loop (void) { @@ -116,13 +140,14 @@ void write_dc (int auth_file_fd, struct dc *DC) { } assert (write (auth_file_fd, &DC->server_salt, 8) == 8); + assert (write (auth_file_fd, &DC->has_auth, 4) == 4); } int our_id; void write_auth_file (void) { int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); - int x = DC_SERIALIZED_MAGIC; + int x = DC_SERIALIZED_MAGIC_V2; assert (write (auth_file_fd, &x, 4) == 4); x = MAX_DC_ID; assert (write (auth_file_fd, &x, 4) == 4); @@ -143,7 +168,7 @@ void write_auth_file (void) { close (auth_file_fd); } -void read_dc (int auth_file_fd, int id) { +void read_dc (int auth_file_fd, int id, unsigned ver) { int port = 0; assert (read (auth_file_fd, &port, 4) == 4); int l = 0; @@ -159,37 +184,48 @@ void read_dc (int auth_file_fd, int id) { if (DC->auth_key_id) { DC->flags |= 1; } + if (ver != DC_SERIALIZED_MAGIC) { + assert (read (auth_file_fd, &DC->has_auth, 4) == 4); + } else { + DC->has_auth = 0; + } } void empty_auth_file (void) { struct dc *DC = alloc_dc (1, strdup (TG_SERVER), 443); assert (DC); dc_working_num = 1; + auth_state = 0; write_auth_file (); } +int need_dc_list_update; void read_auth_file (void) { int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); if (auth_file_fd < 0) { empty_auth_file (); } assert (auth_file_fd >= 0); - int x; - if (read (auth_file_fd, &x, 4) < 4 || x != DC_SERIALIZED_MAGIC) { + unsigned x; + unsigned m; + if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) { close (auth_file_fd); empty_auth_file (); return; } assert (read (auth_file_fd, &x, 4) == 4); - assert (x >= 0 && x <= MAX_DC_ID); + assert (x <= MAX_DC_ID); assert (read (auth_file_fd, &dc_working_num, 4) == 4); assert (read (auth_file_fd, &auth_state, 4) == 4); + if (m == DC_SERIALIZED_MAGIC) { + auth_state = 700; + } int i; - for (i = 0; i <= x; i++) { + for (i = 0; i <= (int)x; i++) { int y; assert (read (auth_file_fd, &y, 4) == 4); if (y) { - read_dc (auth_file_fd, i); + read_dc (auth_file_fd, i, m); } } int l = read (auth_file_fd, &our_id, 4); @@ -197,59 +233,148 @@ void read_auth_file (void) { assert (!l); } close (auth_file_fd); + DC_working = DC_list[dc_working_num]; + if (m == DC_SERIALIZED_MAGIC) { + DC_working->has_auth = 1; + } +} + +extern int max_chat_size; +int mcs (void) { + return max_chat_size; } int readline_active; +int new_dc_num; int loop (void) { on_start (); read_auth_file (); + readline_active = 1; + rl_set_prompt (""); + assert (DC_list[dc_working_num]); - DC_working = DC_list[dc_working_num]; - if (!DC_working->auth_key_id) { + if (auth_state == 0) { + DC_working = DC_list[dc_working_num]; + assert (!DC_working->auth_key_id); dc_authorize (DC_working); - } else { - dc_create_session (DC_working); + assert (DC_working->auth_key_id); + auth_state = 100; + write_auth_file (); } - if (!auth_state) { + + if (verbosity) { + logprintf ("Requesting info about DC...\n"); + } + do_help_get_config (); + net_loop (0, mcs); + if (verbosity) { + logprintf ("DC_info: %d new DC got\n", new_dc_num); + } + if (new_dc_num) { + int i; + for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->auth_key_id) { + dc_authorize (DC_list[i]); + assert (DC_list[i]->auth_key_id); + write_auth_file (); + } + } + + if (auth_state == 100) { if (!default_username) { size_t size = 0; char *user = 0; - if (!user && !auth_token) { + if (!user) { printf ("Telephone number (with '+' sign): "); - if (getline (&user, &size, stdin) == -1) { + if (net_getline (&user, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } - user[strlen (user) - 1] = 0; set_default_username (user); } } - do_send_code (default_username); - char *code = 0; - size_t size = 0; - printf ("Code from sms: "); - while (1) { - if (getline (&code, &size, stdin) == -1) { + int res = do_auth_check_phone (default_username); + assert (res >= 0); + logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); + if (res > 0) { + do_send_code (default_username); + char *code = 0; + size_t size = 0; + printf ("Code from sms: "); + while (1) { + if (net_getline (&code, &size) == -1) { + perror ("getline()"); + exit (EXIT_FAILURE); + } + if (do_send_code_result (code) >= 0) { + break; + } + printf ("Invalid code. Try again: "); + free (code); + } + auth_state = 300; + } else { + printf ("User is not registered. Do you want to register? [Y/n] "); + char *code; + size_t size; + if (net_getline (&code, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } - code[strlen (code) - 1] = 0; - if (do_send_code_result (code) >= 0) { - break; + if (!*code || *code == 'y') { + printf ("Ok, starting registartion.\n"); + } else { + printf ("Then try again\n"); + exit (EXIT_SUCCESS); } - printf ("Invalid code. Try again: "); + char *first_name; + printf ("Name: "); + if (net_getline (&first_name, &size) == -1) { + perror ("getline()"); + exit (EXIT_FAILURE); + } + char *last_name; + printf ("Name: "); + if (net_getline (&last_name, &size) == -1) { + perror ("getline()"); + exit (EXIT_FAILURE); + } + + int dc_num = do_get_nearest_dc (); + assert (dc_num >= 0 && dc_num <= MAX_DC_NUM && DC_list[dc_num]); + dc_working_num = dc_num; + DC_working = DC_list[dc_working_num]; + + do_send_code (default_username); + printf ("Code from sms: "); + while (1) { + if (net_getline (&code, &size) == -1) { + perror ("getline()"); + exit (EXIT_FAILURE); + } + if (do_send_code_result_auth (code, first_name, last_name) >= 0) { + break; + } + printf ("Invalid code. Try again: "); + free (code); + } + auth_state = 300; } - auth_state = 1; } + int i; + for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->has_auth) { + do_export_auth (i); + do_import_auth (i); + DC_list[i]->has_auth = 1; + write_auth_file (); + } write_auth_file (); fflush (stdin); fflush (stdout); fflush (stderr); - readline_active = 1; rl_callback_handler_install (get_default_prompt (), interpreter); rl_attempted_completion_function = (CPPFunction *) complete_text; rl_completion_entry_function = complete_none; diff --git a/net.h b/net.h index 674ead9..ff9b4e5 100644 --- a/net.h +++ b/net.h @@ -73,9 +73,11 @@ struct dc { int server_time_delta; double server_time_udelta; + int has_auth; }; #define DC_SERIALIZED_MAGIC 0x64582faa +#define DC_SERIALIZED_MAGIC_V2 0x94032abb struct dc_serialized { int magic; int port; diff --git a/queries.c b/queries.c index 872ba4e..325e558 100644 --- a/queries.c +++ b/queries.c @@ -206,6 +206,7 @@ void query_result (long long id UU) { if (verbosity) { logprintf ( "No such query\n"); } + in_ptr = in_end; } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { remove_event_timer (&q->ev); @@ -213,6 +214,7 @@ void query_result (long long id UU) { queries_tree = tree_delete_query (queries_tree, q); if (q->methods && q->methods->on_answer) { q->methods->on_answer (q); + assert (in_ptr == in_end); } free (q->data); free (q); @@ -263,6 +265,7 @@ void work_timers (void) { int max_chat_size; int want_dc_num; +int new_dc_num; extern struct dc *DC_list[]; extern struct dc *DC_working; @@ -294,6 +297,7 @@ int help_get_config_on_answer (struct query *q UU) { } if (!DC_list[id]) { alloc_dc (id, strndup (ip, l2), port); + new_dc_num ++; } } max_chat_size = fetch_int (); @@ -307,10 +311,16 @@ struct query_methods help_get_config_methods = { .on_answer = help_get_config_on_answer }; +void do_help_get_config (void) { + clear_packet (); + out_int (CODE_help_get_config); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0); +} + char *phone_code_hash; int send_code_on_answer (struct query *q UU) { assert (fetch_int () == CODE_auth_sent_code); - assert (fetch_int () == (int)CODE_bool_true); + assert (fetch_bool ()); int l = prefetch_strlen (); char *s = fetch_str (l); if (phone_code_hash) { @@ -350,6 +360,7 @@ char *suser; extern int dc_working_num; void do_send_code (const char *user) { suser = strdup (user); + fprintf (stderr, "user='%s'\n", user); want_dc_num = 0; clear_packet (); out_int (CODE_auth_send_code); @@ -363,29 +374,11 @@ void do_send_code (const char *user) { net_loop (0, code_is_sent); if (want_dc_num == -1) { return; } - if (DC_list[want_dc_num]) { - DC_working = DC_list[want_dc_num]; - if (!DC_working->auth_key_id) { - dc_authorize (DC_working); - } - if (!DC_working->sessions[0]) { - dc_create_session (DC_working); - } - dc_working_num = want_dc_num; - } else { - clear_packet (); - out_int (CODE_help_get_config); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0); - net_loop (0, config_got); - DC_working = DC_list[want_dc_num]; - if (!DC_working->auth_key_id) { - dc_authorize (DC_working); - } - if (!DC_working->sessions[0]) { - dc_create_session (DC_working); - } - dc_working_num = want_dc_num; + DC_working = DC_list[want_dc_num]; + if (!DC_working->sessions[0]) { + dc_create_session (DC_working); } + dc_working_num = want_dc_num; want_dc_num = 0; clear_packet (); out_int (CODE_auth_send_code); @@ -400,6 +393,97 @@ void do_send_code (const char *user) { assert (want_dc_num == -1); } + +int check_phone_result; +int cr_f (void) { + return check_phone_result >= 0; +} + +int check_phone_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_auth_checked_phone); + check_phone_result = fetch_bool (); + fetch_bool (); + return 0; +} + +int check_phone_on_error (struct query *q UU, int error_code, int l, char *error) { + int s = strlen ("PHONE_MIGRATE_"); + int s2 = strlen ("NETWORK_MIGRATE_"); + if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { + int i = error[s] - '0'; + assert (DC_list[i]); + dc_working_num = i; + DC_working = DC_list[i]; + write_auth_file (); + check_phone_result = 1; + } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s)) { + int i = error[s2] - '0'; + assert (DC_list[i]); + dc_working_num = i; + DC_working = DC_list[i]; + write_auth_file (); + check_phone_result = 1; + } else { + logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); + assert (0); + } + return 0; +} + +struct query_methods check_phone_methods = { + .on_answer = check_phone_on_answer, + .on_error = check_phone_on_error +}; + +int do_auth_check_phone (const char *user) { + suser = strdup (user); + clear_packet (); + out_int (CODE_auth_check_phone); + out_string (user); + printf ("'%s'\n", user); + check_phone_result = -1; + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, 0); + net_loop (0, cr_f); + return check_phone_result; +} + +int nearest_dc_num; +int nr_f (void) { + return nearest_dc_num >= 0; +} + +int nearest_dc_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_nearest_dc); + char *country = fetch_str_dup (); + if (verbosity > 0) { + logprintf ("Server thinks that you are in %s\n", country); + } + fetch_int (); // this_dc + nearest_dc_num = fetch_int (); + assert (nearest_dc_num >= 0); + return 0; +} + +int fail_on_error (struct query *q UU, int error_code UU, int l UU, char *error UU) { + fprintf (stderr, "error #%d: %.*s\n", error_code, l, error); + assert (0); + return 0; +} + +struct query_methods nearest_dc_methods = { + .on_answer = nearest_dc_on_answer, + .on_error = fail_on_error +}; + +int do_get_nearest_dc (void) { + clear_packet (); + out_int (CODE_help_get_nearest_dc); + nearest_dc_num = -1; + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &nearest_dc_methods, 0); + net_loop (0, nr_f); + return nearest_dc_num; +} + int sign_in_ok; int sign_in_is_ok (void) { return sign_in_ok; @@ -415,12 +499,14 @@ int sign_in_on_answer (struct query *q UU) { if (verbosity) { logprintf ( "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); } + DC_working->has_auth = 1; return 0; } int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); sign_in_ok = -1; + assert (0); return 0; } @@ -441,6 +527,20 @@ int do_send_code_result (const char *code) { return sign_in_ok; } +int do_send_code_result_auth (const char *code, const char *first_name, const char *last_name) { + clear_packet (); + out_int (CODE_auth_sign_up); + out_string (suser); + out_string (phone_code_hash); + out_string (code); + out_string (first_name); + out_string (last_name); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, 0); + sign_in_ok = 0; + net_loop (0, sign_in_is_ok); + return sign_in_ok; +} + extern char *user_list[]; int get_contacts_on_answer (struct query *q UU) { @@ -1219,3 +1319,65 @@ void do_load_video (struct video *V, int next) { D->fd = -1; load_next_part (D); } + +char *export_auth_str; +int export_auth_str_len; +int is_export_auth_str (void) { + return export_auth_str != 0; +} +int isn_export_auth_str (void) { + return export_auth_str == 0; +} + +int export_auth_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_auth_exported_authorization); + int l = fetch_int (); + if (!our_id) { + our_id = l; + } else { + assert (our_id == l); + } + l = prefetch_strlen (); + char *s = malloc (l); + memcpy (s, fetch_str (l), l); + export_auth_str_len = l; + export_auth_str = s; + return 0; +} + +struct query_methods export_auth_methods = { + .on_answer = export_auth_on_answer, + .on_error = fail_on_error +}; + +void do_export_auth (int num) { + export_auth_str = 0; + clear_packet (); + out_int (CODE_auth_export_authorization); + out_int (num); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &export_auth_methods, 0); + net_loop (0, is_export_auth_str); +} + +int import_auth_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_auth_authorization); + fetch_int (); // expires + fetch_alloc_user (); + free (export_auth_str); + export_auth_str = 0; + return 0; +} + +struct query_methods import_auth_methods = { + .on_answer = import_auth_on_answer, + .on_error = fail_on_error +}; + +void do_import_auth (int num) { + clear_packet (); + out_int (CODE_auth_import_authorization); + out_int (our_id); + out_cstring (export_auth_str, export_auth_str_len); + send_query (DC_list[num], packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, 0); + net_loop (0, isn_export_auth_str); +} diff --git a/queries.h b/queries.h index 39fb6cd..1a93b1f 100644 --- a/queries.h +++ b/queries.h @@ -84,5 +84,11 @@ struct video; void do_load_photo (struct photo *photo, int next); void do_load_video_thumb (struct video *video, int next); void do_load_video (struct video *V, int next); +void do_help_get_config (void); +int do_auth_check_phone (const char *user); +int do_get_nearest_dc (void); +int do_send_code_result_auth (const char *code, const char *first_name, const char *last_name); +void do_import_auth (int num); +void do_export_auth (int num); #endif