From e02fcd47dcca92d92caadea4f8c7b0305ec3a08e Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 3 Oct 2013 16:37:21 +0400 Subject: [PATCH 001/465] first commit --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 From 78f4d7185530ac0991ecd5d59a7e2681e8a365ca Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 3 Oct 2013 16:38:25 +0400 Subject: [PATCH 002/465] Added some files --- Makefile | 17 +++++ include.h | 6 ++ interface.c | 156 +++++++++++++++++++++++++++++++++++++++++ interface.h | 7 ++ loop.c | 44 ++++++++++++ loop.h | 4 ++ main.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++ telegram.h | 0 8 files changed, 432 insertions(+) create mode 100644 Makefile create mode 100644 include.h create mode 100644 interface.c create mode 100644 interface.h create mode 100644 loop.c create mode 100644 loop.h create mode 100644 main.c create mode 100644 telegram.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6b83182 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +CC=cc +CFLAGS=-c -Wall -Wextra -fPIC +LDFLAGS=-lreadline +LD=cc + +SRC=main.c loop.c interface.c +OBJ=$(SRC:.c=.o) +EXE=telegram + +all: $(SRC) $(EXE) + +$(EXE): $(OBJ) + $(LD) $(LDFLAGS) $(OBJ) -o $@ + +.c.o: + $(CC) $(CFLAGS) $< -o $@ + diff --git a/include.h b/include.h new file mode 100644 index 0000000..03f271d --- /dev/null +++ b/include.h @@ -0,0 +1,6 @@ +#ifndef __INCLUDE_H__ +#define __INCLUDE_H__ + +#define UU __attribute__ ((unused)) + +#endif diff --git a/interface.c b/interface.c new file mode 100644 index 0000000..61f6931 --- /dev/null +++ b/interface.c @@ -0,0 +1,156 @@ +#define _GNU_SOURCE +#include +#include + +#include +#include + +#include +#include +#include "include.h" +char *default_prompt = ">"; + +char *get_default_prompt (void) { + return default_prompt; +} + +char *complete_none (const char *text UU, int state UU) { + return 0; +} + +char *commands[] = { + "help", + "msg", + 0 }; + +int commands_flags[] = { + 070, + 072, +}; + +char *a = 0; +char **user_list = &a; +char **chat_list = &a; + +int init_token (char **q) { + char *r = *q; + while (*r == ' ') { r ++; } + if (!*r) { return 0; } + q = &r; + return 1; +} + +char *get_token (char **q, int *l) { + char *r = *q; + while (*r == ' ') { r ++; } + if (!*r) { + q = &r; + *l = 0; + return 0; + } + int neg = 0; + char *s = r; + while (*r && (*r != ' ' || neg)) { + if (*r == '\\') { + neg = 1 - neg; + } else { + neg = 0; + } + } + q = &r; + *l = r - s; + return s; +} + + +int get_complete_mode (void) { + char *q = rl_line_buffer; + if (!init_token (&q)) { return 0; } + int l = 0; + char *r = get_token (&q, &l); + if (!*q) { return 0; } + + char **command = commands; + int n = 0; + int flags = -1; + while (*command) { + if ((int)strlen (*command) == l && !memcmp (r, *command, l)) { + flags = commands_flags[n]; + break; + } + n ++; + command ++; + } + if (flags == -1) { + return -1; + } + int s = 0; + while (1) { + get_token (&q, &l); + if (!*q) { return flags & 7; } + s ++; + if (s <= 4) { flags >>= 3; } + } +} + +int complete_string_list (char **list, int index, const char *text, int len, char **R) { + index ++; + int cc = 0; + while (cc <= 1 && list[index] && strncmp (list[index], text, len)) { + index ++; + if (!list[index]) { index = 0; cc ++; } + } + if (list[index] && cc <= 1) { + *R = strdup (list[index]); + return index; + } else { + *R = 0; + return -1; + } +} +char *command_generator (const char *text, int state) { + static int len, index, mode; + + if (!state) { + len = strlen (text); + index = -1; + + rl_line_buffer[rl_point] = '\0'; /* the effect should be such + * that the cursor position + * is at the end of line for + * the auto completion regex + * above (note the $ at end) + */ + + mode = get_complete_mode (); + } else { + if (index == -1) { return 0; } + } + + if (mode == -1) { return 0; } + + char *R = 0; + switch (mode & 7) { + case 0: + index = complete_string_list (commands, index, text, len, &R); + return R; + case 1: + index = complete_string_list (user_list, index, text, len, &R); + return R; + case 2: + index = complete_string_list (chat_list, index, text, len, &R); + return R; + case 3: + return rl_filename_completion_function(text,state); + default: + return 0; + } +} + +char **complete_text (char *text, int start UU, int end UU) { + return (char **) rl_completion_matches (text, command_generator); +} + +void interpreter (char *line UU) { + assert (0); +} diff --git a/interface.h b/interface.h new file mode 100644 index 0000000..763dde8 --- /dev/null +++ b/interface.h @@ -0,0 +1,7 @@ +#ifndef __INTERFACE_H__ +#define __INTERFACE_H__ +char *get_default_prompt (void); +char *complete_none (const char *text, int state); +char **complete_text (char *text, int start, int end); +void interpreter (char *line); +#endif diff --git a/loop.c b/loop.c new file mode 100644 index 0000000..49be9ab --- /dev/null +++ b/loop.c @@ -0,0 +1,44 @@ +#define READLINE_CALLBACKS + +#include +#include + +#include +#include +#include +#include + +#include "interface.h" +extern char *default_username; +extern char *auth_token; +void set_default_username (const char *s); + + + +int main_loop (void) { + assert (0); +} + +int loop (void) { + size_t size = 0; + char *user = default_username; + + if (!user && !auth_token) { + printf ("Telephone number (with '+' sign): "); + if (getline (&user, &size, stdin) == -1) { + perror ("getline()"); + exit (EXIT_FAILURE); + } + user[strlen (user) - 1] = '\0'; + set_default_username (user); + } + + fflush (stdin); + + rl_callback_handler_install (get_default_prompt (), interpreter); + rl_attempted_completion_function = (CPPFunction *) complete_text; + rl_completion_entry_function = complete_none; + + return main_loop (); +} + diff --git a/loop.h b/loop.h new file mode 100644 index 0000000..d70a3e6 --- /dev/null +++ b/loop.h @@ -0,0 +1,4 @@ +#ifndef __LOOP_H__ +#define __LOOP_H__ +int loop (void); +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..cd3b7af --- /dev/null +++ b/main.c @@ -0,0 +1,198 @@ +/* + main.c: main initialization file + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "loop.h" + +#define PROGNAME "telegram-client" +#define VERSION "0.01" + +#define CONFIG_DIRECTORY ".telegram/" +#define CONFIG_FILE CONFIG_DIRECTORY "config" +#define DOWNLOADS_DIRECTORY "downloads/" + +#define CONFIG_DIRECTORY_MODE 0700 + +#define DEFAULT_CONFIG_CONTENTS \ + "# This is an empty config file\n" \ + "# Feel free to put something here\n" + +char *default_username; +int setup_mode; +char *auth_token; + +void set_default_username (const char *s) { + if (default_username) { + free (default_username); + } + default_username = strdup (s); +} + +void set_setup_mode (void) { + setup_mode = 1; +} + + +/* {{{ TERMINAL */ +tcflag_t old_lflag; +cc_t old_vtime; +struct termios term; + +void get_terminal_attributes (void) { + if (tcgetattr (STDIN_FILENO, &term) < 0) { + perror ("tcgetattr()"); + exit (EXIT_FAILURE); + } + old_lflag = term.c_lflag; + old_vtime = term.c_cc[VTIME]; +} +/* }}} */ + +char *get_home_directory (void) { + struct passwd *current_passwd; + uid_t user_id; + setpwent (); + user_id = getuid (); + while ((current_passwd = getpwent ())) { + if (current_passwd->pw_uid == user_id) { + return current_passwd->pw_dir; + } + } + return 0; +} + +char *get_config_directory (void) { + char *config_directory; + int length = strlen (get_home_directory ()) + strlen (CONFIG_DIRECTORY) + 2; + + config_directory = (char *) calloc (length, sizeof (char)); + sprintf (config_directory, "%s/" CONFIG_DIRECTORY, + get_home_directory ()); + + return config_directory; +} + +char *get_config_filename (void) { + char *config_filename; + int length = strlen (get_home_directory ()) + strlen (CONFIG_FILE) + 2; + + config_filename = (char *) calloc (length, sizeof (char)); + sprintf (config_filename, "%s/" CONFIG_FILE, get_home_directory ()); + return config_filename; +} + +char *get_downloads_directory (void) +{ + char *downloads_directory; + int length = strlen (get_config_directory ()) + strlen (DOWNLOADS_DIRECTORY) + 2; + + downloads_directory = (char *) calloc (length, sizeof (char)); + sprintf (downloads_directory, "%s/" DOWNLOADS_DIRECTORY, get_config_directory ()); + + return downloads_directory; +} + +void running_for_first_time (void) { + struct stat *config_file_stat = NULL; + int config_file_fd; + char *config_directory = get_config_directory (); + char *config_filename = get_config_filename (); + char *downloads_directory = get_downloads_directory (); + + if (mkdir (config_directory, CONFIG_DIRECTORY_MODE) != 0) { + return; + } else { + printf ("\nRunning " PROGNAME " for first time!!\n"); + printf ("[%s] created\n", config_directory); + } + + // see if config file is there + if (stat (config_filename, config_file_stat) != 0) { + // config file missing, so touch it + config_file_fd = open (config_filename, O_CREAT | O_RDWR, S_IRWXU); + if (config_file_fd == -1) { + perror ("open[config_file]"); + exit (EXIT_FAILURE); + } + if (fchmod (config_file_fd, CONFIG_DIRECTORY_MODE) != 0) { + perror ("fchmod[" CONFIG_FILE "]"); + exit (EXIT_FAILURE); + } + if (write (config_file_fd, DEFAULT_CONFIG_CONTENTS, strlen (DEFAULT_CONFIG_CONTENTS)) <= 0) { + perror ("write[config_file]"); + exit (EXIT_FAILURE); + } + close (config_file_fd); + printf ("[%s] created\n", config_filename); + + /* create downloads directory */ + if (mkdir (downloads_directory, 0755) !=0) { + perror ("creating download directory"); + exit (EXIT_FAILURE); + } + } + + set_setup_mode (); +} + +void inner_main (void) { + loop (); +} + +void usage (void) { + printf ("%s [-u username]\n", PROGNAME); + exit (1); +} + +void args_parse (int argc, char **argv) { + int opt = 0; + while ((opt = getopt (argc, argv, "u:h")) != -1) { + switch (opt) { + case 'u': + set_default_username (optarg); + break; + case 'h': + default: + usage (); + break; + } + } +} + +int main (int argc, char **argv) { + running_for_first_time (); + + get_terminal_attributes (); + + args_parse (argc, argv); + + inner_main (); + + return 0; +} diff --git a/telegram.h b/telegram.h new file mode 100644 index 0000000..e69de29 From 9c70da9ed7b34fbdedfdfeb5a2f6eed990361f89 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 3 Oct 2013 20:09:06 +0400 Subject: [PATCH 003/465] many fixes --- Makefile | 2 +- interface.c | 19 +++++++++---------- loop.c | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 6b83182..bdf94b2 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ EXE=telegram all: $(SRC) $(EXE) $(EXE): $(OBJ) - $(LD) $(LDFLAGS) $(OBJ) -o $@ + $(LD) $(OBJ) $(LDFLAGS) -o $@ .c.o: $(CC) $(CFLAGS) $< -o $@ diff --git a/interface.c b/interface.c index 61f6931..e060a00 100644 --- a/interface.c +++ b/interface.c @@ -27,7 +27,7 @@ int commands_flags[] = { 070, 072, }; - + char *a = 0; char **user_list = &a; char **chat_list = &a; @@ -36,7 +36,7 @@ int init_token (char **q) { char *r = *q; while (*r == ' ') { r ++; } if (!*r) { return 0; } - q = &r; + *q = r; return 1; } @@ -44,7 +44,7 @@ char *get_token (char **q, int *l) { char *r = *q; while (*r == ' ') { r ++; } if (!*r) { - q = &r; + *q = r; *l = 0; return 0; } @@ -56,8 +56,9 @@ char *get_token (char **q, int *l) { } else { neg = 0; } + r++; } - q = &r; + *q = r; *l = r - s; return s; } @@ -74,7 +75,7 @@ int get_complete_mode (void) { int n = 0; int flags = -1; while (*command) { - if ((int)strlen (*command) == l && !memcmp (r, *command, l)) { + if (!strncmp (r, *command, l)) { flags = commands_flags[n]; break; } @@ -95,12 +96,10 @@ int get_complete_mode (void) { int complete_string_list (char **list, int index, const char *text, int len, char **R) { index ++; - int cc = 0; - while (cc <= 1 && list[index] && strncmp (list[index], text, len)) { + while (list[index] && strncmp (list[index], text, len)) { index ++; - if (!list[index]) { index = 0; cc ++; } } - if (list[index] && cc <= 1) { + if (list[index]) { *R = strdup (list[index]); return index; } else { @@ -110,7 +109,7 @@ int complete_string_list (char **list, int index, const char *text, int len, cha } char *command_generator (const char *text, int state) { static int len, index, mode; - + if (!state) { len = strlen (text); index = -1; diff --git a/loop.c b/loop.c index 49be9ab..2c4a27a 100644 --- a/loop.c +++ b/loop.c @@ -8,6 +8,8 @@ #include #include +#include + #include "interface.h" extern char *default_username; extern char *auth_token; @@ -16,7 +18,36 @@ void set_default_username (const char *s); int main_loop (void) { - assert (0); + fd_set inp, outp; + struct timeval tv; + while (1) { + FD_ZERO (&inp); + FD_ZERO (&outp); + FD_SET (0, &inp); + tv.tv_sec = 1; + tv.tv_usec = 0; + + int lfd = 0; + + if (select (lfd + 1, &inp, &outp, NULL, &tv) < 0) { + if (errno == EINTR) { + /* resuming from interrupt, so not an error situation, + this generally happens when you suspend your + messenger with "C-z" and then "fg". This is allowed " + */ + rl_reset_line_state (); + rl_forced_update_display (); + continue; + } + perror ("select()"); + break; + } + + if (FD_ISSET (0, &inp)) { + rl_callback_read_char (); + } + } + return 0; } int loop (void) { From f773c0cf18d059a4c7f854989e2c552112d916cb Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 3 Oct 2013 20:10:53 +0400 Subject: [PATCH 004/465] tab replaced with spaces --- interface.c | 10 +++++----- loop.c | 30 +++++++++++++++--------------- main.c | 28 ++++++++++++++-------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/interface.c b/interface.c index e060a00..f43a7bf 100644 --- a/interface.c +++ b/interface.c @@ -115,11 +115,11 @@ char *command_generator (const char *text, int state) { index = -1; rl_line_buffer[rl_point] = '\0'; /* the effect should be such - * that the cursor position - * is at the end of line for - * the auto completion regex - * above (note the $ at end) - */ + * that the cursor position + * is at the end of line for + * the auto completion regex + * above (note the $ at end) + */ mode = get_complete_mode (); } else { diff --git a/loop.c b/loop.c index 2c4a27a..25c6822 100644 --- a/loop.c +++ b/loop.c @@ -26,25 +26,25 @@ int main_loop (void) { FD_SET (0, &inp); tv.tv_sec = 1; tv.tv_usec = 0; - + int lfd = 0; if (select (lfd + 1, &inp, &outp, NULL, &tv) < 0) { if (errno == EINTR) { - /* resuming from interrupt, so not an error situation, - this generally happens when you suspend your - messenger with "C-z" and then "fg". This is allowed " - */ - rl_reset_line_state (); - rl_forced_update_display (); - continue; - } - perror ("select()"); - break; + /* resuming from interrupt, so not an error situation, + this generally happens when you suspend your + messenger with "C-z" and then "fg". This is allowed " + */ + rl_reset_line_state (); + rl_forced_update_display (); + continue; + } + perror ("select()"); + break; } if (FD_ISSET (0, &inp)) { - rl_callback_read_char (); + rl_callback_read_char (); } } return 0; @@ -57,9 +57,9 @@ int loop (void) { if (!user && !auth_token) { printf ("Telephone number (with '+' sign): "); if (getline (&user, &size, stdin) == -1) { - perror ("getline()"); - exit (EXIT_FAILURE); - } + perror ("getline()"); + exit (EXIT_FAILURE); + } user[strlen (user) - 1] = '\0'; set_default_username (user); } diff --git a/main.c b/main.c index cd3b7af..8de3c38 100644 --- a/main.c +++ b/main.c @@ -93,7 +93,7 @@ char *get_config_directory (void) { config_directory = (char *) calloc (length, sizeof (char)); sprintf (config_directory, "%s/" CONFIG_DIRECTORY, - get_home_directory ()); + get_home_directory ()); return config_directory; } @@ -136,26 +136,26 @@ void running_for_first_time (void) { if (stat (config_filename, config_file_stat) != 0) { // config file missing, so touch it config_file_fd = open (config_filename, O_CREAT | O_RDWR, S_IRWXU); - if (config_file_fd == -1) { - perror ("open[config_file]"); - exit (EXIT_FAILURE); - } + if (config_file_fd == -1) { + perror ("open[config_file]"); + exit (EXIT_FAILURE); + } if (fchmod (config_file_fd, CONFIG_DIRECTORY_MODE) != 0) { - perror ("fchmod[" CONFIG_FILE "]"); - exit (EXIT_FAILURE); - } + perror ("fchmod[" CONFIG_FILE "]"); + exit (EXIT_FAILURE); + } if (write (config_file_fd, DEFAULT_CONFIG_CONTENTS, strlen (DEFAULT_CONFIG_CONTENTS)) <= 0) { - perror ("write[config_file]"); - exit (EXIT_FAILURE); - } + perror ("write[config_file]"); + exit (EXIT_FAILURE); + } close (config_file_fd); printf ("[%s] created\n", config_filename); /* create downloads directory */ if (mkdir (downloads_directory, 0755) !=0) { - perror ("creating download directory"); - exit (EXIT_FAILURE); - } + perror ("creating download directory"); + exit (EXIT_FAILURE); + } } set_setup_mode (); From 3243c29a8ce161c3599ffd35971212ee0eaa35ac Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 12 Oct 2013 00:52:20 +0400 Subject: [PATCH 005/465] Big commit --- Makefile | 6 +- interface.c | 29 +- interface.h | 2 + loop.c | 218 ++++++++++-- loop.h | 2 + main.c | 56 ++- mtproto-client.c | 864 +++++++++++++++++++++++++++++++++++++++++++++++ mtproto-client.h | 7 + mtproto-common.c | 337 ++++++++++++++++++ mtproto-common.h | 416 +++++++++++++++++++++++ net.c | 436 ++++++++++++++++++++++++ net.h | 121 +++++++ queries.c | 404 ++++++++++++++++++++++ queries.h | 47 +++ structures.c | 81 +++++ structures.h | 31 ++ telegram.h | 1 + tree.h | 116 +++++++ 18 files changed, 3134 insertions(+), 40 deletions(-) create mode 100644 mtproto-client.c create mode 100644 mtproto-client.h create mode 100644 mtproto-common.c create mode 100644 mtproto-common.h create mode 100644 net.c create mode 100644 net.h create mode 100644 queries.c create mode 100644 queries.h create mode 100644 structures.c create mode 100644 structures.h create mode 100644 tree.h diff --git a/Makefile b/Makefile index bdf94b2..b57528a 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ CC=cc -CFLAGS=-c -Wall -Wextra -fPIC -LDFLAGS=-lreadline +CFLAGS=-c -Wall -Wextra -Werror -fPIC -ggdb -O2 -fno-omit-frame-pointer -fno-strict-aliasing -rdynamic +LDFLAGS=-lreadline -lssl -lcrypto -lrt -lz -ggdb -rdynamic LD=cc -SRC=main.c loop.c interface.c +SRC=main.c loop.c interface.c net.c mtproto-common.c mtproto-client.c queries.c structures.c OBJ=$(SRC:.c=.o) EXE=telegram diff --git a/interface.c b/interface.c index f43a7bf..472df60 100644 --- a/interface.c +++ b/interface.c @@ -4,10 +4,11 @@ #include #include - +#include #include #include #include "include.h" +#include "queries.h" char *default_prompt = ">"; char *get_default_prompt (void) { @@ -21,11 +22,13 @@ char *complete_none (const char *text UU, int state UU) { char *commands[] = { "help", "msg", + "contact_list", 0 }; int commands_flags[] = { 070, 072, + 00, }; char *a = 0; @@ -151,5 +154,27 @@ char **complete_text (char *text, int start UU, int end UU) { } void interpreter (char *line UU) { - assert (0); + if (!memcmp (line, "contact_list", 12)) { + do_update_contact_list (); + } +} + +void rprintf (const char *format, ...) { + + int saved_point = rl_point; + char *saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + + va_list ap; + va_start (ap, format); + vfprintf (stdout, format, ap); + va_end (ap); + + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); } diff --git a/interface.h b/interface.h index 763dde8..a0d2376 100644 --- a/interface.h +++ b/interface.h @@ -4,4 +4,6 @@ char *get_default_prompt (void); char *complete_none (const char *text, int state); char **complete_text (char *text, int start, int end); void interpreter (char *line); + +void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); #endif diff --git a/loop.c b/loop.c index 25c6822..f5d515a 100644 --- a/loop.c +++ b/loop.c @@ -9,62 +9,212 @@ #include #include +#include +#include +#include +#include +#include #include "interface.h" +#include "net.h" +#include "mtproto-client.h" +#include "mtproto-common.h" +#include "queries.h" +#include "telegram.h" + extern char *default_username; extern char *auth_token; void set_default_username (const char *s); +int default_dc_num; +void net_loop (int flags, int (*is_end)(void)) { + while (!is_end ()) { + struct pollfd fds[101]; + int cc = 0; + if (flags & 1) { + fds[0].fd = 0; + fds[0].events = POLLIN; + cc ++; + } -int main_loop (void) { - fd_set inp, outp; - struct timeval tv; - while (1) { - FD_ZERO (&inp); - FD_ZERO (&outp); - FD_SET (0, &inp); - tv.tv_sec = 1; - tv.tv_usec = 0; - - int lfd = 0; - - if (select (lfd + 1, &inp, &outp, NULL, &tv) < 0) { - if (errno == EINTR) { - /* resuming from interrupt, so not an error situation, - this generally happens when you suspend your - messenger with "C-z" and then "fg". This is allowed " - */ + int x = connections_make_poll_array (fds + cc, 101 - cc) + cc; + double timer = next_timer_in (); + if (timer > 1000) { timer = 1000; } + if (poll (fds, x, timer) < 0) { + /* resuming from interrupt, so not an error situation, + this generally happens when you suspend your + messenger with "C-z" and then "fg". This is allowed " + */ + if (flags & 1) { rl_reset_line_state (); rl_forced_update_display (); - continue; } - perror ("select()"); - break; + work_timers (); + continue; } - - if (FD_ISSET (0, &inp)) { + work_timers (); + if ((flags & 1) && (fds[0].revents & POLLIN)) { rl_callback_read_char (); } + connections_poll_result (fds + cc, x - cc); } +} + +int ret1 (void) { return 0; } + +int main_loop (void) { + net_loop (1, ret1); return 0; } -int loop (void) { - size_t size = 0; - char *user = default_username; - if (!user && !auth_token) { - printf ("Telephone number (with '+' sign): "); - if (getline (&user, &size, stdin) == -1) { - perror ("getline()"); - exit (EXIT_FAILURE); - } - user[strlen (user) - 1] = '\0'; - set_default_username (user); +struct dc *DC_list[MAX_DC_ID + 1]; +struct dc *DC_working; +int dc_working_num; +int auth_state; +char *get_auth_key_filename (void); +int zero[512]; + + +void write_dc (int auth_file_fd, struct dc *DC) { + assert (write (auth_file_fd, &DC->port, 4) == 4); + int l = strlen (DC->ip); + assert (write (auth_file_fd, &l, 4) == 4); + assert (write (auth_file_fd, DC->ip, l) == l); + if (DC->flags & 1) { + assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); + assert (write (auth_file_fd, DC->auth_key, 256) == 256); + } else { + assert (write (auth_file_fd, zero, 256 + 8) == 256 + 8); } + + assert (write (auth_file_fd, &DC->server_salt, 8) == 8); +} + +void write_auth_file (void) { + int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU); + assert (auth_file_fd >= 0); + int x = DC_SERIALIZED_MAGIC; + assert (write (auth_file_fd, &x, 4) == 4); + x = MAX_DC_ID; + assert (write (auth_file_fd, &x, 4) == 4); + assert (write (auth_file_fd, &dc_working_num, 4) == 4); + assert (write (auth_file_fd, &auth_state, 4) == 4); + int i; + for (i = 0; i <= MAX_DC_ID; i++) { + if (DC_list[i]) { + x = 1; + assert (write (auth_file_fd, &x, 4) == 4); + write_dc (auth_file_fd, DC_list[i]); + } else { + x = 0; + assert (write (auth_file_fd, &x, 4) == 4); + } + } + close (auth_file_fd); +} + +void read_dc (int auth_file_fd, int id) { + int port = 0; + assert (read (auth_file_fd, &port, 4) == 4); + int l = 0; + assert (read (auth_file_fd, &l, 4) == 4); + assert (l >= 0); + char *ip = malloc (l + 1); + assert (read (auth_file_fd, ip, l) == l); + ip[l] = 0; + struct dc *DC = alloc_dc (id, ip, port); + assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8); + assert (read (auth_file_fd, &DC->auth_key, 256) == 256); + assert (read (auth_file_fd, &DC->server_salt, 8) == 8); + if (DC->auth_key_id) { + DC->flags |= 1; + } +} + +void empty_auth_file (void) { + struct dc *DC = alloc_dc (1, strdup (TG_SERVER), 443); + assert (DC); + dc_working_num = 1; + write_auth_file (); +} + +void read_auth_file (void) { + int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU); + 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) { + close (auth_file_fd); + empty_auth_file (); + return; + } + assert (read (auth_file_fd, &x, 4) == 4); + assert (x >= 0 && x <= MAX_DC_ID); + assert (read (auth_file_fd, &dc_working_num, 4) == 4); + assert (read (auth_file_fd, &auth_state, 4) == 4); + int i; + for (i = 0; i <= x; i++) { + int y; + assert (read (auth_file_fd, &y, 4) == 4); + if (y) { + read_dc (auth_file_fd, i); + } + } + close (auth_file_fd); +} + +int loop (void) { + on_start (); + read_auth_file (); + assert (DC_list[dc_working_num]); + DC_working = DC_list[dc_working_num]; + if (!DC_working->auth_key_id) { + dc_authorize (DC_working); + } else { + dc_create_session (DC_working); + } + if (!auth_state) { + if (!default_username) { + size_t size = 0; + char *user = 0; + + if (!user && !auth_token) { + printf ("Telephone number (with '+' sign): "); + if (getline (&user, &size, stdin) == -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) { + perror ("getline()"); + exit (EXIT_FAILURE); + } + code[strlen (code) - 1] = 0; + if (do_send_code_result (code) >= 0) { + break; + } + printf ("Invalid code. Try again: "); + } + auth_state = 1; + } + + write_auth_file (); fflush (stdin); + fflush (stdout); + fflush (stderr); rl_callback_handler_install (get_default_prompt (), interpreter); rl_attempted_completion_function = (CPPFunction *) complete_text; diff --git a/loop.h b/loop.h index d70a3e6..88b38ee 100644 --- a/loop.h +++ b/loop.h @@ -1,4 +1,6 @@ #ifndef __LOOP_H__ #define __LOOP_H__ int loop (void); +void net_loop (int flags, int (*end)(void)); +void write_auth_file (void); #endif diff --git a/main.c b/main.c index 8de3c38..5d5c557 100644 --- a/main.c +++ b/main.c @@ -27,14 +27,18 @@ #include #include #include +#include +#include #include "loop.h" +#include "mtproto-client.h" #define PROGNAME "telegram-client" #define VERSION "0.01" #define CONFIG_DIRECTORY ".telegram/" #define CONFIG_FILE CONFIG_DIRECTORY "config" +#define AUTH_KEY_FILE CONFIG_DIRECTORY "auth" #define DOWNLOADS_DIRECTORY "downloads/" #define CONFIG_DIRECTORY_MODE 0700 @@ -72,6 +76,13 @@ void get_terminal_attributes (void) { old_lflag = term.c_lflag; old_vtime = term.c_cc[VTIME]; } + +void set_terminal_attributes (void) { + if (tcsetattr (STDIN_FILENO, 0, &term) < 0) { + perror ("tcsetattr()"); + exit (EXIT_FAILURE); + } +} /* }}} */ char *get_home_directory (void) { @@ -107,6 +118,15 @@ char *get_config_filename (void) { return config_filename; } +char *get_auth_key_filename (void) { + char *auth_key_filename; + int length = strlen (get_home_directory ()) + strlen (AUTH_KEY_FILE) + 2; + + auth_key_filename = (char *) calloc (length, sizeof (char)); + sprintf (auth_key_filename, "%s/" AUTH_KEY_FILE, get_home_directory ()); + return auth_key_filename; +} + char *get_downloads_directory (void) { char *downloads_directory; @@ -149,6 +169,11 @@ void running_for_first_time (void) { exit (EXIT_FAILURE); } close (config_file_fd); + int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU); + int x = -1; + assert (write (auth_file_fd, &x, 4) == 4); + close (auth_file_fd); + printf ("[%s] created\n", config_filename); /* create downloads directory */ @@ -170,13 +195,26 @@ void usage (void) { exit (1); } +extern char *rsa_public_key_name; +extern int verbosity; +extern int default_dc_num; + void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:h")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:")) != -1) { switch (opt) { case 'u': set_default_username (optarg); break; + case 'k': + rsa_public_key_name = strdup (optarg); + break; + case 'v': + verbosity ++; + break; + case 'n': + default_dc_num = atoi (optarg); + break; case 'h': default: usage (); @@ -185,7 +223,23 @@ void args_parse (int argc, char **argv) { } } +void print_backtrace (void) { + void *buffer[255]; + const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); + backtrace_symbols_fd (buffer, calls, 1); + exit(EXIT_FAILURE); +} + +void sig_handler (int signum) { + set_terminal_attributes (); + printf ("signal %d received\n", signum); + print_backtrace (); +} + + int main (int argc, char **argv) { + signal (SIGSEGV, sig_handler); + signal (SIGABRT, sig_handler); running_for_first_time (); get_terminal_attributes (); diff --git a/mtproto-client.c b/mtproto-client.c new file mode 100644 index 0000000..5a6802b --- /dev/null +++ b/mtproto-client.c @@ -0,0 +1,864 @@ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "net.h" +#include "include.h" +#include "queries.h" +#include "loop.h" + +#define sha1 SHA1 + +#include "mtproto-common.h" + +#define MAX_NET_RES (1L << 16) + +int verbosity; +int auth_success; +enum dc_state c_state; +char nonce[256]; +char new_nonce[256]; +char server_nonce[256]; + +int rpc_execute (struct connection *c, int op, int len); +int rpc_becomes_ready (struct connection *c); +int rpc_close (struct connection *c); + +struct connection_methods auth_methods = { + .execute = rpc_execute, + .ready = rpc_becomes_ready, + .close = rpc_close +}; + +long long precise_time; +long long precise_time_rdtsc; +double get_utime (int clock_id) { + struct timespec T; + #if _POSIX_TIMERS + assert (clock_gettime (clock_id, &T) >= 0); + double res = T.tv_sec + (double) T.tv_nsec * 1e-9; + #else + #error "No high-precision clock" + double res = time (); + #endif + if (clock_id == CLOCK_REALTIME) { + precise_time = (long long) (res * (1LL << 32)); + precise_time_rdtsc = rdtsc (); + } + return res; +} + + + +#define STATS_BUFF_SIZE (64 << 10) +int stats_buff_len; +char stats_buff[STATS_BUFF_SIZE]; + +#define MAX_RESPONSE_SIZE (1L << 24) + +char Response[MAX_RESPONSE_SIZE]; +int Response_len; + +/* + * + * STATE MACHINE + * + */ + +char *rsa_public_key_name = "id_rsa.pub"; +RSA *pubKey; +long long pk_fingerprint; + +static int rsa_load_public_key (const char *public_key_name) { + pubKey = NULL; + FILE *f = fopen (public_key_name, "r"); + if (f == NULL) { + fprintf (stderr, "Couldn't open public key file: %s\n", public_key_name); + return -1; + } + pubKey = PEM_read_RSAPublicKey (f, NULL, NULL, NULL); + fclose (f); + if (pubKey == NULL) { + fprintf (stderr, "PEM_read_RSAPublicKey returns NULL.\n"); + return -1; + } + + return 0; +} + + + + + +int auth_work_start (struct connection *c); + +/* + * + * UNAUTHORIZED (DH KEY EXCHANGE) PROTOCOL PART + * + */ + +BIGNUM dh_prime, dh_g, g_a, dh_power, auth_key_num; +char s_power [256]; + +struct { + long long auth_key_id; + long long out_msg_id; + int msg_len; +} unenc_msg_header; + + +#define ENCRYPT_BUFFER_INTS 16384 +int encrypt_buffer[ENCRYPT_BUFFER_INTS]; + +#define DECRYPT_BUFFER_INTS 16384 +int decrypt_buffer[ENCRYPT_BUFFER_INTS]; + +int encrypt_packet_buffer (void) { + return pad_rsa_encrypt ((char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4, pubKey->n, pubKey->e); +} + +int encrypt_packet_buffer_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32]) { + init_aes_unauth (server_nonce, hidden_client_nonce, AES_ENCRYPT); + return pad_aes_encrypt ((char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4); +} + + +int rpc_send_packet (struct connection *c) { + int len = (packet_ptr - packet_buffer) * 4; + c->out_packet_num ++; + long long next_msg_id = (long long) ((1LL << 32) * get_utime (CLOCK_REALTIME)) & -4; + if (next_msg_id <= unenc_msg_header.out_msg_id) { + unenc_msg_header.out_msg_id += 4; + } else { + unenc_msg_header.out_msg_id = next_msg_id; + } + unenc_msg_header.msg_len = len; + + int total_len = len + 20; + assert (total_len > 0 && !(total_len & 0xfc000003)); + total_len >>= 2; + if (total_len < 0x7f) { + assert (write_out (c, &total_len, 1) == 1); + } else { + total_len = (total_len << 8) | 0x7f; + assert (write_out (c, &total_len, 4) == 4); + } + write_out (c, &unenc_msg_header, 20); + write_out (c, packet_buffer, len); + flush_out (c); + return 1; +} + +int rpc_send_message (struct connection *c, void *data, int len) { + assert (len > 0 && !(len & 0xfc000003)); + int total_len = len >> 2; + if (total_len < 0x7f) { + assert (write_out (c, &total_len, 1) == 1); + } else { + total_len = (total_len << 8) | 0x7f; + assert (write_out (c, &total_len, 4) == 4); + } + c->out_packet_num ++; + write_out (c, data, len); + flush_out (c); + return 1; +} + +int send_req_pq_packet (struct connection *c) { + assert (c_state == st_init); + assert (RAND_pseudo_bytes ((unsigned char *) nonce, 16) >= 0); + unenc_msg_header.out_msg_id = 0; + clear_packet (); + out_int (CODE_req_pq); + out_ints ((int *)nonce, 4); + rpc_send_packet (c); + c_state = st_reqpq_sent; + return 1; +} + + +unsigned long long gcd (unsigned long long a, unsigned long long b) { + return b ? gcd (b, a % b) : a; +} + +//typedef unsigned int uint128_t __attribute__ ((mode(TI))); +unsigned long long what; +unsigned p1, p2; + +int process_respq_answer (struct connection *c, char *packet, int len) { + int i; + if (verbosity) { + fprintf (stderr, "process_respq_answer(), len=%d\n", len); + } + assert (len >= 76); + assert (!*(long long *) packet); + assert (*(int *) (packet + 16) == len - 20); + assert (!(len & 3)); + assert (*(int *) (packet + 20) == CODE_resPQ); + assert (!memcmp (packet + 24, nonce, 16)); + memcpy (server_nonce, packet + 40, 16); + char *from = packet + 56; + int clen = *from++; + assert (clen <= 8); + what = 0; + for (i = 0; i < clen; i++) { + what = (what << 8) + (unsigned char)*from++; + } + + while (((unsigned long)from) & 3) ++from; + + p1 = 0, p2 = 0; + + if (verbosity >= 2) { + fprintf (stderr, "%lld received\n", what); + } + + int it = 0; + unsigned long long g = 0; + for (i = 0; i < 3 || it < 1000; i++) { + int q = ((lrand48() & 15) + 17) % what; + unsigned long long x = (long long)lrand48 () % (what - 1) + 1, y = x; + int lim = 1 << (i + 18); + int j; + for (j = 1; j < lim; j++) { + ++it; + unsigned long long a = x, b = x, c = q; + while (b) { + if (b & 1) { + c += a; + if (c >= what) { + c -= what; + } + } + a += a; + if (a >= what) { + a -= what; + } + b >>= 1; + } + x = c; + unsigned long long z = x < y ? what + x - y : x - y; + g = gcd (z, what); + if (g != 1) { + break; + } + if (!(j & (j - 1))) { + y = x; + } + } + if (g > 1 && g < what) break; + } + + assert (g > 1 && g < what); + p1 = g; + p2 = what / g; + if (p1 > p2) { + unsigned t = p1; p1 = p2; p2 = t; + } + + + if (verbosity) { + fprintf (stderr, "p1 = %d, p2 = %d, %d iterations\n", p1, p2, it); + } + + /// ++p1; /// + + assert (*(int *) (from) == CODE_vector); + int fingerprints_num = *(int *)(from + 4); + assert (fingerprints_num >= 1 && fingerprints_num <= 64 && len == fingerprints_num * 8 + 8 + (from - packet)); + long long *fingerprints = (long long *) (from + 8); + for (i = 0; i < fingerprints_num; i++) { + if (fingerprints[i] == pk_fingerprint) { + //fprintf (stderr, "found our public key at position %d\n", i); + break; + } + } + if (i == fingerprints_num) { + fprintf (stderr, "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); + exit (2); + } + // create inner part (P_Q_inner_data) + clear_packet (); + packet_ptr += 5; + out_int (CODE_p_q_inner_data); + out_cstring (packet + 57, clen); + //out_int (0x0f01); // pq=15 + + if (p1 < 256) { + clen = 1; + } else if (p1 < 65536) { + clen = 2; + } else if (p1 < 16777216) { + clen = 3; + } else { + clen = 4; + } + p1 = __builtin_bswap32 (p1); + out_cstring ((char *)&p1 + 4 - clen, clen); + p1 = __builtin_bswap32 (p1); + + if (p2 < 256) { + clen = 1; + } else if (p2 < 65536) { + clen = 2; + } else if (p2 < 16777216) { + clen = 3; + } else { + clen = 4; + } + p2 = __builtin_bswap32 (p2); + out_cstring ((char *)&p2 + 4 - clen, clen); + p2 = __builtin_bswap32 (p2); + + //out_int (0x0301); // p=3 + //out_int (0x0501); // q=5 + out_ints ((int *) nonce, 4); + out_ints ((int *) server_nonce, 4); + assert (RAND_pseudo_bytes ((unsigned char *) new_nonce, 32) >= 0); + out_ints ((int *) new_nonce, 8); + sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); + + int l = encrypt_packet_buffer (); + + clear_packet (); + out_int (CODE_req_DH_params); + out_ints ((int *) nonce, 4); + out_ints ((int *) server_nonce, 4); + //out_int (0x0301); // p=3 + //out_int (0x0501); // q=5 + if (p1 < 256) { + clen = 1; + } else if (p1 < 65536) { + clen = 2; + } else if (p1 < 16777216) { + clen = 3; + } else { + clen = 4; + } + p1 = __builtin_bswap32 (p1); + out_cstring ((char *)&p1 + 4 - clen, clen); + p1 = __builtin_bswap32 (p1); + if (p2 < 256) { + clen = 1; + } else if (p2 < 65536) { + clen = 2; + } else if (p2 < 16777216) { + clen = 3; + } else { + clen = 4; + } + p2 = __builtin_bswap32 (p2); + out_cstring ((char *)&p2 + 4 - clen, clen); + p2 = __builtin_bswap32 (p2); + + out_long (pk_fingerprint); + out_cstring ((char *) encrypt_buffer, l); + + c_state = st_reqdh_sent; + + return rpc_send_packet (c); +} + +int process_dh_answer (struct connection *c, char *packet, int len) { + if (verbosity) { + fprintf (stderr, "process_dh_answer(), len=%d\n", len); + } + if (len < 116) { + fprintf (stderr, "%u * %u = %llu", p1, p2, what); + } + assert (len >= 116); + assert (!*(long long *) packet); + assert (*(int *) (packet + 16) == len - 20); + assert (!(len & 3)); + assert (*(int *) (packet + 20) == (int)CODE_server_DH_params_ok); + assert (!memcmp (packet + 24, nonce, 16)); + assert (!memcmp (packet + 40, server_nonce, 16)); + init_aes_unauth (server_nonce, new_nonce, AES_DECRYPT); + in_ptr = (int *)(packet + 56); + in_end = (int *)(packet + len); + int l = prefetch_strlen (); + assert (l > 0); + l = pad_aes_decrypt (fetch_str (l), l, (char *) decrypt_buffer, DECRYPT_BUFFER_INTS * 4 - 16); + assert (in_ptr == in_end); + assert (l >= 60); + assert (decrypt_buffer[5] == (int)CODE_server_DH_inner_data); + assert (!memcmp (decrypt_buffer + 6, nonce, 16)); + assert (!memcmp (decrypt_buffer + 10, server_nonce, 16)); + assert (decrypt_buffer[14] == 2); + in_ptr = decrypt_buffer + 15; + in_end = decrypt_buffer + (l >> 2); + BN_init (&dh_prime); + BN_init (&g_a); + assert (fetch_bignum (&dh_prime) > 0); + assert (fetch_bignum (&g_a) > 0); + int server_time = *in_ptr++; + assert (in_ptr <= in_end); + + static char sha1_buffer[20]; + sha1 ((unsigned char *) decrypt_buffer + 20, (in_ptr - decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); + assert (!memcmp (decrypt_buffer, sha1_buffer, 20)); + assert ((char *) in_end - (char *) in_ptr < 16); + + GET_DC(c)->server_time_delta = server_time - time (0); + GET_DC(c)->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); + //fprintf (stderr, "server time is %d, delta = %d\n", server_time, server_time_delta); + + // Build set_client_DH_params answer + clear_packet (); + packet_ptr += 5; + out_int (CODE_client_DH_inner_data); + out_ints ((int *) nonce, 4); + out_ints ((int *) server_nonce, 4); + out_long (0LL); + + BN_init (&dh_g); + BN_set_word (&dh_g, 2); + + assert (RAND_pseudo_bytes ((unsigned char *)s_power, 256) >= 0); + BIGNUM *dh_power = BN_new (); + assert (BN_bin2bn ((unsigned char *)s_power, 256, dh_power) == dh_power); + + BIGNUM *y = BN_new (); + assert (BN_mod_exp (y, &dh_g, dh_power, &dh_prime, BN_ctx) == 1); + out_bignum (y); + BN_free (y); + + BN_init (&auth_key_num); + assert (BN_mod_exp (&auth_key_num, &g_a, dh_power, &dh_prime, BN_ctx) == 1); + l = BN_num_bytes (&auth_key_num); + assert (l >= 250 && l <= 256); + assert (BN_bn2bin (&auth_key_num, (unsigned char *)GET_DC(c)->auth_key)); + memset (GET_DC(c)->auth_key + l, 0, 256 - l); + BN_free (dh_power); + BN_free (&auth_key_num); + BN_free (&dh_g); + BN_free (&g_a); + BN_free (&dh_prime); + + //hexdump (auth_key, auth_key + 256); + + sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); + + //hexdump ((char *)packet_buffer, (char *)packet_ptr); + + l = encrypt_packet_buffer_aes_unauth (server_nonce, new_nonce); + + clear_packet (); + out_int (CODE_set_client_DH_params); + out_ints ((int *) nonce, 4); + out_ints ((int *) server_nonce, 4); + out_cstring ((char *) encrypt_buffer, l); + + c_state = st_client_dh_sent; + + return rpc_send_packet (c); +} + + +int process_auth_complete (struct connection *c UU, char *packet, int len) { + if (verbosity) { + fprintf (stderr, "process_dh_answer(), len=%d\n", len); + } + assert (len == 72); + assert (!*(long long *) packet); + assert (*(int *) (packet + 16) == len - 20); + assert (!(len & 3)); + assert (*(int *) (packet + 20) == CODE_dh_gen_ok); + assert (!memcmp (packet + 24, nonce, 16)); + assert (!memcmp (packet + 40, server_nonce, 16)); + static unsigned char tmp[44], sha1_buffer[20]; + memcpy (tmp, new_nonce, 32); + tmp[32] = 1; + sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); + GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); + memcpy (tmp + 33, sha1_buffer, 8); + sha1 (tmp, 41, sha1_buffer); + assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); + GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; + if (verbosity >= 3) { + fprintf (stderr, "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); + } + //kprintf ("OK\n"); + + //c->status = conn_error; + //sleep (1); + + c_state = st_authorized; + //return 1; + if (verbosity) { + fprintf (stderr, "Auth success\n"); + } + auth_success ++; + GET_DC(c)->flags |= 1; + write_auth_file (); + return 1; +} + +/* + * + * AUTHORIZED (MAIN) PROTOCOL PART + * + */ + +struct encrypted_message enc_msg; + +long long client_last_msg_id, server_last_msg_id; + +double get_server_time (struct dc *DC) { + if (!DC->server_time_udelta) { + DC->server_time_udelta = get_utime (CLOCK_REALTIME) - get_utime (CLOCK_MONOTONIC); + } + return get_utime (CLOCK_MONOTONIC) + DC->server_time_udelta; +} + +long long generate_next_msg_id (struct dc *DC) { + long long next_id = (long long) (get_server_time (DC) * (1LL << 32)) & -4; + if (next_id <= client_last_msg_id) { + next_id = client_last_msg_id += 4; + } else { + client_last_msg_id = next_id; + } + return next_id; +} + +void init_enc_msg (struct session *S, int useful) { + struct dc *DC = S->dc; + assert (DC->auth_key_id); + enc_msg.auth_key_id = DC->auth_key_id; + assert (DC->server_salt); + enc_msg.server_salt = DC->server_salt; + if (!S->session_id) { + assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); + } + enc_msg.session_id = S->session_id; + //enc_msg.auth_key_id2 = auth_key_id; + enc_msg.msg_id = generate_next_msg_id (DC); + //enc_msg.msg_id -= 0x10000000LL * (lrand48 () & 15); + //kprintf ("message id %016llx\n", enc_msg.msg_id); + enc_msg.seq_no = S->seq_no; + if (useful) { + enc_msg.seq_no |= 1; + } + S->seq_no += 2; +}; + +int aes_encrypt_message (struct dc *DC, struct encrypted_message *enc) { + unsigned char sha1_buffer[20]; + const int MINSZ = offsetof (struct encrypted_message, message); + const int UNENCSZ = offsetof (struct encrypted_message, server_salt); + int enc_len = (MINSZ - UNENCSZ) + enc->msg_len; + assert (enc->msg_len >= 0 && enc->msg_len <= MAX_MESSAGE_INTS * 4 - 16 && !(enc->msg_len & 3)); + sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); + //printf ("enc_len is %d\n", enc_len); + if (verbosity >= 2) { + fprintf (stderr, "sending message with sha1 %08x\n", *(int *)sha1_buffer); + } + memcpy (enc->msg_key, sha1_buffer + 4, 16); + init_aes_auth (DC->auth_key, enc->msg_key, AES_ENCRYPT); + //hexdump ((char *)enc, (char *)enc + enc_len + 24); + return pad_aes_encrypt ((char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); +} + +long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful) { + struct dc *DC = GET_DC(c); + struct session *S = c->session; + assert (S); + const int UNENCSZ = offsetof (struct encrypted_message, server_salt); + if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) { + return -1; + } + if (msg) { + memcpy (enc_msg.message, msg, msg_ints * 4); + enc_msg.msg_len = msg_ints * 4; + } else { + if ((enc_msg.msg_len & 0x80000003) || enc_msg.msg_len > MAX_MESSAGE_INTS * 4 - 16) { + return -1; + } + } + init_enc_msg (S, useful); + + //hexdump ((char *)msg, (char *)msg + (msg_ints * 4)); + int l = aes_encrypt_message (DC, &enc_msg); + //hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24); + assert (l > 0); + rpc_send_message (c, &enc_msg, l + UNENCSZ); + + return client_last_msg_id; +} + +int longpoll_count, good_messages; + +int auth_work_start (struct connection *c UU) { + return 1; +} + +void rpc_execute_answer (struct connection *c, long long msg_id UU); +void work_container (struct connection *c, long long msg_id UU) { + if (verbosity) { + fprintf (stderr, "work_container: msg_id = %lld\n", msg_id); + } + assert (fetch_int () == CODE_msg_container); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + long long id = fetch_long (); + int seqno = fetch_int (); + if (seqno & 1) { + insert_seqno (c->session, seqno); + } + int bytes = fetch_int (); + int *t = in_ptr; + rpc_execute_answer (c, id); + assert (in_ptr == t + (bytes / 4)); + } +} + +void work_new_session_created (struct connection *c, long long msg_id UU) { + if (verbosity) { + fprintf (stderr, "work_new_session_created: msg_id = %lld\n", msg_id); + } + assert (fetch_int () == (int)CODE_new_session_created); + fetch_long (); // first message id + //DC->session_id = fetch_long (); + fetch_long (); // unique_id + GET_DC(c)->server_salt = fetch_long (); +} + +void work_msgs_ack (struct connection *c UU, long long msg_id UU) { + if (verbosity) { + fprintf (stderr, "work_msgs_ack: msg_id = %lld\n", msg_id); + } + assert (fetch_int () == CODE_msgs_ack); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + long long id = fetch_long (); + query_ack (id); + } +} + +void work_rpc_result (struct connection *c UU, long long msg_id UU) { + if (verbosity) { + fprintf (stderr, "work_rpc_result: msg_id = %lld\n", msg_id); + } + assert (fetch_int () == (int)CODE_rpc_result); + long long id = fetch_long (); + int op = prefetch_int (); + if (op == CODE_rpc_error) { + query_error (id); + } else { + query_result (id); + } +} + +void rpc_execute_answer (struct connection *c, long long msg_id UU) { + int op = prefetch_int (); + switch (op) { + case CODE_msg_container: + work_container (c, msg_id); + return; + case CODE_new_session_created: + work_new_session_created (c, msg_id); + return; + case CODE_msgs_ack: + work_msgs_ack (c, msg_id); + return; + case CODE_rpc_result: + work_rpc_result (c, msg_id); + return; + } + fprintf (stderr, "Unknown message: \n"); + hexdump_in (); +} + +int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { + const int MINSZ = offsetof (struct encrypted_message, message); + const int UNENCSZ = offsetof (struct encrypted_message, server_salt); + if (verbosity) { + fprintf (stderr, "process_rpc_message(), len=%d\n", len); + } + assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); + struct dc *DC = GET_DC(c); + assert (enc->auth_key_id == DC->auth_key_id); + assert (DC->auth_key_id); + init_aes_auth (DC->auth_key + 8, enc->msg_key, AES_DECRYPT); + int l = pad_aes_decrypt ((char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); + assert (l == len - UNENCSZ); + //assert (enc->auth_key_id2 == enc->auth_key_id); + assert (!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12); + static unsigned char sha1_buffer[20]; + sha1 ((void *)&enc->server_salt, enc->msg_len + (MINSZ - UNENCSZ), sha1_buffer); + assert (!memcmp (&enc->msg_key, sha1_buffer + 4, 16)); + //assert (enc->server_salt == server_salt); //in fact server salt can change + if (DC->server_salt != enc->server_salt) { + DC->server_salt = enc->server_salt; + write_auth_file (); + } + int this_server_time = enc->msg_id >> 32LL; + double st = get_server_time (DC); + assert (this_server_time >= st - 300 && this_server_time <= st + 30); + //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); + if (verbosity >= 2) { + fprintf (stderr, "received mesage id %016llx\n", enc->msg_id); + } + server_last_msg_id = enc->msg_id; + + //*(long long *)(longpoll_query + 3) = *(long long *)((char *)(&enc->msg_id) + 0x3c); + //*(long long *)(longpoll_query + 5) = *(long long *)((char *)(&enc->msg_id) + 0x3c); + + assert (l >= (MINSZ - UNENCSZ) + 8); + //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); + if (verbosity >= 2) { + fprintf (stderr, "OK, message is good!\n"); + } + ++good_messages; + + in_ptr = enc->message; + in_end = in_ptr + (enc->msg_len / 4); + + if (enc->seq_no & 1) { + insert_seqno (c->session, enc->seq_no); + } + assert (c->session->session_id == enc->session_id); + rpc_execute_answer (c, enc->msg_id); + return 0; +} + + +int rpc_execute (struct connection *c, int op, int len) { + if (verbosity) { + fprintf (stderr, "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); + } + + if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { + fprintf (stderr, "answer too long (%d bytes), skipping\n", len); + return 0; + } + + int Response_len = len; + + assert (read_in (c, Response, Response_len) == Response_len); + Response[Response_len] = 0; + if (verbosity >= 2) { + fprintf (stderr, "have %d Response bytes\n", Response_len); + } + + setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); + int o = c_state; + if (GET_DC(c)->flags & 1) { o = st_authorized;} + switch (o) { + case st_reqpq_sent: + process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); + setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); + return 0; + case st_reqdh_sent: + process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); + setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); + return 0; + case st_client_dh_sent: + process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); + setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); + return 0; + case st_authorized: + process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); + setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); + return 0; + default: + fprintf (stderr, "fatal: cannot receive answer in state %d\n", c_state); + exit (2); + } + + return 0; +} + + +int tc_close (struct connection *c, int who) { + if (verbosity) { + fprintf (stderr, "outbound http connection #%d : closing by %d\n", c->fd, who); + } + return 0; +} + +int tc_becomes_ready (struct connection *c) { + if (verbosity) { + fprintf (stderr, "outbound connection #%d becomes ready\n", c->fd); + } + char byte = 0xef; + assert (write_out (c, &byte, 1) == 1); + flush_out (c); + + setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); + int o = c_state; + if (GET_DC(c)->flags & 1) { o = st_authorized; } + switch (o) { + case st_init: + send_req_pq_packet (c); + break; + case st_authorized: + auth_work_start (c); + break; + default: + fprintf (stderr, "c_state = %d\n", c_state); + assert (0); + } + return 0; +} + +int rpc_becomes_ready (struct connection *c) { + return tc_becomes_ready (c); +} + +int rpc_close (struct connection *c) { + return tc_close (c, 0); +} + +int auth_is_success (void) { + return auth_success; +} + +void on_start (void) { + prng_seed (0, 0); + + if (rsa_load_public_key (rsa_public_key_name) < 0) { + perror ("rsa_load_public_key"); + exit (1); + } + if (verbosity) { + fprintf (stderr, "public key '%s' loaded successfully\n", rsa_public_key_name); + } + pk_fingerprint = compute_rsa_key_fingerprint (pubKey); +} + +int auth_ok (void) { + return auth_success; +} + +void dc_authorize (struct dc *DC) { + c_state = 0; + auth_success = 0; + if (!DC->sessions[0]) { + dc_create_session (DC); + } + if (verbosity) { + fprintf (stderr, "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); + } + net_loop (0, auth_ok); +} diff --git a/mtproto-client.h b/mtproto-client.h new file mode 100644 index 0000000..200e128 --- /dev/null +++ b/mtproto-client.h @@ -0,0 +1,7 @@ +#ifndef __MTPROTO_CLIENT_H__ +#define __MTPROTO_CLIENT_H__ +#include "net.h" +void on_start (void); +long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); +void dc_authorize (struct dc *DC); +#endif diff --git a/mtproto-common.c b/mtproto-common.c new file mode 100644 index 0000000..e00845b --- /dev/null +++ b/mtproto-common.c @@ -0,0 +1,337 @@ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtproto-common.h" + +long long rsa_encrypted_chunks, rsa_decrypted_chunks; + +BN_CTX *BN_ctx; +int verbosity; + +int get_random_bytes (void *buf, int n) { + int r = 0, h = open ("/dev/random", O_RDONLY | O_NONBLOCK); + if (h >= 0) { + r = read (h, buf, n); + if (r > 0) { + if (verbosity >= 3) { + fprintf (stderr, "added %d bytes of real entropy to secure random numbers seed\n", r); + } + } + close (h); + } + + if (r < n) { + h = open ("/dev/urandom", O_RDONLY); + if (h < 0) { + return r; + } + int s = read (h, buf + r, n - r); + close (h); + if (s < 0) { + return r; + } + r += s; + } + + if (r >= (int)sizeof (long)) { + *(long *)buf ^= lrand48 (); + srand48 (*(long *)buf); + } + + return r; +} + + +void prng_seed (const char *password_filename, int password_length) { + unsigned char *a = calloc (64 + password_length, 1); + assert (a != NULL); + long long r = rdtsc (); + struct timespec T; + assert (clock_gettime(CLOCK_REALTIME, &T) >= 0); + memcpy (a, &T.tv_sec, 4); + memcpy (a+4, &T.tv_nsec, 4); + memcpy (a+8, &r, 8); + unsigned short p = getpid (); + memcpy (a + 16, &p, 2); + int s = get_random_bytes (a + 18, 32) + 18; + if (password_filename) { + int fd = open (password_filename, O_RDONLY); + if (fd < 0) { + fprintf (stderr, "Warning: fail to open password file - \"%s\", %m.\n", password_filename); + } else { + int l = read (fd, a + s, password_length); + if (l < 0) { + fprintf (stderr, "Warning: fail to read password file - \"%s\", %m.\n", password_filename); + } else { + if (verbosity > 0) { + fprintf (stderr, "read %d bytes from password file.\n", l); + } + s += l; + } + close (fd); + } + } + RAND_seed (a, s); + BN_ctx = BN_CTX_new (); + memset (a, 0, s); + free (a); +} + +int serialize_bignum (BIGNUM *b, char *buffer, int maxlen) { + int itslen = BN_num_bytes (b); + int reqlen; + if (itslen < 254) { + reqlen = itslen + 1; + } else { + reqlen = itslen + 4; + } + int newlen = (reqlen + 3) & -4; + int pad = newlen - reqlen; + reqlen = newlen; + if (reqlen > maxlen) { + return -reqlen; + } + if (itslen < 254) { + *buffer++ = itslen; + } else { + *(int *)buffer = (itslen << 8) + 0xfe; + buffer += 4; + } + int l = BN_bn2bin (b, (unsigned char *)buffer); + assert (l == itslen); + buffer += l; + while (pad --> 0) { + *buffer++ = 0; + } + return reqlen; +} + + +long long compute_rsa_key_fingerprint (RSA *key) { + static char tempbuff[4096]; + static unsigned char sha[20]; + assert (key->n && key->e); + int l1 = serialize_bignum (key->n, tempbuff, 4096); + assert (l1 > 0); + int l2 = serialize_bignum (key->e, tempbuff + l1, 4096 - l1); + assert (l2 > 0 && l1 + l2 <= 4096); + SHA1 ((unsigned char *)tempbuff, l1 + l2, sha); + return *(long long *)(sha + 12); +} + +void out_cstring (const char *str, long len) { + assert (len >= 0 && len < (1 << 24)); + assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); + char *dest = (char *) packet_ptr; + if (len < 254) { + *dest++ = len; + } else { + *packet_ptr = (len << 8) + 0xfe; + dest += 4; + } + memcpy (dest, str, len); + dest += len; + while ((long) dest & 3) { + *dest++ = 0; + } + packet_ptr = (int *) dest; +} + +void out_cstring_careful (const char *str, long len) { + assert (len >= 0 && len < (1 << 24)); + assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); + char *dest = (char *) packet_ptr; + if (len < 254) { + dest++; + if (dest != str) { + memmove (dest, str, len); + } + dest[-1] = len; + } else { + dest += 4; + if (dest != str) { + memmove (dest, str, len); + } + *packet_ptr = (len << 8) + 0xfe; + } + dest += len; + while ((long) dest & 3) { + *dest++ = 0; + } + packet_ptr = (int *) dest; +} + + +void out_data (const char *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); + packet_ptr += len >> 2; +} + +int *in_ptr, *in_end; + +int fetch_bignum (BIGNUM *x) { + int l = prefetch_strlen (); + if (l < 0) { + return l; + } + char *str = fetch_str (l); + assert (BN_bin2bn ((unsigned char *) str, l, x) == x); + return l; +} + +int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E) { + int pad = (255000 - from_len - 32) % 255 + 32; + int chunks = (from_len + pad) / 255; + int bits = BN_num_bits (N); + assert (bits >= 2041 && bits <= 2048); + assert (from_len > 0 && from_len <= 2550); + assert (size >= chunks * 256); + assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, pad) >= 0); + int i; + BIGNUM x, y; + BN_init (&x); + BN_init (&y); + rsa_encrypted_chunks += chunks; + for (i = 0; i < chunks; i++) { + BN_bin2bn ((unsigned char *) from, 255, &x); + assert (BN_mod_exp (&y, &x, E, N, BN_ctx) == 1); + unsigned l = 256 - BN_num_bytes (&y); + assert (l <= 256); + memset (to, 0, l); + BN_bn2bin (&y, (unsigned char *) to + l); + to += 256; + } + BN_free (&x); + BN_free (&y); + return chunks * 256; +} + +int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D) { + if (from_len < 0 || from_len > 0x1000 || (from_len & 0xff)) { + return -1; + } + int chunks = (from_len >> 8); + int bits = BN_num_bits (N); + assert (bits >= 2041 && bits <= 2048); + assert (size >= chunks * 255); + int i; + BIGNUM x, y; + BN_init (&x); + BN_init (&y); + for (i = 0; i < chunks; i++) { + ++rsa_decrypted_chunks; + BN_bin2bn ((unsigned char *) from, 256, &x); + assert (BN_mod_exp (&y, &x, D, N, BN_ctx) == 1); + int l = BN_num_bytes (&y); + if (l > 255) { + BN_free (&x); + BN_free (&y); + return -1; + } + assert (l >= 0 && l <= 255); + memset (to, 0, 255 - l); + BN_bn2bin (&y, (unsigned char *) to + 255 - l); + to += 255; + } + BN_free (&x); + BN_free (&y); + return chunks * 255; +} + +unsigned char aes_key_raw[32], aes_iv[32]; +AES_KEY aes_key; + +void init_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32], int encrypt) { + static unsigned char buffer[64], hash[20]; + memcpy (buffer, hidden_client_nonce, 32); + memcpy (buffer + 32, server_nonce, 16); + SHA1 (buffer, 48, aes_key_raw); + memcpy (buffer + 32, hidden_client_nonce, 32); + SHA1 (buffer, 64, aes_iv + 8); + memcpy (buffer, server_nonce, 16); + memcpy (buffer + 16, hidden_client_nonce, 32); + SHA1 (buffer, 48, hash); + memcpy (aes_key_raw + 20, hash, 12); + memcpy (aes_iv, hash + 12, 8); + memcpy (aes_iv + 28, hidden_client_nonce, 4); + if (encrypt == AES_ENCRYPT) { + AES_set_encrypt_key (aes_key_raw, 32*8, &aes_key); + } else { + AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key); + } +} + +void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt) { + static unsigned char buffer[48], hash[20]; + // sha1_a = SHA1 (msg_key + substr (auth_key, 0, 32)); + // sha1_b = SHA1 (substr (auth_key, 32, 16) + msg_key + substr (auth_key, 48, 16)); + // sha1_с = SHA1 (substr (auth_key, 64, 32) + msg_key); + // sha1_d = SHA1 (msg_key + substr (auth_key, 96, 32)); + // aes_key = substr (sha1_a, 0, 8) + substr (sha1_b, 8, 12) + substr (sha1_c, 4, 12); + // aes_iv = substr (sha1_a, 8, 12) + substr (sha1_b, 0, 8) + substr (sha1_c, 16, 4) + substr (sha1_d, 0, 8); + memcpy (buffer, msg_key, 16); + memcpy (buffer + 16, auth_key, 32); + SHA1 (buffer, 48, hash); + memcpy (aes_key_raw, hash, 8); + memcpy (aes_iv, hash + 8, 12); + + memcpy (buffer, auth_key + 32, 16); + memcpy (buffer + 16, msg_key, 16); + memcpy (buffer + 32, auth_key + 48, 16); + SHA1 (buffer, 48, hash); + memcpy (aes_key_raw + 8, hash + 8, 12); + memcpy (aes_iv + 12, hash, 8); + + memcpy (buffer, auth_key + 64, 32); + memcpy (buffer + 32, msg_key, 16); + SHA1 (buffer, 48, hash); + memcpy (aes_key_raw + 20, hash + 4, 12); + memcpy (aes_iv + 20, hash + 16, 4); + + memcpy (buffer, msg_key, 16); + memcpy (buffer + 16, auth_key + 96, 32); + SHA1 (buffer, 48, hash); + memcpy (aes_iv + 24, hash, 8); + + if (encrypt == AES_ENCRYPT) { + AES_set_encrypt_key (aes_key_raw, 32*8, &aes_key); + } else { + AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key); + } +} + +int pad_aes_encrypt (char *from, int from_len, char *to, int size) { + int padded_size = (from_len + 15) & -16; + assert (from_len > 0 && padded_size <= size); + if (from_len < padded_size) { + assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, padded_size - from_len) >= 0); + } + AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, padded_size, &aes_key, aes_iv, AES_ENCRYPT); + return padded_size; +} + +int pad_aes_decrypt (char *from, int from_len, char *to, int size) { + if (from_len <= 0 || from_len > size || (from_len & 15)) { + return -1; + } + AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, from_len, &aes_key, aes_iv, AES_DECRYPT); + return from_len; +} + + diff --git a/mtproto-common.h b/mtproto-common.h new file mode 100644 index 0000000..808aa89 --- /dev/null +++ b/mtproto-common.h @@ -0,0 +1,416 @@ +#ifndef __MTPROTO_COMMON_H__ +#define __MTPROTO_COMMON_H__ + +#include +#include +#include +#include +#include + +/* DH key exchange protocol data structures */ +#define CODE_req_pq 0x60469778 +#define CODE_resPQ 0x05162463 +#define CODE_req_DH_params 0xd712e4be +#define CODE_p_q_inner_data 0x83c95aec +#define CODE_server_DH_inner_data 0xb5890dba +#define CODE_server_DH_params_fail 0x79cb045d +#define CODE_server_DH_params_ok 0xd0e8075c +#define CODE_set_client_DH_params 0xf5045f1f +#define CODE_client_DH_inner_data 0x6643b654 +#define CODE_dh_gen_ok 0x3bcbf734 +#define CODE_dh_gen_retry 0x46dc1fb9 +#define CODE_dh_gen_fail 0xa69dae02 + +/* generic data structures */ +#define CODE_vector_long 0xc734a64e +#define CODE_vector_int 0xa03855ae +#define CODE_vector_Object 0xa351ae8e +#define CODE_vector 0x1cb5c415 + +/* service messages */ +#define CODE_rpc_result 0xf35c6d01 +#define CODE_rpc_error 0x2144ca19 +#define CODE_msg_container 0x73f1f8dc +#define CODE_msg_copy 0xe06046b2 +#define CODE_http_wait 0x9299359f +#define CODE_msgs_ack 0x62d6b459 +#define CODE_bad_msg_notification 0xa7eff811 +#define CODE_bad_server_salt 0xedab447b +#define CODE_msgs_state_req 0xda69fb52 +#define CODE_msgs_state_info 0x04deb57d +#define CODE_msgs_all_info 0x8cc0d131 +#define CODE_new_session_created 0x9ec20908 +#define CODE_msg_resend_req 0x7d861a08 +#define CODE_ping 0x7abe77ec +#define CODE_pong 0x347773c5 +#define CODE_destroy_session 0xe7512126 +#define CODE_destroy_session_ok 0xe22045fc +#define CODE_destroy_session_none 0x62d350c9 +#define CODE_destroy_sessions 0x9a6face8 +#define CODE_destroy_sessions_res 0xa8164668 +#define CODE_get_future_salts 0xb921bd04 +#define CODE_future_salt 0x0949d9dc +#define CODE_future_salts 0xae500895 +#define CODE_rpc_drop_answer 0x58e4a740 +#define CODE_rpc_answer_unknown 0x5e2ad36e +#define CODE_rpc_answer_dropped_running 0xcd78e586 +#define CODE_rpc_answer_dropped 0xa43ad8b7 +#define CODE_msg_detailed_info 0x276d3ec6 +#define CODE_msg_new_detailed_info 0x809db6df +#define CODE_ping_delay_disconnect 0xf3427b8c + +/* sample rpc query/response structures */ +#define CODE_getUser 0xb0f732d5 +#define CODE_getUsers 0x2d84d5f5 +#define CODE_user 0xd23c81a3 +#define CODE_no_user 0xc67599d1 + +#define CODE_msgs_random 0x12345678 +#define CODE_random_msg 0x87654321 + +#define RPC_INVOKE_REQ 0x2374df3d +#define RPC_INVOKE_KPHP_REQ 0x99a37fda +#define RPC_REQ_RUNNING 0x346d5efa +#define RPC_REQ_ERROR 0x7ae432f5 +#define RPC_REQ_RESULT 0x63aeda4e +#define RPC_READY 0x6a34cac7 +#define RPC_STOP_READY 0x59d86654 +#define RPC_SEND_SESSION_MSG 0x1ed5a3cc +#define RPC_RESPONSE_INDIRECT 0x2194f56e + +/* RPC for workers */ +#define CODE_send_session_msg 0x81bb412c +#define CODE_sendMsgOk 0x29841ee2 +#define CODE_sendMsgNoSession 0x2b2b9e78 +#define CODE_sendMsgFailed 0x4b0cbd57 +#define CODE_get_auth_sessions 0x611f7845 +#define CODE_authKeyNone 0x8a8bc1f3 +#define CODE_authKeySessions 0x6b7f026c +#define CODE_add_session_box 0xe707e295 +#define CODE_set_session_box 0x193d4231 +#define CODE_replace_session_box 0xcb101b49 +#define CODE_replace_session_box_cas 0xb2bbfa78 +#define CODE_delete_session_box 0x01b78d81 +#define CODE_delete_session_box_cas 0xb3fdc3c5 +#define CODE_session_box_no_session 0x43f46c33 +#define CODE_session_box_created 0xe1dd5d40 +#define CODE_session_box_replaced 0xbd9cb6b2 +#define CODE_session_box_deleted 0xaf8fd05e +#define CODE_session_box_not_found 0xb3560a7f +#define CODE_session_box_found 0x560fe356 +#define CODE_session_box_changed 0x014b31b8 +#define CODE_get_session_box 0x8793a924 +#define CODE_get_session_box_cond 0x7888fab6 +#define CODE_session_box_session_absent 0x9e234062 +#define CODE_session_box_absent 0xa1a106eb +#define CODE_session_box 0x7956cd97 +#define CODE_session_box_large 0xb568d189 +#define CODE_get_sessions_activity 0x059dc5f6 +#define CODE_sessions_activities 0x60ce5b1d +#define CODE_get_session_activity 0x96dbac11 +#define CODE_session_activity 0xe175e8e0 + +/* RPC for front/proxy */ +#define RPC_FRONT 0x27a456f3 +#define RPC_FRONT_ACK 0x624abd23 +#define RPC_FRONT_ERR 0x71dda175 +#define RPC_PROXY_REQ 0x36cef1ee +#define RPC_PROXY_ANS 0x4403da0d +#define RPC_CLOSE_CONN 0x1fcf425d +#define RPC_CLOSE_EXT 0x5eb634a2 +#define RPC_SIMPLE_ACK 0x3bac409b + + + +#define CODE_auth_send_code 0xd16ff372 +#define CODE_auth_sent_code 0x2215bcbd +#define CODE_help_get_config 0xc4f9186b +#define CODE_config 0x232d5905 +#define CODE_dc_option 0x2ec2a43c +#define CODE_bool_false 0xbc799737 +#define CODE_bool_true 0x997275b5 +#define CODE_user_self 0x720535ec +#define CODE_auth_authorization 0xf6b673a4 +#define CODE_user_profile_photo_empty 0x4f11bae1 +#define CODE_user_profile_photo 0x990d1493 +#define CODE_user_status_empty 0x9d05049 +#define CODE_user_status_online 0xedb93949 +#define CODE_user_status_offline 0x8c703f +#define CODE_sign_in 0xbcd51581 +#define CODE_file_location 0x53d69076 +#define CODE_file_location_unavailable 0x7c596b46 +#define CODE_contacts_get_contacts 0x22c6aa08 +#define CODE_contacts_contacts 0x6f8b8cb2 +#define CODE_contact 0xf911c994 +#define CODE_user_empty 0x200250ba +#define CODE_user_contact 0xf2fb8319 +#define CODE_user_request 0x22e8ceb0 +#define CODE_user_foreign 0x5214c89d +#define CODE_user_deleted 0xb29ad7cc +#define CODE_gzip_packed 0x3072cfa1 + + +/* not really a limit, for struct encrypted_message only */ +// #define MAX_MESSAGE_INTS 16384 +#define MAX_MESSAGE_INTS 1048576 +#define MAX_PROTO_MESSAGE_INTS 1048576 + +#pragma pack(push,4) +struct encrypted_message { + // unencrypted header + long long auth_key_id; + char msg_key[16]; + // encrypted part, starts with encrypted header + long long server_salt; + long long session_id; + // long long auth_key_id2; // removed + // first message follows + long long msg_id; + int seq_no; + int msg_len; // divisible by 4 + int message[MAX_MESSAGE_INTS]; +}; + +struct worker_descr { + int addr; + int port; + int pid; + int start_time; + int id; +}; + +struct rpc_ready_packet { + int len; + int seq_num; + int type; + struct worker_descr worker; + int worker_ready_cnt; + int crc32; +}; + + +struct front_descr { + int addr; + int port; + int pid; + int start_time; + int id; +}; + +struct rpc_front_packet { + int len; + int seq_num; + int type; + struct front_descr front; + long long hash_mult; + int rem, mod; + int crc32; +}; + +struct middle_descr { + int addr; + int port; + int pid; + int start_time; + int id; +}; + +struct rpc_front_ack { + int len; + int seq_num; + int type; + struct middle_descr middle; + int crc32; +}; + +struct rpc_front_err { + int len; + int seq_num; + int type; + int errcode; + struct middle_descr middle; + long long hash_mult; + int rem, mod; + int crc32; +}; + +struct rpc_proxy_req { + int len; + int seq_num; + int type; + int flags; + long long ext_conn_id; + unsigned char remote_ipv6[16]; + int remote_port; + unsigned char our_ipv6[16]; + int our_port; + int data[]; +}; + +#define PROXY_HDR(__x) ((struct rpc_proxy_req *)((__x) - offsetof(struct rpc_proxy_req, data))) + +struct rpc_proxy_ans { + int len; + int seq_num; + int type; + int flags; // +16 = small error packet, +8 = flush immediately + long long ext_conn_id; + int data[]; +}; + +struct rpc_close_conn { + int len; + int seq_num; + int type; + long long ext_conn_id; + int crc32; +}; + +struct rpc_close_ext { + int len; + int seq_num; + int type; + long long ext_conn_id; + int crc32; +}; + +struct rpc_simple_ack { + int len; + int seq_num; + int type; + long long ext_conn_id; + int confirm_key; + int crc32; +}; + +#pragma pack(pop) + +BN_CTX *BN_ctx; + +void prng_seed (const char *password_filename, int password_length); +int serialize_bignum (BIGNUM *b, char *buffer, int maxlen); +long long compute_rsa_key_fingerprint (RSA *key); + +#define PACKET_BUFFER_SIZE (16384 * 100) // temp fix +int packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr; + +static inline void out_ints (int *what, int len) { + assert (packet_ptr + len <= packet_buffer + PACKET_BUFFER_SIZE); + memcpy (packet_ptr, what, len * 4); + packet_ptr += len; +} + + +static inline void out_int (int x) { + assert (packet_ptr + 1 <= packet_buffer + PACKET_BUFFER_SIZE); + *packet_ptr++ = x; +} + + +static inline void out_long (long long x) { + assert (packet_ptr + 2 <= packet_buffer + PACKET_BUFFER_SIZE); + *(long long *)packet_ptr = x; + packet_ptr += 2; +} + +static inline void clear_packet (void) { + packet_ptr = packet_buffer; +} + +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); + +static inline void out_string (const char *str) { + out_cstring (str, strlen (str)); +} + +static inline void out_bignum (BIGNUM *n) { + int l = serialize_bignum (n, (char *)packet_ptr, (PACKET_BUFFER_SIZE - (packet_ptr - packet_buffer)) * 4); + assert (l > 0); + packet_ptr += l >> 2; +} + +extern int *in_ptr, *in_end; + +static inline int prefetch_strlen (void) { + if (in_ptr >= in_end) { + return -1; + } + unsigned l = *in_ptr; + if ((l & 0xff) < 0xfe) { + l &= 0xff; + return (in_end >= in_ptr + (l >> 2) + 1) ? (int)l : -1; + } else if ((l & 0xff) == 0xfe) { + l >>= 8; + return (l >= 254 && in_end >= in_ptr + ((l + 7) >> 2)) ? (int)l : -1; + } else { + return -1; + } +} + + +static inline char *fetch_str (int len) { + if (len < 254) { + char *str = (char *) in_ptr + 1; + in_ptr += 1 + (len >> 2); + return str; + } else { + char *str = (char *) in_ptr + 4; + in_ptr += (len + 7) >> 2; + return str; + } +} + +static inline char *fetch_str_dup (void) { + int l = prefetch_strlen (); + return strndup (fetch_str (l), l); +} + +static __inline__ unsigned long long rdtsc(void) { + unsigned hi, lo; + __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); + return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); +} + +static inline long have_prefetch_ints (void) { + return in_end - in_ptr; +} + +int fetch_bignum (BIGNUM *x); + +static inline int fetch_int (void) { + return *(in_ptr ++); +} + +static inline int prefetch_int (void) { + return *(in_ptr); +} + +static inline long long fetch_long (void) { + long long r = *(long long *)in_ptr; + in_ptr += 2; + return r; +} + +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); +int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D); + +extern long long rsa_encrypted_chunks, rsa_decrypted_chunks; + +extern unsigned char aes_key_raw[32], aes_iv[32]; +extern AES_KEY aes_key; + +void init_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32], int encrypt); +void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt); +int pad_aes_encrypt (char *from, int from_len, char *to, int size); +int pad_aes_decrypt (char *from, int from_len, char *to, int size); + +static inline void hexdump_in (void) { + int *ptr = in_ptr; + while (ptr < in_end) { fprintf (stderr, " %08x", *(ptr ++)); } + fprintf (stderr, "\n"); +} +#endif diff --git a/net.c b/net.c new file mode 100644 index 0000000..69e5c4c --- /dev/null +++ b/net.c @@ -0,0 +1,436 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "net.h" +#include "include.h" +#include "mtproto-client.h" +#include "mtproto-common.h" +#include "tree.h" + +DEFINE_TREE(int,int,int_cmp,0) + +int verbosity; +extern struct connection_methods auth_methods; + +struct connection_buffer *new_connection_buffer (int size) { + struct connection_buffer *b = malloc (sizeof (*b)); + memset (b, 0, sizeof (*b)); + b->start = malloc (size); + b->end = b->start + size; + b->rptr = b->wptr = b->start; + return b; +} + +void delete_connection_buffer (struct connection_buffer *b) { + free (b->start); + free (b); +} + +int write_out (struct connection *c, const void *data, int len) { + if (!len) { return 0; } + assert (len > 0); + int x = 0; + if (!c->out_head) { + struct connection_buffer *b = new_connection_buffer (1 << 20); + c->out_head = c->out_tail = b; + } + while (len) { + if (c->out_tail->end - c->out_tail->wptr >= len) { + memcpy (c->out_tail->wptr, data, len); + c->out_tail->wptr += len; + c->out_bytes += len; + return x + len; + } else { + int y = c->out_tail->end - c->out_tail->wptr; + assert (y < len); + memcpy (c->out_tail->wptr, data, y); + x += y; + len -= y; + data += y; + struct connection_buffer *b = new_connection_buffer (1 << 20); + c->out_tail->next = b; + b->next = 0; + c->out_tail = b; + c->out_bytes += y; + } + } + return x; +} + +int read_in (struct connection *c, void *data, int len) { + if (!len) { return 0; } + assert (len > 0); + if (len > c->in_bytes) { + len = c->in_bytes; + } + int x = 0; + while (len) { + int y = c->in_head->wptr - c->in_head->rptr; + if (y > len) { + memcpy (data, c->in_head->rptr, len); + c->in_head->rptr += len; + c->in_bytes -= len; + return x + len; + } else { + memcpy (data, c->in_head->rptr, y); + c->in_bytes -= y; + x += y; + data += y; + len -= y; + void *old = c->in_head; + c->in_head = c->in_head->next; + if (!c->in_head) { + c->in_tail = 0; + } + delete_connection_buffer (old); + } + } + return x; +} + +int read_in_lookup (struct connection *c, void *data, int len) { + if (!len) { return 0; } + assert (len > 0); + if (len > c->in_bytes) { + len = c->in_bytes; + } + int x = 0; + struct connection_buffer *b = c->in_head; + while (len) { + int y = b->wptr - b->rptr; + if (y > len) { + memcpy (data, b->rptr, len); + return x + len; + } else { + memcpy (data, b->rptr, y); + x += y; + b = b->next; + } + } + return x; +} + +void flush_out (struct connection *c UU) { +} + +#define MAX_CONNECTIONS 100 +struct connection *Connections[MAX_CONNECTIONS]; +int max_connection_fd; + +struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods) { + struct connection *c = malloc (sizeof (*c)); + memset (c, 0, sizeof (*c)); + struct hostent *h; + if (!(h = gethostbyname (host)) || h->h_addrtype != AF_INET || h->h_length != 4 || !h->h_addr_list || !h->h_addr) { + assert (0); + } + int fd; + assert ((fd = socket (AF_INET, SOCK_STREAM, 0)) != -1); + assert (fd >= 0 && fd < MAX_CONNECTIONS); + if (fd > max_connection_fd) { + max_connection_fd = fd; + } + int flags = -1; + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); + setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)); + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags)); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + addr.sin_addr.s_addr = inet_addr (host); + + + fcntl (fd, F_SETFL, O_NONBLOCK); + + if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { + if (errno != EINPROGRESS) { + fprintf (stderr, "Can not connect to %s:%d %m\n", host, port); + close (fd); + free (c); + return 0; + } + } + + struct pollfd s; + s.fd = fd; + s.events = POLLOUT | POLLERR | POLLRDHUP | POLLHUP; + + if (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { + perror ("poll"); + close (fd); + free (c); + return 0; + } + + c->session = session; + c->fd = fd; + c->ip = htonl (*(int *)h->h_addr); + c->flags = 0; + c->state = conn_ready; + c->methods = methods; + assert (!Connections[fd]); + Connections[fd] = c; + if (verbosity) { + fprintf (stderr, "connect to %s:%d successful\n", host, port); + } + if (c->methods->ready) { + c->methods->ready (c); + } + return c; +} + +void fail_connection (struct connection *c) { + struct connection_buffer *b = c->out_head; + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + b = c->in_head; + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + c->out_head = c->out_tail = c->in_head = c->in_tail = 0; + c->state = conn_failed; + c->out_bytes = c->in_bytes = 0; +} + +void try_write (struct connection *c) { + if (verbosity) { + fprintf (stderr, "try write: fd = %d\n", c->fd); + } + int x = 0; + while (c->out_head) { + int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + if (r >= 0) { + x += r; + c->out_head->rptr += r; + if (c->out_head->rptr != c->out_head->wptr) { + break; + } + struct connection_buffer *b = c->out_head; + c->out_head = b->next; + if (!c->out_head) { + c->out_tail = 0; + } + delete_connection_buffer (b); + } else { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + fail_connection (c); + return; + } else { + break; + } + } + } + if (verbosity) { + fprintf (stderr, "Sent %d bytes to %d\n", x, c->fd); + } + c->out_bytes -= x; +} + +void hexdump (struct connection_buffer *b) { + int pos = 0; + int rem = 8; + while (b) { + unsigned char *c = b->rptr; + while (c != b->wptr) { + if (rem == 8) { + if (pos) { printf ("\n"); } + printf ("%04d", pos); + } + printf (" %02x", (int)*c); + rem --; + pos ++; + if (!rem) { + rem = 8; + } + c ++; + } + b = b->next; + } + printf ("\n"); + +} + +void try_rpc_read (struct connection *c) { + assert (c->in_head); + if (verbosity >= 4) { + hexdump (c->in_head); + } + + while (1) { + if (c->in_bytes < 1) { return; } + unsigned len = 0; + unsigned t = 0; + assert (read_in_lookup (c, &len, 1) == 1); + if (len >= 1 && len <= 0x7e) { + if (c->in_bytes < (int)(4 * len)) { return; } + } else { + if (c->in_bytes < 4) { return; } + assert (read_in_lookup (c, &len, 4) == 4); + len = (len >> 8); + if (c->in_bytes < (int)(4 * len)) { return; } + len = 0x7f; + } + + if (len >= 1 && len <= 0x7e) { + assert (read_in (c, &t, 1) == 1); + assert (t == len); + assert (len >= 1); + } else { + assert (len == 0x7f); + assert (read_in (c, &len, 4) == 4); + len = (len >> 8); + assert (len >= 1); + } + len *= 4; + int op; + assert (read_in_lookup (c, &op, 4) == 4); + c->methods->execute (c, op, len); + } +} + +void try_read (struct connection *c) { + if (verbosity) { + fprintf (stderr, "try read: fd = %d\n", c->fd); + } + if (!c->in_tail) { + c->in_head = c->in_tail = new_connection_buffer (1 << 20); + } + int x = 0; + while (1) { + int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); + if (r >= 0) { + c->in_tail->wptr += r; + x += r; + if (c->in_tail->wptr != c->in_tail->end) { + break; + } + struct connection_buffer *b = new_connection_buffer (1 << 20); + c->in_tail->next = b; + c->in_tail = b; + } else { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + fail_connection (c); + return; + } else { + break; + } + } + } + if (verbosity) { + fprintf (stderr, "Received %d bytes from %d\n", x, c->fd); + } + c->in_bytes += x; + if (x) { + try_rpc_read (c); + } +} + +int connections_make_poll_array (struct pollfd *fds, int max) { + int _max = max; + int i; + for (i = 0; i <= max_connection_fd; i++) if (Connections[i] && Connections[i]->state != conn_failed) { + assert (max > 0); + struct connection *c = Connections[i]; + fds[0].fd = c->fd; + fds[0].events = POLLERR | POLLHUP | POLLRDHUP | POLLIN; + if (c->out_bytes || c->state == conn_connecting) { + fds[0].events |= POLLOUT; + } + fds ++; + max --; + } + if (verbosity >= 3) { + fprintf (stderr, "%d connections in poll\n", _max - max); + } + return _max - max; +} + +void connections_poll_result (struct pollfd *fds, int max) { + if (verbosity >= 2) { + fprintf (stderr, "connections_poll_result: max = %d\n", max); + } + int i; + for (i = 0; i < max; i++) { + struct connection *c = Connections[fds[i].fd]; + if (fds[i].revents & POLLIN) { + try_read (c); + } + if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) { + if (verbosity) { + fprintf (stderr, "fail connection\n"); + } + fail_connection (c); + } else if (fds[i].revents & POLLOUT) { + if (c->state == conn_connecting) { + c->state = conn_ready; + } + if (c->out_bytes) { + try_write (c); + } + } + } +} + +int send_all_acks (struct session *S) { + clear_packet (); + out_int (tree_count_int (S->ack_tree)); + while (S->ack_tree) { + int x = tree_get_min_int (S->ack_tree); + out_int (x); + S->ack_tree = tree_delete_int (S->ack_tree, x); + } + encrypt_send_message (S->c, packet_buffer, packet_ptr - packet_buffer, 0); + return 0; +} + +void insert_seqno (struct session *S, int seqno) { + if (!S->ack_tree) { + S->ev.alarm = (void *)send_all_acks; + S->ev.self = (void *)S; + S->ev.timeout = get_double_time () + ACK_TIMEOUT; + insert_event_timer (&S->ev); + } + if (!tree_lookup_int (S->ack_tree, seqno)) { + S->ack_tree = tree_insert_int (S->ack_tree, seqno, lrand48 ()); + } +} + +extern struct dc *DC_list[]; + +struct dc *alloc_dc (int id, char *ip, int port) { + assert (!DC_list[id]); + struct dc *DC = malloc (sizeof (*DC)); + memset (DC, 0, sizeof (*DC)); + DC->id = id; + DC->ip = ip; + DC->port = port; + DC_list[id] = DC; + return DC; +} + +void dc_create_session (struct dc *DC) { + struct session *S = malloc (sizeof (*S)); + memset (S, 0, sizeof (*S)); + assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); + S->dc = DC; + S->c = create_connection (DC->ip, DC->port, S, &auth_methods); + assert (!DC->sessions[0]); + DC->sessions[0] = S; +} diff --git a/net.h b/net.h new file mode 100644 index 0000000..e934920 --- /dev/null +++ b/net.h @@ -0,0 +1,121 @@ +#ifndef __NET_H__ +#define __NET_H__ + +#include +struct dc; +#include "queries.h" +#define TG_SERVER "173.240.5.1" +//#define TG_SERVER "95.142.192.66" +#define TG_APP_HASH "3bc14c6455ef1595ec86a125762c3aad" +#define TG_APP_ID 51 + +#define ACK_TIMEOUT 60 +#define MAX_DC_ID 10 + +enum dc_state{ + st_init, + st_reqpq_sent, + st_reqdh_sent, + st_client_dh_sent, + st_authorized, + st_error +} ; + +struct connection; +struct connection_methods { + int (*ready) (struct connection *c); + int (*close) (struct connection *c); + int (*execute) (struct connection *c, int op, int len); +}; + + +#define MAX_DC_SESSIONS 3 + +struct session { + struct dc *dc; + long long session_id; + int seq_no; + struct connection *c; + struct tree_int *ack_tree; + struct event_timer ev; +}; + +struct dc { + int id; + int port; + int flags; + char *ip; + char *user; + struct session *sessions[MAX_DC_SESSIONS]; + char auth_key[256]; + long long auth_key_id; + long long server_salt; + + int server_time_delta; + double server_time_udelta; +}; + +#define DC_SERIALIZED_MAGIC 0x64582faa +struct dc_serialized { + int magic; + int port; + char ip[64]; + char user[64]; + char auth_key[256]; + long long auth_key_id, server_salt; + int authorized; +}; + +struct connection_buffer { + void *start; + void *end; + void *rptr; + void *wptr; + struct connection_buffer *next; +}; + +enum conn_state { + conn_none, + conn_connecting, + conn_ready, + conn_failed, + conn_stopped +}; + +struct connection { + int fd; + int ip; + int port; + int flags; + enum conn_state state; + int ipv6[4]; + struct connection_buffer *in_head; + struct connection_buffer *in_tail; + struct connection_buffer *out_head; + struct connection_buffer *out_tail; + int in_bytes; + int out_bytes; + int packet_num; + int out_packet_num; + struct connection_methods *methods; + struct session *session; + void *extra; +}; + +extern struct connection *Connections[]; + +int write_out (struct connection *c, const void *data, int len); +void flush_out (struct connection *c); +int read_in (struct connection *c, void *data, int len); + +void create_all_outbound_connections (void); + +struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods); +int connections_make_poll_array (struct pollfd *fds, int max); +void connections_poll_result (struct pollfd *fds, int max); +void dc_create_session (struct dc *DC); +void insert_seqno (struct session *S, int seqno); +struct dc *alloc_dc (int id, char *ip, int port); + +#define GET_DC(c) (c->session->dc) +#endif diff --git a/queries.c b/queries.c new file mode 100644 index 0000000..13b21ca --- /dev/null +++ b/queries.c @@ -0,0 +1,404 @@ +#include +#include +#include +#include + +#include "include.h" +#include "mtproto-client.h" +#include "queries.h" +#include "tree.h" +#include "mtproto-common.h" +#include "telegram.h" +#include "loop.h" +#include "structures.h" +#include "interface.h" + +int verbosity; + +#define QUERY_TIMEOUT 0.3 + +#define memcmp8(a,b) memcmp ((a), (b), 8) +DEFINE_TREE (query, struct query *, memcmp8, 0) ; +struct tree_query *queries_tree; + +double get_double_time (void) { + struct timespec tv; + clock_gettime (CLOCK_REALTIME, &tv); + return tv.tv_sec + 1e-9 * tv.tv_nsec; +} + +struct query *query_get (long long id) { + return tree_lookup_query (queries_tree, (void *)&id); +} + +int alarm_query (struct query *q) { + assert (q); + return 0; +} + +struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods) { + assert (DC); + assert (DC->auth_key_id); + if (!DC->sessions[0]) { + dc_create_session (DC); + } + if (verbosity) { + fprintf (stderr, "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); + } + struct query *q = malloc (sizeof (*q)); + q->data_len = ints; + q->data = malloc (4 * ints); + memcpy (q->data, data, 4 * ints); + q->msg_id = encrypt_send_message (DC->sessions[0]->c, data, ints, 1); + if (verbosity) { + fprintf (stderr, "Msg_id is %lld\n", q->msg_id); + } + q->methods = methods; + if (queries_tree) { + fprintf (stderr, "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + } + queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); + + q->ev.alarm = (void *)alarm_query; + q->ev.timeout = get_double_time () + QUERY_TIMEOUT; + q->ev.self = (void *)q; + insert_event_timer (&q->ev); + return q; +} + +void query_ack (long long id) { + struct query *q = query_get (id); + if (q) { q->flags |= QUERY_ACK_RECEIVED; } +} + +void query_error (long long id) { + assert (fetch_int () == CODE_rpc_error); + int error_code = fetch_int (); + int error_len = prefetch_strlen (); + char *error = fetch_str (error_len); + if (verbosity) { + fprintf (stderr, "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); + } + struct query *q = query_get (id); + if (!q) { + if (verbosity) { + fprintf (stderr, "No such query\n"); + } + } else { + remove_event_timer (&q->ev); + queries_tree = tree_delete_query (queries_tree, q); + if (q->methods && q->methods->on_error) { + q->methods->on_error (q, error_code, error_len, error); + } + free (q->data); + free (q); + } +} + +#define MAX_PACKED_SIZE (1 << 20) +static int packed_buffer[MAX_PACKED_SIZE / 4]; + +void query_result (long long id UU) { + if (verbosity) { + fprintf (stderr, "result for query #%lld\n", id); + } + if (verbosity >= 4) { + fprintf (stderr, "result: "); + hexdump_in (); + } + int op = prefetch_int (); + int *end = 0; + int *eend = 0; + if (op == CODE_gzip_packed) { + fetch_int (); + int l = prefetch_strlen (); + char *s = fetch_str (l); + size_t dl = MAX_PACKED_SIZE; + + z_stream strm = {0}; + assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); + strm.avail_in = l; + strm.next_in = (void *)s; + strm.avail_out = MAX_PACKED_SIZE; + strm.next_out = (void *)packed_buffer; + + int err = inflate (&strm, Z_FINISH); + if (verbosity) { + fprintf (stderr, "inflate error = %d\n", err); + fprintf (stderr, "inflated %d bytes\n", (int)strm.total_out); + } + end = in_ptr; + eend = in_end; + assert (dl % 4 == 0); + in_ptr = packed_buffer; + in_end = in_ptr + strm.total_out / 4; + if (verbosity >= 4) { + fprintf (stderr, "Unzipped data: "); + hexdump_in (); + } + } + struct query *q = query_get (id); + if (!q) { + if (verbosity) { + fprintf (stderr, "No such query\n"); + } + } else { + remove_event_timer (&q->ev); + queries_tree = tree_delete_query (queries_tree, q); + if (q->methods && q->methods->on_answer) { + q->methods->on_answer (q); + } + free (q->data); + free (q); + } + if (end) { + in_ptr = end; + in_end = eend; + } +} + +#define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) +DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) +struct tree_timer *timer_tree; + +void insert_event_timer (struct event_timer *ev) { + return; + fprintf (stderr, "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + tree_check_timer (timer_tree); + timer_tree = tree_insert_timer (timer_tree, ev, lrand48 ()); + tree_check_timer (timer_tree); +} + +void remove_event_timer (struct event_timer *ev) { + return; + fprintf (stderr, "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + tree_check_timer (timer_tree); + timer_tree = tree_delete_timer (timer_tree, ev); + tree_check_timer (timer_tree); +} + +double next_timer_in (void) { + if (!timer_tree) { return 1e100; } + return tree_get_min_timer (timer_tree)->timeout; +} + +void work_timers (void) { + double t = get_double_time (); + while (timer_tree) { + struct event_timer *ev = tree_get_min_timer (timer_tree); + assert (ev); + if (ev->timeout > t) { break; } + remove_event_timer (ev); + ev->alarm (ev->self); + } +} + +int max_chat_size; +int want_dc_num; +extern struct dc *DC_list[]; +extern struct dc *DC_working; + +int help_get_config_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_config); + fetch_int (); + + unsigned test_mode = fetch_int (); + assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false); + assert (test_mode == CODE_bool_false); + int this_dc = fetch_int (); + if (verbosity) { + fprintf (stderr, "this_dc = %d\n", this_dc); + } + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + assert (n <= 10); + int i; + for (i = 0; i < n; i++) { + assert (fetch_int () == CODE_dc_option); + int id = fetch_int (); + int l1 = prefetch_strlen (); + char *name = fetch_str (l1); + int l2 = prefetch_strlen (); + char *ip = fetch_str (l2); + int port = fetch_int (); + if (verbosity) { + fprintf (stderr, "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + } + if (!DC_list[id]) { + alloc_dc (id, strndup (ip, l2), port); + } + } + max_chat_size = fetch_int (); + if (verbosity >= 2) { + fprintf (stderr, "chat_size = %d\n", max_chat_size); + } + return 0; +} + +struct query_methods help_get_config_methods = { + .on_answer = help_get_config_on_answer +}; + +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); + int l = prefetch_strlen (); + char *s = fetch_str (l); + if (phone_code_hash) { + free (phone_code_hash); + } + phone_code_hash = strndup (s, l); + want_dc_num = -1; + return 0; +} + +int send_code_on_error (struct query *q UU, int error_code, int l, char *error) { + int s = strlen ("PHONE_MIGRATE_"); + if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { + int i = error[s] - '0'; + want_dc_num = i; + } else { + fprintf (stderr, "error_code = %d, error = %.*s\n", error_code, l, error); + assert (0); + } + return 0; +} + +struct query_methods send_code_methods = { + .on_answer = send_code_on_answer, + .on_error = send_code_on_error +}; + +int code_is_sent (void) { + return want_dc_num; +} + +int config_got (void) { + return DC_list[want_dc_num] != 0; +} + +char *suser; +extern int dc_working_num; +void do_send_code (const char *user) { + suser = strdup (user); + want_dc_num = 0; + clear_packet (); + out_int (CODE_auth_send_code); + out_string (user); + out_int (0); + out_int (TG_APP_ID); + out_string (TG_APP_HASH); + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods); + 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); + 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; + } + want_dc_num = 0; + clear_packet (); + out_int (CODE_auth_send_code); + out_string (user); + out_int (0); + out_int (TG_APP_ID); + out_string (TG_APP_HASH); + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods); + net_loop (0, code_is_sent); + assert (want_dc_num == -1); +} + +int sign_in_ok; +int sign_in_is_ok (void) { + return sign_in_ok; +} + +struct user User; + +int sign_in_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_auth_authorization); + int expires = fetch_int (); + fetch_user (&User); + sign_in_ok = 1; + if (verbosity) { + fprintf (stderr, "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); + } + return 0; +} + +int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { + fprintf (stderr, "error_code = %d, error = %.*s\n", error_code, l, error); + sign_in_ok = -1; + return 0; +} + +struct query_methods sign_in_methods = { + .on_answer = sign_in_on_answer, + .on_error = sign_in_on_error +}; + +int do_send_code_result (const char *code) { + clear_packet (); + out_int (CODE_sign_in); + out_string (suser); + out_string (phone_code_hash); + out_string (code); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods); + sign_in_ok = 0; + net_loop (0, sign_in_is_ok); + return sign_in_ok; +} + +int get_contacts_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_contacts_contacts); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + assert (fetch_int () == (int)CODE_contact); + fetch_int (); // id + fetch_int (); // mutual + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + struct user User; + fetch_user (&User); + rprintf ("User: id = %d, first_name = %s, last_name = %s\n", User.id, User.first_name, User.last_name); + } + return 0; +} + +struct query_methods get_contacts_methods = { + .on_answer = get_contacts_on_answer, +}; + + +void do_update_contact_list (void) { + clear_packet (); + out_int (CODE_contacts_get_contacts); + out_string (""); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods); +} diff --git a/queries.h b/queries.h new file mode 100644 index 0000000..3f812e2 --- /dev/null +++ b/queries.h @@ -0,0 +1,47 @@ +#include "net.h" +#ifndef __QUERIES_H__ +#define __QUERIES_H__ + +#define QUERY_ACK_RECEIVED 1 + +struct query; +struct query_methods { + int (*on_answer)(struct query *q); + int (*on_error)(struct query *q, int error_code, int len, char *error); + int (*on_timeout)(struct query *q); +}; + +struct event_timer { + double timeout; + int (*alarm)(void *self); + void *self; +}; + +struct query { + long long msg_id; + int data_len; + int flags; + void *data; + struct query_methods *methods; + struct event_timer ev; +}; + + +struct query *send_query (struct dc *DC, int len, void *data, struct query_methods *methods); +void query_ack (long long id); +void query_error (long long id); +void query_result (long long id); + +void insert_event_timer (struct event_timer *ev); +void remove_event_timer (struct event_timer *ev); +double next_timer_in (void); +void work_timers (void); + +extern struct query_methods help_get_config_methods; + +void do_send_code (const char *user); +int do_send_code_result (const char *code); +double get_double_time (void); + +void do_update_contact_list (void); +#endif diff --git a/structures.c b/structures.c new file mode 100644 index 0000000..aad5eb2 --- /dev/null +++ b/structures.c @@ -0,0 +1,81 @@ +#include +#include "structures.h" +#include "mtproto-common.h" + +void fetch_file_location (struct file_location *loc) { + int x = fetch_int (); + if (x == CODE_file_location_unavailable) { + loc->dc = -1; + loc->volume = fetch_long (); + loc->local_id = fetch_int (); + loc->secret = fetch_long (); + } else { + assert (x == CODE_file_location); + loc->dc = fetch_int ();; + loc->volume = fetch_long (); + loc->local_id = fetch_int (); + loc->secret = fetch_long (); + } +} + +void fetch_user_status (struct user_status *S) { + int x = fetch_int (); + switch (x) { + case CODE_user_status_empty: + S->online = 0; + break; + case CODE_user_status_online: + S->online = 1; + S->when = fetch_int (); + break; + case CODE_user_status_offline: + S->online = -1; + S->when = fetch_int (); + break; + default: + assert (0); + } +} + +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 (); + if (x == CODE_user_empty) { + U->flags = 1; + return; + } + U->first_name = fetch_str_dup (); + U->last_name = fetch_str_dup (); + if (x == CODE_user_deleted) { + U->flags = 2; + return; + } + if (x == CODE_user_self) { + U->flags = 4; + } else { + U->access_hash = fetch_long (); + } + if (x == CODE_user_foreign) { + U->flags |= 8; + } else { + U->phone = fetch_str_dup (); + } + unsigned y = fetch_int (); + if (y == CODE_user_profile_photo_empty) { + U->photo_small.dc = -2; + U->photo_big.dc = -2; + } else { + assert (y == CODE_user_profile_photo); + fetch_file_location (&U->photo_small); + fetch_file_location (&U->photo_big); + } + fetch_user_status (&U->status); + if (x == CODE_user_self) { + assert (fetch_int () == (int)CODE_bool_false); + } + if (x == CODE_user_contact) { + U->flags |= 16; + } +} diff --git a/structures.h b/structures.h new file mode 100644 index 0000000..bdb34bc --- /dev/null +++ b/structures.h @@ -0,0 +1,31 @@ +#ifndef __STRUCTURES_H__ +#define __STRUCTURES_H__ + + +struct file_location { + int dc; + long long volume; + int local_id; + long long secret; +}; + +struct user_status { + int online; + int when; +}; + +struct user { + int id; + int flags; + char *first_name; + char *last_name; + char *phone; + long long access_hash; + struct file_location photo_big; + struct file_location photo_small; + struct user_status status; +}; + +void fetch_file_location (struct file_location *loc); +void fetch_user (struct user *U); +#endif diff --git a/telegram.h b/telegram.h index e69de29..3958159 100644 --- a/telegram.h +++ b/telegram.h @@ -0,0 +1 @@ +#define MAX_DC_NUM 9 diff --git a/tree.h b/tree.h new file mode 100644 index 0000000..3145139 --- /dev/null +++ b/tree.h @@ -0,0 +1,116 @@ +#ifndef __TREE_H__ +#define __TREE_H__ +#include + +#include +#include +#include + +#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ +struct tree_ ## X_NAME { \ + struct tree_ ## X_NAME *left, *right;\ + X_TYPE x;\ + int y;\ +};\ +\ +struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ + struct tree_ ## X_NAME *T = malloc (sizeof (*T));\ + T->x = x;\ + T->y = y;\ + T->left = T->right = 0;\ + return T;\ +}\ +\ +void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ + free (T);\ +}\ +\ +void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ + if (!T) {\ + *L = *R = 0;\ + } else {\ + int c = X_CMP (x, T->x);\ + if (c < 0) {\ + tree_split_ ## X_NAME (T->left, x, L, &T->left);\ + *R = T;\ + } else {\ + tree_split_ ## X_NAME (T->right, x, &T->right, R);\ + *L = T;\ + }\ + }\ +}\ +\ +struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ + if (!T) {\ + return new_tree_node_ ## X_NAME (x, y);\ + } else {\ + if (y > T->y) {\ + struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\ + tree_split_ ## X_NAME (T, x, &N->left, &N->right);\ + return N;\ + } else {\ + int c = X_CMP (x, T->x);\ + assert (c);\ + return tree_insert_ ## X_NAME (c < 0 ? T->left : T->right, x, y);\ + }\ + }\ +}\ +\ +struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\ + if (!L || !R) {\ + return L ? L : R;\ + } else {\ + if (L->y > R->y) {\ + L->right = tree_merge_ ## X_NAME (L->right, R);\ + return L;\ + } else {\ + R->left = tree_merge_ ## X_NAME (L, R->left);\ + return R;\ + }\ + }\ +}\ +\ +struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ + assert (T);\ + int c = X_CMP (x, T->x);\ + if (!c) {\ + struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\ + delete_tree_node_ ## X_NAME (T);\ + return N;\ + } else {\ + return tree_delete_ ## X_NAME (c < 0 ? T->left : T->right, x);\ + }\ +}\ +\ +X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\ + if (!T) { return X_UNSET; } \ + while (T->left) { T = T->left; }\ + return T->x; \ +} \ +\ +X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ + int c;\ + while (T && (c = X_CMP (x, T->x))) {\ + T = (c < 0 ? T->left : T->right);\ + }\ + return T ? T->x : X_UNSET;\ +}\ +\ +int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return 0; }\ + return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ +}\ +void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ + if (!T) { return; }\ + if (T->left) { \ + assert (T->left->y <= T->y);\ + assert (X_CMP (T->left->x, T->x) < 0); \ + }\ + if (T->right) { \ + assert (T->right->y <= T->y);\ + assert (X_CMP (T->right->x, T->x) > 0); \ + }\ +}\ + +#define int_cmp(a,b) ((a) - (b)) +#endif From bf291df34a46be15a640e27681e1bde99c6e28ae Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sun, 13 Oct 2013 14:18:08 +0400 Subject: [PATCH 006/465] Many fixes. Now (maybe) works authorization and get contact list query --- Makefile | 1 + interface.c | 114 ++++++++++++++++++++++++++++++++++++++++------- interface.h | 10 +++++ loop.c | 2 + mtproto-client.c | 63 +++++++++++++------------- mtproto-common.c | 9 ++-- mtproto-common.h | 5 +-- net.c | 27 +++++------ queries.c | 53 +++++++++++----------- structures.c | 64 ++++++++++++++++++++++++++ structures.h | 6 +++ telegram.h | 1 + tree.h | 14 +++++- 13 files changed, 277 insertions(+), 92 deletions(-) diff --git a/Makefile b/Makefile index b57528a..f608ae3 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ LD=cc SRC=main.c loop.c interface.c net.c mtproto-common.c mtproto-client.c queries.c structures.c OBJ=$(SRC:.c=.o) EXE=telegram +HDRS=include.h interface.h loop.h mtproto-client.h mtproto-common.h net.h queries.h structures.h telegram.h tree.h all: $(SRC) $(EXE) diff --git a/interface.c b/interface.c index 472df60..9ad1643 100644 --- a/interface.c +++ b/interface.c @@ -9,6 +9,10 @@ #include #include "include.h" #include "queries.h" + +#include "interface.h" +#include "telegram.h" +#include "structures.h" char *default_prompt = ">"; char *get_default_prompt (void) { @@ -23,16 +27,18 @@ char *commands[] = { "help", "msg", "contact_list", + "stats", 0 }; int commands_flags[] = { 070, 072, - 00, + 07, + 07, }; char *a = 0; -char **user_list = &a; +char *user_list[MAX_USER_NUM + 1]; char **chat_list = &a; int init_token (char **q) { @@ -91,12 +97,27 @@ int get_complete_mode (void) { int s = 0; while (1) { get_token (&q, &l); - if (!*q) { return flags & 7; } + if (!*q) { return flags ? flags & 7 : 7; } s ++; if (s <= 4) { flags >>= 3; } } } +extern int user_num; +extern struct user *Users[]; +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))) { + index ++; + } + if (index < user_num) { + *R = strdup (Users[index]->print_name); + return index; + } else { + return -1; + } +} + int complete_string_list (char **list, int index, const char *text, int len, char **R) { index ++; while (list[index] && strncmp (list[index], text, len)) { @@ -137,7 +158,7 @@ char *command_generator (const char *text, int state) { index = complete_string_list (commands, index, text, len, &R); return R; case 1: - index = complete_string_list (user_list, index, text, len, &R); + index = complete_user_list (index, text, len, &R); return R; case 2: index = complete_string_list (chat_list, index, text, len, &R); @@ -154,27 +175,90 @@ char **complete_text (char *text, int start UU, int end UU) { } void interpreter (char *line UU) { + if (line && *line) { + add_history (line); + } if (!memcmp (line, "contact_list", 12)) { do_update_contact_list (); + } else if (!memcmp (line, "stats", 5)) { + static char stat_buf[1 << 15]; + print_stat (stat_buf, (1 << 15) - 1); + printf ("%s\n", stat_buf); } } +int readline_active; void rprintf (const char *format, ...) { - - int saved_point = rl_point; - char *saved_line = rl_copy_text(0, rl_end); - rl_save_prompt(); - rl_replace_line("", 0); - rl_redisplay(); + int saved_point = 0; + char *saved_line = 0; + if (readline_active) { + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + } va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); - rl_restore_prompt(); - rl_replace_line(saved_line, 0); - rl_point = saved_point; - rl_redisplay(); - free(saved_line); + if (readline_active) { + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); + } +} + +void hexdump (int *in_ptr, int *in_end) { + int saved_point = 0; + char *saved_line = 0; + if (readline_active) { + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + } + int *ptr = in_ptr; + while (ptr < in_end) { fprintf (stdout, " %08x", *(ptr ++)); } + fprintf (stdout, "\n"); + + if (readline_active) { + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); + } +} + +void logprintf (const char *format, ...) { + int saved_point = 0; + char *saved_line = 0; + if (readline_active) { + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + } + + printf (COLOR_GREY " *** "); + va_list ap; + va_start (ap, format); + vfprintf (stdout, format, ap); + va_end (ap); + printf (COLOR_NORMAL); + + if (readline_active) { + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); + } } diff --git a/interface.h b/interface.h index a0d2376..949ecdf 100644 --- a/interface.h +++ b/interface.h @@ -1,9 +1,19 @@ #ifndef __INTERFACE_H__ #define __INTERFACE_H__ + +#define COLOR_RED "\033[31;1m" +#define COLOR_NORMAL "\033[0m" +#define COLOR_GREEN "\033[32;1m" +#define COLOR_GREY "\033[37;1m" + + char *get_default_prompt (void); char *complete_none (const char *text, int state); char **complete_text (char *text, int start, int end); void interpreter (char *line); void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void iprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +void hexdump (int *in_ptr, int *in_end); #endif diff --git a/loop.c b/loop.c index f5d515a..c91287b 100644 --- a/loop.c +++ b/loop.c @@ -167,6 +167,7 @@ void read_auth_file (void) { close (auth_file_fd); } +int readline_active; int loop (void) { on_start (); read_auth_file (); @@ -216,6 +217,7 @@ int loop (void) { 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/mtproto-client.c b/mtproto-client.c index 5a6802b..bbfd8ae 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -22,6 +22,7 @@ #include "include.h" #include "queries.h" #include "loop.h" +#include "interface.h" #define sha1 SHA1 @@ -89,13 +90,13 @@ static int rsa_load_public_key (const char *public_key_name) { pubKey = NULL; FILE *f = fopen (public_key_name, "r"); if (f == NULL) { - fprintf (stderr, "Couldn't open public key file: %s\n", public_key_name); + logprintf ( "Couldn't open public key file: %s\n", public_key_name); return -1; } pubKey = PEM_read_RSAPublicKey (f, NULL, NULL, NULL); fclose (f); if (pubKey == NULL) { - fprintf (stderr, "PEM_read_RSAPublicKey returns NULL.\n"); + logprintf ( "PEM_read_RSAPublicKey returns NULL.\n"); return -1; } @@ -205,7 +206,7 @@ unsigned p1, p2; int process_respq_answer (struct connection *c, char *packet, int len) { int i; if (verbosity) { - fprintf (stderr, "process_respq_answer(), len=%d\n", len); + logprintf ( "process_respq_answer(), len=%d\n", len); } assert (len >= 76); assert (!*(long long *) packet); @@ -227,7 +228,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { p1 = 0, p2 = 0; if (verbosity >= 2) { - fprintf (stderr, "%lld received\n", what); + logprintf ( "%lld received\n", what); } int it = 0; @@ -275,7 +276,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { if (verbosity) { - fprintf (stderr, "p1 = %d, p2 = %d, %d iterations\n", p1, p2, it); + logprintf ( "p1 = %d, p2 = %d, %d iterations\n", p1, p2, it); } /// ++p1; /// @@ -286,12 +287,12 @@ int process_respq_answer (struct connection *c, char *packet, int len) { long long *fingerprints = (long long *) (from + 8); for (i = 0; i < fingerprints_num; i++) { if (fingerprints[i] == pk_fingerprint) { - //fprintf (stderr, "found our public key at position %d\n", i); + //logprintf ( "found our public key at position %d\n", i); break; } } if (i == fingerprints_num) { - fprintf (stderr, "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); + logprintf ( "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); exit (2); } // create inner part (P_Q_inner_data) @@ -378,10 +379,10 @@ int process_respq_answer (struct connection *c, char *packet, int len) { int process_dh_answer (struct connection *c, char *packet, int len) { if (verbosity) { - fprintf (stderr, "process_dh_answer(), len=%d\n", len); + logprintf ( "process_dh_answer(), len=%d\n", len); } if (len < 116) { - fprintf (stderr, "%u * %u = %llu", p1, p2, what); + logprintf ( "%u * %u = %llu", p1, p2, what); } assert (len >= 116); assert (!*(long long *) packet); @@ -418,7 +419,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { GET_DC(c)->server_time_delta = server_time - time (0); GET_DC(c)->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); - //fprintf (stderr, "server time is %d, delta = %d\n", server_time, server_time_delta); + //logprintf ( "server time is %d, delta = %d\n", server_time, server_time_delta); // Build set_client_DH_params answer clear_packet (); @@ -474,7 +475,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { int process_auth_complete (struct connection *c UU, char *packet, int len) { if (verbosity) { - fprintf (stderr, "process_dh_answer(), len=%d\n", len); + logprintf ( "process_dh_answer(), len=%d\n", len); } assert (len == 72); assert (!*(long long *) packet); @@ -493,7 +494,7 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; if (verbosity >= 3) { - fprintf (stderr, "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); + logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); } //kprintf ("OK\n"); @@ -503,7 +504,7 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { c_state = st_authorized; //return 1; if (verbosity) { - fprintf (stderr, "Auth success\n"); + logprintf ( "Auth success\n"); } auth_success ++; GET_DC(c)->flags |= 1; @@ -568,7 +569,7 @@ int aes_encrypt_message (struct dc *DC, struct encrypted_message *enc) { sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); //printf ("enc_len is %d\n", enc_len); if (verbosity >= 2) { - fprintf (stderr, "sending message with sha1 %08x\n", *(int *)sha1_buffer); + logprintf ( "sending message with sha1 %08x\n", *(int *)sha1_buffer); } memcpy (enc->msg_key, sha1_buffer + 4, 16); init_aes_auth (DC->auth_key, enc->msg_key, AES_ENCRYPT); @@ -612,7 +613,7 @@ int auth_work_start (struct connection *c UU) { void rpc_execute_answer (struct connection *c, long long msg_id UU); void work_container (struct connection *c, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_container: msg_id = %lld\n", msg_id); + logprintf ( "work_container: msg_id = %lld\n", msg_id); } assert (fetch_int () == CODE_msg_container); int n = fetch_int (); @@ -632,7 +633,7 @@ void work_container (struct connection *c, long long msg_id UU) { void work_new_session_created (struct connection *c, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_new_session_created: msg_id = %lld\n", msg_id); + logprintf ( "work_new_session_created: msg_id = %lld\n", msg_id); } assert (fetch_int () == (int)CODE_new_session_created); fetch_long (); // first message id @@ -643,7 +644,7 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { void work_msgs_ack (struct connection *c UU, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_msgs_ack: msg_id = %lld\n", msg_id); + logprintf ( "work_msgs_ack: msg_id = %lld\n", msg_id); } assert (fetch_int () == CODE_msgs_ack); assert (fetch_int () == CODE_vector); @@ -657,7 +658,7 @@ void work_msgs_ack (struct connection *c UU, long long msg_id UU) { void work_rpc_result (struct connection *c UU, long long msg_id UU) { if (verbosity) { - fprintf (stderr, "work_rpc_result: msg_id = %lld\n", msg_id); + logprintf ( "work_rpc_result: msg_id = %lld\n", msg_id); } assert (fetch_int () == (int)CODE_rpc_result); long long id = fetch_long (); @@ -685,7 +686,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { work_rpc_result (c, msg_id); return; } - fprintf (stderr, "Unknown message: \n"); + logprintf ( "Unknown message: \n"); hexdump_in (); } @@ -693,7 +694,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); if (verbosity) { - fprintf (stderr, "process_rpc_message(), len=%d\n", len); + logprintf ( "process_rpc_message(), len=%d\n", len); } assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); struct dc *DC = GET_DC(c); @@ -717,7 +718,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); if (verbosity >= 2) { - fprintf (stderr, "received mesage id %016llx\n", enc->msg_id); + logprintf ( "received mesage id %016llx\n", enc->msg_id); } server_last_msg_id = enc->msg_id; @@ -727,7 +728,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (l >= (MINSZ - UNENCSZ) + 8); //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); if (verbosity >= 2) { - fprintf (stderr, "OK, message is good!\n"); + logprintf ( "OK, message is good!\n"); } ++good_messages; @@ -745,11 +746,11 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int rpc_execute (struct connection *c, int op, int len) { if (verbosity) { - fprintf (stderr, "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); + logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); } if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - fprintf (stderr, "answer too long (%d bytes), skipping\n", len); + logprintf ( "answer too long (%d bytes), skipping\n", len); return 0; } @@ -758,7 +759,7 @@ int rpc_execute (struct connection *c, int op, int len) { assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; if (verbosity >= 2) { - fprintf (stderr, "have %d Response bytes\n", Response_len); + logprintf ( "have %d Response bytes\n", Response_len); } setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); @@ -782,7 +783,7 @@ int rpc_execute (struct connection *c, int op, int len) { setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); return 0; default: - fprintf (stderr, "fatal: cannot receive answer in state %d\n", c_state); + logprintf ( "fatal: cannot receive answer in state %d\n", c_state); exit (2); } @@ -792,14 +793,14 @@ int rpc_execute (struct connection *c, int op, int len) { int tc_close (struct connection *c, int who) { if (verbosity) { - fprintf (stderr, "outbound http connection #%d : closing by %d\n", c->fd, who); + logprintf ( "outbound http connection #%d : closing by %d\n", c->fd, who); } return 0; } int tc_becomes_ready (struct connection *c) { if (verbosity) { - fprintf (stderr, "outbound connection #%d becomes ready\n", c->fd); + logprintf ( "outbound connection #%d becomes ready\n", c->fd); } char byte = 0xef; assert (write_out (c, &byte, 1) == 1); @@ -816,7 +817,7 @@ int tc_becomes_ready (struct connection *c) { auth_work_start (c); break; default: - fprintf (stderr, "c_state = %d\n", c_state); + logprintf ( "c_state = %d\n", c_state); assert (0); } return 0; @@ -842,7 +843,7 @@ void on_start (void) { exit (1); } if (verbosity) { - fprintf (stderr, "public key '%s' loaded successfully\n", rsa_public_key_name); + logprintf ( "public key '%s' loaded successfully\n", rsa_public_key_name); } pk_fingerprint = compute_rsa_key_fingerprint (pubKey); } @@ -858,7 +859,7 @@ void dc_authorize (struct dc *DC) { dc_create_session (DC); } if (verbosity) { - fprintf (stderr, "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); + logprintf ( "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); } net_loop (0, auth_ok); } diff --git a/mtproto-common.c b/mtproto-common.c index e00845b..3a0c5a1 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -16,6 +16,7 @@ #include #include "mtproto-common.h" +#include "interface.h" long long rsa_encrypted_chunks, rsa_decrypted_chunks; @@ -28,7 +29,7 @@ int get_random_bytes (void *buf, int n) { r = read (h, buf, n); if (r > 0) { if (verbosity >= 3) { - fprintf (stderr, "added %d bytes of real entropy to secure random numbers seed\n", r); + logprintf ( "added %d bytes of real entropy to secure random numbers seed\n", r); } } close (h); @@ -71,14 +72,14 @@ void prng_seed (const char *password_filename, int password_length) { if (password_filename) { int fd = open (password_filename, O_RDONLY); if (fd < 0) { - fprintf (stderr, "Warning: fail to open password file - \"%s\", %m.\n", password_filename); + logprintf ( "Warning: fail to open password file - \"%s\", %m.\n", password_filename); } else { int l = read (fd, a + s, password_length); if (l < 0) { - fprintf (stderr, "Warning: fail to read password file - \"%s\", %m.\n", password_filename); + logprintf ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename); } else { if (verbosity > 0) { - fprintf (stderr, "read %d bytes from password file.\n", l); + logprintf ( "read %d bytes from password file.\n", l); } s += l; } diff --git a/mtproto-common.h b/mtproto-common.h index 808aa89..ac3ffc5 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -7,6 +7,7 @@ #include #include +#include "interface.h" /* DH key exchange protocol data structures */ #define CODE_req_pq 0x60469778 #define CODE_resPQ 0x05162463 @@ -409,8 +410,6 @@ int pad_aes_encrypt (char *from, int from_len, char *to, int size); int pad_aes_decrypt (char *from, int from_len, char *to, int size); static inline void hexdump_in (void) { - int *ptr = in_ptr; - while (ptr < in_end) { fprintf (stderr, " %08x", *(ptr ++)); } - fprintf (stderr, "\n"); + hexdump (in_ptr, in_end); } #endif diff --git a/net.c b/net.c index 69e5c4c..ed5a835 100644 --- a/net.c +++ b/net.c @@ -17,6 +17,7 @@ #include "mtproto-client.h" #include "mtproto-common.h" #include "tree.h" +#include "interface.h" DEFINE_TREE(int,int,int_cmp,0) @@ -156,7 +157,7 @@ struct connection *create_connection (const char *host, int port, struct session if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { if (errno != EINPROGRESS) { - fprintf (stderr, "Can not connect to %s:%d %m\n", host, port); + logprintf ( "Can not connect to %s:%d %m\n", host, port); close (fd); free (c); return 0; @@ -183,7 +184,7 @@ struct connection *create_connection (const char *host, int port, struct session assert (!Connections[fd]); Connections[fd] = c; if (verbosity) { - fprintf (stderr, "connect to %s:%d successful\n", host, port); + logprintf ( "connect to %s:%d successful\n", host, port); } if (c->methods->ready) { c->methods->ready (c); @@ -211,7 +212,7 @@ void fail_connection (struct connection *c) { void try_write (struct connection *c) { if (verbosity) { - fprintf (stderr, "try write: fd = %d\n", c->fd); + logprintf ( "try write: fd = %d\n", c->fd); } int x = 0; while (c->out_head) { @@ -238,12 +239,12 @@ void try_write (struct connection *c) { } } if (verbosity) { - fprintf (stderr, "Sent %d bytes to %d\n", x, c->fd); + logprintf ( "Sent %d bytes to %d\n", x, c->fd); } c->out_bytes -= x; } -void hexdump (struct connection_buffer *b) { +void hexdump_buf (struct connection_buffer *b) { int pos = 0; int rem = 8; while (b) { @@ -270,7 +271,7 @@ void hexdump (struct connection_buffer *b) { void try_rpc_read (struct connection *c) { assert (c->in_head); if (verbosity >= 4) { - hexdump (c->in_head); + hexdump_buf (c->in_head); } while (1) { @@ -307,7 +308,7 @@ void try_rpc_read (struct connection *c) { void try_read (struct connection *c) { if (verbosity) { - fprintf (stderr, "try read: fd = %d\n", c->fd); + logprintf ( "try read: fd = %d\n", c->fd); } if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); @@ -334,7 +335,7 @@ void try_read (struct connection *c) { } } if (verbosity) { - fprintf (stderr, "Received %d bytes from %d\n", x, c->fd); + logprintf ( "Received %d bytes from %d\n", x, c->fd); } c->in_bytes += x; if (x) { @@ -356,15 +357,15 @@ int connections_make_poll_array (struct pollfd *fds, int max) { fds ++; max --; } - if (verbosity >= 3) { - fprintf (stderr, "%d connections in poll\n", _max - max); + if (verbosity >= 10) { + logprintf ( "%d connections in poll\n", _max - max); } return _max - max; } void connections_poll_result (struct pollfd *fds, int max) { - if (verbosity >= 2) { - fprintf (stderr, "connections_poll_result: max = %d\n", max); + if (verbosity >= 10) { + logprintf ( "connections_poll_result: max = %d\n", max); } int i; for (i = 0; i < max; i++) { @@ -374,7 +375,7 @@ void connections_poll_result (struct pollfd *fds, int max) { } if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) { if (verbosity) { - fprintf (stderr, "fail connection\n"); + logprintf ( "fail connection\n"); } fail_connection (c); } else if (fds[i].revents & POLLOUT) { diff --git a/queries.c b/queries.c index 13b21ca..893ed96 100644 --- a/queries.c +++ b/queries.c @@ -43,7 +43,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth dc_create_session (DC); } if (verbosity) { - fprintf (stderr, "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); + logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } struct query *q = malloc (sizeof (*q)); q->data_len = ints; @@ -51,11 +51,11 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth memcpy (q->data, data, 4 * ints); q->msg_id = encrypt_send_message (DC->sessions[0]->c, data, ints, 1); if (verbosity) { - fprintf (stderr, "Msg_id is %lld\n", q->msg_id); + logprintf ( "Msg_id is %lld\n", q->msg_id); } q->methods = methods; if (queries_tree) { - fprintf (stderr, "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); } queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); @@ -77,12 +77,12 @@ void query_error (long long id) { int error_len = prefetch_strlen (); char *error = fetch_str (error_len); if (verbosity) { - fprintf (stderr, "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); + logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); } struct query *q = query_get (id); if (!q) { if (verbosity) { - fprintf (stderr, "No such query\n"); + logprintf ( "No such query\n"); } } else { remove_event_timer (&q->ev); @@ -100,10 +100,10 @@ static int packed_buffer[MAX_PACKED_SIZE / 4]; void query_result (long long id UU) { if (verbosity) { - fprintf (stderr, "result for query #%lld\n", id); + logprintf ( "result for query #%lld\n", id); } if (verbosity >= 4) { - fprintf (stderr, "result: "); + logprintf ( "result: "); hexdump_in (); } int op = prefetch_int (); @@ -124,8 +124,8 @@ void query_result (long long id UU) { int err = inflate (&strm, Z_FINISH); if (verbosity) { - fprintf (stderr, "inflate error = %d\n", err); - fprintf (stderr, "inflated %d bytes\n", (int)strm.total_out); + logprintf ( "inflate error = %d\n", err); + logprintf ( "inflated %d bytes\n", (int)strm.total_out); } end = in_ptr; eend = in_end; @@ -133,14 +133,14 @@ void query_result (long long id UU) { in_ptr = packed_buffer; in_end = in_ptr + strm.total_out / 4; if (verbosity >= 4) { - fprintf (stderr, "Unzipped data: "); + logprintf ( "Unzipped data: "); hexdump_in (); } } struct query *q = query_get (id); if (!q) { if (verbosity) { - fprintf (stderr, "No such query\n"); + logprintf ( "No such query\n"); } } else { remove_event_timer (&q->ev); @@ -162,16 +162,18 @@ DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) struct tree_timer *timer_tree; void insert_event_timer (struct event_timer *ev) { - return; - fprintf (stderr, "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + if (verbosity > 2) { + logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + } tree_check_timer (timer_tree); timer_tree = tree_insert_timer (timer_tree, ev, lrand48 ()); tree_check_timer (timer_tree); } void remove_event_timer (struct event_timer *ev) { - return; - fprintf (stderr, "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + if (verbosity > 2) { + logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + } tree_check_timer (timer_tree); timer_tree = tree_delete_timer (timer_tree, ev); tree_check_timer (timer_tree); @@ -207,7 +209,7 @@ int help_get_config_on_answer (struct query *q UU) { assert (test_mode == CODE_bool_false); int this_dc = fetch_int (); if (verbosity) { - fprintf (stderr, "this_dc = %d\n", this_dc); + logprintf ( "this_dc = %d\n", this_dc); } assert (fetch_int () == CODE_vector); int n = fetch_int (); @@ -222,7 +224,7 @@ int help_get_config_on_answer (struct query *q UU) { char *ip = fetch_str (l2); int port = fetch_int (); if (verbosity) { - fprintf (stderr, "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } if (!DC_list[id]) { alloc_dc (id, strndup (ip, l2), port); @@ -230,7 +232,7 @@ int help_get_config_on_answer (struct query *q UU) { } max_chat_size = fetch_int (); if (verbosity >= 2) { - fprintf (stderr, "chat_size = %d\n", max_chat_size); + logprintf ( "chat_size = %d\n", max_chat_size); } return 0; } @@ -259,7 +261,7 @@ int send_code_on_error (struct query *q UU, int error_code, int l, char *error) int i = error[s] - '0'; want_dc_num = i; } else { - fprintf (stderr, "error_code = %d, error = %.*s\n", error_code, l, error); + logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); assert (0); } return 0; @@ -343,13 +345,13 @@ int sign_in_on_answer (struct query *q UU) { fetch_user (&User); sign_in_ok = 1; if (verbosity) { - fprintf (stderr, "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); + logprintf ( "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); } return 0; } int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { - fprintf (stderr, "error_code = %d, error = %.*s\n", error_code, l, error); + logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); sign_in_ok = -1; return 0; } @@ -371,11 +373,13 @@ int do_send_code_result (const char *code) { return sign_in_ok; } +extern char *user_list[]; + int get_contacts_on_answer (struct query *q UU) { + int i; assert (fetch_int () == (int)CODE_contacts_contacts); assert (fetch_int () == CODE_vector); int n = fetch_int (); - int i; for (i = 0; i < n; i++) { assert (fetch_int () == (int)CODE_contact); fetch_int (); // id @@ -384,9 +388,8 @@ int get_contacts_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); n = fetch_int (); for (i = 0; i < n; i++) { - struct user User; - fetch_user (&User); - rprintf ("User: id = %d, first_name = %s, last_name = %s\n", User.id, User.first_name, User.last_name); + struct user *U = fetch_alloc_user (); + rprintf ("User #%d: " COLOR_RED "%s %s" COLOR_NORMAL " (" COLOR_GREEN "%s" COLOR_NORMAL ")\n", U->id, U->first_name, U->last_name, U->print_name); } return 0; } diff --git a/structures.c b/structures.c index aad5eb2..e67770e 100644 --- a/structures.c +++ b/structures.c @@ -1,6 +1,8 @@ #include #include "structures.h" #include "mtproto-common.h" +#include "telegram.h" +#include "tree.h" void fetch_file_location (struct file_location *loc) { int x = fetch_int (); @@ -48,6 +50,25 @@ void fetch_user (struct user *U) { } U->first_name = fetch_str_dup (); U->last_name = fetch_str_dup (); + if (!strlen (U->first_name)) { + if (!strlen (U->last_name)) { + U->print_name = strdup ("none"); + } else { + U->print_name = strdup (U->last_name); + } + } else { + if (!strlen (U->last_name)) { + U->print_name = strdup (U->first_name); + } else { + U->print_name = malloc (strlen (U->first_name) + strlen (U->last_name) + 2); + sprintf (U->print_name, "%s_%s", U->first_name, U->last_name); + } + } + char *s = U->print_name; + while (*s) { + if (*s == ' ') { *s = '_'; } + s++; + } if (x == CODE_user_deleted) { U->flags = 2; return; @@ -79,3 +100,46 @@ void fetch_user (struct user *U) { U->flags |= 16; } } + + +#define user_cmp(a,b) ((a)->id - (b)->id) + +DEFINE_TREE(user,struct user *,user_cmp,0) +struct tree_user *user_tree; + +int user_num; +struct user *Users[MAX_USER_NUM]; +int users_allocated; + +struct user *fetch_alloc_user (void) { + struct user *U = malloc (sizeof (*U)); + fetch_user (U); + users_allocated ++; + struct user *U1 = tree_lookup_user (user_tree, U); + if (U1) { + free_user (U1); + memcpy (U1, U, sizeof (*U)); + free (U); + users_allocated --; + return U1; + } else { + user_tree = tree_insert_user (user_tree, U, lrand48 ()); + Users[user_num ++] = U; + return U; + } +} + +void free_user (struct user *U) { + if (U->first_name) { free (U->first_name); } + if (U->last_name) { free (U->last_name); } + if (U->print_name) { free (U->print_name); } + if (U->phone) { free (U->phone); } +} + +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); +} diff --git a/structures.h b/structures.h index bdb34bc..e3d05c1 100644 --- a/structures.h +++ b/structures.h @@ -20,6 +20,7 @@ struct user { 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; @@ -28,4 +29,9 @@ struct user { void fetch_file_location (struct file_location *loc); void fetch_user (struct user *U); +struct user *fetch_alloc_user (void); + +void free_user (struct user *U); + +int print_stat (char *s, int len); #endif diff --git a/telegram.h b/telegram.h index 3958159..30d8f40 100644 --- a/telegram.h +++ b/telegram.h @@ -1 +1,2 @@ #define MAX_DC_NUM 9 +#define MAX_USER_NUM 1000 diff --git a/tree.h b/tree.h index 3145139..250b060 100644 --- a/tree.h +++ b/tree.h @@ -51,7 +51,12 @@ struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYP } else {\ int c = X_CMP (x, T->x);\ assert (c);\ - return tree_insert_ ## X_NAME (c < 0 ? T->left : T->right, x, y);\ + if (c < 0) { \ + T->left = tree_insert_ ## X_NAME (T->left, x, y);\ + } else { \ + T->right = tree_insert_ ## X_NAME (T->right, x, y);\ + } \ + return T; \ }\ }\ }\ @@ -96,6 +101,13 @@ X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ return T ? T->x : X_UNSET;\ }\ \ +void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ + if (!T) { return; } \ + tree_act_ ## X_NAME (T->left, act); \ + act (T->x); \ + tree_act_ ## X_NAME (T->right, act); \ +}\ +\ int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ if (!T) { return 0; }\ return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ From 5f2080e956105be104201be3910a8bbe2fdc5b8e Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sun, 13 Oct 2013 16:30:53 +0400 Subject: [PATCH 007/465] Some fixes. Added automaticly generated constants.h --- Makefile | 2 + constants.h | 253 +++++++++++++++++++++++++++++++++++++++++++++++ mtproto-common.h | 97 +----------------- queries.c | 2 +- structures.c | 32 ++++++ structures.h | 12 +++ 6 files changed, 301 insertions(+), 97 deletions(-) create mode 100644 constants.h diff --git a/Makefile b/Makefile index f608ae3..11a112b 100644 --- a/Makefile +++ b/Makefile @@ -16,3 +16,5 @@ $(EXE): $(OBJ) .c.o: $(CC) $(CFLAGS) $< -o $@ +clean: + rm *.o telegram || true diff --git a/constants.h b/constants.h new file mode 100644 index 0000000..2719d44 --- /dev/null +++ b/constants.h @@ -0,0 +1,253 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H +#define CODE_bool_false 0xbc799737 +#define CODE_bool_true 0x997275b5 +#define CODE_vector 0x1cb5c415 +#define CODE_error 0xc4b9f9bb +#define CODE_null 0x56730bcc +#define CODE_input_peer_empty 0x7f3b18ea +#define CODE_input_peer_self 0x7da07ec9 +#define CODE_input_peer_contact 0x1023dbe8 +#define CODE_input_peer_foreign 0x9b447325 +#define CODE_input_peer_chat 0x179be863 +#define CODE_input_user_empty 0xb98886cf +#define CODE_input_user_self 0xf7c1b13f +#define CODE_input_user_contact 0x86e94f65 +#define CODE_input_user_foreign 0x655e74ff +#define CODE_input_phone_contact 0xf392b7f4 +#define CODE_input_file 0xf52ff27f +#define CODE_input_media_empty 0x9664f57f +#define CODE_input_media_uploaded_photo 0x2dc53a7d +#define CODE_input_media_photo 0x8f2ab2ec +#define CODE_input_media_geo_point 0xf9c44144 +#define CODE_input_media_contact 0xa6e45987 +#define CODE_input_media_uploaded_video 0x4847d92a +#define CODE_input_media_uploaded_thumb_video 0xe628a145 +#define CODE_input_media_video 0x7f023ae6 +#define CODE_input_chat_photo_empty 0x1ca48f57 +#define CODE_input_chat_uploaded_photo 0x94254732 +#define CODE_input_chat_photo 0xb2e1bf08 +#define CODE_input_geo_point_empty 0xe4c123d6 +#define CODE_input_geo_point 0xf3b7acc9 +#define CODE_input_photo_empty 0x1cd7bf0d +#define CODE_input_photo 0xfb95c6c4 +#define CODE_input_video_empty 0x5508ec75 +#define CODE_input_video 0xee579652 +#define CODE_input_file_location 0x14637196 +#define CODE_input_video_file_location 0x3d0364ec +#define CODE_input_photo_crop_auto 0xade6b004 +#define CODE_input_photo_crop 0xd9915325 +#define CODE_input_app_event 0x770656a8 +#define CODE_peer_user 0x9db1bc6d +#define CODE_peer_chat 0xbad0e5bb +#define CODE_storage_file_unknown 0xaa963b05 +#define CODE_storage_file_jpeg 0x7efe0e +#define CODE_storage_file_gif 0xcae1aadf +#define CODE_storage_file_png 0xa4f63c0 +#define CODE_storage_file_mp3 0x528a0677 +#define CODE_storage_file_mov 0x4b09ebbc +#define CODE_storage_file_partial 0x40bc6f52 +#define CODE_storage_file_mp4 0xb3cea0e4 +#define CODE_storage_file_webp 0x1081464c +#define CODE_file_location_unavailable 0x7c596b46 +#define CODE_file_location 0x53d69076 +#define CODE_user_empty 0x200250ba +#define CODE_user_self 0x720535ec +#define CODE_user_contact 0xf2fb8319 +#define CODE_user_request 0x22e8ceb0 +#define CODE_user_foreign 0x5214c89d +#define CODE_user_deleted 0xb29ad7cc +#define CODE_user_profile_photo_empty 0x4f11bae1 +#define CODE_user_profile_photo 0x990d1493 +#define CODE_user_status_empty 0x9d05049 +#define CODE_user_status_online 0xedb93949 +#define CODE_user_status_offline 0x8c703f +#define CODE_chat_empty 0x9ba2d800 +#define CODE_chat 0x6e9c9bc7 +#define CODE_chat_forbidden 0xfb0ccc41 +#define CODE_chat_full 0x630e61be +#define CODE_chat_participant 0xc8d7493e +#define CODE_chat_participants_forbidden 0xfd2bb8a +#define CODE_chat_participants 0x7841b415 +#define CODE_chat_photo_empty 0x37c1011c +#define CODE_chat_photo 0x6153276a +#define CODE_message_empty 0x83e5de54 +#define CODE_message 0x22eb6aba +#define CODE_message_forwarded 0x5f46804 +#define CODE_message_service 0x9f8d60bb +#define CODE_message_media_empty 0x3ded6320 +#define CODE_message_media_photo 0xc8c45a2a +#define CODE_message_media_video 0xa2d24290 +#define CODE_message_media_geo 0x56e0d474 +#define CODE_message_media_contact 0x5e7d2f39 +#define CODE_message_media_unsupported 0x29632a36 +#define CODE_message_action_empty 0xb6aef7b0 +#define CODE_message_action_chat_create 0xa6638b9a +#define CODE_message_action_chat_edit_title 0xb5a1ce5a +#define CODE_message_action_chat_edit_photo 0x7fcb13a8 +#define CODE_message_action_chat_delete_photo 0x95e3fbef +#define CODE_message_action_chat_add_user 0x5e3cfc4b +#define CODE_message_action_chat_delete_user 0xb2ae9b0c +#define CODE_dialog 0x214a8cdf +#define CODE_photo_empty 0x2331b22d +#define CODE_photo 0x22b56751 +#define CODE_photo_size_empty 0xe17e23c +#define CODE_photo_size 0x77bfb61b +#define CODE_photo_cached_size 0xe9a734fa +#define CODE_video_empty 0xc10658a8 +#define CODE_video 0x5a04a49f +#define CODE_geo_point_empty 0x1117dd5f +#define CODE_geo_point 0x2049d70c +#define CODE_auth_checked_phone 0xe300cc3b +#define CODE_auth_sent_code 0x2215bcbd +#define CODE_auth_authorization 0xf6b673a4 +#define CODE_auth_exported_authorization 0xdf969c2d +#define CODE_input_notify_peer 0xb8bc5b0c +#define CODE_input_notify_users 0x193b4417 +#define CODE_input_notify_chats 0x4a95e84e +#define CODE_input_notify_all 0xa429b886 +#define CODE_input_peer_notify_events_empty 0xf03064d8 +#define CODE_input_peer_notify_events_all 0xe86a2c74 +#define CODE_input_peer_notify_settings 0x3cf4b1be +#define CODE_peer_notify_events_empty 0xadd53cb3 +#define CODE_peer_notify_events_all 0x6d1ded88 +#define CODE_peer_notify_settings_empty 0x70a68512 +#define CODE_peer_notify_settings 0xddbcd4a5 +#define CODE_wall_paper 0xccb03657 +#define CODE_user_full 0x771095da +#define CODE_contact 0xf911c994 +#define CODE_imported_contact 0xd0028438 +#define CODE_contact_blocked 0x561bc879 +#define CODE_contact_found 0xea879f95 +#define CODE_contact_suggested 0x3de191a1 +#define CODE_contact_status 0xaa77b873 +#define CODE_chat_located 0x3631cf4c +#define CODE_contacts_foreign_link_unknown 0x133421f8 +#define CODE_contacts_foreign_link_requested 0xa7801f47 +#define CODE_contacts_foreign_link_mutual 0x1bea8ce1 +#define CODE_contacts_my_link_empty 0xd22a1c60 +#define CODE_contacts_my_link_requested 0x6c69efee +#define CODE_contacts_my_link_contact 0xc240ebd9 +#define CODE_contacts_link 0xeccea3f5 +#define CODE_contacts_contacts 0x6f8b8cb2 +#define CODE_contacts_contacts_not_modified 0xb74ba9d2 +#define CODE_contacts_imported_contacts 0xd1cd0a4c +#define CODE_contacts_blocked 0x1c138d15 +#define CODE_contacts_blocked_slice 0x900802a1 +#define CODE_contacts_found 0x566000e +#define CODE_contacts_suggested 0x5649dcc5 +#define CODE_messages_dialogs 0x15ba6c40 +#define CODE_messages_dialogs_slice 0x71e094f3 +#define CODE_messages_messages 0x8c718e87 +#define CODE_messages_messages_slice 0xb446ae3 +#define CODE_messages_message_empty 0x3f4e0648 +#define CODE_messages_message 0xff90c417 +#define CODE_messages_stated_messages 0x969478bb +#define CODE_messages_stated_message 0xd07ae726 +#define CODE_messages_sent_message 0xd1f4d35c +#define CODE_messages_chat 0x40e9002a +#define CODE_messages_chats 0x8150cbd8 +#define CODE_messages_chat_full 0xe5d7d19c +#define CODE_messages_affected_history 0xb7de36f2 +#define CODE_input_messages_filter_empty 0x57e2f66c +#define CODE_input_messages_filter_photos 0x9609a51c +#define CODE_input_messages_filter_video 0x9fc00e65 +#define CODE_input_messages_filter_photo_video 0x56e9f0e4 +#define CODE_update_new_message 0x13abdb3 +#define CODE_update_message_i_d 0x4e90bfd6 +#define CODE_update_read_messages 0xc6649e31 +#define CODE_update_delete_messages 0xa92bfe26 +#define CODE_update_restore_messages 0xd15de04d +#define CODE_update_user_typing 0x6baa8508 +#define CODE_update_chat_user_typing 0x3c46cfe6 +#define CODE_update_chat_participants 0x7761198 +#define CODE_update_user_status 0x1bfbd823 +#define CODE_update_user_name 0xda22d9ad +#define CODE_update_user_photo 0xbb8ba607 +#define CODE_update_contact_registered 0x2575bbb9 +#define CODE_update_contact_link 0x51a48a9a +#define CODE_update_activation 0x6f690963 +#define CODE_update_new_authorization 0x8f06529a +#define CODE_updates_state 0xa0d9c0c +#define CODE_updates_difference_empty 0x5d75a138 +#define CODE_updates_difference 0x8adb0077 +#define CODE_updates_difference_slice 0xc5e839b4 +#define CODE_updates_too_long 0xe317af7e +#define CODE_update_short_message 0xd3f45784 +#define CODE_update_short_chat_message 0x2b2fbd4e +#define CODE_update_short 0x78d4dec1 +#define CODE_updates_combined 0x725b04c3 +#define CODE_updates 0x74ae4240 +#define CODE_photos_photos 0x8dca6aa5 +#define CODE_photos_photos_slice 0x15051f54 +#define CODE_photos_photo 0x20212ca8 +#define CODE_upload_file 0x96a18d5 +#define CODE_dc_option 0x2ec2a43c +#define CODE_config 0x232d5905 +#define CODE_nearest_dc 0x8e1a1775 +#define CODE_help_invite_text 0x18cb9f78 +#define CODE_invoke_after_msg 0xcb9f372d +#define CODE_invoke_after_msgs 0x3dc4b4f0 +#define CODE_invoke_with_layer1 0x53835315 +#define CODE_init_connection 0x3fc12e08 +#define CODE_auth_check_phone 0x6fe51dfb +#define CODE_auth_send_code 0xd16ff372 +#define CODE_auth_send_call 0x3c51564 +#define CODE_auth_sign_up 0x1b067634 +#define CODE_auth_sign_in 0xbcd51581 +#define CODE_auth_log_out 0x5717da40 +#define CODE_auth_reset_authorizations 0x9fab0d1a +#define CODE_auth_send_invites 0x771c1d97 +#define CODE_auth_export_authorization 0xe5bfffcd +#define CODE_auth_import_authorization 0xe3ef9613 +#define CODE_account_register_device 0xa28557ac +#define CODE_account_unregister_device 0x65c55b40 +#define CODE_account_update_notify_settings 0x84be5b93 +#define CODE_account_get_notify_settings 0x12b3ad31 +#define CODE_account_reset_notify_settings 0xdb7e1747 +#define CODE_account_update_profile 0xf0888d68 +#define CODE_account_update_status 0x6628562c +#define CODE_account_get_wall_papers 0xc04cfac2 +#define CODE_users_get_users 0xd91a548 +#define CODE_users_get_full_user 0xca30a5b1 +#define CODE_contacts_get_statuses 0xc4a353ee +#define CODE_contacts_get_contacts 0x22c6aa08 +#define CODE_contacts_import_contacts 0xda30b32d +#define CODE_contacts_search 0x11f812d8 +#define CODE_contacts_get_suggested 0xcd773428 +#define CODE_contacts_delete_contact 0x8e953744 +#define CODE_contacts_delete_contacts 0x59ab389e +#define CODE_contacts_block 0x332b49fc +#define CODE_contacts_unblock 0xe54100bd +#define CODE_contacts_get_blocked 0xf57c350f +#define CODE_messages_get_messages 0x4222fa74 +#define CODE_messages_get_dialogs 0xeccf1df6 +#define CODE_messages_get_history 0x92a1df2f +#define CODE_messages_search 0x7e9f2ab +#define CODE_messages_read_history 0xb04f2510 +#define CODE_messages_delete_history 0xf4f8fb61 +#define CODE_messages_delete_messages 0x14f2dd0a +#define CODE_messages_restore_messages 0x395f9d7e +#define CODE_messages_received_messages 0x28abcb68 +#define CODE_messages_set_typing 0x719839e9 +#define CODE_messages_send_message 0x4cde0aab +#define CODE_messages_send_media 0xa3c85d76 +#define CODE_messages_forward_messages 0x514cd10f +#define CODE_messages_get_chats 0x3c6aa187 +#define CODE_messages_get_full_chat 0x3b831c66 +#define CODE_messages_edit_chat_title 0xb4bc68b5 +#define CODE_messages_edit_chat_photo 0xd881821d +#define CODE_messages_add_chat_user 0x2ee9ee9e +#define CODE_messages_delete_chat_user 0xc3c5cd23 +#define CODE_messages_create_chat 0x419d9aee +#define CODE_updates_get_state 0xedd4882a +#define CODE_updates_get_difference 0x5b36855a +#define CODE_photos_update_profile_photo 0xeef579a0 +#define CODE_photos_upload_profile_photo 0xd50f9c88 +#define CODE_upload_save_file_part 0xb304a621 +#define CODE_upload_get_file 0xe3a6cfb5 +#define CODE_help_get_config 0xc4f9186b +#define CODE_help_get_nearest_dc 0x1fb33026 +#define CODE_help_save_app_log 0x6f02f748 +#define CODE_help_get_invite_text 0xa4a95186 +#endif diff --git a/mtproto-common.h b/mtproto-common.h index ac3ffc5..6c7f156 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -8,6 +8,7 @@ #include #include "interface.h" +#include "constants.h" /* DH key exchange protocol data structures */ #define CODE_req_pq 0x60469778 #define CODE_resPQ 0x05162463 @@ -22,18 +23,11 @@ #define CODE_dh_gen_retry 0x46dc1fb9 #define CODE_dh_gen_fail 0xa69dae02 -/* generic data structures */ -#define CODE_vector_long 0xc734a64e -#define CODE_vector_int 0xa03855ae -#define CODE_vector_Object 0xa351ae8e -#define CODE_vector 0x1cb5c415 - /* service messages */ #define CODE_rpc_result 0xf35c6d01 #define CODE_rpc_error 0x2144ca19 #define CODE_msg_container 0x73f1f8dc #define CODE_msg_copy 0xe06046b2 -#define CODE_http_wait 0x9299359f #define CODE_msgs_ack 0x62d6b459 #define CODE_bad_msg_notification 0xa7eff811 #define CODE_bad_server_salt 0xedab447b @@ -59,95 +53,6 @@ #define CODE_msg_detailed_info 0x276d3ec6 #define CODE_msg_new_detailed_info 0x809db6df #define CODE_ping_delay_disconnect 0xf3427b8c - -/* sample rpc query/response structures */ -#define CODE_getUser 0xb0f732d5 -#define CODE_getUsers 0x2d84d5f5 -#define CODE_user 0xd23c81a3 -#define CODE_no_user 0xc67599d1 - -#define CODE_msgs_random 0x12345678 -#define CODE_random_msg 0x87654321 - -#define RPC_INVOKE_REQ 0x2374df3d -#define RPC_INVOKE_KPHP_REQ 0x99a37fda -#define RPC_REQ_RUNNING 0x346d5efa -#define RPC_REQ_ERROR 0x7ae432f5 -#define RPC_REQ_RESULT 0x63aeda4e -#define RPC_READY 0x6a34cac7 -#define RPC_STOP_READY 0x59d86654 -#define RPC_SEND_SESSION_MSG 0x1ed5a3cc -#define RPC_RESPONSE_INDIRECT 0x2194f56e - -/* RPC for workers */ -#define CODE_send_session_msg 0x81bb412c -#define CODE_sendMsgOk 0x29841ee2 -#define CODE_sendMsgNoSession 0x2b2b9e78 -#define CODE_sendMsgFailed 0x4b0cbd57 -#define CODE_get_auth_sessions 0x611f7845 -#define CODE_authKeyNone 0x8a8bc1f3 -#define CODE_authKeySessions 0x6b7f026c -#define CODE_add_session_box 0xe707e295 -#define CODE_set_session_box 0x193d4231 -#define CODE_replace_session_box 0xcb101b49 -#define CODE_replace_session_box_cas 0xb2bbfa78 -#define CODE_delete_session_box 0x01b78d81 -#define CODE_delete_session_box_cas 0xb3fdc3c5 -#define CODE_session_box_no_session 0x43f46c33 -#define CODE_session_box_created 0xe1dd5d40 -#define CODE_session_box_replaced 0xbd9cb6b2 -#define CODE_session_box_deleted 0xaf8fd05e -#define CODE_session_box_not_found 0xb3560a7f -#define CODE_session_box_found 0x560fe356 -#define CODE_session_box_changed 0x014b31b8 -#define CODE_get_session_box 0x8793a924 -#define CODE_get_session_box_cond 0x7888fab6 -#define CODE_session_box_session_absent 0x9e234062 -#define CODE_session_box_absent 0xa1a106eb -#define CODE_session_box 0x7956cd97 -#define CODE_session_box_large 0xb568d189 -#define CODE_get_sessions_activity 0x059dc5f6 -#define CODE_sessions_activities 0x60ce5b1d -#define CODE_get_session_activity 0x96dbac11 -#define CODE_session_activity 0xe175e8e0 - -/* RPC for front/proxy */ -#define RPC_FRONT 0x27a456f3 -#define RPC_FRONT_ACK 0x624abd23 -#define RPC_FRONT_ERR 0x71dda175 -#define RPC_PROXY_REQ 0x36cef1ee -#define RPC_PROXY_ANS 0x4403da0d -#define RPC_CLOSE_CONN 0x1fcf425d -#define RPC_CLOSE_EXT 0x5eb634a2 -#define RPC_SIMPLE_ACK 0x3bac409b - - - -#define CODE_auth_send_code 0xd16ff372 -#define CODE_auth_sent_code 0x2215bcbd -#define CODE_help_get_config 0xc4f9186b -#define CODE_config 0x232d5905 -#define CODE_dc_option 0x2ec2a43c -#define CODE_bool_false 0xbc799737 -#define CODE_bool_true 0x997275b5 -#define CODE_user_self 0x720535ec -#define CODE_auth_authorization 0xf6b673a4 -#define CODE_user_profile_photo_empty 0x4f11bae1 -#define CODE_user_profile_photo 0x990d1493 -#define CODE_user_status_empty 0x9d05049 -#define CODE_user_status_online 0xedb93949 -#define CODE_user_status_offline 0x8c703f -#define CODE_sign_in 0xbcd51581 -#define CODE_file_location 0x53d69076 -#define CODE_file_location_unavailable 0x7c596b46 -#define CODE_contacts_get_contacts 0x22c6aa08 -#define CODE_contacts_contacts 0x6f8b8cb2 -#define CODE_contact 0xf911c994 -#define CODE_user_empty 0x200250ba -#define CODE_user_contact 0xf2fb8319 -#define CODE_user_request 0x22e8ceb0 -#define CODE_user_foreign 0x5214c89d -#define CODE_user_deleted 0xb29ad7cc #define CODE_gzip_packed 0x3072cfa1 diff --git a/queries.c b/queries.c index 893ed96..8742f13 100644 --- a/queries.c +++ b/queries.c @@ -363,7 +363,7 @@ struct query_methods sign_in_methods = { int do_send_code_result (const char *code) { clear_packet (); - out_int (CODE_sign_in); + out_int (CODE_auth_sign_in); out_string (suser); out_string (phone_code_hash); out_string (code); diff --git a/structures.c b/structures.c index e67770e..0bed6f8 100644 --- a/structures.c +++ b/structures.c @@ -101,6 +101,38 @@ 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 (); + if (x == CODE_chat_empty) { + C->flags = 1; + return; + } + if (x == CODE_chat_forbidden) { + C->flags |= 8; + } + C->title = fetch_str_dup (); + C->print_title = strdup (C->title); + char *s = C->print_title; + while (*s) { + if (*s == ' ') { *s = '_'; } + s ++; + } + if (x == CODE_chat) { + unsigned y = fetch_int (); + if (y == CODE_chat_photo_empty) { + C->photo_small.dc = -2; + C->photo_big.dc = -2; + } else { + assert (y == CODE_chat_photo); + fetch_file_location (&C->photo_small); + fetch_file_location (&C->photo_big); + } + } + +} #define user_cmp(a,b) ((a)->id - (b)->id) diff --git a/structures.h b/structures.h index e3d05c1..717a5aa 100644 --- a/structures.h +++ b/structures.h @@ -27,6 +27,18 @@ struct user { struct user_status status; }; +struct chat { + int id; + int flags; + char *title; + char *print_title; + int user_num; + int date; + int version; + struct file_location photo_big; + struct file_location photo_small; +}; + void fetch_file_location (struct file_location *loc); void fetch_user (struct user *U); struct user *fetch_alloc_user (void); From baa56b709c215f4f7ffd495513c615a482ec54c9 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 14 Oct 2013 21:26:25 +0400 Subject: [PATCH 008/465] Commit parse of many structures (message, chat, photo, etc) --- gen_constants_h.awk | 19 +++ interface.c | 24 +++- mtproto-common.h | 16 ++- structures.c | 334 +++++++++++++++++++++++++++++++++++++++++--- structures.h | 116 ++++++++++++++- telegram.h | 1 + tg.pub | 9 ++ 7 files changed, 490 insertions(+), 29 deletions(-) create mode 100644 gen_constants_h.awk create mode 100644 tg.pub 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----- + From a8a18a80764eba25a8468c4f729b646fe3e984e5 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Wed, 16 Oct 2013 23:19:39 +0400 Subject: [PATCH 009/465] Sometimes updates work --- interface.c | 23 ++++++ interface.h | 4 + mtproto-client.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++ mtproto-common.h | 9 ++- net.c | 1 + queries.c | 63 +++++++++++++++- queries.h | 2 + structures.c | 85 +++++++++++++++++++++ structures.h | 7 ++ 9 files changed, 381 insertions(+), 4 deletions(-) diff --git a/interface.c b/interface.c index e20f90f..bedc835 100644 --- a/interface.c +++ b/interface.c @@ -198,6 +198,18 @@ void interpreter (char *line UU) { static char stat_buf[1 << 15]; print_stat (stat_buf, (1 << 15) - 1); printf ("%s\n", stat_buf); + } else if (!memcmp (line, "msg ", 4)) { + char *q = line + 4; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id < 0)) { + index ++; + } + while (*q && (*q == ' ' || *q == '\t')) { q ++; } + if (*q && index < user_num + chat_num) { + do_send_message (Peers[index], q); + } } } @@ -276,3 +288,14 @@ void logprintf (const char *format, ...) { free(saved_line); } } + +void print_message (struct message *M) { + union user_chat *U = user_chat_get (M->from_id); + if (!M->service) { + if (U && U->id > 0) { + rprintf (COLOR_RED "%s %s " COLOR_GREEN " >>> " COLOR_NORMAL " %s\n", U->user.first_name, U->user.last_name, M->message); + } else { + rprintf (COLOR_RED "User #%d " COLOR_GREEN " >>> " COLOR_NORMAL " %s\n", M->from_id, M->message); + } + } +} diff --git a/interface.h b/interface.h index 949ecdf..29e9e30 100644 --- a/interface.h +++ b/interface.h @@ -5,6 +5,7 @@ #define COLOR_NORMAL "\033[0m" #define COLOR_GREEN "\033[32;1m" #define COLOR_GREY "\033[37;1m" +#define COLOR_YELLOW "\033[33;1m" char *get_default_prompt (void); @@ -16,4 +17,7 @@ void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); void iprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); void hexdump (int *in_ptr, int *in_end); + +struct message; +void print_message (struct message *M); #endif diff --git a/mtproto-client.c b/mtproto-client.c index bbfd8ae..6ebcf16 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -23,6 +23,7 @@ #include "queries.h" #include "loop.h" #include "interface.h" +#include "structures.h" #define sha1 SHA1 @@ -611,6 +612,181 @@ int auth_work_start (struct connection *c UU) { } void rpc_execute_answer (struct connection *c, long long msg_id UU); + +void work_update (struct connection *c UU, long long msg_id UU) { + unsigned op = fetch_int (); + switch (op) { + case CODE_update_new_message: + { + struct message *M = fetch_alloc_message (); + print_message (M); + break; + }; + case CODE_update_message_i_d: + { + int id = fetch_int (); // id + int new = fetch_long (); // random_id + struct message *M = message_get (new); + update_message_id (M, id); + } + break; + case CODE_update_read_messages: + { + assert (fetch_int () == (int)CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + int id = fetch_int (); + struct message *M = message_get (id); + if (M) { + M->unread = 0; + } + } + fetch_int (); //pts + } + break; + case CODE_update_user_typing: + { + int id = fetch_int (); + union user_chat *U = user_chat_get (id); + if (U) { + rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name); + } + } + break; + case CODE_update_chat_user_typing: + { + int chat_id = fetch_int (); + int id = fetch_int (); + union user_chat *C = user_chat_get (-chat_id); + union user_chat *U = user_chat_get (id); + if (U && C) { + rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing in chat %s....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, C->chat.title); + } + } + break; + case CODE_update_user_status: + { + int user_id = fetch_int (); + union user_chat *U = user_chat_get (user_id); + if (U) { + fetch_user_status (&U->user.status); + rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is now %s\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, (U->user.status.online > 0) ? "online" : "offline"); + } else { + struct user_status t; + fetch_user_status (&t); + } + } + break; + case CODE_update_user_name: + { + int user_id = fetch_int (); + union user_chat *UC = user_chat_get (user_id); + if (UC) { + struct user *U = &UC->user; + if (U->first_name) { free (U->first_name); } + if (U->last_name) { free (U->first_name); } + if (U->print_name) { free (U->first_name); } + U->first_name = fetch_str_dup (); + U->last_name = fetch_str_dup (); + if (!strlen (U->first_name)) { + if (!strlen (U->last_name)) { + U->print_name = strdup ("none"); + } else { + U->print_name = strdup (U->last_name); + } + } else { + if (!strlen (U->last_name)) { + U->print_name = strdup (U->first_name); + } else { + U->print_name = malloc (strlen (U->first_name) + strlen (U->last_name) + 2); + sprintf (U->print_name, "%s_%s", U->first_name, U->last_name); + } + } + } else { + int l; + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + } + } + break; + case CODE_update_user_photo: + { + int user_id = fetch_int (); + union user_chat *UC = user_chat_get (user_id); + if (UC) { + struct user *U = &UC->user; + unsigned y = fetch_int (); + if (y == CODE_user_profile_photo_empty) { + U->photo_big.dc = -2; + U->photo_small.dc = -2; + } else { + assert (y == CODE_user_profile_photo); + fetch_file_location (&U->photo_small); + fetch_file_location (&U->photo_big); + } + } else { + struct file_location t; + unsigned y = fetch_int (); + if (y == CODE_user_profile_photo_empty) { + } else { + assert (y == CODE_user_profile_photo); + fetch_file_location (&t); + fetch_file_location (&t); + } + } + } + break; + default: + logprintf ("Unknown update type %08x\n", op); + } +} + +void work_update_short (struct connection *c, long long msg_id) { + assert (fetch_int () == CODE_update_short); + work_update (c, msg_id); + fetch_int (); // date +} + +void work_updates (struct connection *c, long long msg_id) { + assert (fetch_int () == CODE_updates); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + work_update (c, msg_id); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_user (); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_chat (); + } + fetch_int (); // date + fetch_int (); // seq + +} + +void work_update_short_message (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == (int)CODE_update_short_message); + struct message *M = fetch_alloc_message_short (); + print_message (M); +} + +void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == CODE_update_short_chat_message); + struct message *M = fetch_alloc_message_short_chat (); + print_message (M); +} + void work_container (struct connection *c, long long msg_id UU) { if (verbosity) { logprintf ( "work_container: msg_id = %lld\n", msg_id); @@ -671,6 +847,9 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { } void rpc_execute_answer (struct connection *c, long long msg_id UU) { + if (verbosity >= 5) { + hexdump_in (); + } int op = prefetch_int (); switch (op) { case CODE_msg_container: @@ -685,6 +864,18 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_rpc_result: work_rpc_result (c, msg_id); return; + case CODE_update_short: + work_update_short (c, msg_id); + return; + case CODE_updates: + work_updates (c, msg_id); + return; + case CODE_update_short_message: + work_update_short_message (c, msg_id); + return; + case CODE_update_short_chat_message: + work_update_short_chat_message (c, msg_id); + return; } logprintf ( "Unknown message: \n"); hexdump_in (); diff --git a/mtproto-common.h b/mtproto-common.h index b0357c6..be30560 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -255,8 +255,12 @@ static inline int prefetch_strlen (void) { } } - +extern int verbosity; static inline char *fetch_str (int len) { + assert (len >= 0); + if (verbosity > 6) { + logprintf ("fetch_string: len = %d\n", len); + } if (len < 254) { char *str = (char *) in_ptr + 1; in_ptr += 1 + (len >> 2); @@ -289,6 +293,9 @@ static inline long have_prefetch_ints (void) { int fetch_bignum (BIGNUM *x); static inline int fetch_int (void) { + if (verbosity > 6) { + logprintf ("fetch_int: 0x%08x (%d)\n", *in_ptr, *in_ptr); + } return *(in_ptr ++); } diff --git a/net.c b/net.c index ed5a835..8e44e17 100644 --- a/net.c +++ b/net.c @@ -391,6 +391,7 @@ void connections_poll_result (struct pollfd *fds, int max) { int send_all_acks (struct session *S) { clear_packet (); + out_int (CODE_msgs_ack); out_int (tree_count_int (S->ack_tree)); while (S->ack_tree) { int x = tree_get_min_int (S->ack_tree); diff --git a/queries.c b/queries.c index 8742f13..b984e74 100644 --- a/queries.c +++ b/queries.c @@ -46,6 +46,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } struct query *q = malloc (sizeof (*q)); + memset (q, 0, sizeof (*q)); q->data_len = ints; q->data = malloc (4 * ints); memcpy (q->data, data, 4 * ints); @@ -68,7 +69,10 @@ 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; } + if (q) { + remove_event_timer (&q->ev); + q->flags |= QUERY_ACK_RECEIVED; + } } void query_error (long long id) { @@ -85,7 +89,9 @@ void query_error (long long id) { logprintf ( "No such query\n"); } } else { - remove_event_timer (&q->ev); + if (!(q->flags & QUERY_ACK_RECEIVED)) { + remove_event_timer (&q->ev); + } queries_tree = tree_delete_query (queries_tree, q); if (q->methods && q->methods->on_error) { q->methods->on_error (q, error_code, error_len, error); @@ -143,7 +149,9 @@ void query_result (long long id UU) { logprintf ( "No such query\n"); } } else { - remove_event_timer (&q->ev); + if (!(q->flags & QUERY_ACK_RECEIVED)) { + remove_event_timer (&q->ev); + } queries_tree = tree_delete_query (queries_tree, q); if (q->methods && q->methods->on_answer) { q->methods->on_answer (q); @@ -191,6 +199,10 @@ void work_timers (void) { assert (ev); if (ev->timeout > t) { break; } remove_event_timer (ev); + assert (ev->alarm); + if (verbosity) { + logprintf ("Alarm\n"); + } ev->alarm (ev->self); } } @@ -405,3 +417,48 @@ void do_update_contact_list (void) { out_string (""); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods); } + + +int msg_send_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_sent_message); + int uid = fetch_int (); // uid + int date = fetch_int (); // date + int ptr = fetch_int (); // ptr + int seq = fetch_int (); // seq + logprintf ("Sent: uid = %d, date = %d, ptr = %d, seq = %d\n", uid, date, ptr, seq); + return 0; +} + +struct query_methods msg_send_methods = { + .on_answer = msg_send_on_answer +}; + +int out_message_num; +void do_send_message (union user_chat *U, const char *msg) { + if (!out_message_num) { + out_message_num = lrand48 (); + } + clear_packet (); + out_int (CODE_messages_send_message); + if (U->id < 0) { + out_int (CODE_input_peer_chat); + out_int (-U->id); + } else { + if (U->user.access_hash) { + out_int (CODE_input_peer_foreign); + out_int (U->id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_peer_contact); + out_int (U->id); + } + } + out_string (msg); + out_long (out_message_num ++); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods); + if (U->id < 0) { + rprintf (COLOR_RED "%s" COLOR_GREEN " <<< " COLOR_NORMAL "%s\n", U->chat.title, msg); + } else { + rprintf (COLOR_RED "%s %s" COLOR_GREEN " <<< " COLOR_NORMAL "%s\n", U->user.first_name, U->user.last_name, msg); + } +} diff --git a/queries.h b/queries.h index 3f812e2..c13ed76 100644 --- a/queries.h +++ b/queries.h @@ -44,4 +44,6 @@ int do_send_code_result (const char *code); double get_double_time (void); void do_update_contact_list (void); +union user_chat; +void do_send_message (union user_chat *U, const char *msg); #endif diff --git a/structures.c b/structures.c index 87d81fa..bebe2b0 100644 --- a/structures.c +++ b/structures.c @@ -4,6 +4,8 @@ #include "telegram.h" #include "tree.h" +int verbosity; + void fetch_file_location (struct file_location *loc) { int x = fetch_int (); if (x == CODE_file_location_unavailable) { @@ -234,6 +236,28 @@ void fetch_message_action (struct message_action *M) { } } +void fetch_message_short (struct message *M) { + memset (M, 0, sizeof (*M)); + M->id = fetch_int (); + M->from_id = fetch_int (); + M->message = fetch_str_dup (); + fetch_int (); // pts + M->date = fetch_int (); + fetch_int (); // seq +} + +void fetch_message_short_chat (struct message *M) { + memset (M, 0, sizeof (*M)); + M->id = fetch_int (); + M->from_id = fetch_int (); + M->to_id = fetch_int (); + M->message = fetch_str_dup (); + fetch_int (); // pts + M->date = fetch_int (); + fetch_int (); // seq +} + + void fetch_message_media (struct message_media *M) { memset (M, 0, sizeof (*M)); M->type = fetch_int (); @@ -442,6 +466,49 @@ struct message *fetch_alloc_message (void) { } } +struct message *fetch_alloc_message_short (void) { + struct message *M = malloc (sizeof (*M)); + fetch_message_short (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 message *fetch_alloc_message_short_chat (void) { + struct message *M = malloc (sizeof (*M)); + fetch_message_short_chat (M); + if (verbosity >= 2) { + logprintf ("Read message with id %d\n", M->id); + } + 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); @@ -475,3 +542,21 @@ int print_stat (char *s, int len) { messages_allocated ); } + +union user_chat *user_chat_get (int id) { + union user_chat U; + U.id = id; + return tree_lookup_peer (peer_tree, &U); +} + +struct message *message_get (int id) { + struct message M; + M.id = id; + return tree_lookup_message (message_tree, &M); +} + +void update_message_id (struct message *M, int id) { + message_tree = tree_delete_message (message_tree, M); + M->id = id; + message_tree = tree_insert_message (message_tree, M, lrand48 ()); +} diff --git a/structures.h b/structures.h index df89632..2b527c5 100644 --- a/structures.h +++ b/structures.h @@ -142,12 +142,19 @@ struct message { }; void fetch_file_location (struct file_location *loc); +void fetch_user_status (struct user_status *S); void fetch_user (struct user *U); struct user *fetch_alloc_user (void); 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); void free_user (struct user *U); void free_chat (struct chat *U); int print_stat (char *s, int len); +union user_chat *user_chat_get (int id); +struct message *message_get (int id); +void update_message_id (struct message *M, int id); #endif From e40ae9590da468d6f4d5dfb845b5ec08f471737f Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 18 Oct 2013 20:00:47 +0400 Subject: [PATCH 010/465] Many bug fixes. Added dialog_list query --- interface.c | 84 +++++++++++++++++++++++++++++++++--- interface.h | 1 + mtproto-client.c | 44 +++++++++++++++++++ mtproto-common.h | 8 ++++ queries.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++- queries.h | 2 + structures.c | 54 +++++++++++++++++------ structures.h | 1 + 8 files changed, 282 insertions(+), 21 deletions(-) diff --git a/interface.c b/interface.c index bedc835..af608ec 100644 --- a/interface.c +++ b/interface.c @@ -13,6 +13,8 @@ #include "interface.h" #include "telegram.h" #include "structures.h" + +#include "mtproto-common.h" char *default_prompt = ">"; char *get_default_prompt (void) { @@ -28,6 +30,8 @@ char *commands[] = { "msg", "contact_list", "stats", + "history", + "dialog_list", 0 }; int commands_flags[] = { @@ -35,6 +39,8 @@ int commands_flags[] = { 072, 07, 07, + 072, + 07, }; char *a = 0; @@ -194,6 +200,8 @@ void interpreter (char *line UU) { } if (!memcmp (line, "contact_list", 12)) { do_update_contact_list (); + } else if (!memcmp (line, "dialog_list", 11)) { + do_get_dialog_list (); } else if (!memcmp (line, "stats", 5)) { static char stat_buf[1 << 15]; print_stat (stat_buf, (1 << 15) - 1); @@ -203,13 +211,32 @@ void interpreter (char *line UU) { int len; char *text = get_token (&q, &len); int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id < 0)) { + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { index ++; } while (*q && (*q == ' ' || *q == '\t')) { q ++; } if (*q && index < user_num + chat_num) { do_send_message (Peers[index], q); } + } else if (!memcmp (line, "history", 7)) { + char *q = line + 7; + int len; + char *text = get_token (&q, &len); + int index = 0; + 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 + chat_num) { + char *text = get_token (&q, &len); + int limit = 40; + if (text) { + limit = atoi (text); + if (limit <= 0 || limit >= 1000000) { + limit = 40; + } + } + do_get_history (Peers[index], limit); + } } } @@ -289,13 +316,58 @@ void logprintf (const char *format, ...) { } } +const char *message_media_type_str (struct message_media *M) { + static char buf[1000]; + switch (M->type) { + case CODE_message_media_empty: + return ""; + case CODE_message_media_photo: + return "[photo]"; + case CODE_message_media_video: + return "[video]"; + case CODE_message_media_geo: + sprintf (buf, "[geo] %.6lf:%.6lf", M->geo.latitude, M->geo.longitude); + return buf; + case CODE_message_media_contact: + snprintf (buf, 999, "[contact] " COLOR_RED "%s %s" COLOR_NORMAL " %s", M->first_name, M->last_name, M->phone); + return buf; + case CODE_message_media_unsupported: + return "[unsupported]"; + default: + assert (0); + return ""; + + } +} + void print_message (struct message *M) { - union user_chat *U = user_chat_get (M->from_id); - if (!M->service) { - if (U && U->id > 0) { - rprintf (COLOR_RED "%s %s " COLOR_GREEN " >>> " COLOR_NORMAL " %s\n", U->user.first_name, U->user.last_name, M->message); + if (M->service) { + rprintf ("Service message\n"); + return; + } + if (M->to_id >= 0) { + if (M->out) { + union user_chat *U = user_chat_get (M->to_id); + assert (M->from_id >= 0); + if (U) { + rprintf (COLOR_RED "%s %s" COLOR_GREEN " <<< %s %s" COLOR_NORMAL "\n", U->user.first_name, U->user.last_name, M->message, message_media_type_str (&M->media)); + } else { + rprintf (COLOR_RED "User #%d" COLOR_GREEN " <<< %s %s" COLOR_NORMAL "\n", M->from_id, M->message, message_media_type_str (&M->media)); + } } else { - rprintf (COLOR_RED "User #%d " COLOR_GREEN " >>> " COLOR_NORMAL " %s\n", M->from_id, M->message); + union user_chat *U = user_chat_get (M->from_id); + assert (M->from_id >= 0); + if (U) { + rprintf (COLOR_RED "%s %s" COLOR_BLUE " >>> %s %s" COLOR_NORMAL "\n", U->user.first_name, U->user.last_name, M->message, message_media_type_str (&M->media)); + } else { + rprintf (COLOR_RED "User #%d" COLOR_BLUE " >>> %s %s" COLOR_NORMAL "\n", M->from_id, M->message, message_media_type_str (&M->media)); + } + } + } else { + rprintf ("Message to chat %d\n", -M->to_id); + union user_chat *C = user_chat_get (M->to_id); + if (C) { + rprintf ("Chat %s\n", C->chat.title); } } } diff --git a/interface.h b/interface.h index 29e9e30..df1b1d3 100644 --- a/interface.h +++ b/interface.h @@ -6,6 +6,7 @@ #define COLOR_GREEN "\033[32;1m" #define COLOR_GREY "\033[37;1m" #define COLOR_YELLOW "\033[33;1m" +#define COLOR_BLUE "\033[34;1m" char *get_default_prompt (void); diff --git a/mtproto-client.c b/mtproto-client.c index 6ebcf16..168b075 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "net.h" #include "include.h" @@ -619,6 +620,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { case CODE_update_new_message: { struct message *M = fetch_alloc_message (); + fetch_int (); //pts print_message (M); break; }; @@ -846,6 +848,45 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { } } +#define MAX_PACKED_SIZE (1 << 20) +void work_packed (struct connection *c, long long msg_id) { + assert (fetch_int () == CODE_gzip_packed); + static int in_gzip; + static int buf[MAX_PACKED_SIZE >> 2]; + assert (!in_gzip); + in_gzip = 1; + + int l = prefetch_strlen (); + char *s = fetch_str (l); + size_t dl = MAX_PACKED_SIZE; + + z_stream strm = {0}; + assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); + strm.avail_in = l; + strm.next_in = (void *)s; + strm.avail_out = MAX_PACKED_SIZE; + strm.next_out = (void *)buf; + + int err = inflate (&strm, Z_FINISH); + if (verbosity) { + logprintf ( "inflate error = %d\n", err); + logprintf ( "inflated %d bytes\n", (int)strm.total_out); + } + int *end = in_ptr; + int *eend = in_end; + assert (dl % 4 == 0); + in_ptr = buf; + in_end = in_ptr + strm.total_out / 4; + if (verbosity >= 4) { + logprintf ( "Unzipped data: "); + hexdump_in (); + } + rpc_execute_answer (c, msg_id); + in_ptr = end; + in_end = eend; + in_gzip = 0; +} + void rpc_execute_answer (struct connection *c, long long msg_id UU) { if (verbosity >= 5) { hexdump_in (); @@ -876,6 +917,9 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_update_short_chat_message: work_update_short_chat_message (c, msg_id); return; + case CODE_gzip_packed: + work_packed (c, msg_id); + return; } logprintf ( "Unknown message: \n"); hexdump_in (); diff --git a/mtproto-common.h b/mtproto-common.h index be30560..498de9e 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -299,6 +299,14 @@ static inline int fetch_int (void) { return *(in_ptr ++); } +static inline int fetch_bool (void) { + if (verbosity > 6) { + logprintf ("fetch_bool: 0x%08x (%d)\n", *in_ptr, *in_ptr); + } + assert (*(in_ptr) == (int)CODE_bool_true || *(in_ptr) == (int)CODE_bool_false); + return *(in_ptr ++) == (int)CODE_bool_true; +} + static inline int prefetch_int (void) { return *(in_ptr); } diff --git a/queries.c b/queries.c index b984e74..807f111 100644 --- a/queries.c +++ b/queries.c @@ -33,6 +33,8 @@ struct query *query_get (long long id) { int alarm_query (struct query *q) { assert (q); + q->ev.timeout = get_double_time () + QUERY_TIMEOUT; + insert_event_timer (&q->ev); return 0; } @@ -69,7 +71,7 @@ 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) { + if (q && !(q->flags & QUERY_ACK_RECEIVED)) { remove_event_timer (&q->ev); q->flags |= QUERY_ACK_RECEIVED; } @@ -462,3 +464,108 @@ void do_send_message (union user_chat *U, const char *msg) { rprintf (COLOR_RED "%s %s" COLOR_GREEN " <<< " COLOR_NORMAL "%s\n", U->user.first_name, U->user.last_name, msg); } } + +int get_history_on_answer (struct query *q UU) { + static struct message *ML[10000]; + int i; + int x = fetch_int (); + if (x == (int)CODE_messages_messages_slice) { + fetch_int (); + rprintf ("...\n"); + } else { + assert (x == (int)CODE_messages_messages); + } + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + for (i = 0; i < n; i++) { + struct message *M = fetch_alloc_message (); + if (i <= 9999) { + ML[i] = M; + } + } + if (n > 10000) { n = 10000; } + for (i = n - 1; i >= 0; i--) { + print_message (ML[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 (); + } + return 0; +} + +struct query_methods get_history_methods = { + .on_answer = get_history_on_answer, +}; + + +void do_get_history (union user_chat *U, int limit) { + clear_packet (); + out_int (CODE_messages_get_history); + if (U->id < 0) { + out_int (CODE_input_peer_chat); + out_int (-U->id); + } else { + if (U->user.access_hash) { + out_int (CODE_input_peer_foreign); + out_int (U->id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_peer_contact); + out_int (U->id); + } + } + out_int (0); + out_int (0); + out_int (limit); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods); +} + +int get_dialogs_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_messages_dialogs); + assert (fetch_int () == CODE_vector); + int n, i; + n = fetch_int (); + for (i = 0; i < n; i++) { + assert (fetch_int () == CODE_dialog); + fetch_peer_id (); + fetch_int (); + fetch_int (); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_message (); + } + 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 (); + } + return 0; +} + +struct query_methods get_dialogs_methods = { + .on_answer = get_dialogs_on_answer, +}; + + +void do_get_dialog_list (void) { + clear_packet (); + out_int (CODE_messages_get_dialogs); + out_int (0); + out_int (0); + out_int (1000); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods); +} diff --git a/queries.h b/queries.h index c13ed76..67a5698 100644 --- a/queries.h +++ b/queries.h @@ -46,4 +46,6 @@ double get_double_time (void); void do_update_contact_list (void); union user_chat; void do_send_message (union user_chat *U, const char *msg); +void do_get_history (union user_chat *U, int limit); +void do_get_dialog_list (void); #endif diff --git a/structures.c b/structures.c index bebe2b0..cf4a678 100644 --- a/structures.c +++ b/structures.c @@ -148,6 +148,7 @@ void fetch_chat (struct chat *C) { } void fetch_photo_size (struct photo_size *S) { + memset (S, 0, sizeof (*S)); unsigned x = fetch_int (); assert (x == CODE_photo_size || x == CODE_photo_cached_size); S->type = fetch_str_dup (); @@ -162,9 +163,15 @@ void fetch_photo_size (struct photo_size *S) { } void fetch_geo (struct geo *G) { - assert (fetch_int () == CODE_geo_point); - G->longitude = fetch_double (); - G->latitude = fetch_double (); + unsigned x = fetch_int (); + if (x == CODE_geo_point) { + G->longitude = fetch_double (); + G->latitude = fetch_double (); + } else { + assert (x == CODE_geo_point_empty); + G->longitude = 0; + G->latitude = 0; + } } void fetch_photo (struct photo *P) { @@ -244,17 +251,19 @@ void fetch_message_short (struct message *M) { fetch_int (); // pts M->date = fetch_int (); fetch_int (); // seq + M->media.type = CODE_message_media_empty; } void fetch_message_short_chat (struct message *M) { memset (M, 0, sizeof (*M)); M->id = fetch_int (); M->from_id = fetch_int (); - M->to_id = fetch_int (); + M->to_id = -fetch_int (); M->message = fetch_str_dup (); fetch_int (); // pts M->date = fetch_int (); fetch_int (); // seq + M->media.type = CODE_message_media_empty; } @@ -283,10 +292,21 @@ void fetch_message_media (struct message_media *M) { M->data = fetch_str_dup (); break; default: + logprintf ("type = 0x%08x\n", M->type); assert (0); } } +int fetch_peer_id (void) { + unsigned x =fetch_int (); + if (x == CODE_peer_user) { + return fetch_int (); + } else { + assert (CODE_peer_chat); + return -fetch_int (); + } +} + void fetch_message (struct message *M) { memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); @@ -301,9 +321,9 @@ void fetch_message (struct message *M) { 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->to_id = fetch_peer_id (); + M->out = fetch_bool (); + M->unread = fetch_bool (); M->date = fetch_int (); if (x == CODE_message_service) { M->service = 1; @@ -360,21 +380,27 @@ void free_user (struct user *U) { void free_photo_size (struct photo_size *S) { free (S->type); - free (S->data); + if (S->data) { + 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]); + if (!P->access_hash) { return; } + if (P->caption) { free (P->caption); } + if (P->sizes) { + int i; + for (i = 0; i < P->sizes_num; i++) { + free_photo_size (&P->sizes[i]); + } + free (P->sizes); } - free (P->sizes); } void free_video (struct video *V) { + if (!V->access_hash) { return; } free (V->caption); - free (&V->thumb); + free_photo_size (&V->thumb); } void free_message_media (struct message_media *M) { diff --git a/structures.h b/structures.h index 2b527c5..990fed6 100644 --- a/structures.h +++ b/structures.h @@ -149,6 +149,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); +int fetch_peer_id (void); void free_user (struct user *U); void free_chat (struct chat *U); From 1ceaa48b78c7582f85e821b1f0594c16e5154dda Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 18 Oct 2013 20:05:55 +0400 Subject: [PATCH 011/465] Fixed hostory for queries --- interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.c b/interface.c index af608ec..e296d55 100644 --- a/interface.c +++ b/interface.c @@ -223,7 +223,7 @@ void interpreter (char *line UU) { int len; char *text = get_token (&q, &len); int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id < 0)) { + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { index ++; } if (index < user_num + chat_num) { From 820840ec4df78b61d53604e6155be72798ce283a Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 18 Oct 2013 22:00:19 +0400 Subject: [PATCH 012/465] Fixed some compilation errors --- interface.c | 7 ++++--- mtproto-client.c | 3 ++- queries.c | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/interface.c b/interface.c index e296d55..3dfeb1e 100644 --- a/interface.c +++ b/interface.c @@ -1,12 +1,13 @@ #define _GNU_SOURCE -#include -#include - #include #include #include #include #include + +#include +#include + #include "include.h" #include "queries.h" diff --git a/mtproto-client.c b/mtproto-client.c index 168b075..a44933f 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -860,7 +860,8 @@ void work_packed (struct connection *c, long long msg_id) { char *s = fetch_str (l); size_t dl = MAX_PACKED_SIZE; - z_stream strm = {0}; + z_stream strm; + memset (&strm, 0, sizeof (strm)); assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); strm.avail_in = l; strm.next_in = (void *)s; diff --git a/queries.c b/queries.c index 807f111..bf3cfc8 100644 --- a/queries.c +++ b/queries.c @@ -123,7 +123,8 @@ void query_result (long long id UU) { char *s = fetch_str (l); size_t dl = MAX_PACKED_SIZE; - z_stream strm = {0}; + z_stream strm; + memset (&strm, 0, sizeof (strm)); assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); strm.avail_in = l; strm.next_in = (void *)s; From 0fef150a94ac34296ed03a2c53a1ef4880af2d35 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 18 Oct 2013 22:08:20 +0400 Subject: [PATCH 013/465] mtproto-client: fix server time on first mesasge --- mtproto-client.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mtproto-client.c b/mtproto-client.c index a44933f..d7bde57 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -949,7 +949,12 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, DC->server_salt = enc->server_salt; write_auth_file (); } + int this_server_time = enc->msg_id >> 32LL; + if (!DC->server_time_delta) { + DC->server_time_delta = this_server_time - time (0); + DC->server_time_udelta = this_server_time - get_utime (CLOCK_MONOTONIC); + } double st = get_server_time (DC); assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); From 6cc1b3d3494e94c1867603202856156ba048f887 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 18 Oct 2013 23:30:24 +0400 Subject: [PATCH 014/465] Fixed small bug. Changed interface --- interface.c | 166 +++++++++++++++++++++++++++++++++++++++++++++------ interface.h | 1 + loop.c | 6 ++ queries.c | 47 +++++++++------ queries.h | 3 +- structures.c | 15 ++++- structures.h | 1 + 7 files changed, 201 insertions(+), 38 deletions(-) diff --git a/interface.c b/interface.c index 3dfeb1e..dbef70f 100644 --- a/interface.c +++ b/interface.c @@ -267,6 +267,32 @@ void rprintf (const char *format, ...) { } } +int saved_point; +char *saved_line; +int prompt_was; +void print_start (void) { + assert (!prompt_was); + if (readline_active) { + saved_point = rl_point; + saved_line = rl_copy_text(0, rl_end); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); + } + prompt_was = 1; +} +void print_end (void) { + assert (prompt_was); + if (readline_active) { + rl_restore_prompt(); + rl_replace_line(saved_line, 0); + rl_point = saved_point; + rl_redisplay(); + free(saved_line); + } + prompt_was = 0; +} + void hexdump (int *in_ptr, int *in_end) { int saved_point = 0; char *saved_line = 0; @@ -341,34 +367,138 @@ const char *message_media_type_str (struct message_media *M) { } } +int color_stack_pos; +const char *color_stack[10]; + +void push_color (const char *color) { + assert (color_stack_pos < 10); + color_stack[color_stack_pos ++] = color; + printf ("%s", color); +} + +void pop_color (void) { + assert (color_stack_pos > 0); + color_stack_pos --; + if (color_stack_pos >= 1) { + printf ("%s", color_stack[color_stack_pos] - 1); + } else { + printf ("%s", COLOR_NORMAL); + } +} + +void print_media (struct message_media *M) { + switch (M->type) { + case CODE_message_media_empty: + return; + case CODE_message_media_photo: + printf ("[photo]"); + return; + case CODE_message_media_video: + printf ("[video]"); + return; + case CODE_message_media_geo: + printf ("[geo] "); + printf ("%.6lf:%.6lf", M->geo.latitude, M->geo.longitude); + return; + case CODE_message_media_contact: + printf ("[contact] "); + push_color (COLOR_RED); + printf ("%s %s ", M->first_name, M->last_name); + pop_color (); + printf ("%s", M->phone); + return; + case CODE_message_media_unsupported: + printf ("[unsupported]"); + return; + default: + assert (0); + } +} + +void print_user_name (int id, union user_chat *U) { + push_color (COLOR_RED); + if (!U) { + printf ("user#%d", id); + } else if (!U->user.first_name) { + printf ("%s", U->user.last_name); + } else if (!U->user.last_name) { + printf ("%s", U->user.first_name); + } else { + printf ("%s %s", U->user.first_name, U->user.last_name); + } + pop_color (); +} + +void print_chat_name (int id, union user_chat *C) { + push_color (COLOR_MAGENTA); + if (!C) { + printf ("chat#%d", -id); + } else { + printf ("%s", C->chat.title); + } + pop_color (); +} + +static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +void print_date (long t) { + struct tm *tm = localtime (&t); + if (time (0) - t < 12 * 60 * 60) { + printf ("[%02d:%02d] ", tm->tm_hour, tm->tm_min); + } else { + printf ("[%02d %s]", tm->tm_mday, monthes[tm->tm_mon]); + } +} + +int our_id; void print_message (struct message *M) { if (M->service) { rprintf ("Service message\n"); return; } + + + print_start (); if (M->to_id >= 0) { if (M->out) { - union user_chat *U = user_chat_get (M->to_id); - assert (M->from_id >= 0); - if (U) { - rprintf (COLOR_RED "%s %s" COLOR_GREEN " <<< %s %s" COLOR_NORMAL "\n", U->user.first_name, U->user.last_name, M->message, message_media_type_str (&M->media)); - } else { - rprintf (COLOR_RED "User #%d" COLOR_GREEN " <<< %s %s" COLOR_NORMAL "\n", M->from_id, M->message, message_media_type_str (&M->media)); - } + push_color (COLOR_GREEN); + print_date (M->date); + pop_color (); + printf (" "); + print_user_name (M->to_id, user_chat_get (M->to_id)); + push_color (COLOR_GREEN); + printf (" <<< "); } else { - union user_chat *U = user_chat_get (M->from_id); - assert (M->from_id >= 0); - if (U) { - rprintf (COLOR_RED "%s %s" COLOR_BLUE " >>> %s %s" COLOR_NORMAL "\n", U->user.first_name, U->user.last_name, M->message, message_media_type_str (&M->media)); - } else { - rprintf (COLOR_RED "User #%d" COLOR_BLUE " >>> %s %s" COLOR_NORMAL "\n", M->from_id, M->message, message_media_type_str (&M->media)); - } + push_color (COLOR_BLUE); + print_date (M->date); + pop_color (); + printf (" "); + print_user_name (M->from_id, user_chat_get (M->from_id)); + push_color (COLOR_BLUE); + printf (" >>> "); } } else { - rprintf ("Message to chat %d\n", -M->to_id); - union user_chat *C = user_chat_get (M->to_id); - if (C) { - rprintf ("Chat %s\n", C->chat.title); + push_color (COLOR_MAGENTA); + print_date (M->date); + pop_color (); + printf (" "); + print_chat_name (M->to_id, user_chat_get (M->to_id)); + printf (" "); + print_user_name (M->from_id, user_chat_get (M->from_id)); + if (M->from_id == our_id) { + push_color (COLOR_GREEN); + } else { + push_color (COLOR_BLUE); } + printf (" >>> "); } + if (M->message && strlen (M->message)) { + printf ("%s", M->message); + } + if (M->media.type != CODE_message_media_empty) { + print_media (&M->media); + } + pop_color (); + assert (!color_stack_pos); + printf ("\n"); + print_end(); } diff --git a/interface.h b/interface.h index df1b1d3..eacf061 100644 --- a/interface.h +++ b/interface.h @@ -7,6 +7,7 @@ #define COLOR_GREY "\033[37;1m" #define COLOR_YELLOW "\033[33;1m" #define COLOR_BLUE "\033[34;1m" +#define COLOR_MAGENTA "\033[35;1m" char *get_default_prompt (void); diff --git a/loop.c b/loop.c index c91287b..55707fb 100644 --- a/loop.c +++ b/loop.c @@ -92,6 +92,7 @@ void write_dc (int auth_file_fd, struct dc *DC) { assert (write (auth_file_fd, &DC->server_salt, 8) == 8); } +int our_id; void write_auth_file (void) { int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU); assert (auth_file_fd >= 0); @@ -112,6 +113,7 @@ void write_auth_file (void) { assert (write (auth_file_fd, &x, 4) == 4); } } + assert (write (auth_file_fd, &our_id, 4) == 4); close (auth_file_fd); } @@ -164,6 +166,10 @@ void read_auth_file (void) { read_dc (auth_file_fd, i); } } + int l = read (auth_file_fd, &our_id, 4); + if (l < 4) { + assert (!l); + } close (auth_file_fd); } diff --git a/queries.c b/queries.c index bf3cfc8..f3139c0 100644 --- a/queries.c +++ b/queries.c @@ -38,7 +38,7 @@ int alarm_query (struct query *q) { return 0; } -struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods) { +struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { assert (DC); assert (DC->auth_key_id); if (!DC->sessions[0]) { @@ -66,6 +66,8 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth q->ev.timeout = get_double_time () + QUERY_TIMEOUT; q->ev.self = (void *)q; insert_event_timer (&q->ev); + + q->extra = extra; return q; } @@ -307,7 +309,7 @@ void do_send_code (const char *user) { out_int (TG_APP_ID); out_string (TG_APP_HASH); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); if (want_dc_num == -1) { return; } @@ -323,7 +325,7 @@ void do_send_code (const char *user) { } else { clear_packet (); out_int (CODE_help_get_config); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods); + 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) { @@ -342,7 +344,7 @@ void do_send_code (const char *user) { out_int (TG_APP_ID); out_string (TG_APP_HASH); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); assert (want_dc_num == -1); } @@ -382,7 +384,7 @@ int do_send_code_result (const char *code) { out_string (suser); out_string (phone_code_hash); out_string (code); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods); + 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; @@ -418,17 +420,20 @@ void do_update_contact_list (void) { clear_packet (); out_int (CODE_contacts_get_contacts); out_string (""); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, 0); } int msg_send_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_sent_message); - int uid = fetch_int (); // uid + int id = fetch_int (); // id int date = fetch_int (); // date int ptr = fetch_int (); // ptr int seq = fetch_int (); // seq - logprintf ("Sent: uid = %d, date = %d, ptr = %d, seq = %d\n", uid, date, ptr, seq); + struct message *M = q->extra; + M->id = id; + message_insert (M); + logprintf ("Sent: id = %d, date = %d, ptr = %d, seq = %d\n", id, date, ptr, seq); return 0; } @@ -437,12 +442,17 @@ struct query_methods msg_send_methods = { }; int out_message_num; +int our_id; void do_send_message (union user_chat *U, const char *msg) { if (!out_message_num) { - out_message_num = lrand48 (); + out_message_num = -lrand48 (); } clear_packet (); out_int (CODE_messages_send_message); + struct message *M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->from_id = our_id; + M->to_id = U->id; if (U->id < 0) { out_int (CODE_input_peer_chat); out_int (-U->id); @@ -456,14 +466,15 @@ void do_send_message (union user_chat *U, const char *msg) { out_int (U->id); } } + M->message = strdup (msg); + M->out = 1; + M->media.type = CODE_message_media_empty; + M->id = out_message_num; + M->date = time (0); out_string (msg); - out_long (out_message_num ++); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods); - if (U->id < 0) { - rprintf (COLOR_RED "%s" COLOR_GREEN " <<< " COLOR_NORMAL "%s\n", U->chat.title, msg); - } else { - rprintf (COLOR_RED "%s %s" COLOR_GREEN " <<< " COLOR_NORMAL "%s\n", U->user.first_name, U->user.last_name, msg); - } + out_long ((--out_message_num) - (1ll << 32)); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M); + print_message (M); } int get_history_on_answer (struct query *q UU) { @@ -525,7 +536,7 @@ void do_get_history (union user_chat *U, int limit) { out_int (0); out_int (0); out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, 0); } int get_dialogs_on_answer (struct query *q UU) { @@ -568,5 +579,5 @@ void do_get_dialog_list (void) { out_int (0); out_int (0); out_int (1000); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); } diff --git a/queries.h b/queries.h index 67a5698..84012aa 100644 --- a/queries.h +++ b/queries.h @@ -24,10 +24,11 @@ struct query { void *data; struct query_methods *methods; struct event_timer ev; + void *extra; }; -struct query *send_query (struct dc *DC, int len, void *data, struct query_methods *methods); +struct query *send_query (struct dc *DC, int len, void *data, struct query_methods *methods, void *extra); void query_ack (long long id); void query_error (long long id); void query_result (long long id); diff --git a/structures.c b/structures.c index cf4a678..a70a5d1 100644 --- a/structures.c +++ b/structures.c @@ -3,7 +3,7 @@ #include "mtproto-common.h" #include "telegram.h" #include "tree.h" - +#include "loop.h" int verbosity; void fetch_file_location (struct file_location *loc) { @@ -41,6 +41,7 @@ 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 (); @@ -50,6 +51,13 @@ void fetch_user (struct user *U) { U->flags = 1; return; } + if (x == CODE_user_self) { + assert (!our_id || (our_id == U->id)); + if (!our_id) { + our_id = U->id; + write_auth_file (); + } + } U->first_name = fetch_str_dup (); U->last_name = fetch_str_dup (); if (!strlen (U->first_name)) { @@ -586,3 +594,8 @@ void update_message_id (struct message *M, int id) { M->id = id; message_tree = tree_insert_message (message_tree, M, lrand48 ()); } + +void message_insert (struct message *M) { + message_add_use (M); + message_tree = tree_insert_message (message_tree, M, lrand48 ()); +} diff --git a/structures.h b/structures.h index 990fed6..02eb976 100644 --- a/structures.h +++ b/structures.h @@ -158,4 +158,5 @@ int print_stat (char *s, int len); 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); #endif From dd6c67008dd849aa92b33fb8c1bfcbe987b6c11e Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 19 Oct 2013 15:46:41 +0400 Subject: [PATCH 015/465] fixed fail on free geo media type --- structures.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/structures.c b/structures.c index a70a5d1..0502ba7 100644 --- a/structures.c +++ b/structures.c @@ -414,6 +414,7 @@ void free_video (struct video *V) { void free_message_media (struct message_media *M) { switch (M->type) { case CODE_message_media_empty: + case CODE_message_media_geo: return; case CODE_message_media_photo: free_photo (&M->photo); @@ -430,6 +431,7 @@ void free_message_media (struct message_media *M) { free (M->data); return; default: + logprintf ("%08x\n", M->type); assert (0); } } From 1c0ba265f0e8428caa23a39f65561a423b7eaed3 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 21 Oct 2013 22:24:31 +0400 Subject: [PATCH 016/465] Support for sending photos. Some fixed bugs. Slightly changed interface --- interface.c | 46 +++++++++++++-- interface.h | 7 +++ mtproto-client.c | 57 ++++++++++++++++--- queries.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++- queries.h | 3 + 5 files changed, 241 insertions(+), 15 deletions(-) diff --git a/interface.c b/interface.c index dbef70f..a246954 100644 --- a/interface.c +++ b/interface.c @@ -33,6 +33,8 @@ char *commands[] = { "stats", "history", "dialog_list", + "send_photo", + "send_video", 0 }; int commands_flags[] = { @@ -42,6 +44,8 @@ int commands_flags[] = { 07, 072, 07, + 0732, + 0732, }; char *a = 0; @@ -219,6 +223,22 @@ void interpreter (char *line UU) { if (*q && index < user_num + chat_num) { do_send_message (Peers[index], q); } + } else if (!memcmp (line, "send_photo", 10)) { + char *q = line + 10; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num) { + int len = 0; + char *f = get_token (&q, &len); + if (len > 0) { + do_send_photo (CODE_input_media_uploaded_photo, + Peers[index]->id, strndup (f, len)); + } + } } else if (!memcmp (line, "history", 7)) { char *q = line + 7; int len; @@ -380,7 +400,7 @@ void pop_color (void) { assert (color_stack_pos > 0); color_stack_pos --; if (color_stack_pos >= 1) { - printf ("%s", color_stack[color_stack_pos] - 1); + printf ("%s", color_stack[color_stack_pos - 1]); } else { printf ("%s", COLOR_NORMAL); } @@ -391,7 +411,11 @@ void print_media (struct message_media *M) { case CODE_message_media_empty: return; case CODE_message_media_photo: - printf ("[photo]"); + if (M->photo.caption && strlen (M->photo.caption)) { + printf ("[photo %s]", M->photo.caption); + } else { + printf ("[photo]"); + } return; case CODE_message_media_video: printf ("[video]"); @@ -466,7 +490,11 @@ void print_message (struct message *M) { printf (" "); print_user_name (M->to_id, user_chat_get (M->to_id)); push_color (COLOR_GREEN); - printf (" <<< "); + if (M->unread) { + printf (" <<< "); + } else { + printf (" ««« "); + } } else { push_color (COLOR_BLUE); print_date (M->date); @@ -474,7 +502,11 @@ void print_message (struct message *M) { printf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); push_color (COLOR_BLUE); - printf (" >>> "); + if (M->unread) { + printf (" >>> "); + } else { + printf (" »»» "); + } } } else { push_color (COLOR_MAGENTA); @@ -489,7 +521,11 @@ void print_message (struct message *M) { } else { push_color (COLOR_BLUE); } - printf (" >>> "); + if (M->unread) { + printf (" >>> "); + } else { + printf (" »»» "); + } } if (M->message && strlen (M->message)) { printf ("%s", M->message); diff --git a/interface.h b/interface.h index eacf061..ecb94f6 100644 --- a/interface.h +++ b/interface.h @@ -22,4 +22,11 @@ void hexdump (int *in_ptr, int *in_end); struct message; void print_message (struct message *M); +void print_chat_name (int id, union user_chat *C); +void print_user_name (int id, union user_chat *U); +//void print_media (struct message_media *M); +void pop_color (void); +void push_color (const char *color); +void print_start (void); +void print_end (void); #endif diff --git a/mtproto-client.c b/mtproto-client.c index d7bde57..afa7767 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -645,15 +645,24 @@ void work_update (struct connection *c UU, long long msg_id UU) { } } fetch_int (); //pts + print_start (); + push_color (COLOR_YELLOW); + printf ("%d messages marked as read\n", n); + pop_color (); + print_end (); } break; case CODE_update_user_typing: { int id = fetch_int (); union user_chat *U = user_chat_get (id); - if (U) { - rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name); - } + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (id, U); + printf (" is typing....\n"); + pop_color (); + print_end (); } break; case CODE_update_chat_user_typing: @@ -662,9 +671,15 @@ void work_update (struct connection *c UU, long long msg_id UU) { int id = fetch_int (); union user_chat *C = user_chat_get (-chat_id); union user_chat *U = user_chat_get (id); - if (U && C) { - rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing in chat %s....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, C->chat.title); - } + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (id, U); + printf (" is typing in chat "); + print_chat_name (-chat_id, C); + printf ("....\n"); + pop_color (); + print_end (); } break; case CODE_update_user_status: @@ -673,7 +688,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { union user_chat *U = user_chat_get (user_id); if (U) { fetch_user_status (&U->user.status); - rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is now %s\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, (U->user.status.online > 0) ? "online" : "offline"); + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, U); + printf (" is now "); + printf ("%s\n", (U->user.status.online > 0) ? "online" : "offline"); + pop_color (); + print_end (); } else { struct user_status t; fetch_user_status (&t); @@ -686,11 +708,20 @@ void work_update (struct connection *c UU, long long msg_id UU) { union user_chat *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, UC); if (U->first_name) { free (U->first_name); } - if (U->last_name) { free (U->first_name); } - if (U->print_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 (); + printf (" changed name to "); + print_user_name (user_id, UC); + printf ("\n"); + pop_color (); + print_end (); if (!strlen (U->first_name)) { if (!strlen (U->last_name)) { U->print_name = strdup ("none"); @@ -722,6 +753,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { union user_chat *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; + + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, UC); + printf (" updated profile photo\n"); + pop_color (); + print_end (); unsigned y = fetch_int (); if (y == CODE_user_profile_photo_empty) { U->photo_big.dc = -2; diff --git a/queries.c b/queries.c index f3139c0..7c4b503 100644 --- a/queries.c +++ b/queries.c @@ -1,7 +1,12 @@ +#define _FILE_OFFSET_BITS 64 #include #include #include #include +#include +#include +#include +#include #include "include.h" #include "mtproto-client.h" @@ -57,8 +62,11 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth logprintf ( "Msg_id is %lld\n", q->msg_id); } q->methods = methods; + q->DC = DC; if (queries_tree) { - logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + if (verbosity >= 2) { + logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + } } queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); @@ -581,3 +589,136 @@ void do_get_dialog_list (void) { out_int (1000); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); } + +struct send_file { + int fd; + long long size; + long long offset; + int part_num; + int part_size; + long long id; + int to_id; + int media_type; + char *file_name; +}; + +void out_peer_id (int id) { + union user_chat *U = user_chat_get (id); + if (id < 0) { + out_int (CODE_input_peer_chat); + out_int (-id); + } else { + if (U && U->user.access_hash) { + out_int (CODE_input_peer_foreign); + out_int (id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_peer_contact); + out_int (id); + } + } +} + +void send_part (struct send_file *f); +int send_file_part_on_answer (struct query *q) { + assert (fetch_int () == (int)CODE_bool_true); + send_part (q->extra); + return 0; +} + +int send_file_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_stated_message); + struct message *M = fetch_alloc_message (); + assert (fetch_int () == CODE_vector); + int n, i; + 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 (); + } + fetch_int (); // pts + fetch_int (); // seq + print_message (M); + return 0; +} + +struct query_methods send_file_part_methods = { + .on_answer = send_file_part_on_answer +}; + +struct query_methods send_file_methods = { + .on_answer = send_file_on_answer +}; + +void send_part (struct send_file *f) { + if (f->fd >= 0) { + clear_packet (); + out_int (CODE_upload_save_file_part); + out_long (f->id); + out_int (f->part_num ++); + static char buf[512 << 10]; + int x = read (f->fd, buf, f->part_size); + assert (x > 0); + out_cstring (buf, x); + f->offset += x; + logprintf ("offset=%lld size=%lld\n", f->offset, f->size); + if (f->offset == f->size) { + close (f->fd); + f->fd = -1; + } + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); + } else { + clear_packet (); + out_int (CODE_messages_send_media); + out_peer_id (f->to_id); + assert (f->media_type == CODE_input_media_uploaded_photo); + out_int (f->media_type); + out_int (CODE_input_file); + out_long (f->id); + out_int (f->part_num); + char *s = f->file_name + strlen (f->file_name); + while (s >= f->file_name && *s != '/') { s --;} + out_string (s + 1); + out_string (""); + out_long (-lrand48 () * (1ll << 32) - lrand48 ()); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); + free (f->file_name); + free (f); + } +} + +void do_send_photo (int type, int to_id, char *file_name) { + int fd = open (file_name, O_RDONLY); + if (fd < 0) { + rprintf ("No such file '%s'\n", file_name); + return; + } + struct stat buf; + fstat (fd, &buf); + long long size = buf.st_size; + if (size <= 0) { + rprintf ("File has zero length\n"); + close (fd); + return; + } + struct send_file *f = malloc (sizeof (*f)); + f->fd = fd; + f->size = size; + f->offset = 0; + f->part_num = 0; + f->part_size = (size / 1000 + 0x3ff) & ~0x3ff; + f->id = lrand48 () * (1ll << 32) + lrand48 (); + f->to_id = to_id; + f->media_type = type; + f->file_name = file_name; + if (f->part_size > (512 << 10)) { + close (fd); + rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); + return; + } + send_part (f); +} diff --git a/queries.h b/queries.h index 84012aa..477cd9b 100644 --- a/queries.h +++ b/queries.h @@ -24,6 +24,7 @@ struct query { void *data; struct query_methods *methods; struct event_timer ev; + struct dc *DC; void *extra; }; @@ -49,4 +50,6 @@ union user_chat; void do_send_message (union user_chat *U, const char *msg); void do_get_history (union user_chat *U, int limit); void do_get_dialog_list (void); +void do_send_photo (int type, int to_id, char *file_name); + #endif From 6893fca7132877847d1b1921bb7ed9db775deb7e Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 21 Oct 2013 23:27:29 +0400 Subject: [PATCH 017/465] Added fetch of all updates. Added print of service messages --- interface.c | 63 ++++++++++++++++++++++++++++++- mtproto-client.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ mtproto-common.h | 4 ++ queries.c | 11 +++++- structures.c | 18 +++++---- 5 files changed, 183 insertions(+), 11 deletions(-) diff --git a/interface.c b/interface.c index a246954..12d5e42 100644 --- a/interface.c +++ b/interface.c @@ -239,6 +239,22 @@ void interpreter (char *line UU) { Peers[index]->id, strndup (f, len)); } } + } else if (!memcmp (line, "send_video", 10)) { + char *q = line + 10; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num) { + int len = 0; + char *f = get_token (&q, &len); + if (len > 0) { + do_send_photo (CODE_input_media_uploaded_video, + Peers[index]->id, strndup (f, len)); + } + } } else if (!memcmp (line, "history", 7)) { char *q = line + 7; int len; @@ -474,9 +490,54 @@ void print_date (long t) { } int our_id; + +void print_service_message (struct message *M) { + print_start (); + push_color (COLOR_GREY); + + print_date (M->date); + printf (" "); + print_chat_name (M->to_id, user_chat_get (M->to_id)); + printf (" "); + print_user_name (M->from_id, user_chat_get (M->from_id)); + + switch (M->action.type) { + case CODE_message_action_empty: + printf ("\n"); + break; + case CODE_message_action_chat_create: + printf (" created chat %s. %d users\n", M->action.title, M->action.user_num); + break; + case CODE_message_action_chat_edit_title: + printf (" changed title to %s\n", + M->action.new_title); + break; + case CODE_message_action_chat_edit_photo: + printf (" changed photo\n"); + break; + case CODE_message_action_chat_delete_photo: + printf (" deleted photo\n"); + break; + case CODE_message_action_chat_add_user: + printf (" added user "); + print_user_name (M->action.user, user_chat_get (M->action.user)); + printf ("\n"); + break; + case CODE_message_action_chat_delete_user: + printf (" deleted user "); + print_user_name (M->action.user, user_chat_get (M->action.user)); + printf ("\n"); + break; + default: + assert (0); + } + pop_color (); + print_end (); +} + void print_message (struct message *M) { if (M->service) { - rprintf ("Service message\n"); + print_service_message (M); return; } diff --git a/mtproto-client.c b/mtproto-client.c index afa7767..53a3d9b 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -782,6 +782,104 @@ void work_update (struct connection *c UU, long long msg_id UU) { } } break; + case CODE_update_restore_messages: + { + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + print_start (); + push_color (COLOR_YELLOW); + printf ("Restored %d messages\n", n); + pop_color (); + print_end (); + fetch_skip (n); + fetch_int (); // pts + } + break; + case CODE_update_chat_participants: + { + assert (fetch_int () == CODE_chat_participants); + int chat_id = fetch_int (); + fetch_int (); // admin_id + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + fetch_skip (n * 4); + fetch_int (); // version + union user_chat *C = user_chat_get (-chat_id); + print_start (); + push_color (COLOR_YELLOW); + printf ("Chat "); + print_chat_name (-chat_id, C); + printf (" changed list: now %d members\n", n); + pop_color (); + print_end (); + } + break; + case CODE_update_contact_registered: + { + int user_id = fetch_int (); + union user_chat *U = user_chat_get (user_id); + fetch_int (); // date + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, U); + printf (" registered\n"); + pop_color (); + print_end (); + } + break; + case CODE_update_contact_link: + { + int user_id = fetch_int (); + union user_chat *U = user_chat_get (user_id); + print_start (); + push_color (COLOR_YELLOW); + printf ("Updated link with user "); + print_user_name (user_id, U); + printf ("\n"); + pop_color (); + print_end (); + unsigned t = fetch_int (); + assert (t == CODE_contacts_my_link_empty || t == CODE_contacts_my_link_requested || t == CODE_contacts_my_link_contact); + if (t == CODE_contacts_my_link_requested) { + fetch_bool (); // has_phone + } + t = fetch_int (); + assert (t == CODE_contacts_foreign_link_unknown || t == CODE_contacts_foreign_link_requested || t == CODE_contacts_foreign_link_mutual); + if (t == CODE_contacts_foreign_link_requested) { + fetch_bool (); // has_phone + } + } + break; + case CODE_update_activation: + { + int user_id = fetch_int (); + union user_chat *U = user_chat_get (user_id); + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, U); + printf (" activated\n"); + pop_color (); + print_end (); + } + break; + case CODE_update_new_authorization: + { + fetch_long (); // auth_key_id + fetch_int (); // date + char *s = fetch_str_dup (); + char *location = fetch_str_dup (); + print_start (); + push_color (COLOR_YELLOW); + printf ("New autorization: device='%s' location='%s'\n", + s, location); + pop_color (); + print_end (); + free (s); + free (location); + } + break; default: logprintf ("Unknown update type %08x\n", op); } diff --git a/mtproto-common.h b/mtproto-common.h index 498de9e..9ac4396 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -280,6 +280,10 @@ static inline char *fetch_str_dup (void) { return s; } +static inline void fetch_skip (int n) { + in_ptr += n; +} + static __inline__ unsigned long long rdtsc(void) { unsigned hi, lo; __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); diff --git a/queries.c b/queries.c index 7c4b503..3b5abfe 100644 --- a/queries.c +++ b/queries.c @@ -665,7 +665,9 @@ void send_part (struct send_file *f) { assert (x > 0); out_cstring (buf, x); f->offset += x; - logprintf ("offset=%lld size=%lld\n", f->offset, f->size); + if (verbosity >= 2) { + logprintf ("offset=%lld size=%lld\n", f->offset, f->size); + } if (f->offset == f->size) { close (f->fd); f->fd = -1; @@ -675,7 +677,7 @@ void send_part (struct send_file *f) { clear_packet (); out_int (CODE_messages_send_media); out_peer_id (f->to_id); - assert (f->media_type == CODE_input_media_uploaded_photo); + assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video); out_int (f->media_type); out_int (CODE_input_file); out_long (f->id); @@ -684,6 +686,11 @@ void send_part (struct send_file *f) { while (s >= f->file_name && *s != '/') { s --;} out_string (s + 1); out_string (""); + if (f->media_type == CODE_input_media_uploaded_video) { + out_int (100); + out_int (100); + out_int (100); + } out_long (-lrand48 () * (1ll << 32) - lrand48 ()); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); free (f->file_name); diff --git a/structures.c b/structures.c index 0502ba7..13abd78 100644 --- a/structures.c +++ b/structures.c @@ -158,15 +158,17 @@ void fetch_chat (struct chat *C) { void fetch_photo_size (struct photo_size *S) { memset (S, 0, sizeof (*S)); unsigned x = fetch_int (); - assert (x == CODE_photo_size || x == CODE_photo_cached_size); + assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); 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 (); + if (x != CODE_photo_size_empty) { + 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 (); + } } } From e2cc2ed7cccc22be73bb5b451b252078ebccf5fe Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 21 Oct 2013 23:47:05 +0400 Subject: [PATCH 018/465] Fixed bug with new message marked as read --- queries.c | 1 + 1 file changed, 1 insertion(+) diff --git a/queries.c b/queries.c index 3b5abfe..bdd45c5 100644 --- a/queries.c +++ b/queries.c @@ -461,6 +461,7 @@ void do_send_message (union user_chat *U, const char *msg) { memset (M, 0, sizeof (*M)); M->from_id = our_id; M->to_id = U->id; + M->unread = 1; if (U->id < 0) { out_int (CODE_input_peer_chat); out_int (-U->id); From b1d8835540a222642fd5b0589118aa41a6e5d9de Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 22 Oct 2013 12:36:07 +0400 Subject: [PATCH 019/465] Added send_text query --- interface.c | 17 +++++++++++++++++ queries.c | 20 ++++++++++++++++++++ queries.h | 1 + 3 files changed, 38 insertions(+) diff --git a/interface.c b/interface.c index 12d5e42..4ded901 100644 --- a/interface.c +++ b/interface.c @@ -35,6 +35,7 @@ char *commands[] = { "dialog_list", "send_photo", "send_video", + "send_text", 0 }; int commands_flags[] = { @@ -46,6 +47,7 @@ int commands_flags[] = { 07, 0732, 0732, + 0732, }; char *a = 0; @@ -255,6 +257,21 @@ void interpreter (char *line UU) { Peers[index]->id, strndup (f, len)); } } + } else if (!memcmp (line, "send_text", 9)) { + char *q = line + 10; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num) { + int len = 0; + char *f = get_token (&q, &len); + if (len > 0) { + do_send_text (Peers[index], strndup (f, len)); + } + } } else if (!memcmp (line, "history", 7)) { char *q = line + 7; int len; diff --git a/queries.c b/queries.c index bdd45c5..dfc9085 100644 --- a/queries.c +++ b/queries.c @@ -486,6 +486,26 @@ void do_send_message (union user_chat *U, const char *msg) { print_message (M); } +void do_send_text (union user_chat *U, char *file_name) { + int fd = open (file_name, O_RDONLY); + if (fd < 0) { + rprintf ("No such file '%s'\n", file_name); + free (file_name); + return; + } + static char buf[(1 << 20) + 1]; + int x = read (fd, buf, (1 << 20) + 1); + if (x == (1 << 20) + 1) { + rprintf ("Too big file '%s'\n", file_name); + free (file_name); + close (fd); + } else { + do_send_message (U, buf); + free (file_name); + close (fd); + } +} + int get_history_on_answer (struct query *q UU) { static struct message *ML[10000]; int i; diff --git a/queries.h b/queries.h index 477cd9b..bb2f5b3 100644 --- a/queries.h +++ b/queries.h @@ -48,6 +48,7 @@ double get_double_time (void); void do_update_contact_list (void); union user_chat; void do_send_message (union user_chat *U, const char *msg); +void do_send_text (union user_chat *U, char *file); void do_get_history (union user_chat *U, int limit); void do_get_dialog_list (void); void do_send_photo (int type, int to_id, char *file_name); From db8a7a774b366ae293e2517b1935798a93501a94 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 22 Oct 2013 19:28:41 +0400 Subject: [PATCH 020/465] Some fixes --- interface.c | 2 +- interface.h | 1 + queries.c | 17 ++++++++++++----- queries.h | 2 +- structures.h | 1 + 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/interface.c b/interface.c index 4ded901..634ab6a 100644 --- a/interface.c +++ b/interface.c @@ -223,7 +223,7 @@ void interpreter (char *line UU) { } while (*q && (*q == ' ' || *q == '\t')) { q ++; } if (*q && index < user_num + chat_num) { - do_send_message (Peers[index], q); + do_send_message (Peers[index], q, strlen (q)); } } else if (!memcmp (line, "send_photo", 10)) { char *q = line + 10; diff --git a/interface.h b/interface.h index ecb94f6..2f9fb9b 100644 --- a/interface.h +++ b/interface.h @@ -21,6 +21,7 @@ void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))) void hexdump (int *in_ptr, int *in_end); struct message; +union user_chat; void print_message (struct message *M); void print_chat_name (int id, union user_chat *C); void print_user_name (int id, union user_chat *U); diff --git a/queries.c b/queries.c index dfc9085..92a5877 100644 --- a/queries.c +++ b/queries.c @@ -107,6 +107,8 @@ void query_error (long long id) { queries_tree = tree_delete_query (queries_tree, q); if (q->methods && q->methods->on_error) { q->methods->on_error (q, error_code, error_len, error); + } else { + logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); } free (q->data); free (q); @@ -451,7 +453,7 @@ struct query_methods msg_send_methods = { int out_message_num; int our_id; -void do_send_message (union user_chat *U, const char *msg) { +void do_send_message (union user_chat *U, const char *msg, int len) { if (!out_message_num) { out_message_num = -lrand48 (); } @@ -475,12 +477,15 @@ void do_send_message (union user_chat *U, const char *msg) { out_int (U->id); } } - M->message = strdup (msg); + M->message = malloc (len + 1); + memcpy (M->message, msg, len); + M->message[len] = 0; + M->message_len = len; M->out = 1; M->media.type = CODE_message_media_empty; M->id = out_message_num; M->date = time (0); - out_string (msg); + out_cstring (msg, len); out_long ((--out_message_num) - (1ll << 32)); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M); print_message (M); @@ -495,12 +500,14 @@ void do_send_text (union user_chat *U, char *file_name) { } static char buf[(1 << 20) + 1]; int x = read (fd, buf, (1 << 20) + 1); + assert (x >= 0); if (x == (1 << 20) + 1) { rprintf ("Too big file '%s'\n", file_name); free (file_name); close (fd); } else { - do_send_message (U, buf); + buf[x] = 0; + do_send_message (U, buf, x); free (file_name); close (fd); } @@ -738,7 +745,7 @@ void do_send_photo (int type, int to_id, char *file_name) { f->size = size; f->offset = 0; f->part_num = 0; - f->part_size = (size / 1000 + 0x3ff) & ~0x3ff; + f->part_size = ((size + 999) / 1000 + 0x3ff) & ~0x3ff; f->id = lrand48 () * (1ll << 32) + lrand48 (); f->to_id = to_id; f->media_type = type; diff --git a/queries.h b/queries.h index bb2f5b3..0200438 100644 --- a/queries.h +++ b/queries.h @@ -47,7 +47,7 @@ double get_double_time (void); void do_update_contact_list (void); union user_chat; -void do_send_message (union user_chat *U, const char *msg); +void do_send_message (union user_chat *U, const char *msg, int len); void do_send_text (union user_chat *U, char *file); void do_get_history (union user_chat *U, int limit); void do_get_dialog_list (void); diff --git a/structures.h b/structures.h index 02eb976..b2a5fe2 100644 --- a/structures.h +++ b/structures.h @@ -136,6 +136,7 @@ struct message { struct message_action action; struct { char *message; + int message_len; struct message_media media; }; }; From 94d55325b49bdaf375c0cbdaf34e4182c892c9d4 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 23 Oct 2013 14:24:59 +0400 Subject: [PATCH 021/465] Added chat_info query. Fixed interface --- interface.c | 61 +++++++++++++++++++++++++++++++--- interface.h | 3 +- loop.c | 6 ++++ queries.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++- queries.h | 2 ++ structures.h | 1 + 6 files changed, 158 insertions(+), 7 deletions(-) diff --git a/interface.c b/interface.c index 634ab6a..c9ac77c 100644 --- a/interface.c +++ b/interface.c @@ -36,6 +36,7 @@ char *commands[] = { "send_photo", "send_video", "send_text", + "chat_info", 0 }; int commands_flags[] = { @@ -48,6 +49,7 @@ int commands_flags[] = { 0732, 0732, 0732, + 074, }; char *a = 0; @@ -132,6 +134,19 @@ int complete_user_list (int index, const char *text, int len, char **R) { } } +int complete_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) || Peers[index]->id > 0)) { + index ++; + } + 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))) { @@ -192,6 +207,9 @@ char *command_generator (const char *text, int state) { return R; case 3: return rl_filename_completion_function(text,state); + case 4: + index = complete_chat_list (index, text, len, &R); + return R; default: return 0; } @@ -272,6 +290,17 @@ void interpreter (char *line UU) { do_send_text (Peers[index], strndup (f, len)); } } + } else if (!memcmp (line, "chat_info", 9)) { + char *q = line + 10; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num && Peers[index]->id < 0) { + do_get_chat_info (Peers[index]); + } } else if (!memcmp (line, "history", 7)) { char *q = line + 7; int len; @@ -472,16 +501,38 @@ void print_media (struct message_media *M) { } } +int unknown_user_list_pos; +int unknown_user_list[1000]; + void print_user_name (int id, union user_chat *U) { push_color (COLOR_RED); if (!U) { printf ("user#%d", id); - } else if (!U->user.first_name) { - printf ("%s", U->user.last_name); - } else if (!U->user.last_name) { - printf ("%s", U->user.first_name); + int i; + for (i = 0; i < unknown_user_list_pos; i++) { + if (unknown_user_list[i] == id) { + id = 0; + break; + } + } + if (id) { + assert (unknown_user_list_pos < 1000); + unknown_user_list[unknown_user_list_pos ++] = id; + } } else { - printf ("%s %s", U->user.first_name, U->user.last_name); + if (U->flags & 20) { + push_color (COLOR_REDB); + } + if (!U->user.first_name) { + printf ("%s", U->user.last_name); + } else if (!U->user.last_name) { + printf ("%s", U->user.first_name); + } else { + printf ("%s %s", U->user.first_name, U->user.last_name); + } + if (U->flags & 20) { + pop_color (); + } } pop_color (); } diff --git a/interface.h b/interface.h index 2f9fb9b..e714725 100644 --- a/interface.h +++ b/interface.h @@ -1,7 +1,8 @@ #ifndef __INTERFACE_H__ #define __INTERFACE_H__ -#define COLOR_RED "\033[31;1m" +#define COLOR_RED "\033[0;31m" +#define COLOR_REDB "\033[1;31m" #define COLOR_NORMAL "\033[0m" #define COLOR_GREEN "\033[32;1m" #define COLOR_GREY "\033[37;1m" diff --git a/loop.c b/loop.c index 55707fb..ffe5646 100644 --- a/loop.c +++ b/loop.c @@ -27,6 +27,8 @@ extern char *auth_token; void set_default_username (const char *s); int default_dc_num; +extern int unknown_user_list_pos; +extern int unknown_user_list[]; void net_loop (int flags, int (*is_end)(void)) { while (!is_end ()) { @@ -58,6 +60,10 @@ void net_loop (int flags, int (*is_end)(void)) { rl_callback_read_char (); } connections_poll_result (fds + cc, x - cc); + if (unknown_user_list_pos) { + do_get_user_list_info_silent (unknown_user_list_pos, unknown_user_list); + unknown_user_list_pos = 0; + } } } diff --git a/queries.c b/queries.c index 92a5877..d609a57 100644 --- a/queries.c +++ b/queries.c @@ -416,7 +416,17 @@ int get_contacts_on_answer (struct query *q UU) { n = fetch_int (); for (i = 0; i < n; i++) { struct user *U = fetch_alloc_user (); - rprintf ("User #%d: " COLOR_RED "%s %s" COLOR_NORMAL " (" COLOR_GREEN "%s" COLOR_NORMAL ")\n", U->id, U->first_name, U->last_name, U->print_name); + print_start (); + push_color (COLOR_YELLOW); + printf ("User #%d: ", U->id); + print_user_name (U->id, (union user_chat *)U); + push_color (COLOR_GREEN); + printf (" ("); + printf ("%s", U->print_name); + printf (")\n"); + pop_color (); + pop_color (); + print_end (); } return 0; } @@ -757,3 +767,83 @@ void do_send_photo (int type, int to_id, char *file_name) { } send_part (f); } + +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 + + print_start (); + push_color (COLOR_YELLOW); + printf ("Chat "); + print_chat_name (-id, user_chat_get (-id)); + printf (" members:\n"); + for (i = 0; i < n; i++) { + printf ("\t\t"); + print_user_name (a[3 * i], user_chat_get (a[3 * i])); + if (a[3 * i] == admin_id) { + printf (" admin"); + } + printf ("\n"); + } + pop_color (); + print_end (); + return 0; +} + +struct query_methods chat_info_methods = { + .on_answer = chat_info_on_answer +}; + +void do_get_chat_info (union user_chat *chat) { + clear_packet (); + out_int (CODE_messages_get_full_chat); + out_int (-chat->id); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0); +} + +int user_list_info_silent_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + fetch_alloc_user (); + } + return 0; +} + +struct query_methods user_list_info_silent_methods = { + .on_answer = user_list_info_silent_on_answer +}; + +void do_get_user_list_info_silent (int num, int *list) { + clear_packet (); + out_int (CODE_users_get_users); + out_int (CODE_vector); + out_int (num); + int i; + for (i = 0; i < num; i++) { + out_int (CODE_input_user_contact); + out_int (list[i]); + //out_long (0); + } + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_list_info_silent_methods, 0); +} diff --git a/queries.h b/queries.h index 0200438..ca10ba2 100644 --- a/queries.h +++ b/queries.h @@ -52,5 +52,7 @@ void do_send_text (union user_chat *U, char *file); void do_get_history (union user_chat *U, int limit); void do_get_dialog_list (void); void do_send_photo (int type, int to_id, char *file_name); +void do_get_chat_info (union user_chat *chat); +void do_get_user_list_info_silent (int num, int *list); #endif diff --git a/structures.h b/structures.h index b2a5fe2..bc6e3c3 100644 --- a/structures.h +++ b/structures.h @@ -37,6 +37,7 @@ struct chat { int user_num; int date; int version; + int admin_id; }; union user_chat { From 121f0f1d14aabd04beb37f09a62bd5fb98db4eb5 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 23 Oct 2013 14:25:41 +0400 Subject: [PATCH 022/465] Fixed unread messages. Added output to dialoglist query --- queries.c | 31 ++++++++++++++++++++++++++++--- structures.c | 2 ++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/queries.c b/queries.c index 92a5877..206a2c8 100644 --- a/queries.c +++ b/queries.c @@ -580,11 +580,19 @@ int get_dialogs_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); int n, i; n = fetch_int (); + static int dlist[3 * 100]; + int dl_size = n; for (i = 0; i < n; i++) { assert (fetch_int () == CODE_dialog); - fetch_peer_id (); - fetch_int (); - fetch_int (); + if (i < 100) { + dlist[3 * i + 0] = fetch_peer_id (); + dlist[3 * i + 1] = fetch_int (); + dlist[3 * i + 2] = fetch_int (); + } else { + fetch_peer_id (); + fetch_int (); + fetch_int (); + } } assert (fetch_int () == CODE_vector); n = fetch_int (); @@ -601,6 +609,23 @@ int get_dialogs_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } + print_start (); + push_color (COLOR_YELLOW); + for (i = dl_size - 1; i >= 0; i--) { + if (dlist[3 * i] < 0) { + union user_chat *UC = user_chat_get (dlist[3 * i]); + printf ("Chat "); + print_chat_name (dlist[3 * i], UC); + printf (": %d unread\n", dlist[3 * i + 2]); + } else { + union user_chat *UC = user_chat_get (dlist[3 * i]); + printf ("User "); + print_user_name (dlist[3 * i], UC); + printf (": %d unread\n", dlist[3 * i + 2]); + } + } + pop_color (); + print_end (); return 0; } diff --git a/structures.c b/structures.c index 13abd78..3257a57 100644 --- a/structures.c +++ b/structures.c @@ -262,6 +262,7 @@ void fetch_message_short (struct message *M) { M->date = fetch_int (); fetch_int (); // seq M->media.type = CODE_message_media_empty; + M->unread = 1; } void fetch_message_short_chat (struct message *M) { @@ -274,6 +275,7 @@ void fetch_message_short_chat (struct message *M) { M->date = fetch_int (); fetch_int (); // seq M->media.type = CODE_message_media_empty; + M->unread = 1; } From e5cc589a0f0f3431d289d7d7fa0c40157e49373c Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 23 Oct 2013 18:26:17 +0400 Subject: [PATCH 023/465] Added GPL-headers to source files --- constants.h | 18 ++++++++++++++++++ include.h | 18 ++++++++++++++++++ interface.c | 19 +++++++++++++++++++ interface.h | 18 ++++++++++++++++++ loop.c | 18 ++++++++++++++++++ loop.h | 18 ++++++++++++++++++ main.c | 30 ++++++++++++++++-------------- mtproto-client.c | 19 +++++++++++++++++++ mtproto-client.h | 19 +++++++++++++++++++ mtproto-common.c | 19 +++++++++++++++++++ mtproto-common.h | 19 +++++++++++++++++++ net.c | 18 ++++++++++++++++++ net.h | 18 ++++++++++++++++++ queries.c | 18 ++++++++++++++++++ queries.h | 18 ++++++++++++++++++ structures.c | 18 ++++++++++++++++++ structures.h | 18 ++++++++++++++++++ telegram.h | 18 ++++++++++++++++++ tree.h | 18 ++++++++++++++++++ 19 files changed, 345 insertions(+), 14 deletions(-) diff --git a/constants.h b/constants.h index 2719d44..ac6b3da 100644 --- a/constants.h +++ b/constants.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef CONSTANTS_H #define CONSTANTS_H #define CODE_bool_false 0xbc799737 diff --git a/include.h b/include.h index 03f271d..bf290a1 100644 --- a/include.h +++ b/include.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef __INCLUDE_H__ #define __INCLUDE_H__ diff --git a/interface.c b/interface.c index c9ac77c..548806f 100644 --- a/interface.c +++ b/interface.c @@ -1,3 +1,22 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ + #define _GNU_SOURCE #include #include diff --git a/interface.h b/interface.h index e714725..eac0fff 100644 --- a/interface.h +++ b/interface.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef __INTERFACE_H__ #define __INTERFACE_H__ diff --git a/loop.c b/loop.c index ffe5646..66836f7 100644 --- a/loop.c +++ b/loop.c @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #define READLINE_CALLBACKS #include diff --git a/loop.h b/loop.h index 88b38ee..2b14f33 100644 --- a/loop.h +++ b/loop.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef __LOOP_H__ #define __LOOP_H__ int loop (void); diff --git a/main.c b/main.c index 5d5c557..60b96d1 100644 --- a/main.c +++ b/main.c @@ -1,19 +1,21 @@ -/* - main.c: main initialization file - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. +/* + This file is part of telegram-client. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #include #include diff --git a/mtproto-client.c b/mtproto-client.c index 53a3d9b..f9ac832 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1,3 +1,22 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Nikolay Durov, Andrey Lopatin 2012-2013 + Copyright Vitaly Valtman 2013 +*/ #define _FILE_OFFSET_BITS 64 #include diff --git a/mtproto-client.h b/mtproto-client.h index 200e128..3958b4e 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -1,3 +1,22 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Nikolay Durov, Andrey Lopatin 2012-2013 + Copyright Vitaly Valtman 2013 +*/ #ifndef __MTPROTO_CLIENT_H__ #define __MTPROTO_CLIENT_H__ #include "net.h" diff --git a/mtproto-common.c b/mtproto-common.c index 3a0c5a1..64f635a 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -1,3 +1,22 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Nikolay Durov, Andrey Lopatin 2012-2013 + Copyright Vitaly Valtman 2013 +*/ #define _FILE_OFFSET_BITS 64 #include diff --git a/mtproto-common.h b/mtproto-common.h index 9ac4396..0c1012f 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -1,3 +1,22 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Nikolay Durov, Andrey Lopatin 2012-2013 + Copyright Vitaly Valtman 2013 +*/ #ifndef __MTPROTO_COMMON_H__ #define __MTPROTO_COMMON_H__ diff --git a/net.c b/net.c index 8e44e17..f806a38 100644 --- a/net.c +++ b/net.c @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #define _GNU_SOURCE #include #include diff --git a/net.h b/net.h index e934920..06633e8 100644 --- a/net.h +++ b/net.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef __NET_H__ #define __NET_H__ diff --git a/queries.c b/queries.c index a647c0e..d73393e 100644 --- a/queries.c +++ b/queries.c @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #define _FILE_OFFSET_BITS 64 #include #include diff --git a/queries.h b/queries.h index ca10ba2..7a9ef52 100644 --- a/queries.h +++ b/queries.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #include "net.h" #ifndef __QUERIES_H__ #define __QUERIES_H__ diff --git a/structures.c b/structures.c index 3257a57..f4c53fc 100644 --- a/structures.c +++ b/structures.c @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #include #include "structures.h" #include "mtproto-common.h" diff --git a/structures.h b/structures.h index bc6e3c3..db535cb 100644 --- a/structures.h +++ b/structures.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef __STRUCTURES_H__ #define __STRUCTURES_H__ diff --git a/telegram.h b/telegram.h index d285b5c..b5ea029 100644 --- a/telegram.h +++ b/telegram.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #define MAX_DC_NUM 9 #define MAX_USER_NUM 1000 #define MAX_CHAT_NUM 1000 diff --git a/tree.h b/tree.h index 250b060..04710f8 100644 --- a/tree.h +++ b/tree.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef __TREE_H__ #define __TREE_H__ #include From bb9a614396ec8c0f2cd441c98f74b4859bb7eabb Mon Sep 17 00:00:00 2001 From: Vysheng Date: Wed, 23 Oct 2013 18:53:22 +0400 Subject: [PATCH 024/465] Added GPL license text --- LICENSE | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. From d289aeb897a61263a511a57635d59bcb882095ff Mon Sep 17 00:00:00 2001 From: Vysheng Date: Wed, 23 Oct 2013 19:18:44 +0400 Subject: [PATCH 025/465] Mark messages as read after history query --- queries.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/queries.c b/queries.c index d73393e..bfcd33f 100644 --- a/queries.c +++ b/queries.c @@ -541,6 +541,39 @@ void do_send_text (union user_chat *U, char *file_name) { } } +int mark_read_on_receive (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_affected_history); + fetch_int (); // pts + fetch_int (); // seq + fetch_int (); // offset + return 0; +} + +struct query_methods mark_read_methods = { + .on_answer = mark_read_on_receive +}; + +void do_messages_mark_read (union user_chat *U, int max_id) { + clear_packet (); + out_int (CODE_messages_read_history); + if (U->id < 0) { + out_int (CODE_input_peer_chat); + out_int (-U->id); + } else { + if (U->user.access_hash) { + out_int (CODE_input_peer_foreign); + out_int (U->id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_peer_contact); + out_int (U->id); + } + } + out_int (max_id); + out_int (0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, 0); +} + int get_history_on_answer (struct query *q UU) { static struct message *ML[10000]; int i; @@ -560,6 +593,7 @@ int get_history_on_answer (struct query *q UU) { } } if (n > 10000) { n = 10000; } + int sn = n; for (i = n - 1; i >= 0; i--) { print_message (ML[i]); } @@ -573,6 +607,9 @@ int get_history_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } + if (sn > 0) { + do_messages_mark_read (q->extra, ML[0]->id); + } return 0; } @@ -600,7 +637,7 @@ void do_get_history (union user_chat *U, int limit) { out_int (0); out_int (0); out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, U); } int get_dialogs_on_answer (struct query *q UU) { From 045467b0dfcb01e9bbdecf36a1ef26aa13367205 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Wed, 23 Oct 2013 21:56:29 +0400 Subject: [PATCH 026/465] Fixed needed msg len --- mtproto-client.c | 3 +++ net.c | 4 ++-- queries.c | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index f9ac832..6293bb8 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1153,6 +1153,9 @@ int rpc_execute (struct connection *c, int op, int len) { int Response_len = len; + if (verbosity >= 2) { + logprintf ("Response_len = %d\n", Response_len); + } assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; if (verbosity >= 2) { diff --git a/net.c b/net.c index f806a38..6fba56e 100644 --- a/net.c +++ b/net.c @@ -298,12 +298,12 @@ void try_rpc_read (struct connection *c) { unsigned t = 0; assert (read_in_lookup (c, &len, 1) == 1); if (len >= 1 && len <= 0x7e) { - if (c->in_bytes < (int)(4 * len)) { return; } + if (c->in_bytes < (int)(1 + 4 * len)) { return; } } else { if (c->in_bytes < 4) { return; } assert (read_in_lookup (c, &len, 4) == 4); len = (len >> 8); - if (c->in_bytes < (int)(4 * len)) { return; } + if (c->in_bytes < (int)(4 + 4 * len)) { return; } len = 0x7f; } diff --git a/queries.c b/queries.c index bfcd33f..a688e31 100644 --- a/queries.c +++ b/queries.c @@ -56,6 +56,9 @@ struct query *query_get (long long id) { int alarm_query (struct query *q) { assert (q); + if (verbosity) { + logprintf ("Alarm query %lld\n", q->msg_id); + } q->ev.timeout = get_double_time () + QUERY_TIMEOUT; insert_event_timer (&q->ev); return 0; From 3755d426edfc6ca975d8efb12ee3ee0c4db1328d Mon Sep 17 00:00:00 2001 From: Vysheng Date: Wed, 23 Oct 2013 22:23:33 +0400 Subject: [PATCH 027/465] Fixed geopoint link view --- interface.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/interface.c b/interface.c index 548806f..fdfc94f 100644 --- a/interface.c +++ b/interface.c @@ -454,7 +454,7 @@ const char *message_media_type_str (struct message_media *M) { case CODE_message_media_video: return "[video]"; case CODE_message_media_geo: - sprintf (buf, "[geo] %.6lf:%.6lf", M->geo.latitude, M->geo.longitude); + sprintf (buf, "[geo] https://maps.google.com/maps?ll=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude); return buf; case CODE_message_media_contact: snprintf (buf, 999, "[contact] " COLOR_RED "%s %s" COLOR_NORMAL " %s", M->first_name, M->last_name, M->phone); @@ -502,8 +502,7 @@ void print_media (struct message_media *M) { printf ("[video]"); return; case CODE_message_media_geo: - printf ("[geo] "); - printf ("%.6lf:%.6lf", M->geo.latitude, M->geo.longitude); + printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude); return; case CODE_message_media_contact: printf ("[contact] "); From 9dacff9d0ed0512a879c311248188427db80a2bc Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 23 Oct 2013 23:22:47 +0400 Subject: [PATCH 028/465] Changed APP_ID --- net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net.h b/net.h index 06633e8..4cbb833 100644 --- a/net.h +++ b/net.h @@ -25,7 +25,7 @@ struct dc; #define TG_SERVER "173.240.5.1" //#define TG_SERVER "95.142.192.66" #define TG_APP_HASH "3bc14c6455ef1595ec86a125762c3aad" -#define TG_APP_ID 51 +#define TG_APP_ID 2899 #define ACK_TIMEOUT 60 #define MAX_DC_ID 10 From f9cf3929600a3d3d39706eb3cbb33696c7272860 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 24 Oct 2013 11:38:32 +0400 Subject: [PATCH 029/465] Fixed some bugs. Fixed interface --- interface.c | 9 +++++++-- interface.h | 1 + queries.c | 13 ++++++++++++- structures.c | 16 ++++++++-------- structures.h | 10 ++++++++++ 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/interface.c b/interface.c index fdfc94f..ffe107f 100644 --- a/interface.c +++ b/interface.c @@ -538,7 +538,7 @@ void print_user_name (int id, union user_chat *U) { unknown_user_list[unknown_user_list_pos ++] = id; } } else { - if (U->flags & 20) { + if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { push_color (COLOR_REDB); } if (!U->user.first_name) { @@ -548,7 +548,7 @@ void print_user_name (int id, union user_chat *U) { } else { printf ("%s %s", U->user.first_name, U->user.last_name); } - if (U->flags & 20) { + if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { pop_color (); } } @@ -575,6 +575,11 @@ void print_date (long t) { } } +void print_date_full (long t) { + struct tm *tm = localtime (&t); + printf ("[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); +} + int our_id; void print_service_message (struct message *M) { diff --git a/interface.h b/interface.h index eac0fff..4f14037 100644 --- a/interface.h +++ b/interface.h @@ -49,4 +49,5 @@ void pop_color (void); void push_color (const char *color); void print_start (void); void print_end (void); +void print_date_full (long t); #endif diff --git a/queries.c b/queries.c index a688e31..f044fe1 100644 --- a/queries.c +++ b/queries.c @@ -444,8 +444,19 @@ int get_contacts_on_answer (struct query *q UU) { push_color (COLOR_GREEN); printf (" ("); printf ("%s", U->print_name); - printf (")\n"); + printf (") "); pop_color (); + if (U->status.online > 0) { + printf ("online\n"); + } else { + if (U->status.online < 0) { + printf ("offline. Was online "); + print_date_full (U->status.when); + } else { + printf ("offline permanent"); + } + printf ("\n"); + } pop_color (); print_end (); } diff --git a/structures.c b/structures.c index f4c53fc..74ead3f 100644 --- a/structures.c +++ b/structures.c @@ -66,7 +66,7 @@ void fetch_user (struct user *U) { 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 (); if (x == CODE_user_empty) { - U->flags = 1; + U->flags = FLAG_EMPTY; return; } if (x == CODE_user_self) { @@ -98,16 +98,16 @@ void fetch_user (struct user *U) { s++; } if (x == CODE_user_deleted) { - U->flags = 2; + U->flags = FLAG_DELETED; return; } if (x == CODE_user_self) { - U->flags = 4; + U->flags = FLAG_USER_SELF; } else { U->access_hash = fetch_long (); } if (x == CODE_user_foreign) { - U->flags |= 8; + U->flags |= FLAG_USER_FOREIGN; } else { U->phone = fetch_str_dup (); } @@ -125,7 +125,7 @@ void fetch_user (struct user *U) { assert (fetch_int () == (int)CODE_bool_false); } if (x == CODE_user_contact) { - U->flags |= 16; + U->flags |= FLAG_USER_CONTACT; } } @@ -135,11 +135,11 @@ void fetch_chat (struct chat *C) { assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); C->id = -fetch_int (); if (x == CODE_chat_empty) { - C->flags = 1; + C->flags = FLAG_EMPTY; return; } if (x == CODE_chat_forbidden) { - C->flags |= 8; + C->flags |= FLAG_FORBIDDEN; } C->title = fetch_str_dup (); C->print_title = strdup (C->title); @@ -161,7 +161,7 @@ void fetch_chat (struct chat *C) { C->user_num = fetch_int (); C->date = fetch_int (); if (fetch_int () == (int)CODE_bool_true) { - C->flags |= 16; + C->flags |= FLAG_CHAT_IN_CHAT; } C->version = fetch_int (); } else { diff --git a/structures.h b/structures.h index db535cb..c700a6a 100644 --- a/structures.h +++ b/structures.h @@ -19,6 +19,16 @@ #ifndef __STRUCTURES_H__ #define __STRUCTURES_H__ +#define FLAG_EMPTY 1 +#define FLAG_DELETED 2 +#define FLAG_FORBIDDEN 4 + + +#define FLAG_USER_SELF 128 +#define FLAG_USER_FOREIGN 256 +#define FLAG_USER_CONTACT 512 + +#define FLAG_CHAT_IN_CHAT 128 struct file_location { int dc; From 65c5cbe1377cb22820051f716bfbdd6bf23378ab Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 24 Oct 2013 19:44:54 +0400 Subject: [PATCH 030/465] Added unread count --- interface.c | 15 ++++++++++++--- loop.c | 2 ++ mtproto-client.c | 5 +++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/interface.c b/interface.c index ffe107f..d006561 100644 --- a/interface.c +++ b/interface.c @@ -35,10 +35,18 @@ #include "structures.h" #include "mtproto-common.h" -char *default_prompt = ">"; +char *default_prompt = "> "; + +int unread_messages; char *get_default_prompt (void) { - return default_prompt; + static char buf[100]; + if (unread_messages) { + sprintf (buf, COLOR_RED "[%d unread]" COLOR_NORMAL "%s", unread_messages, default_prompt); + return buf; + } else { + return default_prompt; + } } char *complete_none (const char *text UU, int state UU) { @@ -385,7 +393,8 @@ void print_start (void) { void print_end (void) { assert (prompt_was); if (readline_active) { - rl_restore_prompt(); + rl_set_prompt (get_default_prompt ()); + rl_redisplay(); rl_replace_line(saved_line, 0); rl_point = saved_point; rl_redisplay(); diff --git a/loop.c b/loop.c index 66836f7..5bde497 100644 --- a/loop.c +++ b/loop.c @@ -48,6 +48,7 @@ int default_dc_num; extern int unknown_user_list_pos; extern int unknown_user_list[]; +int unread_messages; void net_loop (int flags, int (*is_end)(void)) { while (!is_end ()) { struct pollfd fds[101]; @@ -75,6 +76,7 @@ void net_loop (int flags, int (*is_end)(void)) { } work_timers (); if ((flags & 1) && (fds[0].revents & POLLIN)) { + unread_messages = 0; rl_callback_read_char (); } connections_poll_result (fds + cc, x - cc); diff --git a/mtproto-client.c b/mtproto-client.c index 6293bb8..256c2d8 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -633,6 +633,8 @@ int auth_work_start (struct connection *c UU) { void rpc_execute_answer (struct connection *c, long long msg_id UU); +int unread_messages; +int our_id; void work_update (struct connection *c UU, long long msg_id UU) { unsigned op = fetch_int (); switch (op) { @@ -640,6 +642,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { { struct message *M = fetch_alloc_message (); fetch_int (); //pts + unread_messages ++; print_message (M); break; }; @@ -936,12 +939,14 @@ void work_updates (struct connection *c, long long msg_id) { void work_update_short_message (struct connection *c UU, long long msg_id UU) { assert (fetch_int () == (int)CODE_update_short_message); struct message *M = fetch_alloc_message_short (); + unread_messages ++; print_message (M); } void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) { assert (fetch_int () == CODE_update_short_chat_message); struct message *M = fetch_alloc_message_short_chat (); + unread_messages ++; print_message (M); } From dce0af69d7c10e086a2f2f8ec74196bb361cf077 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 24 Oct 2013 20:01:40 +0400 Subject: [PATCH 031/465] Updated README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e69de29..f5dbf33 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,3 @@ +telegram-client. Uses readline interface. + +usage: telegram -k From dfdd18316952ad13f8251b5cf5b83f5d9713366f Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 24 Oct 2013 20:04:38 +0400 Subject: [PATCH 032/465] Fixed APP_HASH --- net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net.h b/net.h index 4cbb833..95995d0 100644 --- a/net.h +++ b/net.h @@ -24,7 +24,7 @@ struct dc; #include "queries.h" #define TG_SERVER "173.240.5.1" //#define TG_SERVER "95.142.192.66" -#define TG_APP_HASH "3bc14c6455ef1595ec86a125762c3aad" +#define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" #define TG_APP_ID 2899 #define ACK_TIMEOUT 60 From 7f47948cc649f54b051306a47511b560406a4e9f Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 24 Oct 2013 21:04:44 +0400 Subject: [PATCH 033/465] Fixed chat_info query --- mtproto-common.h | 4 ++ queries.c | 39 ++++--------- structures.c | 142 +++++++++++++++++++++++++++++++++++++---------- structures.h | 101 ++++++++++++++++++--------------- 4 files changed, 187 insertions(+), 99 deletions(-) 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 From 3fc3d33130e216781c86fe263c7155c325895217 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 24 Oct 2013 22:22:11 +0400 Subject: [PATCH 034/465] Added help. FIxed get dialog list --- interface.c | 18 ++++++++++++++++++ queries.c | 6 +++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index d006561..0957832 100644 --- a/interface.c +++ b/interface.c @@ -347,6 +347,24 @@ void interpreter (char *line UU) { } do_get_history (Peers[index], limit); } + } else if (!memcmp (line, "help", 4)) { + print_start (); + push_color (COLOR_YELLOW); + printf ( + "help - prints this help\n" + "msg Text - sends message to this peer\n" + "contact_list - prints info about users in your contact list\n" + "stats - just for debugging \n" + "history [limit] - prints history (and marks it as read). Default limit = 40\n" + "dialog_list - prints info about your dialogs\n" + "send_photo - sends photo to peer\n" + "send_video - sends video to peer\n" + "send_text - sends text file as plain messages\n" + "chat_info - prints info about chat\n" + ); + pop_color (); + print_end (); + printf ("\033[1K\033H"); } } diff --git a/queries.c b/queries.c index 15a137d..6423f26 100644 --- a/queries.c +++ b/queries.c @@ -655,7 +655,11 @@ void do_get_history (union user_chat *U, int limit) { } int get_dialogs_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_messages_dialogs); + unsigned x = fetch_int (); + assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); + if (x == CODE_messages_dialogs_slice) { + fetch_int (); // total_count + } assert (fetch_int () == CODE_vector); int n, i; n = fetch_int (); From 1a1dd694aa26b560a64d5d23c082890587ea4562 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Thu, 24 Oct 2013 22:25:37 +0400 Subject: [PATCH 035/465] Update README.md Improved Readme --- README.md | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f5dbf33..ddd85a0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,34 @@ -telegram-client. Uses readline interface. +## Telegram messenger CLI + +Command-line interface for [Telegram](http://telegram.org). Uses readline interface. + +### API, Protocol documentation + +Documentation for Telegram API is available here: http://core.telegram.org/api +Documentation for MTproto protocol is available here: http://core.telegram.org/mtproto + +### Installation + +Just run `make` + +### Usage + + ./telegram -k + +By default public key is stored in the same folder named tg.pub: + + ./telegram -k tg.pub + +#### Supported commands: + +* chat_info +* contact_list +* dialog_list +* help +* history +* msg +* send_photo +* send_text +* send_video +* stats -usage: telegram -k From 7eacd3c27a329b313840f6ee4eaeb0e251698680 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 24 Oct 2013 23:48:51 +0400 Subject: [PATCH 036/465] Added some debug info --- mtproto-client.c | 3 +++ queries.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 256c2d8..88fc17b 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -991,6 +991,9 @@ void work_msgs_ack (struct connection *c UU, long long msg_id UU) { int i; for (i = 0; i < n; i++) { long long id = fetch_long (); + if (verbosity) { + logprintf ("ack for %lld\n", id); + } query_ack (id); } } diff --git a/queries.c b/queries.c index 6423f26..9876bf3 100644 --- a/queries.c +++ b/queries.c @@ -51,6 +51,7 @@ double get_double_time (void) { } struct query *query_get (long long id) { + tree_check_query (queries_tree); return tree_lookup_query (queries_tree, (void *)&id); } @@ -59,8 +60,9 @@ int alarm_query (struct query *q) { if (verbosity) { logprintf ("Alarm query %lld\n", q->msg_id); } + tree_delete_query (queries_tree, q); q->ev.timeout = get_double_time () + QUERY_TIMEOUT; - insert_event_timer (&q->ev); + //insert_event_timer (&q->ev); return 0; } @@ -80,7 +82,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth memcpy (q->data, data, 4 * ints); q->msg_id = encrypt_send_message (DC->sessions[0]->c, data, ints, 1); if (verbosity) { - logprintf ( "Msg_id is %lld\n", q->msg_id); + logprintf ( "Msg_id is %lld %p\n", q->msg_id, q); } q->methods = methods; q->DC = DC; @@ -103,6 +105,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)) { + tree_check_query (queries_tree); + assert (q->msg_id == id); q->flags |= QUERY_ACK_RECEIVED; remove_event_timer (&q->ev); } From a89b6a2b9c119e9fbdd07b2cfa9e10b1b2ac30ac Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 25 Oct 2013 02:16:57 +0400 Subject: [PATCH 037/465] Fixed bug in trees, causing fails --- queries.c | 6 ------ tree.h | 7 ++++++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/queries.c b/queries.c index 9876bf3..25154af 100644 --- a/queries.c +++ b/queries.c @@ -51,7 +51,6 @@ double get_double_time (void) { } struct query *query_get (long long id) { - tree_check_query (queries_tree); return tree_lookup_query (queries_tree, (void *)&id); } @@ -105,7 +104,6 @@ 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)) { - tree_check_query (queries_tree); assert (q->msg_id == id); q->flags |= QUERY_ACK_RECEIVED; remove_event_timer (&q->ev); @@ -213,18 +211,14 @@ void insert_event_timer (struct event_timer *ev) { if (verbosity > 2) { logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); } - tree_check_timer (timer_tree); timer_tree = tree_insert_timer (timer_tree, ev, lrand48 ()); - tree_check_timer (timer_tree); } void remove_event_timer (struct event_timer *ev) { if (verbosity > 2) { logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); } - tree_check_timer (timer_tree); timer_tree = tree_delete_timer (timer_tree, ev); - tree_check_timer (timer_tree); } double next_timer_in (void) { diff --git a/tree.h b/tree.h index 04710f8..8f38e17 100644 --- a/tree.h +++ b/tree.h @@ -101,7 +101,12 @@ struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYP delete_tree_node_ ## X_NAME (T);\ return N;\ } else {\ - return tree_delete_ ## X_NAME (c < 0 ? T->left : T->right, x);\ + if (c < 0) { \ + T->left = tree_delete_ ## X_NAME (T->left, x); \ + } else { \ + T->right = tree_delete_ ## X_NAME (T->right, x); \ + } \ + return T; \ }\ }\ \ From bd6c8537293b48178924bfbee3e6fcb39d10f9c2 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 25 Oct 2013 02:21:52 +0400 Subject: [PATCH 038/465] Print info about forwarded message --- interface.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 0957832..c414325 100644 --- a/interface.c +++ b/interface.c @@ -612,8 +612,10 @@ int our_id; void print_service_message (struct message *M) { print_start (); push_color (COLOR_GREY); - + + push_color (COLOR_MAGENTA); print_date (M->date); + pop_color (); printf (" "); print_chat_name (M->to_id, user_chat_get (M->to_id)); printf (" "); @@ -706,6 +708,11 @@ void print_message (struct message *M) { printf (" »»» "); } } + if (M->fwd_from_id) { + printf ("[fwd from "); + print_user_name (M->fwd_from_id, user_chat_get (M->fwd_from_id)); + printf ("] "); + } if (M->message && strlen (M->message)) { printf ("%s", M->message); } From 0230038845f104fb33dce0caa70930af374eb1e1 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 25 Oct 2013 02:32:13 +0400 Subject: [PATCH 039/465] Ask dialog list at start. Try resend query on timeout --- loop.c | 2 ++ queries.c | 13 ++++++++++++- queries.h | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/loop.c b/loop.c index 5bde497..1f3fd0c 100644 --- a/loop.c +++ b/loop.c @@ -254,6 +254,8 @@ int loop (void) { rl_attempted_completion_function = (CPPFunction *) complete_text; rl_completion_entry_function = complete_none; + do_get_dialog_list (); + return main_loop (); } diff --git a/queries.c b/queries.c index 25154af..eb0ab28 100644 --- a/queries.c +++ b/queries.c @@ -61,7 +61,16 @@ int alarm_query (struct query *q) { } tree_delete_query (queries_tree, q); q->ev.timeout = get_double_time () + QUERY_TIMEOUT; - //insert_event_timer (&q->ev); + insert_event_timer (&q->ev); + + clear_packet (); + out_int (CODE_msg_container); + out_long (q->msg_id); + out_int (q->seq_no); + out_int (4 * q->data_len); + out_ints (q->data, q->data_len); + + encrypt_send_message (q->session->c, packet_buffer, packet_ptr - packet_buffer, 0); return 0; } @@ -80,6 +89,8 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth q->data = malloc (4 * ints); memcpy (q->data, data, 4 * ints); q->msg_id = encrypt_send_message (DC->sessions[0]->c, data, ints, 1); + q->session = DC->sessions[0]; + q->seq_no = DC->sessions[0]->seq_no - 1; if (verbosity) { logprintf ( "Msg_id is %lld %p\n", q->msg_id, q); } diff --git a/queries.h b/queries.h index 7a9ef52..dc245c9 100644 --- a/queries.h +++ b/queries.h @@ -39,10 +39,12 @@ struct query { long long msg_id; int data_len; int flags; + int seq_no; void *data; struct query_methods *methods; struct event_timer ev; struct dc *DC; + struct session *session; void *extra; }; From 0cd85d72341200c3de729c7e1f1099b1077cbf2a Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 25 Oct 2013 02:56:11 +0400 Subject: [PATCH 040/465] added #num to contacts with duplicate names --- queries.c | 4 ++++ structures.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/queries.c b/queries.c index eb0ab28..bcbfa8a 100644 --- a/queries.c +++ b/queries.c @@ -453,6 +453,10 @@ int get_contacts_on_answer (struct query *q UU) { push_color (COLOR_GREEN); printf (" ("); printf ("%s", U->print_name); + if (U->phone) { + printf (" "); + printf ("%s", U->phone); + } printf (") "); pop_color (); if (U->status.online > 0) { diff --git a/structures.c b/structures.c index fb9bbca..60f8478 100644 --- a/structures.c +++ b/structures.c @@ -23,6 +23,7 @@ #include "tree.h" #include "loop.h" int verbosity; +union user_chat *Peers[MAX_USER_NUM]; void fetch_file_location (struct file_location *loc) { int x = fetch_int (); @@ -60,6 +61,9 @@ void fetch_user_status (struct user_status *S) { } int our_id; +int user_num; +int chat_num; + void fetch_user (struct user *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); @@ -100,6 +104,48 @@ void fetch_user (struct user *U) { if (*s == ' ') { *s = '_'; } s++; } + int cc = 0; + while (1) { + int ok = 1; + int i; + for (i = 0; i < user_num + chat_num; i++) { + if (Peers[i] != (void *)U && !strcmp (Peers[i]->print_name, U->print_name)) { + ok = 0; + break; + } + } + if (ok) { + break; + } + cc ++; + assert (cc <= 99); + if (cc == 1) { + int l = strlen (U->print_name); + char *s = malloc (l + 3); + memcpy (s, U->print_name, l); + s[l + 2] = 0; + s[l] = '#'; + s[l + 1] = '1'; + free (U->print_name); + U->print_name = s; + } else if (cc == 10) { + int l = strlen (U->print_name); + char *s = malloc (l + 2); + memcpy (s, U->print_name, l); + s[l + 1] = 0; + s[l] = '0'; + s[l - 1] = '1'; + free (U->print_name); + U->print_name = s; + } else { + int l = strlen (U->print_name); + U->print_name[l - 1] ++; + if (U->print_name[l - 1] > '9') { + U->print_name[l - 1] = '0'; + U->print_name[l - 2] ++; + } + } + } if (x == CODE_user_deleted) { U->flags |= FLAG_DELETED; return; @@ -443,7 +489,6 @@ int 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, From a8834ce86c242111b8e13675cada63475f6c8b9d Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Fri, 25 Oct 2013 10:02:29 +0400 Subject: [PATCH 041/465] Added OS note, fixed styles --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index ddd85a0..29ef917 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,17 @@ Command-line interface for [Telegram](http://telegram.org). Uses readline interf ### API, Protocol documentation Documentation for Telegram API is available here: http://core.telegram.org/api + Documentation for MTproto protocol is available here: http://core.telegram.org/mtproto ### Installation Just run `make` +#### Requirements + +Currently only Linux OS is supported. But if you manage to launch it on OS X or other UNIX, please let me know. + ### Usage ./telegram -k From 5dfaf8ca64a4527aa1e5561383c615839d207dea Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 25 Oct 2013 13:28:29 +0400 Subject: [PATCH 042/465] Added some fixes required by GPL --- LICENSE.h | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++ interface.c | 9 ++ main.c | 7 ++ net.h | 2 + queries.c | 1 - 5 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 LICENSE.h diff --git a/LICENSE.h b/LICENSE.h new file mode 100644 index 0000000..0dcf708 --- /dev/null +++ b/LICENSE.h @@ -0,0 +1,339 @@ +" GNU GENERAL PUBLIC LICENSE\n" +" Version 2, June 1991\n" +"\n" +" Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n" +" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" +" Everyone is permitted to copy and distribute verbatim copies\n" +" of this license document, but changing it is not allowed.\n" +"\n" +" Preamble\n" +"\n" +" The licenses for most software are designed to take away your\n" +"freedom to share and change it. By contrast, the GNU General Public\n" +"License is intended to guarantee your freedom to share and change free\n" +"software--to make sure the software is free for all its users. This\n" +"General Public License applies to most of the Free Software\n" +"Foundation's software and to any other program whose authors commit to\n" +"using it. (Some other Free Software Foundation software is covered by\n" +"the GNU Lesser General Public License instead.) You can apply it to\n" +"your programs, too.\n" +"\n" +" When we speak of free software, we are referring to freedom, not\n" +"price. Our General Public Licenses are designed to make sure that you\n" +"have the freedom to distribute copies of free software (and charge for\n" +"this service if you wish), that you receive source code or can get it\n" +"if you want it, that you can change the software or use pieces of it\n" +"in new free programs; and that you know you can do these things.\n" +"\n" +" To protect your rights, we need to make restrictions that forbid\n" +"anyone to deny you these rights or to ask you to surrender the rights.\n" +"These restrictions translate to certain responsibilities for you if you\n" +"distribute copies of the software, or if you modify it.\n" +"\n" +" For example, if you distribute copies of such a program, whether\n" +"gratis or for a fee, you must give the recipients all the rights that\n" +"you have. You must make sure that they, too, receive or can get the\n" +"source code. And you must show them these terms so they know their\n" +"rights.\n" +"\n" +" We protect your rights with two steps: (1) copyright the software, and\n" +"(2) offer you this license which gives you legal permission to copy,\n" +"distribute and/or modify the software.\n" +"\n" +" Also, for each author's protection and ours, we want to make certain\n" +"that everyone understands that there is no warranty for this free\n" +"software. If the software is modified by someone else and passed on, we\n" +"want its recipients to know that what they have is not the original, so\n" +"that any problems introduced by others will not reflect on the original\n" +"authors' reputations.\n" +"\n" +" Finally, any free program is threatened constantly by software\n" +"patents. We wish to avoid the danger that redistributors of a free\n" +"program will individually obtain patent licenses, in effect making the\n" +"program proprietary. To prevent this, we have made it clear that any\n" +"patent must be licensed for everyone's free use or not licensed at all.\n" +"\n" +" The precise terms and conditions for copying, distribution and\n" +"modification follow.\n" +"\n" +" GNU GENERAL PUBLIC LICENSE\n" +" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n" +"\n" +" 0. This License applies to any program or other work which contains\n" +"a notice placed by the copyright holder saying it may be distributed\n" +"under the terms of this General Public License. The \"Program\", below,\n" +"refers to any such program or work, and a \"work based on the Program\"\n" +"means either the Program or any derivative work under copyright law:\n" +"that is to say, a work containing the Program or a portion of it,\n" +"either verbatim or with modifications and/or translated into another\n" +"language. (Hereinafter, translation is included without limitation in\n" +"the term \"modification\".) Each licensee is addressed as \"you\".\n" +"\n" +"Activities other than copying, distribution and modification are not\n" +"covered by this License; they are outside its scope. The act of\n" +"running the Program is not restricted, and the output from the Program\n" +"is covered only if its contents constitute a work based on the\n" +"Program (independent of having been made by running the Program).\n" +"Whether that is true depends on what the Program does.\n" +"\n" +" 1. You may copy and distribute verbatim copies of the Program's\n" +"source code as you receive it, in any medium, provided that you\n" +"conspicuously and appropriately publish on each copy an appropriate\n" +"copyright notice and disclaimer of warranty; keep intact all the\n" +"notices that refer to this License and to the absence of any warranty;\n" +"and give any other recipients of the Program a copy of this License\n" +"along with the Program.\n" +"\n" +"You may charge a fee for the physical act of transferring a copy, and\n" +"you may at your option offer warranty protection in exchange for a fee.\n" +"\n" +" 2. You may modify your copy or copies of the Program or any portion\n" +"of it, thus forming a work based on the Program, and copy and\n" +"distribute such modifications or work under the terms of Section 1\n" +"above, provided that you also meet all of these conditions:\n" +"\n" +" a) You must cause the modified files to carry prominent notices\n" +" stating that you changed the files and the date of any change.\n" +"\n" +" b) You must cause any work that you distribute or publish, that in\n" +" whole or in part contains or is derived from the Program or any\n" +" part thereof, to be licensed as a whole at no charge to all third\n" +" parties under the terms of this License.\n" +"\n" +" c) If the modified program normally reads commands interactively\n" +" when run, you must cause it, when started running for such\n" +" interactive use in the most ordinary way, to print or display an\n" +" announcement including an appropriate copyright notice and a\n" +" notice that there is no warranty (or else, saying that you provide\n" +" a warranty) and that users may redistribute the program under\n" +" these conditions, and telling the user how to view a copy of this\n" +" License. (Exception: if the Program itself is interactive but\n" +" does not normally print such an announcement, your work based on\n" +" the Program is not required to print an announcement.)\n" +"\n" +"These requirements apply to the modified work as a whole. If\n" +"identifiable sections of that work are not derived from the Program,\n" +"and can be reasonably considered independent and separate works in\n" +"themselves, then this License, and its terms, do not apply to those\n" +"sections when you distribute them as separate works. But when you\n" +"distribute the same sections as part of a whole which is a work based\n" +"on the Program, the distribution of the whole must be on the terms of\n" +"this License, whose permissions for other licensees extend to the\n" +"entire whole, and thus to each and every part regardless of who wrote it.\n" +"\n" +"Thus, it is not the intent of this section to claim rights or contest\n" +"your rights to work written entirely by you; rather, the intent is to\n" +"exercise the right to control the distribution of derivative or\n" +"collective works based on the Program.\n" +"\n" +"In addition, mere aggregation of another work not based on the Program\n" +"with the Program (or with a work based on the Program) on a volume of\n" +"a storage or distribution medium does not bring the other work under\n" +"the scope of this License.\n" +"\n" +" 3. You may copy and distribute the Program (or a work based on it,\n" +"under Section 2) in object code or executable form under the terms of\n" +"Sections 1 and 2 above provided that you also do one of the following:\n" +"\n" +" a) Accompany it with the complete corresponding machine-readable\n" +" source code, which must be distributed under the terms of Sections\n" +" 1 and 2 above on a medium customarily used for software interchange; or,\n" +"\n" +" b) Accompany it with a written offer, valid for at least three\n" +" years, to give any third party, for a charge no more than your\n" +" cost of physically performing source distribution, a complete\n" +" machine-readable copy of the corresponding source code, to be\n" +" distributed under the terms of Sections 1 and 2 above on a medium\n" +" customarily used for software interchange; or,\n" +"\n" +" c) Accompany it with the information you received as to the offer\n" +" to distribute corresponding source code. (This alternative is\n" +" allowed only for noncommercial distribution and only if you\n" +" received the program in object code or executable form with such\n" +" an offer, in accord with Subsection b above.)\n" +"\n" +"The source code for a work means the preferred form of the work for\n" +"making modifications to it. For an executable work, complete source\n" +"code means all the source code for all modules it contains, plus any\n" +"associated interface definition files, plus the scripts used to\n" +"control compilation and installation of the executable. However, as a\n" +"special exception, the source code distributed need not include\n" +"anything that is normally distributed (in either source or binary\n" +"form) with the major components (compiler, kernel, and so on) of the\n" +"operating system on which the executable runs, unless that component\n" +"itself accompanies the executable.\n" +"\n" +"If distribution of executable or object code is made by offering\n" +"access to copy from a designated place, then offering equivalent\n" +"access to copy the source code from the same place counts as\n" +"distribution of the source code, even though third parties are not\n" +"compelled to copy the source along with the object code.\n" +"\n" +" 4. You may not copy, modify, sublicense, or distribute the Program\n" +"except as expressly provided under this License. Any attempt\n" +"otherwise to copy, modify, sublicense or distribute the Program is\n" +"void, and will automatically terminate your rights under this License.\n" +"However, parties who have received copies, or rights, from you under\n" +"this License will not have their licenses terminated so long as such\n" +"parties remain in full compliance.\n" +"\n" +" 5. You are not required to accept this License, since you have not\n" +"signed it. However, nothing else grants you permission to modify or\n" +"distribute the Program or its derivative works. These actions are\n" +"prohibited by law if you do not accept this License. Therefore, by\n" +"modifying or distributing the Program (or any work based on the\n" +"Program), you indicate your acceptance of this License to do so, and\n" +"all its terms and conditions for copying, distributing or modifying\n" +"the Program or works based on it.\n" +"\n" +" 6. Each time you redistribute the Program (or any work based on the\n" +"Program), the recipient automatically receives a license from the\n" +"original licensor to copy, distribute or modify the Program subject to\n" +"these terms and conditions. You may not impose any further\n" +"restrictions on the recipients' exercise of the rights granted herein.\n" +"You are not responsible for enforcing compliance by third parties to\n" +"this License.\n" +"\n" +" 7. If, as a consequence of a court judgment or allegation of patent\n" +"infringement or for any other reason (not limited to patent issues),\n" +"conditions are imposed on you (whether by court order, agreement or\n" +"otherwise) that contradict the conditions of this License, they do not\n" +"excuse you from the conditions of this License. If you cannot\n" +"distribute so as to satisfy simultaneously your obligations under this\n" +"License and any other pertinent obligations, then as a consequence you\n" +"may not distribute the Program at all. For example, if a patent\n" +"license would not permit royalty-free redistribution of the Program by\n" +"all those who receive copies directly or indirectly through you, then\n" +"the only way you could satisfy both it and this License would be to\n" +"refrain entirely from distribution of the Program.\n" +"\n" +"If any portion of this section is held invalid or unenforceable under\n" +"any particular circumstance, the balance of the section is intended to\n" +"apply and the section as a whole is intended to apply in other\n" +"circumstances.\n" +"\n" +"It is not the purpose of this section to induce you to infringe any\n" +"patents or other property right claims or to contest validity of any\n" +"such claims; this section has the sole purpose of protecting the\n" +"integrity of the free software distribution system, which is\n" +"implemented by public license practices. Many people have made\n" +"generous contributions to the wide range of software distributed\n" +"through that system in reliance on consistent application of that\n" +"system; it is up to the author/donor to decide if he or she is willing\n" +"to distribute software through any other system and a licensee cannot\n" +"impose that choice.\n" +"\n" +"This section is intended to make thoroughly clear what is believed to\n" +"be a consequence of the rest of this License.\n" +"\n" +" 8. If the distribution and/or use of the Program is restricted in\n" +"certain countries either by patents or by copyrighted interfaces, the\n" +"original copyright holder who places the Program under this License\n" +"may add an explicit geographical distribution limitation excluding\n" +"those countries, so that distribution is permitted only in or among\n" +"countries not thus excluded. In such case, this License incorporates\n" +"the limitation as if written in the body of this License.\n" +"\n" +" 9. The Free Software Foundation may publish revised and/or new versions\n" +"of the General Public License from time to time. Such new versions will\n" +"be similar in spirit to the present version, but may differ in detail to\n" +"address new problems or concerns.\n" +"\n" +"Each version is given a distinguishing version number. If the Program\n" +"specifies a version number of this License which applies to it and \"any\n" +"later version\", you have the option of following the terms and conditions\n" +"either of that version or of any later version published by the Free\n" +"Software Foundation. If the Program does not specify a version number of\n" +"this License, you may choose any version ever published by the Free Software\n" +"Foundation.\n" +"\n" +" 10. If you wish to incorporate parts of the Program into other free\n" +"programs whose distribution conditions are different, write to the author\n" +"to ask for permission. For software which is copyrighted by the Free\n" +"Software Foundation, write to the Free Software Foundation; we sometimes\n" +"make exceptions for this. Our decision will be guided by the two goals\n" +"of preserving the free status of all derivatives of our free software and\n" +"of promoting the sharing and reuse of software generally.\n" +"\n" +" NO WARRANTY\n" +"\n" +" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n" +"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n" +"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n" +"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n" +"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n" +"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n" +"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n" +"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n" +"REPAIR OR CORRECTION.\n" +"\n" +" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n" +"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n" +"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n" +"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n" +"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n" +"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n" +"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n" +"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n" +"POSSIBILITY OF SUCH DAMAGES.\n" +"\n" +" END OF TERMS AND CONDITIONS\n" +"\n" +" How to Apply These Terms to Your New Programs\n" +"\n" +" If you develop a new program, and you want it to be of the greatest\n" +"possible use to the public, the best way to achieve this is to make it\n" +"free software which everyone can redistribute and change under these terms.\n" +"\n" +" To do so, attach the following notices to the program. It is safest\n" +"to attach them to the start of each source file to most effectively\n" +"convey the exclusion of warranty; and each file should have at least\n" +"the \"copyright\" line and a pointer to where the full notice is found.\n" +"\n" +" \n" +" Copyright (C) \n" +"\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License along\n" +" with this program; if not, write to the Free Software Foundation, Inc.,\n" +" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" +"\n" +"Also add information on how to contact you by electronic and paper mail.\n" +"\n" +"If the program is interactive, make it output a short notice like this\n" +"when it starts in an interactive mode:\n" +"\n" +" Gnomovision version 69, Copyright (C) year name of author\n" +" Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n" +" This is free software, and you are welcome to redistribute it\n" +" under certain conditions; type `show c' for details.\n" +"\n" +"The hypothetical commands `show w' and `show c' should show the appropriate\n" +"parts of the General Public License. Of course, the commands you use may\n" +"be called something other than `show w' and `show c'; they could even be\n" +"mouse-clicks or menu items--whatever suits your program.\n" +"\n" +"You should also get your employer (if you work as a programmer) or your\n" +"school, if any, to sign a \"copyright disclaimer\" for the program, if\n" +"necessary. Here is a sample; alter the names:\n" +"\n" +" Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n" +" `Gnomovision' (which makes passes at compilers) written by James Hacker.\n" +"\n" +" , 1 April 1989\n" +" Ty Coon, President of Vice\n" +"\n" +"This General Public License does not permit incorporating your program into\n" +"proprietary programs. If your program is a subroutine library, you may\n" +"consider it more useful to permit linking proprietary applications with the\n" +"library. If this is what you want to do, use the GNU Lesser General\n" +"Public License instead of this License.\n" diff --git a/interface.c b/interface.c index c414325..f3cad4b 100644 --- a/interface.c +++ b/interface.c @@ -64,6 +64,7 @@ char *commands[] = { "send_video", "send_text", "chat_info", + "show_license", 0 }; int commands_flags[] = { @@ -77,6 +78,7 @@ int commands_flags[] = { 0732, 0732, 074, + 07, }; char *a = 0; @@ -365,6 +367,13 @@ void interpreter (char *line UU) { pop_color (); print_end (); printf ("\033[1K\033H"); + } else if (!memcmp (line, "show_license", 12)) { + char *b = +#include "LICENSE.h" + ; + print_start (); + printf ("%s", b); + print_end (); } } diff --git a/main.c b/main.c index 60b96d1..e2b70f3 100644 --- a/main.c +++ b/main.c @@ -244,6 +244,13 @@ int main (int argc, char **argv) { signal (SIGABRT, sig_handler); running_for_first_time (); + printf ( + "Telegram-client version " TG_VERSION ", Copyright (C) year name of author\n" + "Telegram-client comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions; type `show_license' for details.\n" + ); + get_terminal_attributes (); args_parse (argc, argv); diff --git a/net.h b/net.h index 95995d0..4e8487a 100644 --- a/net.h +++ b/net.h @@ -27,6 +27,8 @@ struct dc; #define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" #define TG_APP_ID 2899 +#define TG_VERSION "0.01-beta" + #define ACK_TIMEOUT 60 #define MAX_DC_ID 10 diff --git a/queries.c b/queries.c index eb0ab28..910c9c0 100644 --- a/queries.c +++ b/queries.c @@ -59,7 +59,6 @@ int alarm_query (struct query *q) { if (verbosity) { logprintf ("Alarm query %lld\n", q->msg_id); } - tree_delete_query (queries_tree, q); q->ev.timeout = get_double_time () + QUERY_TIMEOUT; insert_event_timer (&q->ev); From a5029117d44d97aa9f18693b535fc8d2c37bcb9e Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 25 Oct 2013 13:32:10 +0400 Subject: [PATCH 043/465] Small fix to header --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index e2b70f3..1a2997d 100644 --- a/main.c +++ b/main.c @@ -245,7 +245,7 @@ int main (int argc, char **argv) { running_for_first_time (); printf ( - "Telegram-client version " TG_VERSION ", Copyright (C) year name of author\n" + "Telegram-client version " TG_VERSION ", Copyright (C) 2013 Vitaly Valtman\n" "Telegram-client comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions; type `show_license' for details.\n" From 4fd6b442196b8b5874d7bcf5c51858ef7a81234a Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 25 Oct 2013 21:29:02 +0400 Subject: [PATCH 044/465] Added user_info query --- interface.c | 14 +++++++++++++ queries.c | 33 ++++++++++++++++++++++++++++++ queries.h | 1 + structures.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ structures.h | 8 +++++++- 5 files changed, 112 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index f3cad4b..16ec86a 100644 --- a/interface.c +++ b/interface.c @@ -64,6 +64,7 @@ char *commands[] = { "send_video", "send_text", "chat_info", + "user_info", "show_license", 0 }; @@ -78,6 +79,7 @@ int commands_flags[] = { 0732, 0732, 074, + 072, 07, }; @@ -330,6 +332,17 @@ void interpreter (char *line UU) { if (index < user_num + chat_num && Peers[index]->id < 0) { do_get_chat_info (Peers[index]); } + } else if (!memcmp (line, "user_info", 9)) { + char *q = line + 10; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num && Peers[index]->id > 0) { + do_get_user_info (Peers[index]); + } } else if (!memcmp (line, "history", 7)) { char *q = line + 7; int len; @@ -363,6 +376,7 @@ void interpreter (char *line UU) { "send_video - sends video to peer\n" "send_text - sends text file as plain messages\n" "chat_info - prints info about chat\n" + "user_info - prints info about user\n" ); pop_color (); print_end (); diff --git a/queries.c b/queries.c index 910c9c0..d0f6239 100644 --- a/queries.c +++ b/queries.c @@ -911,6 +911,39 @@ void do_get_chat_info (union user_chat *chat) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0); } +int user_info_on_answer (struct query *q UU) { + struct user *U = fetch_alloc_user_full (); + union user_chat *C = (void *)U; + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (U->id, C); + printf (":\n"); + printf ("\t real name: %s %s\n", U->real_first_name, U->real_last_name); + printf ("\t phone: %s\n", U->phone); + pop_color (); + print_end (); + return 0; +} + +struct query_methods user_info_methods = { + .on_answer = user_info_on_answer +}; + +void do_get_user_info (union user_chat *U) { + clear_packet (); + out_int (CODE_users_get_full_user); + if (U->user.access_hash) { + out_int (CODE_input_user_foreign); + out_int (U->id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_user_contact); + out_int (U->id); + } + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0); +} + int user_list_info_silent_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); int n = fetch_int (); diff --git a/queries.h b/queries.h index dc245c9..89e9160 100644 --- a/queries.h +++ b/queries.h @@ -74,5 +74,6 @@ void do_get_dialog_list (void); void do_send_photo (int type, int to_id, char *file_name); void do_get_chat_info (union user_chat *chat); void do_get_user_list_info_silent (int num, int *list); +void do_get_user_info (union user_chat *user); #endif diff --git a/structures.c b/structures.c index fb9bbca..fbbe35e 100644 --- a/structures.c +++ b/structures.c @@ -133,6 +133,44 @@ void fetch_user (struct user *U) { } } +void fetch_notify_settings (void); +void fetch_user_full (struct user *U) { + assert (fetch_int () == CODE_user_full); + fetch_alloc_user (); + unsigned x; + assert (fetch_int () == (int)CODE_contacts_link); + x = fetch_int (); + assert (x == CODE_contacts_my_link_empty || x == CODE_contacts_my_link_requested || x == CODE_contacts_my_link_contact); + U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); + if (x == CODE_contacts_my_link_contact) { + U->flags |= FLAG_USER_IN_CONTACT; + } + if (x == CODE_contacts_my_link_requested) { + fetch_bool (); + } + x = fetch_int (); + assert (x == CODE_contacts_foreign_link_unknown || x == CODE_contacts_foreign_link_requested || x == CODE_contacts_foreign_link_mutual); + U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); + if (x == CODE_contacts_foreign_link_mutual) { + U->flags |= FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT; + } + if (x == CODE_contacts_my_link_requested) { + U->flags |= FLAG_USER_OUT_CONTACT; + fetch_bool (); + } + fetch_alloc_user (); + if (U->flags & FLAG_HAS_PHOTO) { + free_photo (&U->photo); + } + fetch_photo (&U->photo); + fetch_notify_settings (); + U->blocked = fetch_int (); + if (U->real_first_name) { free (U->real_first_name); } + if (U->real_last_name) { free (U->real_last_name); } + U->real_first_name = fetch_str_dup (); + U->real_last_name = fetch_str_dup (); +} + void fetch_chat (struct chat *C) { unsigned x = fetch_int (); assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); @@ -468,6 +506,25 @@ struct user *fetch_alloc_user (void) { } } +struct user *fetch_alloc_user_full (void) { + int data[3]; + prefetch_data (data, 12); + union user_chat *U = user_chat_get (data[2]); + if (U) { + fetch_user_full (&U->user); + return &U->user; + } else { + users_allocated ++; + U = malloc (sizeof (*U)); + memset (U, 0, sizeof (*U)); + U->id = data[2]; + peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + fetch_user_full (&U->user); + Peers[chat_num + (user_num ++ )] = U; + return &U->user; + } +} + void free_user (struct user *U) { if (U->first_name) { free (U->first_name); } if (U->last_name) { free (U->last_name); } diff --git a/structures.h b/structures.h index 6178c75..e08c1f1 100644 --- a/structures.h +++ b/structures.h @@ -27,6 +27,8 @@ #define FLAG_USER_SELF 128 #define FLAG_USER_FOREIGN 256 #define FLAG_USER_CONTACT 512 +#define FLAG_USER_IN_CONTACT 1024 +#define FLAG_USER_OUT_CONTACT 2048 #define FLAG_CHAT_IN_CHAT 128 @@ -79,6 +81,9 @@ struct user { char *phone; long long access_hash; struct user_status status; + int blocked; + char *real_first_name; + char *real_last_name; }; struct chat_user { @@ -185,11 +190,12 @@ void fetch_file_location (struct file_location *loc); void fetch_user_status (struct user_status *S); void fetch_user (struct user *U); struct user *fetch_alloc_user (void); +struct user *fetch_alloc_user_full (void); struct chat *fetch_alloc_chat (void); +struct chat *fetch_alloc_chat_full (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); From cfdfc0d72db171e443afdefa1fcd5d3e25f7c28f Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 25 Oct 2013 21:33:18 +0400 Subject: [PATCH 045/465] Fixed bug in user_info --- structures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structures.c b/structures.c index 15e0276..4902307 100644 --- a/structures.c +++ b/structures.c @@ -200,7 +200,7 @@ void fetch_user_full (struct user *U) { if (x == CODE_contacts_foreign_link_mutual) { U->flags |= FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT; } - if (x == CODE_contacts_my_link_requested) { + if (x == CODE_contacts_foreign_link_requested) { U->flags |= FLAG_USER_OUT_CONTACT; fetch_bool (); } From 5c4fb5ed7f1d0c631895af6af7bf7eb5f0b7f58b Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 25 Oct 2013 21:40:03 +0400 Subject: [PATCH 046/465] Fixed alarm --- queries.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/queries.c b/queries.c index 45ce303..a8bf1cc 100644 --- a/queries.c +++ b/queries.c @@ -56,7 +56,7 @@ struct query *query_get (long long id) { int alarm_query (struct query *q) { assert (q); - if (verbosity) { + if (verbosity >= 1) { logprintf ("Alarm query %lld\n", q->msg_id); } q->ev.timeout = get_double_time () + QUERY_TIMEOUT; @@ -64,6 +64,7 @@ int alarm_query (struct query *q) { clear_packet (); out_int (CODE_msg_container); + out_int (1); out_long (q->msg_id); out_int (q->seq_no); out_int (4 * q->data_len); From f45844419375fd36e9853bcd14da95b70b476b05 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 25 Oct 2013 23:50:10 +0400 Subject: [PATCH 047/465] fwd message --- constants.h | 100 +++++++++++++++++++++++++++++++++++++++++++++------ interface.c | 30 ++++++++++++++++ main.c | 6 +++- queries.c | 34 ++++++++++++++++++ queries.h | 1 + structures.c | 8 ++++- 6 files changed, 167 insertions(+), 12 deletions(-) diff --git a/constants.h b/constants.h index ac6b3da..cb396fa 100644 --- a/constants.h +++ b/constants.h @@ -76,7 +76,7 @@ #define CODE_user_foreign 0x5214c89d #define CODE_user_deleted 0xb29ad7cc #define CODE_user_profile_photo_empty 0x4f11bae1 -#define CODE_user_profile_photo 0x990d1493 +#define CODE_user_profile_photo 0xd559d8c8 #define CODE_user_status_empty 0x9d05049 #define CODE_user_status_online 0xedb93949 #define CODE_user_status_offline 0x8c703f @@ -126,11 +126,11 @@ #define CODE_input_notify_all 0xa429b886 #define CODE_input_peer_notify_events_empty 0xf03064d8 #define CODE_input_peer_notify_events_all 0xe86a2c74 -#define CODE_input_peer_notify_settings 0x3cf4b1be +#define CODE_input_peer_notify_settings 0x46a2ce98 #define CODE_peer_notify_events_empty 0xadd53cb3 #define CODE_peer_notify_events_all 0x6d1ded88 #define CODE_peer_notify_settings_empty 0x70a68512 -#define CODE_peer_notify_settings 0xddbcd4a5 +#define CODE_peer_notify_settings 0x8d5e11ee #define CODE_wall_paper 0xccb03657 #define CODE_user_full 0x771095da #define CODE_contact 0xf911c994 @@ -181,15 +181,15 @@ #define CODE_update_chat_participants 0x7761198 #define CODE_update_user_status 0x1bfbd823 #define CODE_update_user_name 0xda22d9ad -#define CODE_update_user_photo 0xbb8ba607 +#define CODE_update_user_photo 0x95313b0c #define CODE_update_contact_registered 0x2575bbb9 #define CODE_update_contact_link 0x51a48a9a #define CODE_update_activation 0x6f690963 #define CODE_update_new_authorization 0x8f06529a -#define CODE_updates_state 0xa0d9c0c +#define CODE_updates_state 0xa56c2a3e #define CODE_updates_difference_empty 0x5d75a138 -#define CODE_updates_difference 0x8adb0077 -#define CODE_updates_difference_slice 0xc5e839b4 +#define CODE_updates_difference 0xf49ca0 +#define CODE_updates_difference_slice 0xa8fb1981 #define CODE_updates_too_long 0xe317af7e #define CODE_update_short_message 0xd3f45784 #define CODE_update_short_chat_message 0x2b2fbd4e @@ -204,12 +204,60 @@ #define CODE_config 0x232d5905 #define CODE_nearest_dc 0x8e1a1775 #define CODE_help_invite_text 0x18cb9f78 +#define CODE_messages_stated_messages_links 0x3e74f5c6 +#define CODE_messages_stated_message_link 0xa9af2881 +#define CODE_messages_sent_message_link 0xe9db4a3f +#define CODE_input_geo_chat 0x74d456fa +#define CODE_input_notify_geo_chat_peer 0x4d8ddec8 +#define CODE_geo_chat 0x75eaea5a +#define CODE_geo_chat_message_empty 0x60311a9b +#define CODE_geo_chat_message 0x4505f8e1 +#define CODE_geo_chat_message_service 0xd34fa24e +#define CODE_geochats_stated_message 0x17b1578b +#define CODE_geochats_located 0x48feb267 +#define CODE_geochats_messages 0xd1526db1 +#define CODE_geochats_messages_slice 0xbc5863e8 +#define CODE_message_action_geo_chat_create 0x6f038ebc +#define CODE_message_action_geo_chat_checkin 0xc7d53de +#define CODE_update_new_geo_chat_message 0x5a68e3f7 +#define CODE_wall_paper_solid 0x63117f24 +#define CODE_update_new_encrypted_message 0x12bcbd9a +#define CODE_update_encrypted_chat_typing 0x1710f156 +#define CODE_update_encryption 0xb4a2e88d +#define CODE_update_encrypted_messages_read 0x38fe25b7 +#define CODE_encrypted_chat_empty 0xab7ec0a0 +#define CODE_encrypted_chat_waiting 0x3bf703dc +#define CODE_encrypted_chat_requested 0xfda9a7b7 +#define CODE_encrypted_chat 0x6601d14f +#define CODE_encrypted_chat_discarded 0x13d6dd27 +#define CODE_input_encrypted_chat 0xf141b5e1 +#define CODE_encrypted_file_empty 0xc21f497e +#define CODE_encrypted_file 0x4a70994c +#define CODE_input_encrypted_file_empty 0x1837c364 +#define CODE_input_encrypted_file_uploaded 0x64bd0306 +#define CODE_input_encrypted_file 0x5a17b5e5 +#define CODE_input_encrypted_file_location 0xf5235d55 +#define CODE_encrypted_message 0xed18c118 +#define CODE_encrypted_message_service 0x23734b06 +#define CODE_decrypted_message_layer 0x99a438cf +#define CODE_decrypted_message 0x1f814f1f +#define CODE_decrypted_message_service 0xaa48327d +#define CODE_decrypted_message_media_empty 0x89f5c4a +#define CODE_decrypted_message_media_photo 0x32798a8c +#define CODE_decrypted_message_media_video 0x4cee6ef3 +#define CODE_decrypted_message_media_geo_point 0x35480a59 +#define CODE_decrypted_message_media_contact 0x588a0a97 +#define CODE_decrypted_message_action_set_message_t_t_l 0xa1733aec +#define CODE_messages_dh_config_not_modified 0xc0e24635 +#define CODE_messages_dh_config 0x2c221edd +#define CODE_messages_sent_encrypted_message 0x560f8935 +#define CODE_messages_sent_encrypted_file 0x9493ff32 #define CODE_invoke_after_msg 0xcb9f372d #define CODE_invoke_after_msgs 0x3dc4b4f0 #define CODE_invoke_with_layer1 0x53835315 #define CODE_init_connection 0x3fc12e08 #define CODE_auth_check_phone 0x6fe51dfb -#define CODE_auth_send_code 0xd16ff372 +#define CODE_auth_send_code 0x768d5f4d #define CODE_auth_send_call 0x3c51564 #define CODE_auth_sign_up 0x1b067634 #define CODE_auth_sign_in 0xbcd51581 @@ -218,7 +266,7 @@ #define CODE_auth_send_invites 0x771c1d97 #define CODE_auth_export_authorization 0xe5bfffcd #define CODE_auth_import_authorization 0xe3ef9613 -#define CODE_account_register_device 0xa28557ac +#define CODE_account_register_device 0x446c712c #define CODE_account_unregister_device 0x65c55b40 #define CODE_account_update_notify_settings 0x84be5b93 #define CODE_account_get_notify_settings 0x12b3ad31 @@ -259,7 +307,7 @@ #define CODE_messages_delete_chat_user 0xc3c5cd23 #define CODE_messages_create_chat 0x419d9aee #define CODE_updates_get_state 0xedd4882a -#define CODE_updates_get_difference 0x5b36855a +#define CODE_updates_get_difference 0xa041495 #define CODE_photos_update_profile_photo 0xeef579a0 #define CODE_photos_upload_profile_photo 0xd50f9c88 #define CODE_upload_save_file_part 0xb304a621 @@ -268,4 +316,36 @@ #define CODE_help_get_nearest_dc 0x1fb33026 #define CODE_help_save_app_log 0x6f02f748 #define CODE_help_get_invite_text 0xa4a95186 +#define CODE_photos_get_user_photos 0xb7ee553c +#define CODE_invoke_with_layer2 0x289dd1f6 +#define CODE_messages_forward_message 0x3f3f4f2 +#define CODE_messages_send_broadcast 0x41bb0972 +#define CODE_invoke_with_layer3 0xb7475268 +#define CODE_geochats_get_located 0x7f192d8f +#define CODE_geochats_get_recents 0xe1427e6f +#define CODE_geochats_checkin 0x55b3e8fb +#define CODE_geochats_get_full_chat 0x6722dd6f +#define CODE_geochats_edit_chat_title 0x4c8e2273 +#define CODE_geochats_edit_chat_photo 0x35d81a95 +#define CODE_geochats_search 0xcfcdc44d +#define CODE_geochats_get_history 0xb53f7a68 +#define CODE_geochats_set_typing 0x8b8a729 +#define CODE_geochats_send_message 0x61b0044 +#define CODE_geochats_send_media 0xb8f0deff +#define CODE_geochats_create_geo_chat 0xe092e16 +#define CODE_invoke_with_layer4 0xdea0d430 +#define CODE_invoke_with_layer5 0x417a57ae +#define CODE_invoke_with_layer6 0x3a64d54d +#define CODE_invoke_with_layer7 0xa5be56d3 +#define CODE_messages_get_dh_config 0x26cf8950 +#define CODE_messages_request_encryption 0xf64daf43 +#define CODE_messages_accept_encryption 0x3dbc0415 +#define CODE_messages_discard_encryption 0xedd923c5 +#define CODE_messages_set_encrypted_typing 0x791451ed +#define CODE_messages_read_encrypted_history 0x7f4b690a +#define CODE_messages_send_encrypted 0xa9776773 +#define CODE_messages_send_encrypted_file 0x9a901b66 +#define CODE_messages_send_encrypted_service 0x32d439a4 +#define CODE_messages_received_queue 0x55a5bb66 +#define CODE_invoke_with_layer8 0xe9abd9fd #endif diff --git a/interface.c b/interface.c index 16ec86a..cdb5649 100644 --- a/interface.c +++ b/interface.c @@ -38,6 +38,7 @@ char *default_prompt = "> "; int unread_messages; +int msg_num_mode; char *get_default_prompt (void) { static char buf[100]; @@ -65,6 +66,7 @@ char *commands[] = { "send_text", "chat_info", "user_info", + "fwd", "show_license", 0 }; @@ -79,6 +81,7 @@ int commands_flags[] = { 0732, 0732, 074, + 071, 072, 07, }; @@ -321,6 +324,24 @@ void interpreter (char *line UU) { do_send_text (Peers[index], strndup (f, len)); } } + } else if (!memcmp (line, "fwd ", 4)) { + char *q = line + 4; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num) { + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + do_forward_message (Peers[index], num); + } + } + } } else if (!memcmp (line, "chat_info", 9)) { char *q = line + 10; int len; @@ -689,6 +710,9 @@ void print_message (struct message *M) { if (M->to_id >= 0) { if (M->out) { push_color (COLOR_GREEN); + if (msg_num_mode) { + printf ("%d ", M->id); + } print_date (M->date); pop_color (); printf (" "); @@ -701,6 +725,9 @@ void print_message (struct message *M) { } } else { push_color (COLOR_BLUE); + if (msg_num_mode) { + printf ("%d ", M->id); + } print_date (M->date); pop_color (); printf (" "); @@ -714,6 +741,9 @@ void print_message (struct message *M) { } } else { push_color (COLOR_MAGENTA); + if (msg_num_mode) { + printf ("%d ", M->id); + } print_date (M->date); pop_color (); printf (" "); diff --git a/main.c b/main.c index 1a2997d..d5431cd 100644 --- a/main.c +++ b/main.c @@ -52,6 +52,7 @@ char *default_username; int setup_mode; char *auth_token; +int msg_num_mode; void set_default_username (const char *s) { if (default_username) { @@ -203,7 +204,7 @@ extern int default_dc_num; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:N")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -217,6 +218,9 @@ void args_parse (int argc, char **argv) { case 'n': default_dc_num = atoi (optarg); break; + case 'N': + msg_num_mode ++; + break; case 'h': default: usage (); diff --git a/queries.c b/queries.c index a8bf1cc..073188e 100644 --- a/queries.c +++ b/queries.c @@ -879,6 +879,40 @@ void do_send_photo (int type, int to_id, char *file_name) { send_part (f); } +int fwd_msg_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_stated_message); + struct message *M = fetch_alloc_message (); + assert (fetch_int () == CODE_vector); + int n, i; + 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 (); + } + fetch_int (); // pts + fetch_int (); // seq + print_message (M); + return 0; +} + +struct query_methods fwd_msg_methods = { + .on_answer = fwd_msg_on_answer +}; + +void do_forward_message (union user_chat *U, int n) { + clear_packet (); + out_int (CODE_invoke_with_layer3); + out_int (CODE_messages_forward_message); + out_peer_id (U->id); + out_int (n); + out_long (lrand48 () * (1ll << 32) + lrand48 ()); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, 0); +} + int chat_info_on_answer (struct query *q UU) { struct chat *C = fetch_alloc_chat_full (); union user_chat *U = (void *)C; diff --git a/queries.h b/queries.h index 89e9160..191e4ac 100644 --- a/queries.h +++ b/queries.h @@ -75,5 +75,6 @@ void do_send_photo (int type, int to_id, char *file_name); void do_get_chat_info (union user_chat *chat); void do_get_user_list_info_silent (int num, int *list); void do_get_user_info (union user_chat *user); +void do_forward_message (union user_chat *U, int n); #endif diff --git a/structures.c b/structures.c index 4902307..52fdc25 100644 --- a/structures.c +++ b/structures.c @@ -157,16 +157,22 @@ void fetch_user (struct user *U) { } if (x == CODE_user_foreign) { U->flags |= FLAG_USER_FOREIGN; + U->phone = 0; } else { if (U->phone) { free (U->phone); } U->phone = fetch_str_dup (); } + //logprintf ("name = %s, surname = %s, phone = %s\n", U->first_name, U->last_name, U->phone); unsigned y = fetch_int (); + //fprintf (stderr, "y = 0x%08x\n", y); if (y == CODE_user_profile_photo_empty) { U->photo_small.dc = -2; U->photo_big.dc = -2; } else { - assert (y == CODE_user_profile_photo); + assert (y == CODE_user_profile_photo || y == 0x990d1493); + if (y == CODE_user_profile_photo) { + fetch_long (); + } fetch_file_location (&U->photo_small); fetch_file_location (&U->photo_big); } From 138198d0f86fd3cb574fa0621e35030242c77874 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 26 Oct 2013 01:08:52 +0400 Subject: [PATCH 048/465] Restart query on bad server salt --- mtproto-client.c | 13 +++++++++++++ queries.c | 8 ++++++++ queries.h | 1 + 3 files changed, 22 insertions(+) diff --git a/mtproto-client.c b/mtproto-client.c index 88fc17b..c2a66d8 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1052,6 +1052,16 @@ void work_packed (struct connection *c, long long msg_id) { in_gzip = 0; } +void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == (int)CODE_bad_server_salt); + long long id = fetch_long (); + query_restart (id); + fetch_int (); // seq_no + fetch_int (); // error_code + long long new_server_salt = fetch_long (); + GET_DC(c)->server_salt = new_server_salt; +} + void rpc_execute_answer (struct connection *c, long long msg_id UU) { if (verbosity >= 5) { hexdump_in (); @@ -1085,6 +1095,9 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_gzip_packed: work_packed (c, msg_id); return; + case CODE_bad_server_salt: + work_bad_server_salt (c, msg_id); + return; } logprintf ( "Unknown message: \n"); hexdump_in (); diff --git a/queries.c b/queries.c index 073188e..f265931 100644 --- a/queries.c +++ b/queries.c @@ -74,6 +74,14 @@ int alarm_query (struct query *q) { return 0; } +void query_restart (long long id) { + struct query *q = query_get (id); + if (q) { + remove_event_timer (&q->ev); + alarm_query (q); + } +} + struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { assert (DC); assert (DC->auth_key_id); diff --git a/queries.h b/queries.h index 191e4ac..ea58741 100644 --- a/queries.h +++ b/queries.h @@ -53,6 +53,7 @@ struct query *send_query (struct dc *DC, int len, void *data, struct query_metho void query_ack (long long id); void query_error (long long id); void query_result (long long id); +void query_restart (long long id); void insert_event_timer (struct event_timer *ev); void remove_event_timer (struct event_timer *ev); From 4481470819cc62e59db23bbf22565ed39945a59b Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 26 Oct 2013 01:58:01 +0400 Subject: [PATCH 049/465] Fixed signin --- queries.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/queries.c b/queries.c index f265931..b38aa65 100644 --- a/queries.c +++ b/queries.c @@ -356,6 +356,7 @@ void do_send_code (const char *user) { out_int (0); out_int (TG_APP_ID); out_string (TG_APP_HASH); + out_string ("en"); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); @@ -391,6 +392,7 @@ void do_send_code (const char *user) { out_int (0); out_int (TG_APP_ID); out_string (TG_APP_HASH); + out_string ("en"); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); From f8d3fdf2761bea7f3d58887371f73ca233476bb0 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 26 Oct 2013 02:03:36 +0400 Subject: [PATCH 050/465] Fixed read of notify settings --- mtproto-common.h | 3 ++- structures.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/mtproto-common.h b/mtproto-common.h index dc61b3d..ecb082a 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -74,7 +74,8 @@ #define CODE_ping_delay_disconnect 0xf3427b8c #define CODE_gzip_packed 0x3072cfa1 - +#define CODE_input_peer_notify_settings_old 0x3cf4b1be +#define CODE_peer_notify_settings_old 0xddbcd4a5 /* not really a limit, for struct encrypted_message only */ // #define MAX_MESSAGE_INTS 16384 #define MAX_MESSAGE_INTS 1048576 diff --git a/structures.c b/structures.c index 52fdc25..1926525 100644 --- a/structures.c +++ b/structures.c @@ -271,14 +271,21 @@ void fetch_chat (struct chat *C) { 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) { + assert (x == CODE_peer_notify_settings || x == CODE_peer_notify_settings_empty || x == CODE_peer_notify_settings_old); + if (x == CODE_peer_notify_settings_old) { fetch_int (); // mute_until int l = prefetch_strlen (); fetch_str (l); fetch_bool (); // show_previews fetch_int (); // peer notify events } + if (x == CODE_peer_notify_settings) { + fetch_int (); // mute_until + int l = prefetch_strlen (); + fetch_str (l); + fetch_bool (); // show_previews + fetch_int (); // events_mask + } } void fetch_chat_full (struct chat *C) { From c27ce7f6cbb0cbd2a9640002a5474405daedf6cb Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 26 Oct 2013 02:33:17 +0400 Subject: [PATCH 051/465] Support for chat rename --- interface.c | 14 ++++++++++++++ queries.c | 32 ++++++++++++++++++++++++++++++++ queries.h | 1 + 3 files changed, 47 insertions(+) diff --git a/interface.c b/interface.c index cdb5649..6062465 100644 --- a/interface.c +++ b/interface.c @@ -67,6 +67,7 @@ char *commands[] = { "chat_info", "user_info", "fwd", + "rename_chat", "show_license", 0 }; @@ -83,6 +84,7 @@ int commands_flags[] = { 074, 071, 072, + 074, 07, }; @@ -277,6 +279,18 @@ void interpreter (char *line UU) { if (*q && index < user_num + chat_num) { do_send_message (Peers[index], q, strlen (q)); } + } else if (!memcmp (line, "rename_chat", 11)) { + char *q = line + 11; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id >= 0)) { + index ++; + } + while (*q && (*q == ' ' || *q == '\t')) { q ++; } + if (*q && index < user_num + chat_num) { + do_rename_chat (Peers[index], q); + } } else if (!memcmp (line, "send_photo", 10)) { char *q = line + 10; int len; diff --git a/queries.c b/queries.c index b38aa65..719cbd3 100644 --- a/queries.c +++ b/queries.c @@ -923,6 +923,38 @@ void do_forward_message (union user_chat *U, int n) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, 0); } +int rename_chat_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_stated_message); + struct message *M = fetch_alloc_message (); + assert (fetch_int () == CODE_vector); + int n, i; + 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 (); + } + fetch_int (); // pts + fetch_int (); // seq + print_message (M); + return 0; +} + +struct query_methods rename_chat_methods = { + .on_answer = rename_chat_on_answer +}; + +void do_rename_chat (union user_chat *U, char *name) { + clear_packet (); + out_int (CODE_messages_edit_chat_title); + out_int (-U->id); + out_string (name); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, 0); +} + int chat_info_on_answer (struct query *q UU) { struct chat *C = fetch_alloc_chat_full (); union user_chat *U = (void *)C; diff --git a/queries.h b/queries.h index ea58741..18f74bd 100644 --- a/queries.h +++ b/queries.h @@ -77,5 +77,6 @@ void do_get_chat_info (union user_chat *chat); void do_get_user_list_info_silent (int num, int *list); void do_get_user_info (union user_chat *user); void do_forward_message (union user_chat *U, int n); +void do_rename_chat (union user_chat *U, char *name); #endif From 177f0ac25a4470fafc5709a03ea2839b475ab03a Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 26 Oct 2013 19:32:20 +0400 Subject: [PATCH 052/465] Sometimes client can recover from network loss --- mtproto-client.c | 22 ++++++++ mtproto-common.h | 2 + net.c | 132 +++++++++++++++++++++++++++++++++++++++++++---- net.h | 7 ++- queries.c | 11 +++- 5 files changed, 160 insertions(+), 14 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index c2a66d8..fd6bf21 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1062,8 +1062,23 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { GET_DC(c)->server_salt = new_server_salt; } +void work_pong (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == CODE_pong); + fetch_long (); // msg_id + fetch_long (); // ping_id +} + +void work_detained_info (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == CODE_msg_detained_info); + fetch_long (); // msg_id + fetch_long (); // answer_msg_id + fetch_int (); // bytes + fetch_int (); // status +} + void rpc_execute_answer (struct connection *c, long long msg_id UU) { if (verbosity >= 5) { + logprintf ("rpc_execute_answer: fd=%d\n", c->fd); hexdump_in (); } int op = prefetch_int (); @@ -1098,6 +1113,12 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_bad_server_salt: work_bad_server_salt (c, msg_id); return; + case CODE_pong: + work_pong (c, msg_id); + return; + case CODE_msg_detained_info: + work_detained_info (c, msg_id); + return; } logprintf ( "Unknown message: \n"); hexdump_in (); @@ -1158,6 +1179,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, } assert (c->session->session_id == enc->session_id); rpc_execute_answer (c, enc->msg_id); + assert (in_ptr == in_end); return 0; } diff --git a/mtproto-common.h b/mtproto-common.h index ecb082a..ff4f20a 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -76,6 +76,8 @@ #define CODE_input_peer_notify_settings_old 0x3cf4b1be #define CODE_peer_notify_settings_old 0xddbcd4a5 + +#define CODE_msg_detained_info 0x276d3ec6 /* not really a limit, for struct encrypted_message only */ // #define MAX_MESSAGE_INTS 16384 #define MAX_MESSAGE_INTS 1048576 diff --git a/net.c b/net.c index 6fba56e..7d74d79 100644 --- a/net.c +++ b/net.c @@ -42,6 +42,51 @@ DEFINE_TREE(int,int,int_cmp,0) int verbosity; extern struct connection_methods auth_methods; +void fail_connection (struct connection *c); + +void start_ping_timer (struct connection *c); +int ping_alarm (struct connection *c) { + if (verbosity > 2) { + logprintf ("ping alarm\n"); + } + if (get_double_time () - c->last_receive_time > 20) { + c->state = conn_failed; + fail_connection (c); + } else if (get_double_time () - c->last_receive_time > 5 && c->state == conn_ready) { + int x[3]; + x[0] = CODE_ping; + *(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 (); + encrypt_send_message (c, x, 3, 0); + start_ping_timer (c); + } else { + start_ping_timer (c); + } + return 0; +} + +void stop_ping_timer (struct connection *c) { + remove_event_timer (&c->ev); +} + +void start_ping_timer (struct connection *c) { + c->ev.timeout = get_double_time () + 1; + c->ev.alarm = (void *)ping_alarm; + c->ev.self = c; + insert_event_timer (&c->ev); +} + +void restart_connection (struct connection *c); +int fail_alarm (void *ev) { + restart_connection (ev); + return 0; +} +void start_fail_timer (struct connection *c) { + c->ev.timeout = get_double_time () + 10; + c->ev.alarm = (void *)fail_alarm; + c->ev.self = c; + insert_event_timer (&c->ev); +} + struct connection_buffer *new_connection_buffer (int size) { struct connection_buffer *b = malloc (sizeof (*b)); memset (b, 0, sizeof (*b)); @@ -195,10 +240,11 @@ struct connection *create_connection (const char *host, int port, struct session c->session = session; c->fd = fd; - c->ip = htonl (*(int *)h->h_addr); + c->ip = strdup (host); c->flags = 0; c->state = conn_ready; c->methods = methods; + c->port = port; assert (!Connections[fd]); Connections[fd] = c; if (verbosity) { @@ -207,10 +253,60 @@ struct connection *create_connection (const char *host, int port, struct session if (c->methods->ready) { c->methods->ready (c); } + c->last_receive_time = get_double_time (); + start_ping_timer (c); return c; } +void restart_connection (struct connection *c) { + if (c->last_connect_time == time (0)) { + return; + } + + c->last_connect_time = time (0); + int fd; + assert ((fd = socket (AF_INET, SOCK_STREAM, 0)) != -1); + assert (fd >= 0 && fd < MAX_CONNECTIONS); + if (fd > max_connection_fd) { + max_connection_fd = fd; + } + int flags = -1; + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); + setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)); + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags)); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons (c->port); + addr.sin_addr.s_addr = inet_addr (c->ip); + + + fcntl (fd, F_SETFL, O_NONBLOCK); + + if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { + if (errno != EINPROGRESS) { + logprintf ( "Can not connect to %s:%d %m\n", c->ip, c->port); + start_fail_timer (c); + close (fd); + return; + } + } + + c->fd = fd; + c->state = conn_connecting; + c->last_receive_time = get_double_time (); + start_ping_timer (c); + Connections[fd] = c; + + char byte = 0xef; + assert (write_out (c, &byte, 1) == 1); + flush_out (c); +} + void fail_connection (struct connection *c) { + if (c->state == conn_ready || c->state == conn_connecting) { + stop_ping_timer (c); + } struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; @@ -226,6 +322,10 @@ void fail_connection (struct connection *c) { c->out_head = c->out_tail = c->in_head = c->in_tail = 0; c->state = conn_failed; c->out_bytes = c->in_bytes = 0; + close (c->fd); + Connections[c->fd] = 0; + logprintf ("Lost connection to server... \n"); + restart_connection (c); } void try_write (struct connection *c) { @@ -334,6 +434,11 @@ void try_read (struct connection *c) { int x = 0; while (1) { int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); + if (r > 0) { + c->last_receive_time = get_double_time (); + stop_ping_timer (c); + start_ping_timer (c); + } if (r >= 0) { c->in_tail->wptr += r; x += r; @@ -364,16 +469,21 @@ void try_read (struct connection *c) { int connections_make_poll_array (struct pollfd *fds, int max) { int _max = max; int i; - for (i = 0; i <= max_connection_fd; i++) if (Connections[i] && Connections[i]->state != conn_failed) { - assert (max > 0); - struct connection *c = Connections[i]; - fds[0].fd = c->fd; - fds[0].events = POLLERR | POLLHUP | POLLRDHUP | POLLIN; - if (c->out_bytes || c->state == conn_connecting) { - fds[0].events |= POLLOUT; + for (i = 0; i <= max_connection_fd; i++) { + if (Connections[i] && Connections[i]->state == conn_failed) { + restart_connection (Connections[i]); + } + if (Connections[i] && Connections[i]->state != conn_failed) { + assert (max > 0); + struct connection *c = Connections[i]; + fds[0].fd = c->fd; + fds[0].events = POLLERR | POLLHUP | POLLRDHUP | POLLIN; + if (c->out_bytes || c->state == conn_connecting) { + fds[0].events |= POLLOUT; + } + fds ++; + max --; } - fds ++; - max --; } if (verbosity >= 10) { logprintf ( "%d connections in poll\n", _max - max); @@ -398,7 +508,9 @@ void connections_poll_result (struct pollfd *fds, int max) { fail_connection (c); } else if (fds[i].revents & POLLOUT) { if (c->state == conn_connecting) { + logprintf ("connection ready\n"); c->state = conn_ready; + c->last_receive_time = get_double_time (); } if (c->out_bytes) { try_write (c); diff --git a/net.h b/net.h index 4e8487a..674ead9 100644 --- a/net.h +++ b/net.h @@ -32,7 +32,7 @@ struct dc; #define ACK_TIMEOUT 60 #define MAX_DC_ID 10 -enum dc_state{ +enum dc_state { st_init, st_reqpq_sent, st_reqdh_sent, @@ -104,7 +104,7 @@ enum conn_state { struct connection { int fd; - int ip; + char *ip; int port; int flags; enum conn_state state; @@ -117,9 +117,12 @@ struct connection { int out_bytes; int packet_num; int out_packet_num; + int last_connect_time; struct connection_methods *methods; struct session *session; void *extra; + struct event_timer ev; + double last_receive_time; }; extern struct connection *Connections[]; diff --git a/queries.c b/queries.c index 719cbd3..872b9d8 100644 --- a/queries.c +++ b/queries.c @@ -1000,8 +1000,15 @@ int user_info_on_answer (struct query *q UU) { printf ("User "); print_user_name (U->id, C); printf (":\n"); - printf ("\t real name: %s %s\n", U->real_first_name, U->real_last_name); - printf ("\t phone: %s\n", U->phone); + printf ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); + printf ("\tphone: %s\n", U->phone); + if (U->status.online > 0) { + printf ("\tonline\n"); + } else { + printf ("\toffline (was online "); + print_date_full (U->status.when); + printf (")\n"); + } pop_color (); print_end (); return 0; From 352bea698c85ee362993526e33ee7e7d4ed9d325 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 26 Oct 2013 23:57:22 +0400 Subject: [PATCH 053/465] Interface fixes --- loop.c | 4 ++-- main.c | 6 +++--- mtproto-client.c | 12 ++++++------ net.c | 30 +++++++++++++++++++++--------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/loop.c b/loop.c index 1f3fd0c..0aa9fa1 100644 --- a/loop.c +++ b/loop.c @@ -120,7 +120,7 @@ void write_dc (int auth_file_fd, struct dc *DC) { int our_id; void write_auth_file (void) { - int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU); + int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); int x = DC_SERIALIZED_MAGIC; assert (write (auth_file_fd, &x, 4) == 4); @@ -169,7 +169,7 @@ void empty_auth_file (void) { } void read_auth_file (void) { - int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU); + int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); if (auth_file_fd < 0) { empty_auth_file (); } diff --git a/main.c b/main.c index d5431cd..e49744f 100644 --- a/main.c +++ b/main.c @@ -158,7 +158,7 @@ void running_for_first_time (void) { // see if config file is there if (stat (config_filename, config_file_stat) != 0) { // config file missing, so touch it - config_file_fd = open (config_filename, O_CREAT | O_RDWR, S_IRWXU); + config_file_fd = open (config_filename, O_CREAT | O_RDWR, 0600); if (config_file_fd == -1) { perror ("open[config_file]"); exit (EXIT_FAILURE); @@ -172,7 +172,7 @@ void running_for_first_time (void) { exit (EXIT_FAILURE); } close (config_file_fd); - int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU); + int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); int x = -1; assert (write (auth_file_fd, &x, 4) == 4); close (auth_file_fd); @@ -194,7 +194,7 @@ void inner_main (void) { } void usage (void) { - printf ("%s [-u username]\n", PROGNAME); + printf ("%s [-u username] [-h] [-k public key name]\n", PROGNAME); exit (1); } diff --git a/mtproto-client.c b/mtproto-client.c index fd6bf21..bd46ea2 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -103,7 +103,7 @@ int Response_len; * */ -char *rsa_public_key_name = "id_rsa.pub"; +char *rsa_public_key_name = "tg.pub"; RSA *pubKey; long long pk_fingerprint; @@ -964,9 +964,11 @@ void work_container (struct connection *c, long long msg_id UU) { insert_seqno (c->session, seqno); } int bytes = fetch_int (); - int *t = in_ptr; + int *t = in_end; + in_end = in_ptr + (bytes / 4); rpc_execute_answer (c, id); - assert (in_ptr == t + (bytes / 4)); + assert (in_ptr == in_end); + in_end = t; } } @@ -1122,6 +1124,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { } logprintf ( "Unknown message: \n"); hexdump_in (); + in_ptr = in_end; // Will not fail due to assertion in_ptr == in_end } int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { @@ -1166,9 +1169,6 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (l >= (MINSZ - UNENCSZ) + 8); //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); - if (verbosity >= 2) { - logprintf ( "OK, message is good!\n"); - } ++good_messages; in_ptr = enc->message; diff --git a/net.c b/net.c index 7d74d79..b03a5c6 100644 --- a/net.c +++ b/net.c @@ -195,12 +195,11 @@ int max_connection_fd; struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods) { struct connection *c = malloc (sizeof (*c)); memset (c, 0, sizeof (*c)); - struct hostent *h; - if (!(h = gethostbyname (host)) || h->h_addrtype != AF_INET || h->h_length != 4 || !h->h_addr_list || !h->h_addr) { - assert (0); + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + logprintf ("Can not create socket: %m\n"); + exit (1); } - int fd; - assert ((fd = socket (AF_INET, SOCK_STREAM, 0)) != -1); assert (fd >= 0 && fd < MAX_CONNECTIONS); if (fd > max_connection_fd) { max_connection_fd = fd; @@ -231,8 +230,13 @@ struct connection *create_connection (const char *host, int port, struct session s.fd = fd; s.events = POLLOUT | POLLERR | POLLRDHUP | POLLHUP; - if (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { - perror ("poll"); + while (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { + if (errno == EINTR) { continue; } + if (errno) { + logprintf ("Problems in poll: %m\n"); + exit (1); + } + logprintf ("Connect timeout\n"); close (fd); free (c); return 0; @@ -260,12 +264,16 @@ struct connection *create_connection (const char *host, int port, struct session void restart_connection (struct connection *c) { if (c->last_connect_time == time (0)) { + start_fail_timer (c); return; } c->last_connect_time = time (0); - int fd; - assert ((fd = socket (AF_INET, SOCK_STREAM, 0)) != -1); + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + logprintf ("Can not create socket: %m\n"); + exit (1); + } assert (fd >= 0 && fd < MAX_CONNECTIONS); if (fd > max_connection_fd) { max_connection_fd = fd; @@ -563,6 +571,10 @@ void dc_create_session (struct dc *DC) { assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); S->dc = DC; S->c = create_connection (DC->ip, DC->port, S, &auth_methods); + if (!S->c) { + logprintf ("Can not create connection to DC. Is network down?\n"); + exit (1); + } assert (!DC->sessions[0]); DC->sessions[0] = S; } From 78b5d205d76c48fed3e522fd78ed49bce5084f28 Mon Sep 17 00:00:00 2001 From: vysheng Date: Sun, 27 Oct 2013 13:25:14 +0400 Subject: [PATCH 054/465] fixed bug in fetching change user name from not a contact --- mtproto-client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index bd46ea2..2a877f6 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -764,8 +764,6 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_str (l); l = prefetch_strlen (); fetch_str (l); - l = prefetch_strlen (); - fetch_str (l); } } break; From 9565455d3f5aa4d3e33c392b8935798c8ff023b4 Mon Sep 17 00:00:00 2001 From: vysheng Date: Sun, 27 Oct 2013 23:35:02 +0400 Subject: [PATCH 055/465] Load photo/video. Now works only with current DC. --- interface.c | 90 +++++++++++++++++++++++++++++ loop.c | 2 +- queries.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++ queries.h | 6 ++ structures.c | 4 +- 5 files changed, 260 insertions(+), 2 deletions(-) diff --git a/interface.c b/interface.c index 6062465..e5f8281 100644 --- a/interface.c +++ b/interface.c @@ -68,6 +68,12 @@ char *commands[] = { "user_info", "fwd", "rename_chat", + "load_photo", + "view_photo", + "load_video_thumb", + "view_video_thumb", + "load_video", + "view_video", "show_license", 0 }; @@ -86,6 +92,12 @@ int commands_flags[] = { 072, 074, 07, + 07, + 07, + 07, + 07, + 07, + 07, }; char *a = 0; @@ -356,6 +368,84 @@ void interpreter (char *line UU) { } } } + } else if (!memcmp (line, "load_photo ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + do_load_photo (&M->media.photo, 1); + } + } + } + } else if (!memcmp (line, "view_photo ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + do_load_photo (&M->media.photo, 2); + } + } + } + } else if (!memcmp (line, "load_video_thumb ", 16)) { + char *q = line + 16; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video_thumb (&M->media.video, 1); + } + } + } + } else if (!memcmp (line, "view_video_thumb ", 16)) { + char *q = line + 16; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video_thumb (&M->media.video, 2); + } + } + } + } else if (!memcmp (line, "load_video ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video (&M->media.video, 1); + } + } + } + } else if (!memcmp (line, "view_video ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video (&M->media.video, 2); + } + } + } } else if (!memcmp (line, "chat_info", 9)) { char *q = line + 10; int len; diff --git a/loop.c b/loop.c index 0aa9fa1..63a4899 100644 --- a/loop.c +++ b/loop.c @@ -244,7 +244,7 @@ int loop (void) { } write_auth_file (); - + fflush (stdin); fflush (stdout); fflush (stderr); diff --git a/queries.c b/queries.c index 872b9d8..872ba4e 100644 --- a/queries.c +++ b/queries.c @@ -36,6 +36,7 @@ #include "structures.h" #include "interface.h" +char *get_downloads_directory (void); int verbosity; #define QUERY_TIMEOUT 0.3 @@ -1059,3 +1060,162 @@ void do_get_user_list_info_silent (int num, int *list) { } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_list_info_silent_methods, 0); } + +struct download { + int offset; + int size; + long long volume; + long long secret; + long long access_hash; + int local_id; + int dc; + int next; + int fd; + char *name; + long long id; +}; + + +void end_load (struct download *D) { + close (D->fd); + if (D->next == 1) { + logprintf ("Done: %s\n", D->name); + } else if (D->next == 2) { + static char buf[1000]; + sprintf (buf, "xdg-open %s", D->name); + int x = system (buf); + if (x < 0) { + logprintf ("Can not open image viewer: %m\n"); + logprintf ("Image is at %s\n", D->name); + } + } + free (D->name); + free (D); +} + +void load_next_part (struct download *D); +int download_on_answer (struct query *q) { + assert (fetch_int () == (int)CODE_upload_file); + unsigned x = fetch_int (); + struct download *D = q->extra; + if (D->fd == -1) { + static char buf[100]; + sprintf (buf, "%s/tmp_%ld_%ld", get_downloads_directory (), lrand48 (), lrand48 ()); + int l = strlen (buf); + switch (x) { + case CODE_storage_file_unknown: + break; + case CODE_storage_file_jpeg: + sprintf (buf + l, "%s", ".jpg"); + break; + case CODE_storage_file_gif: + sprintf (buf + l, "%s", ".gif"); + break; + case CODE_storage_file_png: + sprintf (buf + l, "%s", ".png"); + break; + case CODE_storage_file_mp3: + sprintf (buf + l, "%s", ".mp3"); + break; + case CODE_storage_file_mov: + sprintf (buf + l, "%s", ".mov"); + break; + case CODE_storage_file_partial: + sprintf (buf + l, "%s", ".part"); + break; + case CODE_storage_file_mp4: + sprintf (buf + l, "%s", ".mp4"); + break; + case CODE_storage_file_webp: + sprintf (buf + l, "%s", ".webp"); + break; + } + D->name = strdup (buf); + D->fd = open (D->name, O_CREAT | O_WRONLY, 0640); + } + fetch_int (); // mtime + int len = prefetch_strlen (); + assert (len >= 0); + assert (write (D->fd, fetch_str (len), len) == len); + D->offset += len; + if (D->offset < D->size) { + load_next_part (D); + return 0; + } else { + end_load (D); + return 0; + } +} + +struct query_methods download_methods = { + .on_answer = download_on_answer +}; + +void load_next_part (struct download *D) { + clear_packet (); + out_int (CODE_upload_get_file); + if (!D->id) { + out_int (CODE_input_file_location); + out_long (D->volume); + out_int (D->local_id); + out_long (D->secret); + } else { + out_int (CODE_input_video_file_location); + out_long (D->id); + out_long (D->access_hash); + } + out_int (D->offset); + out_int (1 << 14); + send_query (DC_list[D->dc], packet_ptr - packet_buffer, packet_buffer, &download_methods, D); + //send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); +} + +void do_load_photo_size (struct photo_size *P, int next) { + assert (P); + assert (next); + struct download *D = malloc (sizeof (*D)); + D->id = 0; + D->offset = 0; + D->size = P->size; + D->volume = P->loc.volume; + D->dc = P->loc.dc; + D->local_id = P->loc.local_id; + D->secret = P->loc.secret; + D->next = next; + D->name = 0; + D->fd = -1; + load_next_part (D); +} + +void do_load_photo (struct photo *photo, int next) { + if (!photo->sizes_num) { return; } + int max = -1; + int maxi = 0; + int i; + for (i = 0; i < photo->sizes_num; i++) { + if (photo->sizes[i].w + photo->sizes[i].h > max) { + max = photo->sizes[i].w + photo->sizes[i].h; + maxi = i; + } + } + do_load_photo_size (&photo->sizes[maxi], next); +} + +void do_load_video_thumb (struct video *video, int next) { + do_load_photo_size (&video->thumb, next); +} + +void do_load_video (struct video *V, int next) { + assert (V); + assert (next); + struct download *D = malloc (sizeof (*D)); + D->offset = 0; + D->size = V->size; + D->id = V->id; + D->access_hash = V->access_hash; + D->dc = V->dc_id; + D->next = next; + D->name = 0; + D->fd = -1; + load_next_part (D); +} diff --git a/queries.h b/queries.h index 18f74bd..39fb6cd 100644 --- a/queries.h +++ b/queries.h @@ -79,4 +79,10 @@ void do_get_user_info (union user_chat *user); void do_forward_message (union user_chat *U, int n); void do_rename_chat (union user_chat *U, char *name); +struct photo; +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); + #endif diff --git a/structures.c b/structures.c index 1926525..a6cdcca 100644 --- a/structures.c +++ b/structures.c @@ -348,7 +348,9 @@ void fetch_photo_size (struct photo_size *S) { if (x == CODE_photo_size) { S->size = fetch_int (); } else { - S->data = fetch_str_dup (); + S->size = prefetch_strlen (); + S->data = malloc (S->size); + memcpy (S->data, fetch_str (S->size), S->size); } } } From 27ee6923df8f1ccdb18ae06a17402e537f892572 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 28 Oct 2013 03:10:40 +0400 Subject: [PATCH 056/465] Changed authorization. Sorry, if that fails anything. Now supports download of photos from other DC --- loop.c | 179 +++++++++++++++++++++++++++++++++++++++------- net.h | 2 + queries.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++------ queries.h | 6 ++ 4 files changed, 345 insertions(+), 50 deletions(-) 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 From a0a2d74361920d03ecc872407b90b4e4a395257f Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 28 Oct 2013 03:24:03 +0400 Subject: [PATCH 057/465] Fixed change from v1 of auth file to v2 --- interface.c | 3 +++ loop.c | 13 +++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface.c b/interface.c index e5f8281..b5155fb 100644 --- a/interface.c +++ b/interface.c @@ -762,6 +762,9 @@ void print_service_message (struct message *M) { push_color (COLOR_GREY); push_color (COLOR_MAGENTA); + if (msg_num_mode) { + printf ("%d ", M->id); + } print_date (M->date); pop_color (); printf (" "); diff --git a/loop.c b/loop.c index 6d6908f..e78a73c 100644 --- a/loop.c +++ b/loop.c @@ -270,13 +270,11 @@ int loop (void) { 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 (); - } + 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) { @@ -362,7 +360,6 @@ int loop (void) { } } - 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); From 5360e1a7dd5bf388eae3fcf499443fc08bd247ff Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 28 Oct 2013 21:51:54 +0400 Subject: [PATCH 058/465] Fixed fail. Removed some debug output --- loop.c | 1 - queries.c | 2 -- structures.c | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/loop.c b/loop.c index e78a73c..916fbf4 100644 --- a/loop.c +++ b/loop.c @@ -107,7 +107,6 @@ int net_getline (char **s, size_t *l) { _l = l; rl_callback_handler_install (0, got_it); net_loop (1, is_got_it); - printf ("'%s'\n", *s); return 0; } diff --git a/queries.c b/queries.c index 325e558..80c97be 100644 --- a/queries.c +++ b/queries.c @@ -360,7 +360,6 @@ 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); @@ -440,7 +439,6 @@ int do_auth_check_phone (const char *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); diff --git a/structures.c b/structures.c index a6cdcca..999f361 100644 --- a/structures.c +++ b/structures.c @@ -109,7 +109,7 @@ void fetch_user (struct user *U) { int ok = 1; int i; for (i = 0; i < user_num + chat_num; i++) { - if (Peers[i] != (void *)U && !strcmp (Peers[i]->print_name, U->print_name)) { + if (Peers[i] != (void *)U && Peers[i]->print_name && !strcmp (Peers[i]->print_name, U->print_name)) { ok = 0; break; } From 1f978fe54a65492987efd8ddcacc8d6a0d770054 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 28 Oct 2013 23:14:34 +0400 Subject: [PATCH 059/465] interface.c: fixed bug with tabs after help command. Added new items to help --- interface.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/interface.c b/interface.c index b5155fb..b5e9d3d 100644 --- a/interface.c +++ b/interface.c @@ -488,7 +488,7 @@ void interpreter (char *line UU) { do_get_history (Peers[index], limit); } } else if (!memcmp (line, "help", 4)) { - print_start (); + //print_start (); push_color (COLOR_YELLOW); printf ( "help - prints this help\n" @@ -502,17 +502,21 @@ void interpreter (char *line UU) { "send_text - sends text file as plain messages\n" "chat_info - prints info about chat\n" "user_info - prints info about user\n" + "fwd - forward message to user. You can see message numbers starting client with -N\n" + "rename_chat \n" + "load_photo/load_video/load_video_thumb - loads photo/video to download dir\n" + "view_photo/view_video/view_video_thumb - loads photo/video to download dir and starts system default viewer\n" + "show_license - prints contents of GPLv2\n" ); pop_color (); - print_end (); + rl_on_new_line (); + //print_end (); printf ("\033[1K\033H"); } else if (!memcmp (line, "show_license", 12)) { char *b = #include "LICENSE.h" ; - print_start (); printf ("%s", b); - print_end (); } } From 57370a260769c63260e9c6fb138077c7de5a6ca9 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 29 Oct 2013 01:56:17 +0400 Subject: [PATCH 060/465] fixed interface. Small changes. --- interface.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/interface.c b/interface.c index b5e9d3d..4e4d9b6 100644 --- a/interface.c +++ b/interface.c @@ -224,17 +224,13 @@ int complete_string_list (char **list, int index, const char *text, int len, cha char *command_generator (const char *text, int state) { static int len, index, mode; + char c = 0; if (!state) { len = strlen (text); index = -1; - - rl_line_buffer[rl_point] = '\0'; /* the effect should be such - * that the cursor position - * is at the end of line for - * the auto completion regex - * above (note the $ at end) - */ - + + c = rl_line_buffer[rl_point]; + rl_line_buffer[rl_point] = 0; mode = get_complete_mode (); } else { if (index == -1) { return 0; } @@ -246,19 +242,26 @@ char *command_generator (const char *text, int state) { switch (mode & 7) { case 0: index = complete_string_list (commands, index, text, len, &R); + if (c) { rl_line_buffer[rl_point] = c; } return R; case 1: index = complete_user_list (index, text, len, &R); + if (c) { rl_line_buffer[rl_point] = c; } return R; case 2: index = complete_user_chat_list (index, text, len, &R); + if (c) { rl_line_buffer[rl_point] = c; } return R; case 3: - return rl_filename_completion_function(text,state); + R = rl_filename_completion_function(text,state); + if (c) { rl_line_buffer[rl_point] = c; } + return R; case 4: index = complete_chat_list (index, text, len, &R); + if (c) { rl_line_buffer[rl_point] = c; } return R; default: + if (c) { rl_line_buffer[rl_point] = c; } return 0; } } @@ -268,6 +271,7 @@ char **complete_text (char *text, int start UU, int end UU) { } void interpreter (char *line UU) { + if (!line) { return; } if (line && *line) { add_history (line); } From 96c47889c3b491be2b50eb97d0a370e6c7dd57c8 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 29 Oct 2013 01:57:22 +0400 Subject: [PATCH 061/465] Fix to prev commit --- interface.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 4e4d9b6..8a40a59 100644 --- a/interface.c +++ b/interface.c @@ -236,7 +236,10 @@ char *command_generator (const char *text, int state) { if (index == -1) { return 0; } } - if (mode == -1) { return 0; } + if (mode == -1) { + if (c) { rl_line_buffer[rl_point] = c; } + return 0; + } char *R = 0; switch (mode & 7) { From c8332f38c725cbf2d3d9bc2aa57dc7d560e297df Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 29 Oct 2013 02:33:13 +0400 Subject: [PATCH 062/465] Fixed interface: show download/upload progress --- interface.c | 33 +++++++++++++++++++++++++++++++-- interface.h | 2 ++ mtproto-client.c | 3 +++ queries.c | 20 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/interface.c b/interface.c index 8a40a59..d9f7eed 100644 --- a/interface.c +++ b/interface.c @@ -40,10 +40,32 @@ char *default_prompt = "> "; int unread_messages; int msg_num_mode; +long long cur_uploading_bytes; +long long cur_uploaded_bytes; +long long cur_downloading_bytes; +long long cur_downloaded_bytes; + + char *get_default_prompt (void) { static char buf[100]; - if (unread_messages) { - sprintf (buf, COLOR_RED "[%d unread]" COLOR_NORMAL "%s", unread_messages, default_prompt); + if (unread_messages || cur_uploading_bytes || cur_downloading_bytes) { + int l = sprintf (buf, COLOR_RED "["); + int ok = 0; + if (unread_messages) { + l += sprintf (buf + l, "%d unread", unread_messages); + ok = 1; + } + if (cur_uploading_bytes) { + if (ok) { *(buf + l) = ' '; l ++; } + ok = 1; + l += sprintf (buf + l, "%lld%%Up", 100 * cur_uploaded_bytes / cur_uploading_bytes); + } + if (cur_downloading_bytes) { + if (ok) { *(buf + l) = ' '; l ++; } + ok = 1; + l += sprintf (buf + l, "%lld%%Down", 100 * cur_downloaded_bytes / cur_downloading_bytes); + } + sprintf (buf + l, "]" COLOR_NORMAL "%s", default_prompt); return buf; } else { return default_prompt; @@ -54,6 +76,13 @@ char *complete_none (const char *text UU, int state UU) { return 0; } +void update_prompt (void) { + print_start (); + rl_set_prompt (get_default_prompt ()); + rl_redisplay (); + print_end (); +} + char *commands[] = { "help", "msg", diff --git a/interface.h b/interface.h index 4f14037..51463a8 100644 --- a/interface.h +++ b/interface.h @@ -50,4 +50,6 @@ void push_color (const char *color); void print_start (void); void print_end (void); void print_date_full (long t); + +void update_prompt (void); #endif diff --git a/mtproto-client.c b/mtproto-client.c index 2a877f6..0b5be0b 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -644,6 +644,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_int (); //pts unread_messages ++; print_message (M); + update_prompt (); break; }; case CODE_update_message_i_d: @@ -939,6 +940,7 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) { struct message *M = fetch_alloc_message_short (); unread_messages ++; print_message (M); + update_prompt (); } void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) { @@ -946,6 +948,7 @@ void work_update_short_chat_message (struct connection *c UU, long long msg_id U struct message *M = fetch_alloc_message_short_chat (); unread_messages ++; print_message (M); + update_prompt (); } void work_container (struct connection *c, long long msg_id UU) { diff --git a/queries.c b/queries.c index 80c97be..f3c78cc 100644 --- a/queries.c +++ b/queries.c @@ -39,6 +39,11 @@ char *get_downloads_directory (void); int verbosity; +long long cur_uploading_bytes; +long long cur_uploaded_bytes; +long long cur_downloading_bytes; +long long cur_downloaded_bytes; + #define QUERY_TIMEOUT 0.3 #define memcmp8(a,b) memcmp ((a), (b), 8) @@ -914,6 +919,9 @@ struct query_methods send_file_methods = { void send_part (struct send_file *f) { if (f->fd >= 0) { + if (!f->part_num) { + cur_uploading_bytes += f->size; + } clear_packet (); out_int (CODE_upload_save_file_part); out_long (f->id); @@ -923,6 +931,7 @@ void send_part (struct send_file *f) { assert (x > 0); out_cstring (buf, x); f->offset += x; + cur_uploaded_bytes += x; if (verbosity >= 2) { logprintf ("offset=%lld size=%lld\n", f->offset, f->size); } @@ -932,6 +941,8 @@ void send_part (struct send_file *f) { } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); } else { + cur_uploaded_bytes -= f->size; + cur_uploading_bytes -= f->size; clear_packet (); out_int (CODE_messages_send_media); out_peer_id (f->to_id); @@ -1175,6 +1186,9 @@ struct download { void end_load (struct download *D) { + cur_downloading_bytes -= D->size; + cur_downloaded_bytes -= D->size; + update_prompt (); close (D->fd); if (D->next == 1) { logprintf ("Done: %s\n", D->name); @@ -1234,6 +1248,8 @@ int download_on_answer (struct query *q) { fetch_int (); // mtime int len = prefetch_strlen (); assert (len >= 0); + cur_downloaded_bytes += len; + update_prompt (); assert (write (D->fd, fetch_str (len), len) == len); D->offset += len; if (D->offset < D->size) { @@ -1250,6 +1266,10 @@ struct query_methods download_methods = { }; void load_next_part (struct download *D) { + if (!D->offset) { + cur_downloading_bytes += D->size; + update_prompt (); + } clear_packet (); out_int (CODE_upload_get_file); if (!D->id) { From 6a804fcfb949578216b4c57db954b7ebf081c3d0 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 30 Oct 2013 04:08:30 +0400 Subject: [PATCH 063/465] Fixed inerface --- interface.c | 565 ++++++++++++++++++++++++++++++---------------------- loop.c | 9 +- queries.c | 80 +++----- queries.h | 14 +- 4 files changed, 358 insertions(+), 310 deletions(-) diff --git a/interface.c b/interface.c index d9f7eed..42a7b3d 100644 --- a/interface.c +++ b/interface.c @@ -40,11 +40,136 @@ char *default_prompt = "> "; int unread_messages; int msg_num_mode; +int in_readline; + long long cur_uploading_bytes; long long cur_uploaded_bytes; long long cur_downloading_bytes; long long cur_downloaded_bytes; +char *line_ptr; +extern int user_num; +extern int chat_num; +extern union user_chat *Peers[]; + +int is_same_word (const char *s, size_t l, const char *word) { + return s && word && strlen (word) == l && !memcmp (s, word, l); +} + +char *next_token (int *l) { + while (*line_ptr == ' ') { line_ptr ++; } + if (!*line_ptr) { + *l = 0; + return 0; + } + int neg = 0; + char *s = line_ptr; + while (*line_ptr && (*line_ptr != ' ' || neg)) { + if (*line_ptr == '\\') { + neg = 1 - neg; + } else { + neg = 0; + } + line_ptr++; + } + *l = line_ptr - s; + return s; +} + +#define NOT_FOUND (int)0x80000000 +int next_token_int (void) { + int l; + char *s = next_token (&l); + if (!s) { return NOT_FOUND; } + char *r; + int x = strtod (s, &r); + if (r == s + l) { + return x; + } else { + return NOT_FOUND; + } +} + +int next_token_user (void) { + int l; + char *s = next_token (&l); + if (!s) { return NOT_FOUND; } + + if (*s == '#') { + s ++; + l --; + if (l > 0) { + int r = atoi (s); + if (r < 0) { return r; } + else { return NOT_FOUND; } + } else { + return NOT_FOUND; + } + } + int index = 0; + while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || Peers[index]->id < 0)) { + index ++; + } + if (index < user_num + chat_num) { + return Peers[index]->id; + } else { + return NOT_FOUND; + } +} + +int next_token_chat (void) { + int l; + char *s = next_token (&l); + if (!s) { return NOT_FOUND; } + + if (*s == '#') { + s ++; + l --; + if (l > 0) { + int r = atoi (s); + if (r < 0) { return r; } + else { return NOT_FOUND; } + } else { + return NOT_FOUND; + } + } + int index = 0; + while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || Peers[index]->id > 0)) { + index ++; + } + if (index < user_num + chat_num) { + return Peers[index]->id; + } else { + return NOT_FOUND; + } +} + +int next_token_user_chat (void) { + int l; + char *s = next_token (&l); + if (!s) { return NOT_FOUND; } + + if (*s == '#') { + s ++; + l --; + if (l > 0) { + int r = atoi (s); + if (r != 0) { return r; } + else { return NOT_FOUND; } + } else { + return NOT_FOUND; + } + } + int index = 0; + while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || !Peers[index]->id)) { + index ++; + } + if (index < user_num + chat_num) { + return Peers[index]->id; + } else { + return NOT_FOUND; + } +} char *get_default_prompt (void) { static char buf[100]; @@ -129,54 +254,22 @@ int commands_flags[] = { 07, }; -char *a = 0; -char *user_list[MAX_USER_NUM + 1]; -char **chat_list = &a; - -int init_token (char **q) { - char *r = *q; - while (*r == ' ') { r ++; } - if (!*r) { return 0; } - *q = r; - return 1; -} - -char *get_token (char **q, int *l) { - char *r = *q; - while (*r == ' ') { r ++; } - if (!*r) { - *q = r; - *l = 0; - return 0; - } - int neg = 0; - char *s = r; - while (*r && (*r != ' ' || neg)) { - if (*r == '\\') { - neg = 1 - neg; - } else { - neg = 0; - } - r++; - } - *q = r; - *l = r - s; - return s; -} - - int get_complete_mode (void) { - char *q = rl_line_buffer; - if (!init_token (&q)) { return 0; } + line_ptr = rl_line_buffer; int l = 0; - char *r = get_token (&q, &l); - if (!*q) { return 0; } - + char *r = next_token (&l); + if (!r) { return 0; } + while (r && r[0] == '[' && r[l - 1] == ']') { + r = next_token (&l); + if (!r) { return 0; } + } + + if (!*line_ptr) { return 0; } char **command = commands; int n = 0; int flags = -1; while (*command) { - if (!strncmp (r, *command, l)) { + if (is_same_word (r, l, *command)) { flags = commands_flags[n]; break; } @@ -184,20 +277,18 @@ int get_complete_mode (void) { command ++; } if (flags == -1) { - return -1; + return 7; } int s = 0; while (1) { - get_token (&q, &l); - if (!*q) { return flags ? flags & 7 : 7; } + if (!next_token (&l) || !*line_ptr) { + return flags ? flags & 7 : 7; + } s ++; if (s <= 4) { flags >>= 3; } } } -extern int user_num; -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 + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id < 0)) { @@ -302,228 +393,221 @@ char **complete_text (char *text, int start UU, int end UU) { return (char **) rl_completion_matches (text, command_generator); } +void work_modifier (const char *s UU) { +} + void interpreter (char *line UU) { - if (!line) { return; } + line_ptr = line; + assert (!in_readline); + in_readline = 1; + if (!line) { + in_readline = 0; + return; + } if (line && *line) { add_history (line); } - if (!memcmp (line, "contact_list", 12)) { + + int l; + char *command; + while (1) { + command = next_token (&l); + if (!command) { return; } + if (*command == '[' && command[l - 1] == ']') { + work_modifier (command); + } else { + break; + } + } + +#define IS_WORD(s) is_same_word (command, l, (s)) +#define RET in_readline = 0; return; + if (IS_WORD ("contact_list")) { do_update_contact_list (); - } else if (!memcmp (line, "dialog_list", 11)) { + } else if (IS_WORD ("dialog_list")) { do_get_dialog_list (); - } else if (!memcmp (line, "stats", 5)) { + } else if (IS_WORD ("stats")) { static char stat_buf[1 << 15]; print_stat (stat_buf, (1 << 15) - 1); printf ("%s\n", stat_buf); - } else if (!memcmp (line, "msg ", 4)) { - char *q = line + 4; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + } else if (IS_WORD ("msg")) { + int id = next_token_user_chat (); + if (id == NOT_FOUND) { + printf ("Bad user/chat id\n"); + RET; } - while (*q && (*q == ' ' || *q == '\t')) { q ++; } - if (*q && index < user_num + chat_num) { - do_send_message (Peers[index], q, strlen (q)); + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty message\n"); + RET; } - } else if (!memcmp (line, "rename_chat", 11)) { - char *q = line + 11; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || Peers[index]->id >= 0)) { - index ++; + do_send_message (id, s, strlen (s)); + } else if (IS_WORD ("rename_chat")) { + int id = next_token_chat (); + if (id == NOT_FOUND) { + printf ("Bad chat id\n"); + RET; } - while (*q && (*q == ' ' || *q == '\t')) { q ++; } - if (*q && index < user_num + chat_num) { - do_rename_chat (Peers[index], q); + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty new name\n"); + RET; } - } else if (!memcmp (line, "send_photo", 10)) { - char *q = line + 10; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + do_rename_chat (id, s); + } else if (IS_WORD ("send_photo")) { + int id = next_token_user_chat (); + if (id == NOT_FOUND) { + printf ("Bad user/chat id\n"); + RET; } - if (index < user_num + chat_num) { - int len = 0; - char *f = get_token (&q, &len); - if (len > 0) { - do_send_photo (CODE_input_media_uploaded_photo, - Peers[index]->id, strndup (f, len)); - } + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty file name\n"); + RET; } - } else if (!memcmp (line, "send_video", 10)) { - char *q = line + 10; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + do_send_photo (CODE_input_media_uploaded_photo, id, strndup (s, t)); + } else if (IS_WORD("send_video")) { + int id = next_token_user_chat (); + if (id == NOT_FOUND) { + printf ("Bad user/chat id\n"); + RET; } - if (index < user_num + chat_num) { - int len = 0; - char *f = get_token (&q, &len); - if (len > 0) { - do_send_photo (CODE_input_media_uploaded_video, - Peers[index]->id, strndup (f, len)); - } + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty file name\n"); + RET; } - } else if (!memcmp (line, "send_text", 9)) { - char *q = line + 10; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + do_send_photo (CODE_input_media_uploaded_video, id, strndup (s, t)); + } else if (IS_WORD ("send_text")) { + int id = next_token_user_chat (); + if (id == NOT_FOUND) { + printf ("Bad user/chat id\n"); + RET; } - if (index < user_num + chat_num) { - int len = 0; - char *f = get_token (&q, &len); - if (len > 0) { - do_send_text (Peers[index], strndup (f, len)); - } + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty file name\n"); + RET; } - } else if (!memcmp (line, "fwd ", 4)) { - char *q = line + 4; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + do_send_text (id, strndup (s, t)); + } else if (IS_WORD ("fwd")) { + int id = next_token_user_chat (); + if (id == NOT_FOUND) { + printf ("Bad user/chat id\n"); + RET; } - if (index < user_num + chat_num) { - int len = 0; - char *f = get_token (&q, &len); - if (f) { - int num = atoi (f); - if (num > 0) { - do_forward_message (Peers[index], num); - } - } + int num = next_token_int (); + if (num == NOT_FOUND || num <= 0) { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "load_photo ", 10)) { - char *q = line + 10; - int len = 0; - char *f = get_token (&q, &len); - if (f) { - int num = atoi (f); - if (num > 0) { - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { - do_load_photo (&M->media.photo, 1); - } - } + do_forward_message (id, num); + } else if (IS_WORD ("load_photo")) { + int num = next_token_int (); + if (num == NOT_FOUND || num <= 0) { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "view_photo ", 10)) { - char *q = line + 10; - int len = 0; - char *f = get_token (&q, &len); - if (f) { - int num = atoi (f); - if (num > 0) { - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { - do_load_photo (&M->media.photo, 2); - } - } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + do_load_photo (&M->media.photo, 1); + } else { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "load_video_thumb ", 16)) { - char *q = line + 16; - int len = 0; - char *f = get_token (&q, &len); - if (f) { - int num = atoi (f); - if (num > 0) { - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { - do_load_video_thumb (&M->media.video, 1); - } - } + } else if (IS_WORD ("view_photo")) { + int num = next_token_int (); + if (num == NOT_FOUND || num <= 0) { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "view_video_thumb ", 16)) { - char *q = line + 16; - int len = 0; - char *f = get_token (&q, &len); - if (f) { - int num = atoi (f); - if (num > 0) { - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { - do_load_video_thumb (&M->media.video, 2); - } - } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + do_load_photo (&M->media.photo, 2); + } else { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "load_video ", 10)) { - char *q = line + 10; - int len = 0; - char *f = get_token (&q, &len); - if (f) { - int num = atoi (f); - if (num > 0) { - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { - do_load_video (&M->media.video, 1); - } - } + } else if (IS_WORD ("load_video_thumb")) { + int num = next_token_int (); + if (num == NOT_FOUND || num <= 0) { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "view_video ", 10)) { - char *q = line + 10; - int len = 0; - char *f = get_token (&q, &len); - if (f) { - int num = atoi (f); - if (num > 0) { - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { - do_load_video (&M->media.video, 2); - } - } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video_thumb (&M->media.video, 1); + } else { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "chat_info", 9)) { - char *q = line + 10; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + } else if (IS_WORD ("view_video_thumb")) { + int num = next_token_int (); + if (num == NOT_FOUND || num <= 0) { + printf ("Bad msg id\n"); + RET; } - if (index < user_num + chat_num && Peers[index]->id < 0) { - do_get_chat_info (Peers[index]); + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video_thumb (&M->media.video, 2); + } else { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "user_info", 9)) { - char *q = line + 10; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + } else if (IS_WORD ("load_video")) { + int num = next_token_int (); + if (num == NOT_FOUND || num <= 0) { + printf ("Bad msg id\n"); + RET; } - if (index < user_num + chat_num && Peers[index]->id > 0) { - do_get_user_info (Peers[index]); + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video (&M->media.video, 1); + } else { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "history", 7)) { - char *q = line + 7; - int len; - char *text = get_token (&q, &len); - int index = 0; - while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; + } else if (IS_WORD ("view_video")) { + int num = next_token_int (); + if (num == NOT_FOUND || num <= 0) { + printf ("Bad msg id\n"); + RET; } - if (index < user_num + chat_num) { - char *text = get_token (&q, &len); - int limit = 40; - if (text) { - limit = atoi (text); - if (limit <= 0 || limit >= 1000000) { - limit = 40; - } - } - do_get_history (Peers[index], limit); + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video (&M->media.video, 2); + } else { + printf ("Bad msg id\n"); + RET; } - } else if (!memcmp (line, "help", 4)) { + } else if (IS_WORD ("chat_info")) { + int id = next_token_chat (); + if (id == NOT_FOUND) { + printf ("Bad chat id\n"); + RET; + } + do_get_chat_info (id); + } else if (IS_WORD ("user_info")) { + int id = next_token_user (); + if (id == NOT_FOUND) { + printf ("Bad user id\n"); + RET; + } + do_get_user_info (id); + } else if (IS_WORD ("history")) { + int id = next_token_user_chat (); + if (id == NOT_FOUND) { + printf ("Bad user/chat id\n"); + RET; + } + int limit = next_token_int (); + do_get_history (id, limit > 0 ? limit : 40); + } else if (IS_WORD ("help")) { //print_start (); push_color (COLOR_YELLOW); printf ( @@ -548,12 +632,15 @@ void interpreter (char *line UU) { rl_on_new_line (); //print_end (); printf ("\033[1K\033H"); - } else if (!memcmp (line, "show_license", 12)) { + } else if (IS_WORD ("show_license")) { char *b = #include "LICENSE.h" ; printf ("%s", b); } +#undef IS_WORD +#undef RET + in_readline = 0; } int readline_active; @@ -586,6 +673,7 @@ int saved_point; char *saved_line; int prompt_was; void print_start (void) { + if (in_readline) { return; } assert (!prompt_was); if (readline_active) { saved_point = rl_point; @@ -597,6 +685,7 @@ void print_start (void) { prompt_was = 1; } void print_end (void) { + if (in_readline) { return; } assert (prompt_was); if (readline_active) { rl_set_prompt (get_default_prompt ()); diff --git a/loop.c b/loop.c index 916fbf4..f87edac 100644 --- a/loop.c +++ b/loop.c @@ -63,14 +63,6 @@ void net_loop (int flags, int (*is_end)(void)) { double timer = next_timer_in (); if (timer > 1000) { timer = 1000; } if (poll (fds, x, timer) < 0) { - /* resuming from interrupt, so not an error situation, - this generally happens when you suspend your - messenger with "C-z" and then "fg". This is allowed " - */ - if (flags & 1) { - rl_reset_line_state (); - rl_forced_update_display (); - } work_timers (); continue; } @@ -102,6 +94,7 @@ int is_got_it (void) { } int net_getline (char **s, size_t *l) { + rl_already_prompted = 1; got_it_ok = 0; _s = s; _l = l; diff --git a/queries.c b/queries.c index f3c78cc..5766bc0 100644 --- a/queries.c +++ b/queries.c @@ -622,7 +622,8 @@ struct query_methods msg_send_methods = { int out_message_num; int our_id; -void do_send_message (union user_chat *U, const char *msg, int len) { +void out_peer_id (int id); +void do_send_message (int id, const char *msg, int len) { if (!out_message_num) { out_message_num = -lrand48 (); } @@ -631,21 +632,9 @@ void do_send_message (union user_chat *U, const char *msg, int len) { struct message *M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); M->from_id = our_id; - M->to_id = U->id; + M->to_id = id; M->unread = 1; - if (U->id < 0) { - out_int (CODE_input_peer_chat); - out_int (-U->id); - } else { - if (U->user.access_hash) { - out_int (CODE_input_peer_foreign); - out_int (U->id); - out_long (U->user.access_hash); - } else { - out_int (CODE_input_peer_contact); - out_int (U->id); - } - } + out_peer_id (id); M->message = malloc (len + 1); memcpy (M->message, msg, len); M->message[len] = 0; @@ -660,7 +649,7 @@ void do_send_message (union user_chat *U, const char *msg, int len) { print_message (M); } -void do_send_text (union user_chat *U, char *file_name) { +void do_send_text (int id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { rprintf ("No such file '%s'\n", file_name); @@ -676,7 +665,7 @@ void do_send_text (union user_chat *U, char *file_name) { close (fd); } else { buf[x] = 0; - do_send_message (U, buf, x); + do_send_message (id, buf, x); free (file_name); close (fd); } @@ -694,22 +683,10 @@ struct query_methods mark_read_methods = { .on_answer = mark_read_on_receive }; -void do_messages_mark_read (union user_chat *U, int max_id) { +void do_messages_mark_read (int id, int max_id) { clear_packet (); out_int (CODE_messages_read_history); - if (U->id < 0) { - out_int (CODE_input_peer_chat); - out_int (-U->id); - } else { - if (U->user.access_hash) { - out_int (CODE_input_peer_foreign); - out_int (U->id); - out_long (U->user.access_hash); - } else { - out_int (CODE_input_peer_contact); - out_int (U->id); - } - } + out_peer_id (id); out_int (max_id); out_int (0); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, 0); @@ -749,7 +726,7 @@ int get_history_on_answer (struct query *q UU) { fetch_alloc_user (); } if (sn > 0) { - do_messages_mark_read (q->extra, ML[0]->id); + do_messages_mark_read ((long)(q->extra), ML[0]->id); } return 0; } @@ -759,26 +736,14 @@ struct query_methods get_history_methods = { }; -void do_get_history (union user_chat *U, int limit) { +void do_get_history (int id, int limit) { clear_packet (); out_int (CODE_messages_get_history); - if (U->id < 0) { - out_int (CODE_input_peer_chat); - out_int (-U->id); - } else { - if (U->user.access_hash) { - out_int (CODE_input_peer_foreign); - out_int (U->id); - out_long (U->user.access_hash); - } else { - out_int (CODE_input_peer_contact); - out_int (U->id); - } - } + out_peer_id (id); out_int (0); out_int (0); out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, U); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, (void *)(long)id); } int get_dialogs_on_answer (struct query *q UU) { @@ -1023,11 +988,11 @@ struct query_methods fwd_msg_methods = { .on_answer = fwd_msg_on_answer }; -void do_forward_message (union user_chat *U, int n) { +void do_forward_message (int id, int n) { clear_packet (); out_int (CODE_invoke_with_layer3); out_int (CODE_messages_forward_message); - out_peer_id (U->id); + out_peer_id (id); out_int (n); out_long (lrand48 () * (1ll << 32) + lrand48 ()); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, 0); @@ -1057,10 +1022,10 @@ struct query_methods rename_chat_methods = { .on_answer = rename_chat_on_answer }; -void do_rename_chat (union user_chat *U, char *name) { +void do_rename_chat (int id, char *name) { clear_packet (); out_int (CODE_messages_edit_chat_title); - out_int (-U->id); + out_int (-id); out_string (name); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, 0); } @@ -1095,10 +1060,10 @@ struct query_methods chat_info_methods = { .on_answer = chat_info_on_answer }; -void do_get_chat_info (union user_chat *chat) { +void do_get_chat_info (int id) { clear_packet (); out_int (CODE_messages_get_full_chat); - out_int (-chat->id); + out_int (-id); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0); } @@ -1128,16 +1093,17 @@ struct query_methods user_info_methods = { .on_answer = user_info_on_answer }; -void do_get_user_info (union user_chat *U) { +void do_get_user_info (int id) { clear_packet (); out_int (CODE_users_get_full_user); - if (U->user.access_hash) { + union user_chat *U = user_chat_get (id); + if (U && U->user.access_hash) { out_int (CODE_input_user_foreign); - out_int (U->id); + out_int (id); out_long (U->user.access_hash); } else { out_int (CODE_input_user_contact); - out_int (U->id); + out_int (id); } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0); } diff --git a/queries.h b/queries.h index 1a93b1f..f6e0fc4 100644 --- a/queries.h +++ b/queries.h @@ -68,16 +68,16 @@ double get_double_time (void); void do_update_contact_list (void); union user_chat; -void do_send_message (union user_chat *U, const char *msg, int len); -void do_send_text (union user_chat *U, char *file); -void do_get_history (union user_chat *U, int limit); +void do_send_message (int id, const char *msg, int len); +void do_send_text (int id, char *file); +void do_get_history (int id, int limit); void do_get_dialog_list (void); void do_send_photo (int type, int to_id, char *file_name); -void do_get_chat_info (union user_chat *chat); +void do_get_chat_info (int id); void do_get_user_list_info_silent (int num, int *list); -void do_get_user_info (union user_chat *user); -void do_forward_message (union user_chat *U, int n); -void do_rename_chat (union user_chat *U, char *name); +void do_get_user_info (int id); +void do_forward_message (int id, int n); +void do_rename_chat (int id, char *name); struct photo; struct video; From f7be3b41cc9f521a1ab4d6f17c13e4df85bb1933 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 30 Oct 2013 14:10:16 +0400 Subject: [PATCH 064/465] Added add_contact/rename_contact queries --- interface.c | 53 +++++++++++++++++++++++++++++++++++++++++ queries.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ queries.h | 1 + 3 files changed, 122 insertions(+) diff --git a/interface.c b/interface.c index 42a7b3d..a0fc830 100644 --- a/interface.c +++ b/interface.c @@ -228,6 +228,8 @@ char *commands[] = { "view_video_thumb", "load_video", "view_video", + "add_contact", + "rename_contact", "show_license", 0 }; @@ -252,6 +254,8 @@ int commands_flags[] = { 07, 07, 07, + 071, + 07, }; int get_complete_mode (void) { @@ -607,6 +611,55 @@ void interpreter (char *line UU) { } int limit = next_token_int (); do_get_history (id, limit > 0 ? limit : 40); + } else if (IS_WORD ("add_contact")) { + int phone_len, first_name_len, last_name_len; + char *phone, *first_name, *last_name; + phone = next_token (&phone_len); + if (!phone) { + printf ("No phone number found\n"); + RET; + } + first_name = next_token (&first_name_len); + if (!first_name_len) { + printf ("No first name found\n"); + RET; + } + last_name = next_token (&last_name_len); + if (!last_name_len) { + printf ("No last name found\n"); + RET; + } + do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 0); + } else if (IS_WORD ("rename_contact")) { + int id = next_token_user (); + if (id == NOT_FOUND) { + printf ("Bad user\n"); + RET; + } + union user_chat *U = user_chat_get (id); + if (!U) { + printf ("No such user\n"); + RET; + } + if (!U->user.phone || !strlen (U->user.phone)) { + printf ("User has no phone. Can not rename\n"); + RET; + } + int phone_len, first_name_len, last_name_len; + char *phone, *first_name, *last_name; + phone_len = strlen (U->user.phone); + phone = U->user.phone; + first_name = next_token (&first_name_len); + if (!first_name_len) { + printf ("No first name found\n"); + RET; + } + last_name = next_token (&last_name_len); + if (!last_name_len) { + printf ("No last name found\n"); + RET; + } + do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 1); } else if (IS_WORD ("help")) { //print_start (); push_color (COLOR_YELLOW); diff --git a/queries.c b/queries.c index 5766bc0..ffd2153 100644 --- a/queries.c +++ b/queries.c @@ -1365,3 +1365,71 @@ void do_import_auth (int num) { send_query (DC_list[num], packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, 0); net_loop (0, isn_export_auth_str); } + +int add_contact_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_contacts_imported_contacts); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + if (n > 0) { + logprintf ("Added successfully"); + } else { + logprintf ("Not added"); + } + int i; + for (i = 0; i < n ; i++) { + assert (fetch_int () == (int)CODE_imported_contact); + fetch_int (); // uid + fetch_long (); // client_id + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n ; i++) { + struct user *U = fetch_alloc_user (); + print_start (); + push_color (COLOR_YELLOW); + printf ("User #%d: ", U->id); + print_user_name (U->id, (union user_chat *)U); + push_color (COLOR_GREEN); + printf (" ("); + printf ("%s", U->print_name); + if (U->phone) { + printf (" "); + printf ("%s", U->phone); + } + printf (") "); + pop_color (); + if (U->status.online > 0) { + printf ("online\n"); + } else { + if (U->status.online < 0) { + printf ("offline. Was online "); + print_date_full (U->status.when); + } else { + printf ("offline permanent"); + } + printf ("\n"); + } + pop_color (); + print_end (); + + } + return 0; +} + +struct query_methods add_contact_methods = { + .on_answer = add_contact_on_answer, +}; + +void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force) { + clear_packet (); + out_int (CODE_contacts_import_contacts); + out_int (CODE_vector); + out_int (1); + out_int (CODE_input_phone_contact); + out_long (lrand48 () * (1ll << 32) + lrand48 ()); + out_cstring (phone, phone_len); + out_cstring (first_name, first_name_len); + out_cstring (last_name, last_name_len); + out_int (force ? CODE_bool_true : CODE_bool_false); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_contact_methods, 0); +} diff --git a/queries.h b/queries.h index f6e0fc4..c5192ba 100644 --- a/queries.h +++ b/queries.h @@ -90,5 +90,6 @@ 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); +void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); #endif From a18b8981220a5075bf0015acfef0f597b544c4f8 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 1 Nov 2013 03:18:34 +0400 Subject: [PATCH 065/465] id for users and chats renamed to peer_id_t. This will make implementing secure chats and geochats easier --- interface.c | 210 ++++++++++++++++++++++------------------------- interface.h | 7 +- mtproto-client.c | 95 +++++++++++++++------ queries.c | 108 +++++++++++++----------- queries.h | 17 ++-- structures.c | 55 +++++++------ structures.h | 72 +++++++++++++--- 7 files changed, 334 insertions(+), 230 deletions(-) diff --git a/interface.c b/interface.c index a0fc830..e582688 100644 --- a/interface.c +++ b/interface.c @@ -50,7 +50,7 @@ long long cur_downloaded_bytes; char *line_ptr; extern int user_num; extern int chat_num; -extern union user_chat *Peers[]; +extern peer_t *Peers[]; int is_same_word (const char *s, size_t l, const char *word) { return s && word && strlen (word) == l && !memcmp (s, word, l); @@ -77,6 +77,8 @@ char *next_token (int *l) { } #define NOT_FOUND (int)0x80000000 +peer_id_t PEER_NOT_FOUND = {.id = NOT_FOUND}; + int next_token_int (void) { int l; char *s = next_token (&l); @@ -90,84 +92,82 @@ int next_token_int (void) { } } -int next_token_user (void) { +peer_id_t next_token_user (void) { int l; char *s = next_token (&l); - if (!s) { return NOT_FOUND; } + if (!s) { return PEER_NOT_FOUND; } - if (*s == '#') { - s ++; - l --; - if (l > 0) { - int r = atoi (s); - if (r < 0) { return r; } - else { return NOT_FOUND; } - } else { - return NOT_FOUND; - } + if (l >= 6 && !memcmp (s, "user#", 5)) { + s += 5; + l -= 5; + int r = atoi (s); + if (r >= 0) { return set_peer_id (PEER_USER, r); } + else { return PEER_NOT_FOUND; } } + int index = 0; - while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || Peers[index]->id < 0)) { + while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) { index ++; } if (index < user_num + chat_num) { return Peers[index]->id; } else { - return NOT_FOUND; + return PEER_NOT_FOUND; } } -int next_token_chat (void) { +peer_id_t next_token_chat (void) { int l; char *s = next_token (&l); - if (!s) { return NOT_FOUND; } - - if (*s == '#') { - s ++; - l --; - if (l > 0) { - int r = atoi (s); - if (r < 0) { return r; } - else { return NOT_FOUND; } - } else { - return NOT_FOUND; - } + if (!s) { return PEER_NOT_FOUND; } + + if (l >= 6 && !memcmp (s, "chat#", 5)) { + s += 5; + l -= 5; + int r = atoi (s); + if (r >= 0) { return set_peer_id (PEER_CHAT, r); } + else { return PEER_NOT_FOUND; } } + int index = 0; - while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || Peers[index]->id > 0)) { + while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { index ++; } if (index < user_num + chat_num) { return Peers[index]->id; } else { - return NOT_FOUND; + return PEER_NOT_FOUND; } } -int next_token_user_chat (void) { +peer_id_t next_token_peer (void) { int l; char *s = next_token (&l); - if (!s) { return NOT_FOUND; } - - if (*s == '#') { - s ++; - l --; - if (l > 0) { - int r = atoi (s); - if (r != 0) { return r; } - else { return NOT_FOUND; } - } else { - return NOT_FOUND; - } + if (!s) { return PEER_NOT_FOUND; } + + if (l >= 6 && !memcmp (s, "user#", 5)) { + s += 5; + l -= 5; + int r = atoi (s); + if (r >= 0) { return set_peer_id (PEER_USER, r); } + else { return PEER_NOT_FOUND; } } + if (l >= 6 && !memcmp (s, "chat#", 5)) { + s += 5; + l -= 5; + int r = atoi (s); + if (r >= 0) { return set_peer_id (PEER_CHAT, r); } + else { return PEER_NOT_FOUND; } + } + int index = 0; - while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || !Peers[index]->id)) { + while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name))) { index ++; } if (index < user_num + chat_num) { return Peers[index]->id; } else { - return NOT_FOUND; + return PEER_NOT_FOUND; } } @@ -295,7 +295,7 @@ int get_complete_mode (void) { int complete_user_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) || Peers[index]->id < 0)) { + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) { index ++; } if (index < user_num + chat_num) { @@ -308,7 +308,7 @@ int complete_user_list (int index, const char *text, int len, char **R) { int complete_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) || Peers[index]->id > 0)) { + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { index ++; } if (index < user_num + chat_num) { @@ -426,6 +426,27 @@ void interpreter (char *line UU) { #define IS_WORD(s) is_same_word (command, l, (s)) #define RET in_readline = 0; return; + + peer_id_t id; +#define GET_PEER \ + id = next_token_peer (); \ + if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ + printf ("Bad user/char id\n"); \ + RET; \ + } +#define GET_PEER_USER \ + id = next_token_user (); \ + if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ + printf ("Bad user id\n"); \ + RET; \ + } +#define GET_PEER_CHAT \ + id = next_token_chat (); \ + if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ + printf ("Bad char id\n"); \ + RET; \ + } + if (IS_WORD ("contact_list")) { do_update_contact_list (); } else if (IS_WORD ("dialog_list")) { @@ -435,11 +456,7 @@ void interpreter (char *line UU) { print_stat (stat_buf, (1 << 15) - 1); printf ("%s\n", stat_buf); } else if (IS_WORD ("msg")) { - int id = next_token_user_chat (); - if (id == NOT_FOUND) { - printf ("Bad user/chat id\n"); - RET; - } + GET_PEER; int t; char *s = next_token (&t); if (!s) { @@ -448,11 +465,7 @@ void interpreter (char *line UU) { } do_send_message (id, s, strlen (s)); } else if (IS_WORD ("rename_chat")) { - int id = next_token_chat (); - if (id == NOT_FOUND) { - printf ("Bad chat id\n"); - RET; - } + GET_PEER_CHAT; int t; char *s = next_token (&t); if (!s) { @@ -461,11 +474,7 @@ void interpreter (char *line UU) { } do_rename_chat (id, s); } else if (IS_WORD ("send_photo")) { - int id = next_token_user_chat (); - if (id == NOT_FOUND) { - printf ("Bad user/chat id\n"); - RET; - } + GET_PEER; int t; char *s = next_token (&t); if (!s) { @@ -474,11 +483,7 @@ void interpreter (char *line UU) { } do_send_photo (CODE_input_media_uploaded_photo, id, strndup (s, t)); } else if (IS_WORD("send_video")) { - int id = next_token_user_chat (); - if (id == NOT_FOUND) { - printf ("Bad user/chat id\n"); - RET; - } + GET_PEER; int t; char *s = next_token (&t); if (!s) { @@ -487,11 +492,7 @@ void interpreter (char *line UU) { } do_send_photo (CODE_input_media_uploaded_video, id, strndup (s, t)); } else if (IS_WORD ("send_text")) { - int id = next_token_user_chat (); - if (id == NOT_FOUND) { - printf ("Bad user/chat id\n"); - RET; - } + GET_PEER; int t; char *s = next_token (&t); if (!s) { @@ -500,11 +501,7 @@ void interpreter (char *line UU) { } do_send_text (id, strndup (s, t)); } else if (IS_WORD ("fwd")) { - int id = next_token_user_chat (); - if (id == NOT_FOUND) { - printf ("Bad user/chat id\n"); - RET; - } + GET_PEER; int num = next_token_int (); if (num == NOT_FOUND || num <= 0) { printf ("Bad msg id\n"); @@ -590,25 +587,13 @@ void interpreter (char *line UU) { RET; } } else if (IS_WORD ("chat_info")) { - int id = next_token_chat (); - if (id == NOT_FOUND) { - printf ("Bad chat id\n"); - RET; - } + GET_PEER_CHAT; do_get_chat_info (id); } else if (IS_WORD ("user_info")) { - int id = next_token_user (); - if (id == NOT_FOUND) { - printf ("Bad user id\n"); - RET; - } + GET_PEER_USER; do_get_user_info (id); } else if (IS_WORD ("history")) { - int id = next_token_user_chat (); - if (id == NOT_FOUND) { - printf ("Bad user/chat id\n"); - RET; - } + GET_PEER; int limit = next_token_int (); do_get_history (id, limit > 0 ? limit : 40); } else if (IS_WORD ("add_contact")) { @@ -631,12 +616,8 @@ void interpreter (char *line UU) { } do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 0); } else if (IS_WORD ("rename_contact")) { - int id = next_token_user (); - if (id == NOT_FOUND) { - printf ("Bad user\n"); - RET; - } - union user_chat *U = user_chat_get (id); + GET_PEER_USER; + peer_t *U = user_chat_get (id); if (!U) { printf ("No such user\n"); RET; @@ -879,20 +860,22 @@ void print_media (struct message_media *M) { int unknown_user_list_pos; int unknown_user_list[1000]; -void print_user_name (int id, union user_chat *U) { +void print_user_name (peer_id_t id, peer_t *U) { + assert (get_peer_type (id) == PEER_USER); push_color (COLOR_RED); if (!U) { - printf ("user#%d", id); + printf ("user#%d", get_peer_id (id)); int i; + int ok = 1; for (i = 0; i < unknown_user_list_pos; i++) { - if (unknown_user_list[i] == id) { - id = 0; + if (unknown_user_list[i] == get_peer_id (id)) { + ok = 0; break; } } - if (id) { + if (ok) { assert (unknown_user_list_pos < 1000); - unknown_user_list[unknown_user_list_pos ++] = id; + unknown_user_list[unknown_user_list_pos ++] = get_peer_id (id); } } else { if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { @@ -912,10 +895,10 @@ void print_user_name (int id, union user_chat *U) { pop_color (); } -void print_chat_name (int id, union user_chat *C) { +void print_chat_name (peer_id_t id, peer_t *C) { push_color (COLOR_MAGENTA); if (!C) { - printf ("chat#%d", -id); + printf ("chat#%d", get_peer_id (id)); } else { printf ("%s", C->chat.title); } @@ -973,12 +956,12 @@ void print_service_message (struct message *M) { break; case CODE_message_action_chat_add_user: printf (" added user "); - print_user_name (M->action.user, user_chat_get (M->action.user)); + print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); printf ("\n"); break; case CODE_message_action_chat_delete_user: printf (" deleted user "); - print_user_name (M->action.user, user_chat_get (M->action.user)); + print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); printf ("\n"); break; default: @@ -988,15 +971,20 @@ void print_service_message (struct message *M) { print_end (); } +peer_id_t last_from_id; +peer_id_t last_to_id; + void print_message (struct message *M) { if (M->service) { print_service_message (M); return; } + last_from_id = M->from_id; + last_to_id = M->to_id; print_start (); - if (M->to_id >= 0) { + if (get_peer_type (M->to_id) == PEER_USER) { if (M->out) { push_color (COLOR_GREEN); if (msg_num_mode) { @@ -1039,7 +1027,7 @@ void print_message (struct message *M) { print_chat_name (M->to_id, user_chat_get (M->to_id)); printf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); - if (M->from_id == our_id) { + if ((get_peer_type (M->from_id) == PEER_USER) && (get_peer_id (M->from_id) == our_id)) { push_color (COLOR_GREEN); } else { push_color (COLOR_BLUE); @@ -1050,7 +1038,7 @@ void print_message (struct message *M) { printf (" »»» "); } } - if (M->fwd_from_id) { + if (get_peer_type (M->fwd_from_id) == PEER_USER) { printf ("[fwd from "); print_user_name (M->fwd_from_id, user_chat_get (M->fwd_from_id)); printf ("] "); diff --git a/interface.h b/interface.h index 51463a8..6a59bbc 100644 --- a/interface.h +++ b/interface.h @@ -18,6 +18,7 @@ */ #ifndef __INTERFACE_H__ #define __INTERFACE_H__ +#include "structures.h" #define COLOR_RED "\033[0;31m" #define COLOR_REDB "\033[1;31m" @@ -40,10 +41,10 @@ void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))) void hexdump (int *in_ptr, int *in_end); struct message; -union user_chat; +union peer; void print_message (struct message *M); -void print_chat_name (int id, union user_chat *C); -void print_user_name (int id, union user_chat *U); +void print_chat_name (peer_id_t id, union peer *C); +void print_user_name (peer_id_t id, union peer *U); //void print_media (struct message_media *M); void pop_color (void); void push_color (const char *color); diff --git a/mtproto-client.c b/mtproto-client.c index 0b5be0b..0752a5c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -635,13 +635,45 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU); int unread_messages; int our_id; +int pts; +int qts; + +void fetch_pts (void) { + int p = fetch_int (); + if (p != pts + 1) { + if (pts) { + logprintf ("Hole in pts p = %d, pts = %d\n", p, pts); + + // get difference should be here + } else { + pts = p; + } + } else { + pts ++; + } +} + +void fetch_qts (void) { + int p = fetch_int (); + if (p != qts + 1) { + if (qts) { + logprintf ("Hole in qts\n"); + // get difference should be here + } else { + qts = p; + } + } else { + qts ++; + } +} + void work_update (struct connection *c UU, long long msg_id UU) { unsigned op = fetch_int (); switch (op) { case CODE_update_new_message: { struct message *M = fetch_alloc_message (); - fetch_int (); //pts + fetch_pts (); unread_messages ++; print_message (M); update_prompt (); @@ -667,7 +699,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { M->unread = 0; } } - fetch_int (); //pts + fetch_pts (); print_start (); push_color (COLOR_YELLOW); printf ("%d messages marked as read\n", n); @@ -677,8 +709,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_user_typing: { - int id = fetch_int (); - union user_chat *U = user_chat_get (id); + peer_id_t id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (id); print_start (); push_color (COLOR_YELLOW); printf ("User "); @@ -690,16 +722,16 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_chat_user_typing: { - int chat_id = fetch_int (); - int id = fetch_int (); - union user_chat *C = user_chat_get (-chat_id); - union user_chat *U = user_chat_get (id); + peer_id_t chat_id = MK_CHAT (fetch_int ()); + peer_id_t id = MK_USER (fetch_int ()); + peer_t *C = user_chat_get (chat_id); + peer_t *U = user_chat_get (id); print_start (); push_color (COLOR_YELLOW); printf ("User "); print_user_name (id, U); printf (" is typing in chat "); - print_chat_name (-chat_id, C); + print_chat_name (chat_id, C); printf ("....\n"); pop_color (); print_end (); @@ -707,8 +739,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_user_status: { - int user_id = fetch_int (); - union user_chat *U = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (user_id); if (U) { fetch_user_status (&U->user.status); print_start (); @@ -727,8 +759,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_user_name: { - int user_id = fetch_int (); - union user_chat *UC = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; print_start (); @@ -770,8 +802,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_user_photo: { - int user_id = fetch_int (); - union user_chat *UC = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; @@ -813,23 +845,36 @@ void work_update (struct connection *c UU, long long msg_id UU) { pop_color (); print_end (); fetch_skip (n); - fetch_int (); // pts + fetch_pts (); + } + break; + case CODE_update_delete_messages: + { + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + print_start (); + push_color (COLOR_YELLOW); + printf ("Deleted %d messages\n", n); + pop_color (); + print_end (); + fetch_skip (n); + fetch_pts (); } break; case CODE_update_chat_participants: { assert (fetch_int () == CODE_chat_participants); - int chat_id = fetch_int (); + peer_id_t chat_id = MK_CHAT (fetch_int ()); fetch_int (); // admin_id assert (fetch_int () == CODE_vector); int n = fetch_int (); fetch_skip (n * 4); fetch_int (); // version - union user_chat *C = user_chat_get (-chat_id); + peer_t *C = user_chat_get (chat_id); print_start (); push_color (COLOR_YELLOW); printf ("Chat "); - print_chat_name (-chat_id, C); + print_chat_name (chat_id, C); printf (" changed list: now %d members\n", n); pop_color (); print_end (); @@ -837,8 +882,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_contact_registered: { - int user_id = fetch_int (); - union user_chat *U = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (user_id); fetch_int (); // date print_start (); push_color (COLOR_YELLOW); @@ -851,8 +896,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_contact_link: { - int user_id = fetch_int (); - union user_chat *U = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (user_id); print_start (); push_color (COLOR_YELLOW); printf ("Updated link with user "); @@ -874,8 +919,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_activation: { - int user_id = fetch_int (); - union user_chat *U = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (user_id); print_start (); push_color (COLOR_YELLOW); printf ("User "); diff --git a/queries.c b/queries.c index ffd2153..0e157bd 100644 --- a/queries.c +++ b/queries.c @@ -562,8 +562,8 @@ int get_contacts_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user (); print_start (); push_color (COLOR_YELLOW); - printf ("User #%d: ", U->id); - print_user_name (U->id, (union user_chat *)U); + printf ("User #%d: ", get_peer_id (U->id)); + print_user_name (U->id, (peer_t *)U); push_color (COLOR_GREEN); printf (" ("); printf ("%s", U->print_name); @@ -622,8 +622,8 @@ struct query_methods msg_send_methods = { int out_message_num; int our_id; -void out_peer_id (int id); -void do_send_message (int id, const char *msg, int len) { +void out_peer_id (peer_id_t id); +void do_send_message (peer_id_t id, const char *msg, int len) { if (!out_message_num) { out_message_num = -lrand48 (); } @@ -631,7 +631,7 @@ void do_send_message (int id, const char *msg, int len) { out_int (CODE_messages_send_message); struct message *M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); - M->from_id = our_id; + M->from_id = MK_USER (our_id); M->to_id = id; M->unread = 1; out_peer_id (id); @@ -649,7 +649,7 @@ void do_send_message (int id, const char *msg, int len) { print_message (M); } -void do_send_text (int id, char *file_name) { +void do_send_text (peer_id_t id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { rprintf ("No such file '%s'\n", file_name); @@ -683,7 +683,7 @@ struct query_methods mark_read_methods = { .on_answer = mark_read_on_receive }; -void do_messages_mark_read (int id, int max_id) { +void do_messages_mark_read (peer_id_t id, int max_id) { clear_packet (); out_int (CODE_messages_read_history); out_peer_id (id); @@ -726,7 +726,7 @@ int get_history_on_answer (struct query *q UU) { fetch_alloc_user (); } if (sn > 0) { - do_messages_mark_read ((long)(q->extra), ML[0]->id); + do_messages_mark_read (*(peer_id_t *)&(q->extra), ML[0]->id); } return 0; } @@ -736,14 +736,14 @@ struct query_methods get_history_methods = { }; -void do_get_history (int id, int limit) { +void do_get_history (peer_id_t id, int limit) { clear_packet (); out_int (CODE_messages_get_history); out_peer_id (id); out_int (0); out_int (0); out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, (void *)(long)id); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, (void *)*(long *)&id); } int get_dialogs_on_answer (struct query *q UU) { @@ -755,14 +755,15 @@ int get_dialogs_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); int n, i; n = fetch_int (); - static int dlist[3 * 100]; + static int dlist[2 * 100]; + static peer_id_t plist[100]; int dl_size = n; for (i = 0; i < n; i++) { assert (fetch_int () == CODE_dialog); if (i < 100) { - dlist[3 * i + 0] = fetch_peer_id (); - dlist[3 * i + 1] = fetch_int (); - dlist[3 * i + 2] = fetch_int (); + plist[i] = fetch_peer_id (); + dlist[2 * i + 0] = fetch_int (); + dlist[2 * i + 1] = fetch_int (); } else { fetch_peer_id (); fetch_int (); @@ -787,16 +788,20 @@ int get_dialogs_on_answer (struct query *q UU) { print_start (); push_color (COLOR_YELLOW); for (i = dl_size - 1; i >= 0; i--) { - if (dlist[3 * i] < 0) { - union user_chat *UC = user_chat_get (dlist[3 * i]); - printf ("Chat "); - print_chat_name (dlist[3 * i], UC); - printf (": %d unread\n", dlist[3 * i + 2]); - } else { - union user_chat *UC = user_chat_get (dlist[3 * i]); + peer_t *UC; + switch (get_peer_type (plist[i])) { + case PEER_USER: + UC = user_chat_get (plist[i]); printf ("User "); - print_user_name (dlist[3 * i], UC); - printf (": %d unread\n", dlist[3 * i + 2]); + print_user_name (plist[i], UC); + printf (": %d unread\n", dlist[2 * i + 1]); + break; + case PEER_CHAT: + UC = user_chat_get (plist[i]); + printf ("Chat "); + print_chat_name (plist[i], UC); + printf (": %d unread\n", dlist[2 * i + 1]); + break; } } pop_color (); @@ -825,25 +830,31 @@ struct send_file { int part_num; int part_size; long long id; - int to_id; + peer_id_t to_id; int media_type; char *file_name; }; -void out_peer_id (int id) { - union user_chat *U = user_chat_get (id); - if (id < 0) { +void out_peer_id (peer_id_t id) { + peer_t *U; + switch (get_peer_type (id)) { + case PEER_CHAT: out_int (CODE_input_peer_chat); - out_int (-id); - } else { + out_int (get_peer_id (id)); + break; + case PEER_USER: + U = user_chat_get (id); if (U && U->user.access_hash) { out_int (CODE_input_peer_foreign); - out_int (id); + out_int (get_peer_id (id)); out_long (U->user.access_hash); } else { out_int (CODE_input_peer_contact); - out_int (id); + out_int (get_peer_id (id)); } + break; + default: + assert (0); } } @@ -932,7 +943,7 @@ void send_part (struct send_file *f) { } } -void do_send_photo (int type, int to_id, char *file_name) { +void do_send_photo (int type, peer_id_t to_id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { rprintf ("No such file '%s'\n", file_name); @@ -988,7 +999,7 @@ struct query_methods fwd_msg_methods = { .on_answer = fwd_msg_on_answer }; -void do_forward_message (int id, int n) { +void do_forward_message (peer_id_t id, int n) { clear_packet (); out_int (CODE_invoke_with_layer3); out_int (CODE_messages_forward_message); @@ -1022,17 +1033,18 @@ struct query_methods rename_chat_methods = { .on_answer = rename_chat_on_answer }; -void do_rename_chat (int id, char *name) { +void do_rename_chat (peer_id_t id, char *name) { clear_packet (); out_int (CODE_messages_edit_chat_title); - out_int (-id); + assert (get_peer_type (id) == PEER_CHAT); + out_int (get_peer_id (id)); out_string (name); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, 0); } int chat_info_on_answer (struct query *q UU) { struct chat *C = fetch_alloc_chat_full (); - union user_chat *U = (void *)C; + peer_t *U = (void *)C; print_start (); push_color (COLOR_YELLOW); printf ("Chat "); @@ -1041,9 +1053,9 @@ int chat_info_on_answer (struct query *q UU) { int i; for (i = 0; i < C->users_num; i++) { printf ("\t\t"); - print_user_name (C->users[i].user_id, user_chat_get (C->users[i].user_id)); + print_user_name (MK_USER (C->users[i].user_id), user_chat_get (MK_USER (C->users[i].user_id))); printf (" invited by "); - print_user_name (C->users[i].inviter_id, user_chat_get (C->users[i].inviter_id)); + print_user_name (MK_USER (C->users[i].inviter_id), user_chat_get (MK_USER (C->users[i].inviter_id))); printf (" at "); print_date_full (C->users[i].date); if (C->users[i].user_id == C->admin_id) { @@ -1060,16 +1072,17 @@ struct query_methods chat_info_methods = { .on_answer = chat_info_on_answer }; -void do_get_chat_info (int id) { +void do_get_chat_info (peer_id_t id) { clear_packet (); out_int (CODE_messages_get_full_chat); - out_int (-id); + assert (get_peer_type (id) == PEER_CHAT); + out_int (get_peer_id (id)); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0); } int user_info_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user_full (); - union user_chat *C = (void *)U; + peer_t *C = (void *)U; print_start (); push_color (COLOR_YELLOW); printf ("User "); @@ -1093,17 +1106,18 @@ struct query_methods user_info_methods = { .on_answer = user_info_on_answer }; -void do_get_user_info (int id) { +void do_get_user_info (peer_id_t id) { clear_packet (); out_int (CODE_users_get_full_user); - union user_chat *U = user_chat_get (id); + assert (get_peer_type (id) == PEER_USER); + peer_t *U = user_chat_get (id); if (U && U->user.access_hash) { out_int (CODE_input_user_foreign); - out_int (id); + out_int (get_peer_id (id)); out_long (U->user.access_hash); } else { out_int (CODE_input_user_contact); - out_int (id); + out_int (get_peer_id (id)); } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0); } @@ -1387,8 +1401,8 @@ int add_contact_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user (); print_start (); push_color (COLOR_YELLOW); - printf ("User #%d: ", U->id); - print_user_name (U->id, (union user_chat *)U); + printf ("User #%d: ", get_peer_id (U->id)); + print_user_name (U->id, (peer_t *)U); push_color (COLOR_GREEN); printf (" ("); printf ("%s", U->print_name); diff --git a/queries.h b/queries.h index c5192ba..34e3838 100644 --- a/queries.h +++ b/queries.h @@ -19,6 +19,7 @@ #include "net.h" #ifndef __QUERIES_H__ #define __QUERIES_H__ +#include "structures.h" #define QUERY_ACK_RECEIVED 1 @@ -68,16 +69,16 @@ double get_double_time (void); void do_update_contact_list (void); union user_chat; -void do_send_message (int id, const char *msg, int len); -void do_send_text (int id, char *file); -void do_get_history (int id, int limit); +void do_send_message (peer_id_t id, const char *msg, int len); +void do_send_text (peer_id_t id, char *file); +void do_get_history (peer_id_t id, int limit); void do_get_dialog_list (void); -void do_send_photo (int type, int to_id, char *file_name); -void do_get_chat_info (int id); +void do_send_photo (int type, peer_id_t to_id, char *file_name); +void do_get_chat_info (peer_id_t id); void do_get_user_list_info_silent (int num, int *list); -void do_get_user_info (int id); -void do_forward_message (int id, int n); -void do_rename_chat (int id, char *name); +void do_get_user_info (peer_id_t id); +void do_forward_message (peer_id_t id, int n); +void do_rename_chat (peer_id_t id, char *name); struct photo; struct video; diff --git a/structures.c b/structures.c index 999f361..366603c 100644 --- a/structures.c +++ b/structures.c @@ -17,13 +17,14 @@ Copyright Vitaly Valtman 2013 */ #include +#include #include "structures.h" #include "mtproto-common.h" #include "telegram.h" #include "tree.h" #include "loop.h" int verbosity; -union user_chat *Peers[MAX_USER_NUM]; +peer_t *Peers[MAX_USER_NUM]; void fetch_file_location (struct file_location *loc) { int x = fetch_int (); @@ -67,16 +68,16 @@ int chat_num; void fetch_user (struct user *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->id = MK_USER (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; return; } if (x == CODE_user_self) { - assert (!our_id || (our_id == U->id)); + assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { - our_id = U->id; + our_id = get_peer_id (U->id); write_auth_file (); } } @@ -226,7 +227,7 @@ void fetch_user_full (struct user *U) { void fetch_chat (struct chat *C) { unsigned x = fetch_int (); assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); - C->id = -fetch_int (); + C->id = MK_CHAT (fetch_int ()); C->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); if (x == CODE_chat_empty) { C->flags |= FLAG_EMPTY; @@ -292,11 +293,11 @@ 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->id = MK_CHAT (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); + assert (fetch_int () == get_peer_id (C->id)); C->admin_id = fetch_int (); assert (fetch_int () == CODE_vector); if (C->users) { @@ -440,7 +441,8 @@ void fetch_message_action (struct message_action *M) { void fetch_message_short (struct message *M) { memset (M, 0, sizeof (*M)); M->id = fetch_int (); - M->from_id = fetch_int (); + M->to_id = MK_USER (our_id); + M->from_id = MK_USER (fetch_int ()); M->message = fetch_str_dup (); fetch_int (); // pts M->date = fetch_int (); @@ -452,8 +454,8 @@ void fetch_message_short (struct message *M) { void fetch_message_short_chat (struct message *M) { memset (M, 0, sizeof (*M)); M->id = fetch_int (); - M->from_id = fetch_int (); - M->to_id = -fetch_int (); + M->from_id = MK_USER (fetch_int ()); + M->to_id = MK_CHAT (fetch_int ()); M->message = fetch_str_dup (); fetch_int (); // pts M->date = fetch_int (); @@ -493,13 +495,13 @@ void fetch_message_media (struct message_media *M) { } } -int fetch_peer_id (void) { +peer_id_t fetch_peer_id (void) { unsigned x =fetch_int (); if (x == CODE_peer_user) { - return fetch_int (); + return MK_USER (fetch_int ()); } else { assert (CODE_peer_chat); - return -fetch_int (); + return MK_CHAT (fetch_int ()); } } @@ -513,10 +515,10 @@ void fetch_message (struct message *M) { return; } if (x == CODE_message_forwarded) { - M->fwd_from_id = fetch_int (); + M->fwd_from_id = MK_USER (fetch_int ()); M->fwd_date = fetch_int (); } - M->from_id = fetch_int (); + M->from_id = MK_USER (fetch_int ()); M->to_id = fetch_peer_id (); M->out = fetch_bool (); M->unread = fetch_bool (); @@ -530,10 +532,11 @@ void fetch_message (struct message *M) { } } -#define user_cmp(a,b) ((a)->id - (b)->id) +#define id_cmp(a,b) ((a)->id - (b)->id) +#define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) -DEFINE_TREE(peer,union user_chat *,user_cmp,0) -DEFINE_TREE(message,struct message *,user_cmp,0) +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; @@ -551,7 +554,7 @@ struct message message_list = { struct user *fetch_alloc_user (void) { int data[2]; prefetch_data (data, 8); - union user_chat *U = user_chat_get (data[1]); + peer_t *U = user_chat_get (MK_USER (data[1])); if (U) { fetch_user (&U->user); return &U->user; @@ -569,7 +572,7 @@ struct user *fetch_alloc_user (void) { struct user *fetch_alloc_user_full (void) { int data[3]; prefetch_data (data, 12); - union user_chat *U = user_chat_get (data[2]); + peer_t *U = user_chat_get (MK_USER (data[2])); if (U) { fetch_user_full (&U->user); return &U->user; @@ -577,7 +580,7 @@ struct user *fetch_alloc_user_full (void) { users_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - U->id = data[2]; + U->id = MK_USER (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_user_full (&U->user); Peers[chat_num + (user_num ++ )] = U; @@ -754,7 +757,7 @@ struct message *fetch_alloc_message_short_chat (void) { struct chat *fetch_alloc_chat (void) { int data[2]; prefetch_data (data, 8); - union user_chat *U = user_chat_get (-data[1]); + peer_t *U = user_chat_get (MK_CHAT (data[1])); if (U) { fetch_chat (&U->chat); return &U->chat; @@ -772,7 +775,7 @@ struct chat *fetch_alloc_chat (void) { struct chat *fetch_alloc_chat_full (void) { int data[3]; prefetch_data (data, 12); - union user_chat *U = user_chat_get (-data[2]); + peer_t *U = user_chat_get (MK_CHAT (data[2])); if (U) { fetch_chat_full (&U->chat); return &U->chat; @@ -780,7 +783,7 @@ struct chat *fetch_alloc_chat_full (void) { chats_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - U->id = -data[2]; + U->id = MK_CHAT (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_chat_full (&U->chat); Peers[(chat_num ++) + user_num] = U; @@ -804,8 +807,8 @@ int print_stat (char *s, int len) { ); } -union user_chat *user_chat_get (int id) { - union user_chat U; +peer_t *user_chat_get (peer_id_t id) { + peer_t U; U.id = id; return tree_lookup_peer (peer_tree, &U); } diff --git a/structures.h b/structures.h index e08c1f1..20b36c9 100644 --- a/structures.h +++ b/structures.h @@ -19,6 +19,9 @@ #ifndef __STRUCTURES_H__ #define __STRUCTURES_H__ +#include +typedef struct { int id; } peer_id_t; + #define FLAG_EMPTY 1 #define FLAG_DELETED 2 #define FLAG_FORBIDDEN 4 @@ -32,6 +35,7 @@ #define FLAG_CHAT_IN_CHAT 128 + struct file_location { int dc; long long volume; @@ -70,7 +74,7 @@ struct user_status { }; struct user { - int id; + peer_id_t id; int flags; char *print_name; struct file_location photo_big; @@ -93,7 +97,7 @@ struct chat_user { }; struct chat { - int id; + peer_id_t id; int flags; char *print_title; struct file_location photo_big; @@ -107,9 +111,9 @@ struct chat { int admin_id; }; -union user_chat { +typedef union peer { struct { - int id; + peer_id_t id; int flags; char *print_name; struct file_location photo_big; @@ -118,7 +122,7 @@ union user_chat { }; struct user user; struct chat chat; -}; +} peer_t; struct video { long long id; @@ -168,10 +172,10 @@ struct message { struct message *next_use, *prev_use; int id; int flags; - int fwd_from_id; + peer_id_t fwd_from_id; int fwd_date; - int from_id; - int to_id; + peer_id_t from_id; + peer_id_t to_id; int out; int unread; int date; @@ -196,16 +200,64 @@ struct chat *fetch_alloc_chat_full (void); struct message *fetch_alloc_message (void); struct message *fetch_alloc_message_short (void); struct message *fetch_alloc_message_short_chat (void); -int fetch_peer_id (void); +peer_id_t fetch_peer_id (void); void free_user (struct user *U); void free_chat (struct chat *U); int print_stat (char *s, int len); -union user_chat *user_chat_get (int id); +peer_t *user_chat_get (peer_id_t 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); + +#define PEER_USER 1 +#define PEER_CHAT 2 +#define PEER_UNKNOWN 0 + +#define MK_USER(id) set_peer_id (PEER_USER,id) +#define MK_CHAT(id) set_peer_id (PEER_CHAT,id) + +static inline int get_peer_type (peer_id_t id) { + if (id.id > 0) { + return PEER_USER; + } + if (id.id < 0) { + return PEER_CHAT; + } + return PEER_UNKNOWN; +} + +static inline int get_peer_id (peer_id_t id) { + switch (get_peer_type (id)) { + case PEER_USER: + return id.id; + case PEER_CHAT: + return -id.id; + default: + return 0; + } +} + +static inline peer_id_t set_peer_id (int type, int id) { + peer_id_t ID; + switch (type) { + case PEER_USER: + ID.id = id; + return ID; + case PEER_CHAT: + ID.id = -id; + return ID; + default: + assert (0); + return ID; + } +} + +static inline int cmp_peer_id (peer_id_t a, peer_id_t b) { + return memcmp (&a, &b, sizeof (a)); +} + #endif From e92a932b34cca959620b743384550c978b1b450c Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 1 Nov 2013 15:27:08 +0400 Subject: [PATCH 066/465] Fixed fail on empty command line --- interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.c b/interface.c index e582688..174fdbc 100644 --- a/interface.c +++ b/interface.c @@ -416,7 +416,7 @@ void interpreter (char *line UU) { char *command; while (1) { command = next_token (&l); - if (!command) { return; } + if (!command) { in_readline = 0; return; } if (*command == '[' && command[l - 1] == ']') { work_modifier (command); } else { From 2ae2406a912aa2ea30fd065bf85461299ec5a0e8 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 1 Nov 2013 19:02:28 +0400 Subject: [PATCH 067/465] Added search query. But it seems, that search does not use stemmer --- interface.c | 14 ++++++++++++++ mtproto-common.h | 1 + queries.c | 28 +++++++++++++++++++++++++--- queries.h | 1 + 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/interface.c b/interface.c index 174fdbc..4ee41d6 100644 --- a/interface.c +++ b/interface.c @@ -231,6 +231,7 @@ char *commands[] = { "add_contact", "rename_contact", "show_license", + "search", 0 }; int commands_flags[] = { @@ -256,6 +257,7 @@ int commands_flags[] = { 07, 071, 07, + 072, }; int get_complete_mode (void) { @@ -671,6 +673,18 @@ void interpreter (char *line UU) { #include "LICENSE.h" ; printf ("%s", b); + } else if (IS_WORD ("search")) { + GET_PEER; + int from = 0; + int to = 0; + int limit = 40; + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty message\n"); + RET; + } + do_msg_search (id, from, to, limit, s); } #undef IS_WORD #undef RET diff --git a/mtproto-common.h b/mtproto-common.h index ff4f20a..02a920e 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -261,6 +261,7 @@ static inline void out_bignum (BIGNUM *n) { extern int *in_ptr, *in_end; +void fetch_pts (void); static inline int prefetch_strlen (void) { if (in_ptr >= in_end) { return -1; diff --git a/queries.c b/queries.c index 0e157bd..5db981e 100644 --- a/queries.c +++ b/queries.c @@ -607,12 +607,12 @@ int msg_send_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_sent_message); int id = fetch_int (); // id int date = fetch_int (); // date - int ptr = fetch_int (); // ptr + fetch_pts (); int seq = fetch_int (); // seq struct message *M = q->extra; M->id = id; message_insert (M); - logprintf ("Sent: id = %d, date = %d, ptr = %d, seq = %d\n", id, date, ptr, seq); + logprintf ("Sent: id = %d, date = %d, seq = %d\n", id, date, seq); return 0; } @@ -725,7 +725,7 @@ int get_history_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } - if (sn > 0) { + if (sn > 0 && q->extra) { do_messages_mark_read (*(peer_id_t *)&(q->extra), ML[0]->id); } return 0; @@ -1447,3 +1447,25 @@ void do_add_contact (const char *phone, int phone_len, const char *first_name, i out_int (force ? CODE_bool_true : CODE_bool_false); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_contact_methods, 0); } + +int msg_search_on_answer (struct query *q UU) { + return get_history_on_answer (q); +} + +struct query_methods msg_search_methods = { + .on_answer = msg_search_on_answer +}; + +void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) { + clear_packet (); + out_int (CODE_messages_search); + out_peer_id (id); + out_string (s); + out_int (CODE_input_messages_filter_empty); + out_int (from); + out_int (to); + out_int (0); // offset + out_int (0); // max_id + out_int (limit); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_search_methods, 0); +} diff --git a/queries.h b/queries.h index 34e3838..5c2abf7 100644 --- a/queries.h +++ b/queries.h @@ -92,5 +92,6 @@ int do_send_code_result_auth (const char *code, const char *first_name, const ch void do_import_auth (int num); void do_export_auth (int num); void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); +void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s); #endif From b6085fe801caf021bf613f27f8f1938a1ecaafd2 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 1 Nov 2013 23:57:57 +0400 Subject: [PATCH 068/465] Somthing fixed. Don't know what --- constants.h | 6 +++++- loop.c | 4 ++-- mtproto-client.c | 35 +++++++++++++++++++++++++++++++++++ mtproto-common.h | 4 ++++ queries.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- queries.h | 1 + structures.c | 43 ++++++++++++++++++++++++++++++++++++++++++- structures.h | 11 +++++++++++ 8 files changed, 143 insertions(+), 7 deletions(-) diff --git a/constants.h b/constants.h index cb396fa..419f1f9 100644 --- a/constants.h +++ b/constants.h @@ -252,10 +252,11 @@ #define CODE_messages_dh_config 0x2c221edd #define CODE_messages_sent_encrypted_message 0x560f8935 #define CODE_messages_sent_encrypted_file 0x9493ff32 +#define CODE_input_file_big 0xfa4f0bb5 +#define CODE_input_encrypted_file_big_uploaded 0x2dc173c8 #define CODE_invoke_after_msg 0xcb9f372d #define CODE_invoke_after_msgs 0x3dc4b4f0 #define CODE_invoke_with_layer1 0x53835315 -#define CODE_init_connection 0x3fc12e08 #define CODE_auth_check_phone 0x6fe51dfb #define CODE_auth_send_code 0x768d5f4d #define CODE_auth_send_call 0x3c51564 @@ -348,4 +349,7 @@ #define CODE_messages_send_encrypted_service 0x32d439a4 #define CODE_messages_received_queue 0x55a5bb66 #define CODE_invoke_with_layer8 0xe9abd9fd +#define CODE_upload_save_big_file_part 0xde7b673d +#define CODE_init_connection 0x69796de9 +#define CODE_invoke_with_layer9 0x76715a63 #endif diff --git a/loop.c b/loop.c index f87edac..ea9c065 100644 --- a/loop.c +++ b/loop.c @@ -311,7 +311,7 @@ int loop (void) { perror ("getline()"); exit (EXIT_FAILURE); } - if (!*code || *code == 'y') { + if (!*code || *code == 'y' || *code == 'Y') { printf ("Ok, starting registartion.\n"); } else { printf ("Then try again\n"); @@ -368,7 +368,7 @@ int loop (void) { rl_attempted_completion_function = (CPPFunction *) complete_text; rl_completion_entry_function = complete_none; - do_get_dialog_list (); + do_get_dialog_list_ex (); return main_loop (); } diff --git a/mtproto-client.c b/mtproto-client.c index 0752a5c..3fb5380 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -946,6 +946,41 @@ void work_update (struct connection *c UU, long long msg_id UU) { free (location); } break; + case CODE_update_new_geo_chat_message: + { + struct message *M = fetch_alloc_geo_message (); + unread_messages ++; + print_message (M); + update_prompt (); + } + break; + case CODE_update_new_encrypted_message: + { + logprintf ("New encrypted message. Unsupported yet\n"); + } + break; + case CODE_update_encryption: + { + logprintf ("New encrypted chat. Unsupported yet\n"); + } + break; + case CODE_update_encrypted_chat_typing: + { + logprintf ("Typing in encrypted chat. Unsupported yet\n"); + } + break; + case CODE_update_encrypted_messages_read: + { + fetch_int (); // chat_id + fetch_int (); // max_date + fetch_int (); // date + print_start (); + push_color (COLOR_YELLOW); + printf ("Messages in encrypted chat mark read \n"); + pop_color (); + print_end (); + } + break; default: logprintf ("Unknown update type %08x\n", op); } diff --git a/mtproto-common.h b/mtproto-common.h index 02a920e..1b93d31 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -377,4 +377,8 @@ int pad_aes_decrypt (char *from, int from_len, char *to, int size); static inline void hexdump_in (void) { hexdump (in_ptr, in_end); } + +static inline void hexdump_out (void) { + hexdump (packet_buffer, packet_ptr); +} #endif diff --git a/queries.c b/queries.c index 5db981e..ee3c985 100644 --- a/queries.c +++ b/queries.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "include.h" #include "mtproto-client.h" @@ -35,6 +36,7 @@ #include "loop.h" #include "structures.h" #include "interface.h" +#include "net.h" char *get_downloads_directory (void); int verbosity; @@ -280,7 +282,7 @@ int help_get_config_on_answer (struct query *q UU) { unsigned test_mode = fetch_int (); assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false); - assert (test_mode == CODE_bool_false); + assert (test_mode == CODE_bool_false || test_mode == CODE_bool_true); int this_dc = fetch_int (); if (verbosity) { logprintf ( "this_dc = %d\n", this_dc); @@ -325,7 +327,7 @@ void do_help_get_config (void) { char *phone_code_hash; int send_code_on_answer (struct query *q UU) { assert (fetch_int () == CODE_auth_sent_code); - assert (fetch_bool ()); + fetch_bool (); int l = prefetch_strlen (); char *s = fetch_str (l); if (phone_code_hash) { @@ -338,9 +340,13 @@ int send_code_on_answer (struct query *q UU) { int send_code_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'; want_dc_num = i; + } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { + int i = error[s2] - '0'; + want_dc_num = i; } else { logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); assert (0); @@ -364,9 +370,11 @@ int config_got (void) { char *suser; extern int dc_working_num; void do_send_code (const char *user) { + logprintf ("sending code\n"); suser = strdup (user); want_dc_num = 0; clear_packet (); + out_int (CODE_invoke_with_layer6); out_int (CODE_auth_send_code); out_string (user); out_int (0); @@ -374,6 +382,7 @@ void do_send_code (const char *user) { out_string (TG_APP_HASH); out_string ("en"); + logprintf ("send_code: dc_num = %d\n", dc_working_num); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); if (want_dc_num == -1) { return; } @@ -383,8 +392,10 @@ void do_send_code (const char *user) { dc_create_session (DC_working); } dc_working_num = want_dc_num; + logprintf ("send_code: dc_num = %d\n", dc_working_num); want_dc_num = 0; clear_packet (); + out_int (CODE_invoke_with_layer6); out_int (CODE_auth_send_code); out_string (user); out_int (0); @@ -420,7 +431,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error DC_working = DC_list[i]; write_auth_file (); check_phone_result = 1; - } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s)) { + } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { int i = error[s2] - '0'; assert (DC_list[i]); dc_working_num = i; @@ -746,6 +757,7 @@ void do_get_history (peer_id_t id, int limit) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, (void *)*(long *)&id); } + int get_dialogs_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); @@ -823,6 +835,34 @@ void do_get_dialog_list (void) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); } +int allow_send_linux_version = 1; +void do_get_dialog_list_ex (void) { + clear_packet (); + out_int (CODE_invoke_with_layer9); + out_int (CODE_init_connection); + out_int (TG_APP_ID); + if (allow_send_linux_version) { + struct utsname st; + uname (&st); + out_string (st.machine); + static char buf[1000000]; + sprintf (buf, "%s %s %s", st.sysname, st.release, st.version); + out_string (buf); + out_string (TG_VERSION " (build " TG_BUILD ")"); + out_string ("En"); + } else { + out_string ("A"); + out_string ("L"); + out_string ("T"); + out_string ("en"); + } + out_int (CODE_messages_get_dialogs); + out_int (0); + out_int (0); + out_int (100); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); +} + struct send_file { int fd; long long size; diff --git a/queries.h b/queries.h index 5c2abf7..8a9cb9b 100644 --- a/queries.h +++ b/queries.h @@ -73,6 +73,7 @@ void do_send_message (peer_id_t id, const char *msg, int len); void do_send_text (peer_id_t id, char *file); void do_get_history (peer_id_t id, int limit); void do_get_dialog_list (void); +void do_get_dialog_list_ex (void); void do_send_photo (int type, peer_id_t to_id, char *file_name); void do_get_chat_info (peer_id_t id); void do_get_user_list_info_silent (int num, int *list); diff --git a/structures.c b/structures.c index 366603c..ade8162 100644 --- a/structures.c +++ b/structures.c @@ -179,7 +179,7 @@ void fetch_user (struct user *U) { } fetch_user_status (&U->status); if (x == CODE_user_self) { - assert (fetch_int () == (int)CODE_bool_false); + fetch_bool (); } if (x == CODE_user_contact) { U->flags |= FLAG_USER_CONTACT; @@ -532,6 +532,27 @@ void fetch_message (struct message *M) { } } +void fetch_geo_message (struct message *M) { + memset (M, 0, sizeof (*M)); + unsigned x = fetch_int (); + assert (x == CODE_geo_chat_message_empty || x == CODE_geo_chat_message || x == CODE_geo_chat_message_service); + M->to_id = MK_GEO_CHAT (fetch_int ()); + M->id = fetch_int (); + if (x == CODE_geo_chat_message_empty) { + M->flags |= 1; + return; + } + M->from_id = MK_USER (fetch_int ()); + M->date = fetch_int (); + if (x == CODE_geo_chat_message_service) { + M->service = 1; + fetch_message_action (&M->action); + } else { + M->message = fetch_str_dup (); + fetch_message_media (&M->media); + } +} + #define id_cmp(a,b) ((a)->id - (b)->id) #define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) @@ -711,6 +732,26 @@ struct message *fetch_alloc_message (void) { } } +struct message *fetch_alloc_geo_message (void) { + struct message *M = malloc (sizeof (*M)); + fetch_geo_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 message *fetch_alloc_message_short (void) { struct message *M = malloc (sizeof (*M)); fetch_message_short (M); diff --git a/structures.h b/structures.h index 20b36c9..462e4d8 100644 --- a/structures.h +++ b/structures.h @@ -198,6 +198,7 @@ struct user *fetch_alloc_user_full (void); struct chat *fetch_alloc_chat (void); struct chat *fetch_alloc_chat_full (void); struct message *fetch_alloc_message (void); +struct message *fetch_alloc_geo_message (void); struct message *fetch_alloc_message_short (void); struct message *fetch_alloc_message_short_chat (void); peer_id_t fetch_peer_id (void); @@ -215,15 +216,20 @@ void fetch_photo (struct photo *P); #define PEER_USER 1 #define PEER_CHAT 2 +#define PEER_GEO_CHAT 3 #define PEER_UNKNOWN 0 #define MK_USER(id) set_peer_id (PEER_USER,id) #define MK_CHAT(id) set_peer_id (PEER_CHAT,id) +#define MK_GEO_CHAT(id) set_peer_id (PEER_GEO_CHAT,id) static inline int get_peer_type (peer_id_t id) { if (id.id > 0) { return PEER_USER; } + if (id.id < -1000000000) { + return PEER_GEO_CHAT; + } if (id.id < 0) { return PEER_CHAT; } @@ -236,6 +242,8 @@ static inline int get_peer_id (peer_id_t id) { return id.id; case PEER_CHAT: return -id.id; + case PEER_GEO_CHAT: + return -id.id - 1000000000; default: return 0; } @@ -250,6 +258,9 @@ static inline peer_id_t set_peer_id (int type, int id) { case PEER_CHAT: ID.id = -id; return ID; + case PEER_GEO_CHAT: + ID.id = -id - 1000000000; + return ID; default: assert (0); return ID; From d0224836585887706c2b17d3e03d6f224e1b2f52 Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 2 Nov 2013 02:24:59 +0400 Subject: [PATCH 069/465] Fixed compilation error --- net.h | 1 + queries.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/net.h b/net.h index ff9b4e5..e9a4aa2 100644 --- a/net.h +++ b/net.h @@ -26,6 +26,7 @@ struct dc; //#define TG_SERVER "95.142.192.66" #define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" #define TG_APP_ID 2899 +#define TG_BUILD "200" #define TG_VERSION "0.01-beta" diff --git a/queries.c b/queries.c index ee3c985..5e1b087 100644 --- a/queries.c +++ b/queries.c @@ -851,9 +851,9 @@ void do_get_dialog_list_ex (void) { out_string (TG_VERSION " (build " TG_BUILD ")"); out_string ("En"); } else { - out_string ("A"); - out_string ("L"); - out_string ("T"); + out_string ("x86"); + out_string ("Linux"); + out_string (TG_VERSION); out_string ("en"); } out_int (CODE_messages_get_dialogs); From aa40f0caab923ef4b2a86b9631a113a81d2fa51a Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 2 Nov 2013 14:14:30 +0400 Subject: [PATCH 070/465] Some changes to add encrypted chat in nearest future --- interface.c | 8 ++-- structures.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++-- structures.h | 37 +++++++++++++-- 3 files changed, 161 insertions(+), 11 deletions(-) diff --git a/interface.c b/interface.c index 4ee41d6..5d1fb53 100644 --- a/interface.c +++ b/interface.c @@ -942,7 +942,7 @@ void print_service_message (struct message *M) { push_color (COLOR_MAGENTA); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); @@ -1002,7 +1002,7 @@ void print_message (struct message *M) { if (M->out) { push_color (COLOR_GREEN); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); @@ -1017,7 +1017,7 @@ void print_message (struct message *M) { } else { push_color (COLOR_BLUE); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); @@ -1033,7 +1033,7 @@ void print_message (struct message *M) { } else { push_color (COLOR_MAGENTA); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); diff --git a/structures.c b/structures.c index ade8162..e821658 100644 --- a/structures.c +++ b/structures.c @@ -23,6 +23,12 @@ #include "telegram.h" #include "tree.h" #include "loop.h" +#include +#include +#include + +#define sha1 SHA1 + int verbosity; peer_t *Peers[MAX_USER_NUM]; @@ -553,7 +559,100 @@ void fetch_geo_message (struct message *M) { } } -#define id_cmp(a,b) ((a)->id - (b)->id) +int *decr_ptr; +int *decr_end; + +int decrypt_encrypted_message (struct secret_chat *E) { + int *msg_key = decr_ptr; + decr_ptr += 4; + assert (decr_ptr < decr_end); + static unsigned char sha1a_buffer[20]; + static unsigned char sha1b_buffer[20]; + static unsigned char sha1c_buffer[20]; + static unsigned char sha1d_buffer[20]; + + static unsigned char buf[64]; + memcpy (buf, msg_key, 16); + memcpy (buf + 16, E->key, 32); + sha1 (buf, 48, sha1a_buffer); + + memcpy (buf, E->key + 8, 16); + memcpy (buf + 16, msg_key, 16); + memcpy (buf + 32, E->key + 12, 16); + sha1 (buf, 48, sha1b_buffer); + + memcpy (buf, E->key + 16, 32); + memcpy (buf + 32, msg_key, 16); + sha1 (buf, 48, sha1c_buffer); + + memcpy (buf, msg_key, 16); + memcpy (buf + 16, E->key + 24, 32); + sha1 (buf, 48, sha1d_buffer); + + static unsigned char iv[32]; + memcpy (iv, sha1a_buffer + 0, 8); + memcpy (iv + 8, sha1b_buffer + 8, 12); + memcpy (iv + 20, sha1c_buffer + 4, 12); + + static unsigned char key[32]; + memcpy (key, sha1a_buffer + 8, 12); + memcpy (key + 12, sha1b_buffer + 0, 8); + memcpy (key + 20, sha1c_buffer + 16, 4); + memcpy (key + 24, sha1d_buffer + 0, 8); + + AES_KEY aes_key; + AES_set_decrypt_key (key, 256, &aes_key); + AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); + + sha1 ((void *)decr_ptr, 4 * (decr_end - decr_ptr), sha1a_buffer); + + if (memcmp (sha1a_buffer, msg_key, 16)) { + logprintf ("Sha1 mismatch\n"); + return -1; + } + return 0; +} + +void fetch_encrypted_message (struct message *M) { + memset (M, 0, sizeof (*M)); + unsigned x = fetch_int (); + assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service); + peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); + M->id = fetch_long (); + peer_t *P = user_chat_get (chat); + if (!P) { + logprintf ("Encrypted message to unknown chat. Dropping\n"); + } + M->date = fetch_int (); + + int len = prefetch_strlen (); + assert (!(len & 15)); + decr_ptr = (void *)fetch_str (len); + decr_end = in_ptr; + if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) { + in_ptr = decr_ptr; + unsigned x = fetch_int (); + if (x == CODE_decrypted_message_layer) { + int layer = fetch_int (); + assert (layer >= 0); + x = fetch_int (); + } + assert (x == CODE_decrypted_message); + assert (M->id = fetch_long ()); + int l = prefetch_strlen (); + fetch_str (l); // random_bytes + M->from_id = MK_USER (fetch_int ()); + M->date = fetch_int (); + M->message = fetch_str_dup (); + } +} + +static int id_cmp (struct message *M1, struct message *M2) { + if (M1->id < M2->id) { return -1; } + else if (M1->id > M2->id) { return 1; } + else { return 0; } +} + #define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) DEFINE_TREE(peer,peer_t *,peer_cmp,0) @@ -752,6 +851,26 @@ struct message *fetch_alloc_geo_message (void) { } } +struct message *fetch_alloc_encrypted_message (void) { + struct message *M = malloc (sizeof (*M)); + fetch_encrypted_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 message *fetch_alloc_message_short (void) { struct message *M = malloc (sizeof (*M)); fetch_message_short (M); @@ -776,7 +895,7 @@ struct message *fetch_alloc_message_short_chat (void) { struct message *M = malloc (sizeof (*M)); fetch_message_short_chat (M); if (verbosity >= 2) { - logprintf ("Read message with id %d\n", M->id); + logprintf ("Read message with id %lld\n", M->id); } struct message *M1 = tree_lookup_message (message_tree, M); messages_allocated ++; @@ -854,13 +973,13 @@ peer_t *user_chat_get (peer_id_t id) { return tree_lookup_peer (peer_tree, &U); } -struct message *message_get (int id) { +struct message *message_get (long long id) { struct message M; M.id = id; return tree_lookup_message (message_tree, &M); } -void update_message_id (struct message *M, int id) { +void update_message_id (struct message *M, long long id) { message_tree = tree_delete_message (message_tree, M); M->id = id; message_tree = tree_insert_message (message_tree, M, lrand48 ()); diff --git a/structures.h b/structures.h index 462e4d8..8e5f5e1 100644 --- a/structures.h +++ b/structures.h @@ -111,6 +111,26 @@ struct chat { int admin_id; }; +enum secret_chat_state { + sc_none, + sc_sent_request, + sc_ok, + sc_bad +}; + +struct secret_chat { + peer_id_t id; + int flags; + char *print_name; + struct file_location photo_big; + struct file_location photo_small; + struct photo photo; + + enum secret_chat_state state; + int key[64]; + long long key_fingerprint; +}; + typedef union peer { struct { peer_id_t id; @@ -122,6 +142,7 @@ typedef union peer { }; struct user user; struct chat chat; + struct secret_chat encr_chat; } peer_t; struct video { @@ -170,7 +191,7 @@ struct message_media { struct message { struct message *next_use, *prev_use; - int id; + long long id; int flags; peer_id_t fwd_from_id; int fwd_date; @@ -208,8 +229,8 @@ void free_chat (struct chat *U); int print_stat (char *s, int len); peer_t *user_chat_get (peer_id_t id); -struct message *message_get (int id); -void update_message_id (struct message *M, int id); +struct message *message_get (long long id); +void update_message_id (struct message *M, long long id); void message_insert (struct message *M); void free_photo (struct photo *P); void fetch_photo (struct photo *P); @@ -217,13 +238,18 @@ void fetch_photo (struct photo *P); #define PEER_USER 1 #define PEER_CHAT 2 #define PEER_GEO_CHAT 3 +#define PEER_ENCR_CHAT 4 #define PEER_UNKNOWN 0 #define MK_USER(id) set_peer_id (PEER_USER,id) #define MK_CHAT(id) set_peer_id (PEER_CHAT,id) #define MK_GEO_CHAT(id) set_peer_id (PEER_GEO_CHAT,id) +#define MK_ENCR_CHAT(id) set_peer_id (PEER_ENCR_CHAT,id) static inline int get_peer_type (peer_id_t id) { + if (id.id > 1000000000) { + return PEER_ENCR_CHAT; + } if (id.id > 0) { return PEER_USER; } @@ -244,6 +270,8 @@ static inline int get_peer_id (peer_id_t id) { return -id.id; case PEER_GEO_CHAT: return -id.id - 1000000000; + case PEER_ENCR_CHAT: + return id.id - 1000000000; default: return 0; } @@ -261,6 +289,9 @@ static inline peer_id_t set_peer_id (int type, int id) { case PEER_GEO_CHAT: ID.id = -id - 1000000000; return ID; + case PEER_ENCR_CHAT: + ID.id = id + 1000000000; + return ID; default: assert (0); return ID; From 05f9d3269807984491e9549ef6414369a33cabca Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 2 Nov 2013 21:01:22 +0400 Subject: [PATCH 071/465] Some code related to encrypted chat. Nothing works yet, but I believe it would work in the nearest future --- interface.c | 20 ++++++ interface.h | 2 + mtproto-client.c | 62 ++++++++++++++-- structures.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++- structures.h | 53 +++++++++++++- 5 files changed, 310 insertions(+), 8 deletions(-) diff --git a/interface.c b/interface.c index 5d1fb53..95f1558 100644 --- a/interface.c +++ b/interface.c @@ -919,6 +919,26 @@ void print_chat_name (peer_id_t id, peer_t *C) { pop_color (); } +void print_encr_chat_name (peer_id_t id, peer_t *C) { + push_color (COLOR_MAGENTA); + if (!C) { + printf ("encr_chat#%d", get_peer_id (id)); + } else { + printf ("%s", C->print_name); + } + pop_color (); +} + +void print_encr_chat_name_full (peer_id_t id, peer_t *C) { + push_color (COLOR_MAGENTA); + if (!C) { + printf ("encr_chat#%d", get_peer_id (id)); + } else { + printf ("%s", C->print_name); + } + pop_color (); +} + static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; void print_date (long t) { struct tm *tm = localtime (&t); diff --git a/interface.h b/interface.h index 6a59bbc..b529762 100644 --- a/interface.h +++ b/interface.h @@ -45,6 +45,8 @@ union peer; void print_message (struct message *M); void print_chat_name (peer_id_t id, union peer *C); void print_user_name (peer_id_t id, union peer *U); +void print_encr_chat_name_full (peer_id_t id, peer_t *C); +void print_encr_chat_name (peer_id_t id, peer_t *C); //void print_media (struct message_media *M); void pop_color (void); void push_color (const char *color); diff --git a/mtproto-client.c b/mtproto-client.c index 3fb5380..7152a40 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -956,27 +956,79 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_new_encrypted_message: { - logprintf ("New encrypted message. Unsupported yet\n"); + struct message *M = fetch_alloc_encrypted_message (); + unread_messages ++; + print_message (M); + update_prompt (); + fetch_qts (); } break; case CODE_update_encryption: { - logprintf ("New encrypted chat. Unsupported yet\n"); + struct secret_chat *E = fetch_alloc_encrypted_chat (); + print_start (); + push_color (COLOR_YELLOW); + switch (E->state) { + case sc_none: + assert (0); + break; + case sc_waiting: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in wait state\n"); + break; + case sc_request: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in request state. Sending request ok\n"); + break; + case sc_ok: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in ok state\n"); + break; + case sc_deleted: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in deleted state\n"); + break; + } + /*if (E->state == state_requested) { + do_accept_encr_chat_request (E); + }*/ + fetch_int (); // date } break; case CODE_update_encrypted_chat_typing: { - logprintf ("Typing in encrypted chat. Unsupported yet\n"); + peer_id_t id = MK_ENCR_CHAT (fetch_int ()); + peer_t *P = user_chat_get (id); + print_start (); + push_color (COLOR_YELLOW); + if (P) { + printf ("User "); + peer_id_t user_id = MK_USER (P->encr_chat.user_id); + print_user_name (user_id, user_chat_get (user_id)); + printf (" typing in secret chat "); + print_encr_chat_name (id, P); + printf ("\n"); + } else { + printf ("Some user is typing in unknown secret chat\n"); + } + pop_color (); + print_end (); } break; case CODE_update_encrypted_messages_read: { - fetch_int (); // chat_id + peer_id_t id = MK_ENCR_CHAT (fetch_int ()); // chat_id fetch_int (); // max_date fetch_int (); // date print_start (); push_color (COLOR_YELLOW); - printf ("Messages in encrypted chat mark read \n"); + printf ("Messages in encrypted chat "); + print_encr_chat_name_full (id, user_chat_get (id)); + printf (" marked read \n"); pop_color (); print_end (); } diff --git a/structures.c b/structures.c index e821658..89055e6 100644 --- a/structures.c +++ b/structures.c @@ -192,6 +192,55 @@ void fetch_user (struct user *U) { } } +void fetch_encrypted_chat (struct secret_chat *U) { + unsigned x = fetch_int (); + assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); + U->id = MK_ENCR_CHAT (fetch_int ()); + U->flags &= ~(FLAG_EMPTY | FLAG_DELETED); + if (x == CODE_encrypted_chat_empty) { + U->state = sc_none; + U->flags |= FLAG_EMPTY; + return; + } + if (x == CODE_encrypted_chat_discarded) { + U->state = sc_deleted; + U->flags |= FLAG_DELETED; + return; + } + U->access_hash = fetch_long (); + U->date = fetch_int (); + U->admin_id = fetch_int (); + U->user_id = fetch_int () + U->admin_id - our_id; + if (x == CODE_encrypted_chat_waiting) { + U->state = sc_waiting; + } else if (x == CODE_encrypted_chat_requested) { + U->state = sc_request; + if (!U->g_key) { + U->g_key = malloc (256); + } + if (!U->nonce) { + U->nonce = malloc (256); + } + assert (prefetch_strlen () == 256); + memcpy (U->g_key, fetch_str (256), 256); + assert (prefetch_strlen () == 256); + memcpy (U->nonce, fetch_str (256), 256); + } else { + U->state = sc_ok; + if (!U->g_key) { + U->g_key = malloc (256); + } + if (!U->nonce) { + U->nonce = malloc (256); + } + assert (prefetch_strlen () == 256); + memcpy (U->g_key, fetch_str (256), 256); + assert (prefetch_strlen () == 256); + memcpy (U->nonce, fetch_str (256), 256); + U->key_fingerprint = fetch_long (); + } +} + void fetch_notify_settings (void); void fetch_user_full (struct user *U) { assert (fetch_int () == CODE_user_full); @@ -501,6 +550,87 @@ void fetch_message_media (struct message_media *M) { } } +void fetch_message_media_encrypted (struct message_media *M) { + memset (M, 0, sizeof (*M)); + unsigned x = fetch_int (); + int l; + switch (M->type) { + case CODE_decrypted_message_media_empty: + M->type = CODE_message_media_empty; + break; + case CODE_decrypted_message_media_photo: + M->type = x; + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_int (); // thumb_w + fetch_int (); // thumb_h + M->encr_photo.w = fetch_int (); + M->encr_photo.h = fetch_int (); + M->encr_photo.size = fetch_int (); + l = fetch_int (); + assert (l > 0); + M->encr_photo.key = malloc (l); + memcpy (M->encr_photo.key, fetch_str (l), l); + + l = fetch_int (); + assert (l > 0); + M->encr_photo.iv = malloc (l); + memcpy (M->encr_photo.iv, fetch_str (l), l); + break; + case CODE_decrypted_message_media_video: + M->type = x; + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_int (); // thumb_w + fetch_int (); // thumb_h + M->encr_video.w = fetch_int (); + M->encr_video.h = fetch_int (); + M->encr_video.size = fetch_int (); + M->encr_video.duration = fetch_int (); + l = fetch_int (); + assert (l > 0); + M->encr_video.key = malloc (l); + memcpy (M->encr_video.key, fetch_str (l), l); + + l = fetch_int (); + assert (l > 0); + M->encr_video.iv = malloc (l); + memcpy (M->encr_video.iv, fetch_str (l), l); + break; +/* case CODE_decrypted_message_media_file: + M->type = x; + M->encr_file.filename = fetch_str_dup (); + l = prefetch_strlen (); + fetch_str (l); // thumb + l = fetch_int (); + assert (l > 0); + M->encr_file.key = malloc (l); + memcpy (M->encr_file.key, fetch_str (l), l); + + l = fetch_int (); + assert (l > 0); + M->encr_file.iv = malloc (l); + memcpy (M->encr_file.iv, fetch_str (l), l); + break; + */ + case CODE_decrypted_message_media_geo_point: + M->geo.longitude = fetch_double (); + M->geo.latitude = fetch_double (); + M->type = CODE_message_media_geo; + break; + case CODE_decrypted_message_media_contact: + M->type = 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; + default: + logprintf ("type = 0x%08x\n", M->type); + assert (0); + } +} + peer_id_t fetch_peer_id (void) { unsigned x =fetch_int (); if (x == CODE_peer_user) { @@ -629,6 +759,7 @@ void fetch_encrypted_message (struct message *M) { assert (!(len & 15)); decr_ptr = (void *)fetch_str (len); decr_end = in_ptr; + M->flags |= FLAG_ENCRYPTED; if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) { in_ptr = decr_ptr; unsigned x = fetch_int (); @@ -643,7 +774,29 @@ void fetch_encrypted_message (struct message *M) { fetch_str (l); // random_bytes M->from_id = MK_USER (fetch_int ()); M->date = fetch_int (); - M->message = fetch_str_dup (); + if (x == CODE_decrypted_message) { + M->message = fetch_str_dup (); + fetch_encrypted_message_file (&M->media); + } else { + assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l); + P->encr_chat.ttl = fetch_int (); + } + } +} + +void fetch_encrypted_message_file (struct message_media *M) { + unsigned x = fetch_int (); + assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); + if (x == CODE_encrypted_file_empty) { + assert (M->type != CODE_decrypted_message_media_photo && M->type != CODE_decrypted_message_media_video); + } else { + assert (M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video); + M->encr_photo.id = fetch_long (); + M->encr_photo.access_hash = fetch_long (); + assert (M->encr_photo.size == fetch_int ()); + M->encr_photo.dc_id = fetch_int (); + M->encr_photo.key_fingerprint = fetch_int (); + } } @@ -689,6 +842,24 @@ struct user *fetch_alloc_user (void) { } } +struct secret_chat *fetch_alloc_encrypted_chat (void) { + int data[2]; + prefetch_data (data, 8); + peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); + if (U) { + fetch_encrypted_chat (&U->encr_chat); + return &U->encr_chat; + } else { + chats_allocated ++; + U = malloc (sizeof (*U)); + memset (U, 0, sizeof (*U)); + fetch_encrypted_chat (&U->encr_chat); + peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + Peers[(chat_num ++) + user_num] = U; + return &U->encr_chat; + } +} + struct user *fetch_alloc_user_full (void) { int data[3]; prefetch_data (data, 12); @@ -759,6 +930,14 @@ void free_message_media (struct message_media *M) { case CODE_message_media_unsupported: free (M->data); return; + case CODE_decrypted_message_media_photo: + free (M->encr_photo.key); + free (M->encr_photo.iv); + return; + case CODE_decrypted_message_media_video: + free (M->encr_video.key); + free (M->encr_video.iv); + return; default: logprintf ("%08x\n", M->type); assert (0); diff --git a/structures.h b/structures.h index 8e5f5e1..e703b69 100644 --- a/structures.h +++ b/structures.h @@ -35,6 +35,7 @@ typedef struct { int id; } peer_id_t; #define FLAG_CHAT_IN_CHAT 128 +#define FLAG_ENCRYPTED 4096 struct file_location { int dc; @@ -68,6 +69,40 @@ struct photo { struct photo_size *sizes; }; +struct encr_photo { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + + int w; + int h; + unsigned char *key; + unsigned char *iv; +}; + +struct encr_video { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + + int w; + int h; + int duration; + unsigned char *key; + unsigned char *iv; +}; + +struct encr_file { + char *filename; + unsigned char *key; + unsigned char *iv; +}; + + struct user_status { int online; int when; @@ -113,9 +148,10 @@ struct chat { enum secret_chat_state { sc_none, - sc_sent_request, + sc_waiting, + sc_request, sc_ok, - sc_bad + sc_deleted }; struct secret_chat { @@ -125,6 +161,13 @@ struct secret_chat { struct file_location photo_big; struct file_location photo_small; struct photo photo; + int user_id; + int admin_id; + int date; + int ttl; + long long access_hash; + unsigned char *g_key; + unsigned char *nonce; enum secret_chat_state state; int key[64]; @@ -185,6 +228,9 @@ struct message_media { char *last_name; int user_id; }; + struct encr_photo encr_photo; + struct encr_video encr_video; + struct encr_file encr_file; void *data; }; }; @@ -218,10 +264,13 @@ struct user *fetch_alloc_user (void); struct user *fetch_alloc_user_full (void); struct chat *fetch_alloc_chat (void); struct chat *fetch_alloc_chat_full (void); +struct secret_chat *fetch_alloc_encrypted_chat (void); struct message *fetch_alloc_message (void); struct message *fetch_alloc_geo_message (void); struct message *fetch_alloc_message_short (void); struct message *fetch_alloc_message_short_chat (void); +struct message *fetch_alloc_encrypted_message (void); +void fetch_encrypted_message_file (struct message_media *M); peer_id_t fetch_peer_id (void); void free_user (struct user *U); From 180cfd22f2db1f8c23b3a9a9ed15910e61bd3b47 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 4 Nov 2013 21:34:27 +0400 Subject: [PATCH 072/465] Partial support for encrypted chats. --- interface.c | 102 ++++++---- interface.h | 2 +- loop.c | 156 +++++++++++++++- loop.h | 2 + main.c | 20 ++ mtproto-client.c | 54 +++++- mtproto-client.h | 1 + mtproto-common.c | 3 + mtproto-common.h | 8 +- net.h | 5 +- queries.c | 470 +++++++++++++++++++++++++++++++++++++++++++++-- queries.h | 3 + structures.c | 434 ++++++++++++++++++++++++++++++------------- structures.h | 55 ++---- 14 files changed, 1082 insertions(+), 233 deletions(-) diff --git a/interface.c b/interface.c index 95f1558..536d3bc 100644 --- a/interface.c +++ b/interface.c @@ -48,9 +48,8 @@ long long cur_downloading_bytes; long long cur_downloaded_bytes; char *line_ptr; -extern int user_num; -extern int chat_num; extern peer_t *Peers[]; +extern int peer_num; int is_same_word (const char *s, size_t l, const char *word) { return s && word && strlen (word) == l && !memcmp (s, word, l); @@ -106,10 +105,10 @@ peer_id_t next_token_user (void) { } int index = 0; - while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) { + while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) { index ++; } - if (index < user_num + chat_num) { + if (index < peer_num) { return Peers[index]->id; } else { return PEER_NOT_FOUND; @@ -130,10 +129,10 @@ peer_id_t next_token_chat (void) { } int index = 0; - while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { + while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { index ++; } - if (index < user_num + chat_num) { + if (index < peer_num) { return Peers[index]->id; } else { return PEER_NOT_FOUND; @@ -161,10 +160,10 @@ peer_id_t next_token_peer (void) { } int index = 0; - while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name))) { + while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name))) { index ++; } - if (index < user_num + chat_num) { + if (index < peer_num) { return Peers[index]->id; } else { return PEER_NOT_FOUND; @@ -232,6 +231,7 @@ char *commands[] = { "rename_contact", "show_license", "search", + "mark_read", 0 }; int commands_flags[] = { @@ -258,6 +258,7 @@ int commands_flags[] = { 071, 07, 072, + 072, }; int get_complete_mode (void) { @@ -297,10 +298,10 @@ int get_complete_mode (void) { int complete_user_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) || get_peer_type (Peers[index]->id) != PEER_USER)) { + while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) { index ++; } - if (index < user_num + chat_num) { + if (index < peer_num) { *R = strdup (Peers[index]->print_name); return index; } else { @@ -310,10 +311,10 @@ int complete_user_list (int index, const char *text, int len, char **R) { int complete_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) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { + while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { index ++; } - if (index < user_num + chat_num) { + if (index < peer_num) { *R = strdup (Peers[index]->print_name); return index; } else { @@ -323,10 +324,10 @@ int complete_chat_list (int index, const char *text, int len, char **R) { 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))) { + while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { index ++; } - if (index < user_num + chat_num) { + if (index < peer_num) { *R = strdup (Peers[index]->print_name); return index; } else { @@ -663,6 +664,8 @@ void interpreter (char *line UU) { "load_photo/load_video/load_video_thumb - loads photo/video to download dir\n" "view_photo/view_video/view_video_thumb - loads photo/video to download dir and starts system default viewer\n" "show_license - prints contents of GPLv2\n" + "search pattern - searches pattern in messages with peer\n" + "mark_read - mark read all received messages with peer\n" ); pop_color (); rl_on_new_line (); @@ -685,6 +688,9 @@ void interpreter (char *line UU) { RET; } do_msg_search (id, from, to, limit, s); + } else if (IS_WORD ("mark_read")) { + GET_PEER; + do_mark_read (id); } #undef IS_WORD #undef RET @@ -796,30 +802,6 @@ void logprintf (const char *format, ...) { } } -const char *message_media_type_str (struct message_media *M) { - static char buf[1000]; - switch (M->type) { - case CODE_message_media_empty: - return ""; - case CODE_message_media_photo: - return "[photo]"; - case CODE_message_media_video: - return "[video]"; - case CODE_message_media_geo: - sprintf (buf, "[geo] https://maps.google.com/maps?ll=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude); - return buf; - case CODE_message_media_contact: - snprintf (buf, 999, "[contact] " COLOR_RED "%s %s" COLOR_NORMAL " %s", M->first_name, M->last_name, M->phone); - return buf; - case CODE_message_media_unsupported: - return "[unsupported]"; - default: - assert (0); - return ""; - - } -} - int color_stack_pos; const char *color_stack[10]; @@ -853,6 +835,12 @@ void print_media (struct message_media *M) { case CODE_message_media_video: printf ("[video]"); return; + case CODE_decrypted_message_media_photo: + printf ("[photo]"); + return; + case CODE_decrypted_message_media_video: + printf ("[video]"); + return; case CODE_message_media_geo: printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude); return; @@ -1009,6 +997,9 @@ peer_id_t last_from_id; peer_id_t last_to_id; void print_message (struct message *M) { + if (M->flags & (FLAG_EMPTY | FLAG_DELETED)) { + return; + } if (M->service) { print_service_message (M); return; @@ -1050,7 +1041,42 @@ void print_message (struct message *M) { printf (" »»» "); } } + } else if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { + peer_t *P = user_chat_get (M->to_id); + assert (P); + if (M->out) { + push_color (COLOR_GREEN); + if (msg_num_mode) { + printf ("%lld ", M->id); + } + print_date (M->date); + printf (" "); + push_color (COLOR_CYAN); + printf (" %s", P->print_name); + pop_color (); + if (M->unread) { + printf (" <<< "); + } else { + printf (" ««« "); + } + } else { + push_color (COLOR_BLUE); + if (msg_num_mode) { + printf ("%lld ", M->id); + } + print_date (M->date); + push_color (COLOR_CYAN); + printf (" %s", P->print_name); + pop_color (); + if (M->unread) { + printf (" >>> "); + } else { + printf (" »»» "); + } + } + } else { + assert (get_peer_type (M->to_id) == PEER_CHAT); push_color (COLOR_MAGENTA); if (msg_num_mode) { printf ("%lld ", M->id); diff --git a/interface.h b/interface.h index b529762..1a4bd32 100644 --- a/interface.h +++ b/interface.h @@ -28,7 +28,7 @@ #define COLOR_YELLOW "\033[33;1m" #define COLOR_BLUE "\033[34;1m" #define COLOR_MAGENTA "\033[35;1m" - +#define COLOR_CYAN "\033[36;1m" char *get_default_prompt (void); char *complete_none (const char *text, int state); diff --git a/loop.c b/loop.c index ea9c065..0e7add0 100644 --- a/loop.c +++ b/loop.c @@ -39,6 +39,7 @@ #include "mtproto-common.h" #include "queries.h" #include "telegram.h" +#include "loop.h" extern char *default_username; extern char *auth_token; @@ -59,6 +60,7 @@ void net_loop (int flags, int (*is_end)(void)) { cc ++; } + write_state_file (); int x = connections_make_poll_array (fds + cc, 101 - cc) + cc; double timer = next_timer_in (); if (timer > 1000) { timer = 1000; } @@ -116,6 +118,8 @@ struct dc *DC_working; int dc_working_num; int auth_state; char *get_auth_key_filename (void); +char *get_state_filename (void); +char *get_secret_chat_filename (void); int zero[512]; @@ -231,11 +235,157 @@ void read_auth_file (void) { } } +int pts, qts, seq, last_date; + +void read_state_file (void) { + int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600); + if (state_file_fd < 0) { + return; + } + int version, magic; + if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; } + if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; } + if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return; } + assert (version >= 0); + int x[4]; + if (read (state_file_fd, x, 16) < 16) { + close (state_file_fd); + return; + } + pts = x[0]; + qts = x[1]; + seq = x[2]; + last_date = x[3]; + close (state_file_fd); +} + +void write_state_file (void) { + static int wseq; + static int wpts; + static int wqts; + static int wdate; + if (wseq >= seq && wpts >= pts && wqts >= qts && wdate >= last_date) { return; } + int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600); + if (state_file_fd < 0) { + return; + } + int x[6]; + x[0] = STATE_FILE_MAGIC; + x[1] = 0; + x[2] = pts; + x[3] = qts; + x[4] = seq; + x[5] = last_date; + assert (write (state_file_fd, x, 24) == 24); + close (state_file_fd); + wseq = seq; wpts = pts; wqts = qts; wdate = last_date; +} + +extern peer_t *Peers[]; +extern int peer_num; + +void read_secret_chat_file (void) { + int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); + if (fd < 0) { + return; + } + int x[2]; + if (read (fd, x, 8) < 8) { + close (fd); return; + } + if (x[0] != (int)SECRET_CHAT_FILE_MAGIC) { close (fd); return; } + int version = x[1]; + assert (version >= 0); + int cc; + assert (read (fd, &cc, 4) == 4); + int i; + for (i = 0; i < cc; i++) { + peer_t *P = malloc (sizeof (*P)); + memset (P, 0, sizeof (*P)); + struct secret_chat *E = &P->encr_chat; + int t; + assert (read (fd, &t, 4) == 4); + P->id = MK_ENCR_CHAT (t); + assert (read (fd, &P->flags, 4) == 4); + assert (read (fd, &t, 4) == 4); + assert (t > 0); + P->print_name = malloc (t + 1); + assert (read (fd, P->print_name, t) == t); + P->print_name[t] = 0; + + assert (read (fd, &E->state, 4) == 4); + assert (read (fd, &E->user_id, 4) == 4); + assert (read (fd, &E->admin_id, 4) == 4); + assert (read (fd, &E->ttl, 4) == 4); + assert (read (fd, &E->access_hash, 8) == 8); + + if (E->state != sc_waiting) { + E->g_key = malloc (256); + assert (read (fd, E->g_key, 256) == 256); + } + E->nonce = malloc (256); + assert (read (fd, E->nonce, 256) == 256); + assert (read (fd, E->key, 256) == 256); + assert (read (fd, &E->key_fingerprint, 8) == 8); + insert_encrypted_chat (P); + } + close (fd); +} + +void write_secret_chat_file (void) { + int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); + if (fd < 0) { + return; + } + int x[2]; + x[0] = SECRET_CHAT_FILE_MAGIC; + x[1] = 0; + assert (write (fd, x, 8) == 8); + int i; + int cc = 0; + for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) { + if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) { + cc ++; + } + } + assert (write (fd, &cc, 4) == 4); + for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) { + if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) { + int t = get_peer_id (Peers[i]->id); + assert (write (fd, &t, 4) == 4); + t = Peers[i]->flags; + assert (write (fd, &t, 4) == 4); + t = strlen (Peers[i]->print_name); + assert (write (fd, &t, 4) == 4); + assert (write (fd, Peers[i]->print_name, t) == t); + + assert (write (fd, &Peers[i]->encr_chat.state, 4) == 4); + + assert (write (fd, &Peers[i]->encr_chat.user_id, 4) == 4); + assert (write (fd, &Peers[i]->encr_chat.admin_id, 4) == 4); + assert (write (fd, &Peers[i]->encr_chat.ttl, 4) == 4); + assert (write (fd, &Peers[i]->encr_chat.access_hash, 8) == 8); + if (Peers[i]->encr_chat.state != sc_waiting) { + assert (write (fd, Peers[i]->encr_chat.g_key, 256) == 256); + } + assert (write (fd, Peers[i]->encr_chat.nonce, 256) == 256); + assert (write (fd, Peers[i]->encr_chat.key, 256) == 256); + assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8); + } + } + close (fd); +} + extern int max_chat_size; int mcs (void) { return max_chat_size; } +extern int difference_got; +int dgot (void) { + return !difference_got; +} + int readline_active; int new_dc_num; int loop (void) { @@ -368,7 +518,11 @@ int loop (void) { rl_attempted_completion_function = (CPPFunction *) complete_text; rl_completion_entry_function = complete_none; - do_get_dialog_list_ex (); + read_state_file (); + read_secret_chat_file (); + do_get_difference (); + net_loop (0, dgot); + do_get_dialog_list (); return main_loop (); } diff --git a/loop.h b/loop.h index 2b14f33..6f7c7e4 100644 --- a/loop.h +++ b/loop.h @@ -21,4 +21,6 @@ int loop (void); void net_loop (int flags, int (*end)(void)); void write_auth_file (void); +void write_state_file (void); +void write_secret_chat_file (void); #endif diff --git a/main.c b/main.c index e49744f..0bd5580 100644 --- a/main.c +++ b/main.c @@ -41,6 +41,8 @@ #define CONFIG_DIRECTORY ".telegram/" #define CONFIG_FILE CONFIG_DIRECTORY "config" #define AUTH_KEY_FILE CONFIG_DIRECTORY "auth" +#define STATE_FILE CONFIG_DIRECTORY "state" +#define SECRET_CHAT_FILE CONFIG_DIRECTORY "secret" #define DOWNLOADS_DIRECTORY "downloads/" #define CONFIG_DIRECTORY_MODE 0700 @@ -130,6 +132,24 @@ char *get_auth_key_filename (void) { return auth_key_filename; } +char *get_state_filename (void) { + char *state_filename; + int length = strlen (get_home_directory ()) + strlen (STATE_FILE) + 2; + + state_filename = (char *) calloc (length, sizeof (char)); + sprintf (state_filename, "%s/" STATE_FILE, get_home_directory ()); + return state_filename; +} + +char *get_secret_chat_filename (void) { + char *secret_chat_filename; + int length = strlen (get_home_directory ()) + strlen (SECRET_CHAT_FILE) + 2; + + secret_chat_filename = (char *) calloc (length, sizeof (char)); + sprintf (secret_chat_filename, "%s/" SECRET_CHAT_FILE, get_home_directory ()); + return secret_chat_filename; +} + char *get_downloads_directory (void) { char *downloads_directory; diff --git a/mtproto-client.c b/mtproto-client.c index 7152a40..467d4a8 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -637,14 +637,18 @@ int unread_messages; int our_id; int pts; int qts; +int last_date; +int seq; void fetch_pts (void) { int p = fetch_int (); + if (p <= pts) { return; } if (p != pts + 1) { if (pts) { - logprintf ("Hole in pts p = %d, pts = %d\n", p, pts); + //logprintf ("Hole in pts p = %d, pts = %d\n", p, pts); // get difference should be here + pts = p; } else { pts = p; } @@ -655,10 +659,12 @@ void fetch_pts (void) { void fetch_qts (void) { int p = fetch_int (); + if (p <= qts) { return; } if (p != qts + 1) { if (qts) { - logprintf ("Hole in qts\n"); + //logprintf ("Hole in qts\n"); // get difference should be here + qts = p; } else { qts = p; } @@ -667,6 +673,24 @@ void fetch_qts (void) { } } +void fetch_date (void) { + int p = fetch_int (); + if (p > last_date) { + last_date = p; + } +} + +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 (); + seq = x; + } else if (x >= seq + 1) { + seq = x; + } +} + void work_update (struct connection *c UU, long long msg_id UU) { unsigned op = fetch_int (); switch (op) { @@ -993,9 +1017,11 @@ void work_update (struct connection *c UU, long long msg_id UU) { printf (" is now in deleted state\n"); break; } - /*if (E->state == state_requested) { + pop_color (); + print_end (); + if (E->state == sc_request) { do_accept_encr_chat_request (E); - }*/ + } fetch_int (); // date } break; @@ -1041,7 +1067,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { void work_update_short (struct connection *c, long long msg_id) { assert (fetch_int () == CODE_update_short); work_update (c, msg_id); - fetch_int (); // date + fetch_date (); } void work_updates (struct connection *c, long long msg_id) { @@ -1062,9 +1088,8 @@ void work_updates (struct connection *c, long long msg_id) { for (i = 0; i < n; i++) { fetch_alloc_chat (); } - fetch_int (); // date - fetch_int (); // seq - + fetch_date (); // date + fetch_seq (); // seq } void work_update_short_message (struct connection *c UU, long long msg_id UU) { @@ -1073,6 +1098,9 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) { unread_messages ++; print_message (M); update_prompt (); + if (M->date > last_date) { + last_date = M->date; + } } void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) { @@ -1081,6 +1109,9 @@ void work_update_short_chat_message (struct connection *c UU, long long msg_id U unread_messages ++; print_message (M); update_prompt (); + if (M->date > last_date) { + last_date = M->date; + } } void work_container (struct connection *c, long long msg_id UU) { @@ -1211,6 +1242,10 @@ void work_detained_info (struct connection *c UU, long long msg_id UU) { fetch_int (); // status } +void work_updates_to_long (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == (int)CODE_updates_too_long); + do_get_difference (); +} void rpc_execute_answer (struct connection *c, long long msg_id UU) { if (verbosity >= 5) { logprintf ("rpc_execute_answer: fd=%d\n", c->fd); @@ -1254,6 +1289,9 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_msg_detained_info: work_detained_info (c, msg_id); return; + case CODE_updates_too_long: + work_updates_to_long (c, msg_id); + return; } logprintf ( "Unknown message: \n"); hexdump_in (); diff --git a/mtproto-client.h b/mtproto-client.h index 3958b4e..9e44df2 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -23,4 +23,5 @@ void on_start (void); long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); void dc_authorize (struct dc *DC); +void work_update (struct connection *c, long long msg_id); #endif diff --git a/mtproto-common.c b/mtproto-common.c index 64f635a..201ab68 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -37,6 +37,9 @@ #include "mtproto-common.h" #include "interface.h" +int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr; +int *packet_buffer = __packet_buffer + 16; + long long rsa_encrypted_chunks, rsa_decrypted_chunks; BN_CTX *BN_ctx; diff --git a/mtproto-common.h b/mtproto-common.h index 1b93d31..94c97ac 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -83,6 +83,7 @@ #define MAX_MESSAGE_INTS 1048576 #define MAX_PROTO_MESSAGE_INTS 1048576 +#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix #pragma pack(push,4) struct encrypted_message { // unencrypted header @@ -219,8 +220,8 @@ void prng_seed (const char *password_filename, int password_length); int serialize_bignum (BIGNUM *b, char *buffer, int maxlen); long long compute_rsa_key_fingerprint (RSA *key); -#define PACKET_BUFFER_SIZE (16384 * 100) // temp fix -int packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr; +extern int *packet_buffer; +extern int *packet_ptr; static inline void out_ints (int *what, int len) { assert (packet_ptr + len <= packet_buffer + PACKET_BUFFER_SIZE); @@ -262,6 +263,9 @@ static inline void out_bignum (BIGNUM *n) { extern int *in_ptr, *in_end; void fetch_pts (void); +void fetch_qts (void); +void fetch_date (void); +void fetch_seq (void); static inline int prefetch_strlen (void) { if (in_ptr >= in_end) { return -1; diff --git a/net.h b/net.h index e9a4aa2..6061e7b 100644 --- a/net.h +++ b/net.h @@ -26,7 +26,7 @@ struct dc; //#define TG_SERVER "95.142.192.66" #define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" #define TG_APP_ID 2899 -#define TG_BUILD "200" +#define TG_BUILD "203" #define TG_VERSION "0.01-beta" @@ -79,6 +79,9 @@ struct dc { #define DC_SERIALIZED_MAGIC 0x64582faa #define DC_SERIALIZED_MAGIC_V2 0x94032abb +#define STATE_FILE_MAGIC 0x84217a0d +#define SECRET_CHAT_FILE_MAGIC 0xa9840add + struct dc_serialized { int magic; int port; diff --git a/queries.c b/queries.c index 5e1b087..1871edd 100644 --- a/queries.c +++ b/queries.c @@ -37,6 +37,12 @@ #include "structures.h" #include "interface.h" #include "net.h" +#include +#include +#include +#include + +#define sha1 SHA1 char *get_downloads_directory (void); int verbosity; @@ -276,6 +282,8 @@ int new_dc_num; extern struct dc *DC_list[]; extern struct dc *DC_working; +/* {{{ Get config */ + int help_get_config_on_answer (struct query *q UU) { assert (fetch_int () == CODE_config); fetch_int (); @@ -323,7 +331,9 @@ void do_help_get_config (void) { out_int (CODE_help_get_config); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0); } +/* }}} */ +/* {{{ Send code */ char *phone_code_hash; int send_code_on_answer (struct query *q UU) { assert (fetch_int () == CODE_auth_sent_code); @@ -407,8 +417,9 @@ void do_send_code (const char *user) { net_loop (0, code_is_sent); assert (want_dc_num == -1); } +/* }}} */ - +/* {{{ Check phone */ int check_phone_result; int cr_f (void) { return check_phone_result >= 0; @@ -460,7 +471,9 @@ int do_auth_check_phone (const char *user) { net_loop (0, cr_f); return check_phone_result; } +/* }}} */ +/* {{{ Nearest DC */ int nearest_dc_num; int nr_f (void) { return nearest_dc_num >= 0; @@ -497,7 +510,9 @@ int do_get_nearest_dc (void) { net_loop (0, nr_f); return nearest_dc_num; } +/* }}} */ +/* {{{ Sign in / Sign up */ int sign_in_ok; int sign_in_is_ok (void) { return sign_in_ok; @@ -554,7 +569,9 @@ int do_send_code_result_auth (const char *code, const char *first_name, const ch net_loop (0, sign_in_is_ok); return sign_in_ok; } +/* }}} */ +/* {{{ Get contacts */ extern char *user_list[]; int get_contacts_on_answer (struct query *q UU) { @@ -612,18 +629,106 @@ void do_update_contact_list (void) { out_string (""); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, 0); } +/* }}} */ +/* {{{ Encrypt decrypted */ +int *encr_extra; +int *encr_ptr; +int *encr_end; + +char *encrypt_decrypted_message (struct secret_chat *E) { + static int msg_key[4]; + static unsigned char sha1a_buffer[20]; + static unsigned char sha1b_buffer[20]; + static unsigned char sha1c_buffer[20]; + static unsigned char sha1d_buffer[20]; + int x = *(encr_ptr); + assert (x >= 0 && !(x & 3)); + sha1 ((void *)encr_ptr, 4 + x, sha1a_buffer); + memcpy (msg_key, sha1a_buffer + 4, 16); + + static unsigned char buf[64]; + memcpy (buf, msg_key, 16); + memcpy (buf + 16, E->key, 32); + sha1 (buf, 48, sha1a_buffer); + + memcpy (buf, E->key + 8, 16); + memcpy (buf + 16, msg_key, 16); + memcpy (buf + 32, E->key + 12, 16); + sha1 (buf, 48, sha1b_buffer); + + memcpy (buf, E->key + 16, 32); + memcpy (buf + 32, msg_key, 16); + sha1 (buf, 48, sha1c_buffer); + + memcpy (buf, msg_key, 16); + memcpy (buf + 16, E->key + 24, 32); + sha1 (buf, 48, sha1d_buffer); + + static unsigned char key[32]; + memcpy (key, sha1a_buffer + 0, 8); + memcpy (key + 8, sha1b_buffer + 8, 12); + memcpy (key + 20, sha1c_buffer + 4, 12); + + static unsigned char iv[32]; + memcpy (iv, sha1a_buffer + 8, 12); + memcpy (iv + 12, sha1b_buffer + 0, 8); + memcpy (iv + 20, sha1c_buffer + 16, 4); + memcpy (iv + 24, sha1d_buffer + 0, 8); + + AES_KEY aes_key; + AES_set_encrypt_key (key, 256, &aes_key); + AES_ige_encrypt ((void *)encr_ptr, (void *)encr_ptr, 4 * (encr_end - encr_ptr), &aes_key, iv, 1); + + return (void *)msg_key; +} + +void encr_start (void) { + encr_extra = packet_ptr; + packet_ptr += 1; // str len + packet_ptr += 2; // fingerprint + packet_ptr += 4; // msg_key + packet_ptr += 1; // len +} + + +void encr_finish (struct secret_chat *E) { + int l = packet_ptr - (encr_extra + 8); + while (((packet_ptr - encr_extra) - 3) & 3) { + out_int (mrand48 ()); + } + + *encr_extra = ((packet_ptr - encr_extra) - 1) * 4 * 256 + 0xfe; + encr_extra ++; + *(long long *)encr_extra = E->key_fingerprint; + encr_extra += 2; + encr_extra[4] = l * 4; + encr_ptr = encr_extra + 4; + encr_end = packet_ptr; + memcpy (encr_extra, encrypt_decrypted_message (E), 16); +} +/* }}} */ + +/* {{{ Seng msg (plain text) */ +int msg_send_encr_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_messages_sent_encrypted_message); + logprintf ("Sent\n"); + struct message *M = q->extra; + M->date = fetch_int (); + message_insert (M); + return 0; +} int msg_send_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_sent_message); int id = fetch_int (); // id - int date = fetch_int (); // date + fetch_date (); fetch_pts (); - int seq = fetch_int (); // seq + fetch_seq (); struct message *M = q->extra; M->id = id; message_insert (M); - logprintf ("Sent: id = %d, date = %d, seq = %d\n", id, date, seq); + logprintf ("Sent: id = %d\n", id); return 0; } @@ -631,10 +736,71 @@ struct query_methods msg_send_methods = { .on_answer = msg_send_on_answer }; +struct query_methods msg_send_encr_methods = { + .on_answer = msg_send_encr_on_answer +}; + int out_message_num; int our_id; void out_peer_id (peer_id_t id); + +void do_send_encr_message (peer_id_t id, const char *msg, int len) { + peer_t *P = user_chat_get (id); + if (!P) { + logprintf ("Can not send to unknown encrypted chat\n"); + return; + } + if (P->encr_chat.state != sc_ok) { + logprintf ("Chat is not yet initialized\n"); + return; + } + clear_packet (); + out_int (CODE_messages_send_encrypted); + out_int (CODE_input_encrypted_chat); + out_int (get_peer_id (id)); + out_long (P->encr_chat.access_hash); + if (!out_message_num) { + out_message_num = -lrand48 (); + } + out_long ((--out_message_num) - (4ll << 32)); + encr_start (); + //out_int (CODE_decrypted_message_layer); + //out_int (8); + out_int (CODE_decrypted_message); + out_long ((out_message_num) - (4ll << 32)); + static int buf[4]; + int i; + for (i = 0; i < 3; i++) { + buf[i] = mrand48 (); + } + out_cstring ((void *)buf, 16); + out_cstring ((void *)msg, len); + out_int (CODE_decrypted_message_media_empty); + encr_finish (&P->encr_chat); + + struct message *M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->from_id = MK_USER (our_id); + M->to_id = id; + M->unread = 1; + M->message = malloc (len + 1); + memcpy (M->message, msg, len); + M->message[len] = 0; + M->message_len = len; + M->out = 1; + M->media.type = CODE_message_media_empty; + M->id = (out_message_num) - (4ll << 32); + M->date = time (0); + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M); + print_message (M); +} + void do_send_message (peer_id_t id, const char *msg, int len) { + if (get_peer_type (id) == PEER_ENCR_CHAT) { + do_send_encr_message (id, msg, len); + return; + } if (!out_message_num) { out_message_num = -lrand48 (); } @@ -659,7 +825,9 @@ void do_send_message (peer_id_t id, const char *msg, int len) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M); print_message (M); } +/* }}} */ +/* {{{ Send text file */ void do_send_text (peer_id_t id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { @@ -681,19 +849,29 @@ void do_send_text (peer_id_t id, char *file_name) { close (fd); } } +/* }}} */ int mark_read_on_receive (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_affected_history); - fetch_int (); // pts - fetch_int (); // seq + fetch_pts (); + fetch_seq (); fetch_int (); // offset return 0; } +int mark_read_encr_on_receive (struct query *q UU) { + fetch_bool (); + return 0; +} + struct query_methods mark_read_methods = { .on_answer = mark_read_on_receive }; +struct query_methods mark_read_encr_methods = { + .on_answer = mark_read_encr_on_receive +}; + void do_messages_mark_read (peer_id_t id, int max_id) { clear_packet (); out_int (CODE_messages_read_history); @@ -703,6 +881,34 @@ void do_messages_mark_read (peer_id_t id, int max_id) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, 0); } +void do_messages_mark_read_encr (peer_id_t id, long long access_hash, int last_time) { + clear_packet (); + out_int (CODE_messages_read_encrypted_history); + out_int (CODE_input_encrypted_chat); + out_int (get_peer_id (id)); + out_long (access_hash); + out_int (last_time); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, 0); +} + +void do_mark_read (peer_id_t id) { + peer_t *P = user_chat_get (id); + if (!P) { + rprintf ("Unknown peer\n"); + return; + } + if (!P->last) { + rprintf ("Unknown last peer message\n"); + return; + } + if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) { + do_messages_mark_read (id, P->last->id); + return; + } + assert (get_peer_type (id) == PEER_ENCR_CHAT); + do_messages_mark_read_encr (id, P->encr_chat.access_hash, P->last->date); +} + int get_history_on_answer (struct query *q UU) { static struct message *ML[10000]; int i; @@ -919,8 +1125,8 @@ int send_file_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } - fetch_int (); // pts - fetch_int (); // seq + fetch_pts (); + fetch_seq (); print_message (M); return 0; } @@ -1029,8 +1235,8 @@ int fwd_msg_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } - fetch_int (); // pts - fetch_int (); // seq + fetch_pts (); + fetch_seq (); print_message (M); return 0; } @@ -1041,7 +1247,7 @@ struct query_methods fwd_msg_methods = { void do_forward_message (peer_id_t id, int n) { clear_packet (); - out_int (CODE_invoke_with_layer3); + out_int (CODE_invoke_with_layer9); out_int (CODE_messages_forward_message); out_peer_id (id); out_int (n); @@ -1063,8 +1269,8 @@ int rename_chat_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } - fetch_int (); // pts - fetch_int (); // seq + fetch_pts (); + fetch_seq (); print_message (M); return 0; } @@ -1509,3 +1715,241 @@ void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) { out_int (limit); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_search_methods, 0); } + +int send_encr_accept_on_answer (struct query *q UU) { + struct secret_chat *E = fetch_alloc_encrypted_chat (); + + if (E->state == sc_ok) { + print_start (); + push_color (COLOR_YELLOW); + printf ("Encrypted connection with "); + print_encr_chat_name (E->id, (void *)E); + printf (" established\n"); + pop_color (); + print_end (); + } else { + print_start (); + push_color (COLOR_YELLOW); + printf ("Encrypted connection with "); + print_encr_chat_name (E->id, (void *)E); + printf (" failed\n"); + pop_color (); + print_end (); + } + return 0; +} + +struct query_methods send_encr_accept_methods = { + .on_answer = send_encr_accept_on_answer +}; + +int encr_root; +unsigned char *encr_prime; +int encr_param_version; +BN_CTX *ctx; + +void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { + int i; + for (i = 0; i < 64; i++) { + *(((int *)random) + i) ^= mrand48 (); + } + BIGNUM *b = BN_bin2bn (random, 256, 0); + assert (b); + BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0); + assert (g_a); + if (!ctx) { + ctx = BN_CTX_new (); + BN_CTX_init (ctx); + } + BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + BIGNUM *r = BN_new (); + BN_init (r); + BN_mod_exp (r, g_a, b, p, ctx); + memset (E->key, 0, sizeof (E->key)); + BN_bn2bin (r, (void *)E->key); + for (i = 0; i < 64; i++) { + E->key[i] ^= *(((int *)E->nonce) + i); + } + static unsigned char sha_buffer[20]; + sha1 ((void *)E->key, 256, sha_buffer); + E->key_fingerprint = *(long long *)(sha_buffer + 12); + + clear_packet (); + out_int (CODE_messages_accept_encryption); + out_int (CODE_input_encrypted_chat); + logprintf ("id = %d\n", get_peer_id (E->id)); + out_int (get_peer_id (E->id)); + out_long (E->access_hash); + + BN_set_word (g_a, encr_root); + BN_mod_exp (r, g_a, b, p, ctx); + static unsigned char buf[256]; + memset (buf, 0, sizeof (buf)); + BN_bn2bin (r, buf); + out_cstring ((void *)buf, 256); + + out_long (E->key_fingerprint); + BN_clear_free (b); + BN_clear_free (g_a); + BN_clear_free (p); + BN_clear_free (r); + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E); +} + +int get_dh_config_on_answer (struct query *q UU) { + unsigned x = fetch_int (); + assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified); + if (x == CODE_messages_dh_config) { + encr_root = fetch_int (); + if (encr_prime) { free (encr_prime); } + int l = prefetch_strlen (); + assert (l == 256); + encr_prime = (void *)fetch_str_dup (); + encr_param_version = fetch_int (); + } + int l = prefetch_strlen (); + assert (l == 256); + unsigned char *random = (void *)fetch_str_dup (); + if (q->extra) { + do_send_accept_encr_chat (q->extra, random); + free (random); + } else { + free (random); + } + return 0; +} + +struct query_methods get_dh_config_methods = { + .on_answer = get_dh_config_on_answer +}; + +void do_accept_encr_chat_request (struct secret_chat *E) { + assert (E->state == sc_request); + + clear_packet (); + out_int (CODE_messages_get_dh_config); + out_int (encr_param_version); + out_int (256); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); +} + +int unread_messages; +int difference_got; +int seq, pts, qts, last_date; +int get_state_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_updates_state); + pts = fetch_int (); + qts = fetch_int (); + last_date = fetch_int (); + seq = fetch_int (); + unread_messages = fetch_int (); + write_state_file (); + difference_got = 1; + return 0; +} + +int get_difference_on_answer (struct query *q UU) { + unsigned x = fetch_int (); + if (x == CODE_updates_difference_empty) { + fetch_date (); + fetch_seq (); + difference_got = 1; + } else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) { + int n, i; + assert (fetch_int () == CODE_vector); + n = fetch_int (); + static struct message *ML[10000]; + int ml_pos = 0; + for (i = 0; i < n; i++) { + if (ml_pos < 10000) { + ML[ml_pos ++] = fetch_alloc_message (); + } else { + fetch_alloc_message (); + } + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + if (ml_pos < 10000) { + ML[ml_pos ++] = fetch_alloc_encrypted_message (); + } else { + fetch_alloc_encrypted_message (); + } + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + work_update (0, 0); + } + 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 (); + } + assert (fetch_int () == (int)CODE_updates_state); + pts = fetch_int (); + qts = fetch_int (); + last_date = fetch_int (); + seq = fetch_int (); + unread_messages = fetch_int (); + write_state_file (); + for (i = 0; i < ml_pos; i++) { + print_message (ML[i]); + } + if (x == CODE_updates_difference_slice) { + do_get_difference (); + } else { + difference_got = 1; + } + } else { + assert (0); + } + return 0; +} + +struct query_methods get_state_methods = { + .on_answer = get_state_on_answer +}; + +struct query_methods get_difference_methods = { + .on_answer = get_difference_on_answer +}; + +void do_get_difference (void) { + difference_got = 0; + clear_packet (); + out_int (CODE_invoke_with_layer9); + out_int (CODE_init_connection); + out_int (TG_APP_ID); + if (allow_send_linux_version) { + struct utsname st; + uname (&st); + out_string (st.machine); + static char buf[1000000]; + sprintf (buf, "%s %s %s", st.sysname, st.release, st.version); + out_string (buf); + out_string (TG_VERSION " (build " TG_BUILD ")"); + out_string ("En"); + } else { + out_string ("x86"); + out_string ("Linux"); + out_string (TG_VERSION); + out_string ("en"); + } + if (seq > 0) { + out_int (CODE_updates_get_difference); + out_int (pts); + out_int (last_date); + out_int (qts); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_difference_methods, 0); + } else { + out_int (CODE_updates_get_state); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0); + } +} diff --git a/queries.h b/queries.h index 8a9cb9b..beff3a8 100644 --- a/queries.h +++ b/queries.h @@ -94,5 +94,8 @@ void do_import_auth (int num); void do_export_auth (int num); void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s); +void do_accept_encr_chat_request (struct secret_chat *E); +void do_get_difference (void); +void do_mark_read (peer_id_t id); #endif diff --git a/structures.c b/structures.c index 89055e6..c5a1035 100644 --- a/structures.c +++ b/structures.c @@ -32,6 +32,10 @@ int verbosity; peer_t *Peers[MAX_USER_NUM]; +int peer_num; +int encr_chats_allocated; +int geo_chats_allocated; + void fetch_file_location (struct file_location *loc) { int x = fetch_int (); if (x == CODE_file_location_unavailable) { @@ -68,8 +72,63 @@ void fetch_user_status (struct user_status *S) { } int our_id; -int user_num; -int chat_num; + +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; + static char buf[10000]; + int i; + int p = 0; + for (i = 0; i < 4; i++) { + if (d[i] && strlen (d[i])) { + p += snprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]); + assert (p < 9990); + } + } + char *s = buf; + while (*s) { + if (*s == ' ') { *s = '_'; } + s++; + } + s = buf; + int cc = 0; + while (1) { + int ok = 1; + int i; + for (i = 0; i < peer_num; i++) { + if (cmp_peer_id (Peers[i]->id, id) && Peers[i]->print_name && !strcmp (Peers[i]->print_name, s)) { + ok = 0; + break; + } + } + if (ok) { + break; + } + cc ++; + assert (cc <= 99); + if (cc == 1) { + int l = strlen (s); + s[l + 2] = 0; + s[l] = '#'; + s[l + 1] = '1'; + } else if (cc == 10) { + int l = strlen (s); + s[l + 1] = 0; + s[l] = '0'; + s[l - 1] = '1'; + } else { + int l = strlen (s); + s[l - 1] ++; + int cc = l - 1; + while (s[cc] > '9') { + s[cc] = '0'; + s[cc - 1] ++; + cc --; + } + } + } + return strdup (s); +} void fetch_user (struct user *U) { unsigned x = fetch_int (); @@ -92,67 +151,8 @@ void fetch_user (struct user *U) { 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)) { - if (!strlen (U->last_name)) { - U->print_name = strdup ("none"); - } else { - U->print_name = strdup (U->last_name); - } - } else { - if (!strlen (U->last_name)) { - U->print_name = strdup (U->first_name); - } else { - U->print_name = malloc (strlen (U->first_name) + strlen (U->last_name) + 2); - sprintf (U->print_name, "%s_%s", U->first_name, U->last_name); - } - } - char *s = U->print_name; - while (*s) { - if (*s == ' ') { *s = '_'; } - s++; - } - int cc = 0; - while (1) { - int ok = 1; - int i; - for (i = 0; i < user_num + chat_num; i++) { - if (Peers[i] != (void *)U && Peers[i]->print_name && !strcmp (Peers[i]->print_name, U->print_name)) { - ok = 0; - break; - } - } - if (ok) { - break; - } - cc ++; - assert (cc <= 99); - if (cc == 1) { - int l = strlen (U->print_name); - char *s = malloc (l + 3); - memcpy (s, U->print_name, l); - s[l + 2] = 0; - s[l] = '#'; - s[l + 1] = '1'; - free (U->print_name); - U->print_name = s; - } else if (cc == 10) { - int l = strlen (U->print_name); - char *s = malloc (l + 2); - memcpy (s, U->print_name, l); - s[l + 1] = 0; - s[l] = '0'; - s[l - 1] = '1'; - free (U->print_name); - U->print_name = s; - } else { - int l = strlen (U->print_name); - U->print_name[l - 1] ++; - if (U->print_name[l - 1] > '9') { - U->print_name[l - 1] = '0'; - U->print_name[l - 2] ++; - } - } - } + + U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); if (x == CODE_user_deleted) { U->flags |= FLAG_DELETED; return; @@ -197,47 +197,96 @@ void fetch_encrypted_chat (struct secret_chat *U) { assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); U->id = MK_ENCR_CHAT (fetch_int ()); U->flags &= ~(FLAG_EMPTY | FLAG_DELETED); + enum secret_chat_state old_state = U->state; if (x == CODE_encrypted_chat_empty) { U->state = sc_none; U->flags |= FLAG_EMPTY; + if (U->state != old_state) { + write_secret_chat_file (); + } return; } if (x == CODE_encrypted_chat_discarded) { U->state = sc_deleted; U->flags |= FLAG_DELETED; + if (U->state != old_state) { + write_secret_chat_file (); + } return; } U->access_hash = fetch_long (); U->date = fetch_int (); U->admin_id = fetch_int (); U->user_id = fetch_int () + U->admin_id - our_id; + if (U->print_name) { free (U->print_name); } + + peer_t *P = user_chat_get (MK_USER (U->user_id)); + if (P) { + U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + } else { + static char buf[100]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (U->id, "!", buf, 0, 0); + } + if (x == CODE_encrypted_chat_waiting) { U->state = sc_waiting; } else if (x == CODE_encrypted_chat_requested) { U->state = sc_request; if (!U->g_key) { - U->g_key = malloc (256); + U->g_key = malloc (256); } + memset (U->g_key, 0, 256); if (!U->nonce) { U->nonce = malloc (256); } - assert (prefetch_strlen () == 256); - memcpy (U->g_key, fetch_str (256), 256); - assert (prefetch_strlen () == 256); - memcpy (U->nonce, fetch_str (256), 256); + memset (U->nonce, 0, 256); + int l = prefetch_strlen (); + char *s = fetch_str (l); + if (l < 256) { + memcpy (U->g_key + 256 - l, s, l); + } else { + memcpy (U->g_key, s + (l - 256), 256); + } + l = prefetch_strlen (); + s = fetch_str (l); + if (l < 256) { + memcpy (U->nonce + 256 - l, s, l); + } else { + memcpy (U->nonce, s + (l - 256), 256); + } } else { U->state = sc_ok; if (!U->g_key) { U->g_key = malloc (256); } + memset (U->g_key, 0, 256); if (!U->nonce) { U->nonce = malloc (256); } - assert (prefetch_strlen () == 256); - memcpy (U->g_key, fetch_str (256), 256); - assert (prefetch_strlen () == 256); - memcpy (U->nonce, fetch_str (256), 256); - U->key_fingerprint = fetch_long (); + memset (U->nonce, 0, 256); + int l = prefetch_strlen (); + char *s = fetch_str (l); + if (l < 256) { + memcpy (U->g_key + 256 - l, s, l); + } else { + memcpy (U->g_key, s + (l - 256), 256); + } + l = prefetch_strlen (); + s = fetch_str (l); + if (l < 256) { + memcpy (U->nonce + 256 - l, s, l); + } else { + memcpy (U->nonce, s + (l - 256), 256); + } + if (!U->key_fingerprint) { + U->key_fingerprint = fetch_long (); + } else { + assert (U->key_fingerprint == fetch_long ()); + } + } + if (U->state != old_state) { + write_secret_chat_file (); } } @@ -294,12 +343,7 @@ void fetch_chat (struct chat *C) { 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; - while (*s) { - if (*s == ' ') { *s = '_'; } - s ++; - } + 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) { @@ -499,9 +543,9 @@ void fetch_message_short (struct message *M) { M->to_id = MK_USER (our_id); M->from_id = MK_USER (fetch_int ()); M->message = fetch_str_dup (); - fetch_int (); // pts + fetch_pts (); M->date = fetch_int (); - fetch_int (); // seq + fetch_seq (); M->media.type = CODE_message_media_empty; M->unread = 1; } @@ -512,9 +556,9 @@ void fetch_message_short_chat (struct message *M) { M->from_id = MK_USER (fetch_int ()); M->to_id = MK_CHAT (fetch_int ()); M->message = fetch_str_dup (); - fetch_int (); // pts + fetch_pts (); M->date = fetch_int (); - fetch_int (); // seq + fetch_seq (); M->media.type = CODE_message_media_empty; M->unread = 1; } @@ -554,7 +598,7 @@ void fetch_message_media_encrypted (struct message_media *M) { memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); int l; - switch (M->type) { + switch (x) { case CODE_decrypted_message_media_empty: M->type = CODE_message_media_empty; break; @@ -567,15 +611,25 @@ void fetch_message_media_encrypted (struct message_media *M) { M->encr_photo.w = fetch_int (); M->encr_photo.h = fetch_int (); M->encr_photo.size = fetch_int (); - l = fetch_int (); - assert (l > 0); - M->encr_photo.key = malloc (l); - memcpy (M->encr_photo.key, fetch_str (l), l); - l = fetch_int (); + l = prefetch_strlen (); assert (l > 0); - M->encr_photo.iv = malloc (l); - memcpy (M->encr_photo.iv, fetch_str (l), l); + M->encr_photo.key = malloc (32); + memset (M->encr_photo.key, 0, 32); + if (l <= 32) { + memcpy (M->encr_photo.key + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_photo.key, fetch_str (l) + (l - 32), 32); + } + M->encr_photo.iv = malloc (32); + l = prefetch_strlen (); + assert (l > 0); + memset (M->encr_photo.iv, 0, 32); + if (l <= 32) { + memcpy (M->encr_photo.iv + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_photo.iv, fetch_str (l) + (l - 32), 32); + } break; case CODE_decrypted_message_media_video: M->type = x; @@ -587,15 +641,25 @@ void fetch_message_media_encrypted (struct message_media *M) { M->encr_video.h = fetch_int (); M->encr_video.size = fetch_int (); M->encr_video.duration = fetch_int (); - l = fetch_int (); - assert (l > 0); - M->encr_video.key = malloc (l); - memcpy (M->encr_video.key, fetch_str (l), l); - l = fetch_int (); + l = prefetch_strlen (); assert (l > 0); - M->encr_video.iv = malloc (l); - memcpy (M->encr_video.iv, fetch_str (l), l); + M->encr_video.key = malloc (32); + memset (M->encr_photo.key, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + } + M->encr_video.iv = malloc (32); + l = prefetch_strlen (); + assert (l > 0); + memset (M->encr_video.iv, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + } break; /* case CODE_decrypted_message_media_file: M->type = x; @@ -719,24 +783,26 @@ int decrypt_encrypted_message (struct secret_chat *E) { memcpy (buf + 16, E->key + 24, 32); sha1 (buf, 48, sha1d_buffer); - static unsigned char iv[32]; - memcpy (iv, sha1a_buffer + 0, 8); - memcpy (iv + 8, sha1b_buffer + 8, 12); - memcpy (iv + 20, sha1c_buffer + 4, 12); - static unsigned char key[32]; - memcpy (key, sha1a_buffer + 8, 12); - memcpy (key + 12, sha1b_buffer + 0, 8); - memcpy (key + 20, sha1c_buffer + 16, 4); - memcpy (key + 24, sha1d_buffer + 0, 8); + memcpy (key, sha1a_buffer + 0, 8); + memcpy (key + 8, sha1b_buffer + 8, 12); + memcpy (key + 20, sha1c_buffer + 4, 12); + + static unsigned char iv[32]; + memcpy (iv, sha1a_buffer + 8, 12); + memcpy (iv + 12, sha1b_buffer + 0, 8); + memcpy (iv + 20, sha1c_buffer + 16, 4); + memcpy (iv + 24, sha1d_buffer + 0, 8); AES_KEY aes_key; AES_set_decrypt_key (key, 256, &aes_key); AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); - sha1 ((void *)decr_ptr, 4 * (decr_end - decr_ptr), sha1a_buffer); + int x = *(decr_ptr); + assert (x >= 0 && !(x & 3)); + sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer); - if (memcmp (sha1a_buffer, msg_key, 16)) { + if (memcmp (sha1a_buffer + 4, msg_key, 16)) { logprintf ("Sha1 mismatch\n"); return -1; } @@ -747,40 +813,72 @@ void fetch_encrypted_message (struct message *M) { memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service); - peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); + unsigned sx = x; M->id = fetch_long (); + peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); + M->to_id = chat; peer_t *P = user_chat_get (chat); if (!P) { logprintf ("Encrypted message to unknown chat. Dropping\n"); + M->flags |= FLAG_EMPTY; } M->date = fetch_int (); + int len = prefetch_strlen (); - assert (!(len & 15)); + assert ((len & 15) == 8); decr_ptr = (void *)fetch_str (len); - decr_end = in_ptr; + decr_end = decr_ptr + (len / 4); M->flags |= FLAG_ENCRYPTED; + int ok = 0; + if (P) { + if (*(long long *)decr_ptr != P->encr_chat.key_fingerprint) { + logprintf ("Encrypted message with bad fingerprint to chat %s\n", P->print_name); + P = 0; + } + decr_ptr += 2; + } if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) { + ok = 1; + int *save_in_ptr = in_ptr; + int *save_in_end = in_end; in_ptr = decr_ptr; + int l = fetch_int (); + in_end = in_ptr + l; unsigned x = fetch_int (); if (x == CODE_decrypted_message_layer) { int layer = fetch_int (); assert (layer >= 0); x = fetch_int (); } - assert (x == CODE_decrypted_message); + assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service); assert (M->id = fetch_long ()); - int l = prefetch_strlen (); + l = prefetch_strlen (); fetch_str (l); // random_bytes - M->from_id = MK_USER (fetch_int ()); - M->date = fetch_int (); if (x == CODE_decrypted_message) { M->message = fetch_str_dup (); - fetch_encrypted_message_file (&M->media); + fetch_message_media_encrypted (&M->media); } else { assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l); P->encr_chat.ttl = fetch_int (); + M->service = 1; } + in_ptr = save_in_ptr; + in_end = save_in_end; + } + + if (sx == CODE_encrypted_message) { + if (ok) { + fetch_encrypted_message_file (&M->media); + } else { + x = fetch_int (); + if (x == CODE_encrypted_file) { + fetch_skip (7); + } else { + assert (x == CODE_encrypted_file_empty); + } + M->media.type = CODE_message_media_empty; + } } } @@ -793,7 +891,8 @@ void fetch_encrypted_message_file (struct message_media *M) { assert (M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video); M->encr_photo.id = fetch_long (); M->encr_photo.access_hash = fetch_long (); - assert (M->encr_photo.size == fetch_int ()); + //assert (M->encr_photo.size == fetch_int ()); + M->encr_photo.size = fetch_int (); // Why it is not the same? M->encr_photo.dc_id = fetch_int (); M->encr_photo.key_fingerprint = fetch_int (); @@ -813,8 +912,6 @@ DEFINE_TREE(message,struct message *,id_cmp,0) struct tree_peer *peer_tree; struct tree_message *message_tree; -int chat_num; -int user_num; int users_allocated; int chats_allocated; int messages_allocated; @@ -837,7 +934,7 @@ struct user *fetch_alloc_user (void) { memset (U, 0, sizeof (*U)); fetch_user (&U->user); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - Peers[chat_num + (user_num ++)] = U; + Peers[peer_num ++] = U; return &U->user; } } @@ -850,16 +947,22 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) { fetch_encrypted_chat (&U->encr_chat); return &U->encr_chat; } else { - chats_allocated ++; + encr_chats_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); fetch_encrypted_chat (&U->encr_chat); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - Peers[(chat_num ++) + user_num] = U; + Peers[peer_num ++] = U; return &U->encr_chat; } } +void insert_encrypted_chat (peer_t *P) { + encr_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); @@ -874,7 +977,7 @@ struct user *fetch_alloc_user_full (void) { U->id = MK_USER (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_user_full (&U->user); - Peers[chat_num + (user_num ++ )] = U; + Peers[peer_num ++] = U; return &U->user; } } @@ -938,6 +1041,8 @@ void free_message_media (struct message_media *M) { free (M->encr_video.key); free (M->encr_video.iv); return; + case 0: + break; default: logprintf ("%08x\n", M->type); assert (0); @@ -964,6 +1069,8 @@ void free_message_action (struct message_action *M) { break; case CODE_message_action_chat_delete_user: break; + case 0: + break; default: assert (0); } @@ -990,6 +1097,61 @@ void message_add_use (struct message *M) { M->prev_use->next_use = M; } +void message_add_peer (struct message *M) { + peer_id_t id; + if (!cmp_peer_id (M->to_id, MK_USER (our_id))) { + id = M->from_id; + } else { + id = M->to_id; + } + peer_t *P = user_chat_get (id); + if (!P) { + P = malloc (sizeof (*P)); + memset (P, 0, sizeof (*P)); + P->id = id; + P->flags = FLAG_EMPTY; + switch (get_peer_type (id)) { + case PEER_USER: + users_allocated ++; + break; + case PEER_CHAT: + chats_allocated ++; + break; + case PEER_GEO_CHAT: + geo_chats_allocated ++; + break; + case PEER_ENCR_CHAT: + encr_chats_allocated ++; + break; + } + peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); + Peers[peer_num ++] = P; + } + M->next = P->last; + if (M->next) { M->next->prev = M; } + M->prev = 0; + P->last = M; +} + +void message_del_peer (struct message *M) { + peer_id_t id; + if (!cmp_peer_id (M->to_id, MK_USER (our_id))) { + id = M->from_id; + } else { + id = M->to_id; + } + peer_t *P = user_chat_get (id); + if (M->prev) { + M->prev->next = M->next; + } + if (M->next) { + M->next->prev = M->prev; + } + if (P && P->last == M) { + P->last = M->next; + } +} + struct message *fetch_alloc_message (void) { struct message *M = malloc (sizeof (*M)); fetch_message (M); @@ -997,14 +1159,17 @@ struct message *fetch_alloc_message (void) { messages_allocated ++; if (M1) { message_del_use (M1); + message_del_peer (M1); free_message (M1); memcpy (M1, M, sizeof (*M)); free (M); message_add_use (M1); + message_add_peer (M1); messages_allocated --; return M1; } else { message_add_use (M); + message_add_peer (M); message_tree = tree_insert_message (message_tree, M, lrand48 ()); return M; } @@ -1017,14 +1182,17 @@ struct message *fetch_alloc_geo_message (void) { messages_allocated ++; if (M1) { message_del_use (M1); + message_del_peer (M1); free_message (M1); memcpy (M1, M, sizeof (*M)); free (M); message_add_use (M1); + message_add_peer (M1); messages_allocated --; return M1; } else { message_add_use (M); + message_add_peer (M); message_tree = tree_insert_message (message_tree, M, lrand48 ()); return M; } @@ -1037,14 +1205,17 @@ struct message *fetch_alloc_encrypted_message (void) { messages_allocated ++; if (M1) { message_del_use (M1); + message_del_peer (M1); free_message (M1); memcpy (M1, M, sizeof (*M)); free (M); message_add_use (M1); + message_add_peer (M1); messages_allocated --; return M1; } else { message_add_use (M); + message_add_peer (M); message_tree = tree_insert_message (message_tree, M, lrand48 ()); return M; } @@ -1057,14 +1228,17 @@ struct message *fetch_alloc_message_short (void) { messages_allocated ++; if (M1) { message_del_use (M1); + message_del_peer (M1); free_message (M1); memcpy (M1, M, sizeof (*M)); free (M); message_add_use (M1); + message_add_peer (M1); messages_allocated --; return M1; } else { message_add_use (M); + message_add_peer (M); message_tree = tree_insert_message (message_tree, M, lrand48 ()); return M; } @@ -1080,14 +1254,17 @@ struct message *fetch_alloc_message_short_chat (void) { messages_allocated ++; if (M1) { message_del_use (M1); + message_del_peer (M1); free_message (M1); memcpy (M1, M, sizeof (*M)); free (M); message_add_use (M1); + message_add_peer (M1); messages_allocated --; return M1; } else { message_add_use (M); + message_add_peer (M); message_tree = tree_insert_message (message_tree, M, lrand48 ()); return M; } @@ -1106,7 +1283,7 @@ struct chat *fetch_alloc_chat (void) { memset (U, 0, sizeof (*U)); fetch_chat (&U->chat); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - Peers[(chat_num ++) + user_num] = U; + Peers[peer_num ++] = U; return &U->chat; } } @@ -1125,7 +1302,7 @@ struct chat *fetch_alloc_chat_full (void) { U->id = MK_CHAT (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_chat_full (&U->chat); - Peers[(chat_num ++) + user_num] = U; + Peers[peer_num ++] = U; return &U->chat; } } @@ -1139,9 +1316,13 @@ int print_stat (char *s, int len) { return snprintf (s, len, "users_allocated\t%d\n" "chats_allocated\t%d\n" + "secret_chats_allocated\t%d\n" + "peer_num\t%d\n" "messages_allocated\t%d\n", users_allocated, chats_allocated, + encr_chats_allocated, + peer_num, messages_allocated ); } @@ -1166,5 +1347,6 @@ void update_message_id (struct message *M, long long id) { void message_insert (struct message *M) { message_add_use (M); + message_add_peer (M); message_tree = tree_insert_message (message_tree, M, lrand48 ()); } diff --git a/structures.h b/structures.h index e703b69..5fdd8b7 100644 --- a/structures.h +++ b/structures.h @@ -20,7 +20,7 @@ #define __STRUCTURES_H__ #include -typedef struct { int id; } peer_id_t; +typedef struct { int type; int id; } peer_id_t; #define FLAG_EMPTY 1 #define FLAG_DELETED 2 @@ -111,6 +111,7 @@ struct user_status { struct user { peer_id_t id; int flags; + struct message *last; char *print_name; struct file_location photo_big; struct file_location photo_small; @@ -134,6 +135,7 @@ struct chat_user { struct chat { peer_id_t id; int flags; + struct message *last; char *print_title; struct file_location photo_big; struct file_location photo_small; @@ -157,6 +159,7 @@ enum secret_chat_state { struct secret_chat { peer_id_t id; int flags; + struct message *last; char *print_name; struct file_location photo_big; struct file_location photo_small; @@ -178,6 +181,7 @@ typedef union peer { struct { peer_id_t id; int flags; + struct message *last; char *print_name; struct file_location photo_big; struct file_location photo_small; @@ -237,6 +241,7 @@ struct message_media { struct message { struct message *next_use, *prev_use; + struct message *next, *prev; long long id; int flags; peer_id_t fwd_from_id; @@ -283,6 +288,7 @@ void update_message_id (struct message *M, long long id); void message_insert (struct message *M); void free_photo (struct photo *P); void fetch_photo (struct photo *P); +void insert_encrypted_chat (peer_t *P); #define PEER_USER 1 #define PEER_CHAT 2 @@ -296,55 +302,18 @@ void fetch_photo (struct photo *P); #define MK_ENCR_CHAT(id) set_peer_id (PEER_ENCR_CHAT,id) static inline int get_peer_type (peer_id_t id) { - if (id.id > 1000000000) { - return PEER_ENCR_CHAT; - } - if (id.id > 0) { - return PEER_USER; - } - if (id.id < -1000000000) { - return PEER_GEO_CHAT; - } - if (id.id < 0) { - return PEER_CHAT; - } - return PEER_UNKNOWN; + return id.type; } static inline int get_peer_id (peer_id_t id) { - switch (get_peer_type (id)) { - case PEER_USER: - return id.id; - case PEER_CHAT: - return -id.id; - case PEER_GEO_CHAT: - return -id.id - 1000000000; - case PEER_ENCR_CHAT: - return id.id - 1000000000; - default: - return 0; - } + return id.id; } static inline peer_id_t set_peer_id (int type, int id) { peer_id_t ID; - switch (type) { - case PEER_USER: - ID.id = id; - return ID; - case PEER_CHAT: - ID.id = -id; - return ID; - case PEER_GEO_CHAT: - ID.id = -id - 1000000000; - return ID; - case PEER_ENCR_CHAT: - ID.id = id + 1000000000; - return ID; - default: - assert (0); - return ID; - } + ID.id = id; + ID.type = type; + return ID; } static inline int cmp_peer_id (peer_id_t a, peer_id_t b) { From 188c2a4f662696ff3394107e43c2a34ceb559021 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 4 Nov 2013 21:47:32 +0400 Subject: [PATCH 073/465] Fixed get hostory to encrypted messages --- queries.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/queries.c b/queries.c index 1871edd..b014aef 100644 --- a/queries.c +++ b/queries.c @@ -851,6 +851,7 @@ void do_send_text (peer_id_t id, char *file_name) { } /* }}} */ +/* {{{ Mark read */ int mark_read_on_receive (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_affected_history); fetch_pts (); @@ -897,18 +898,25 @@ void do_mark_read (peer_id_t id) { rprintf ("Unknown peer\n"); return; } - if (!P->last) { - rprintf ("Unknown last peer message\n"); - return; - } if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) { + if (!P->last) { + rprintf ("Unknown last peer message\n"); + return; + } do_messages_mark_read (id, P->last->id); return; } assert (get_peer_type (id) == PEER_ENCR_CHAT); - do_messages_mark_read_encr (id, P->encr_chat.access_hash, P->last->date); + if (P->last) { + do_messages_mark_read_encr (id, P->encr_chat.access_hash, P->last->date); + } else { + do_messages_mark_read_encr (id, P->encr_chat.access_hash, time (0) - 10); + + } } +/* }}} */ +/* {{{ Get history */ int get_history_on_answer (struct query *q UU) { static struct message *ML[10000]; int i; @@ -952,8 +960,27 @@ struct query_methods get_history_methods = { .on_answer = get_history_on_answer, }; +void do_get_local_history (peer_id_t id, int limit) { + peer_t *P = user_chat_get (id); + if (!P || !P->last) { return; } + struct message *M = P->last; + int count = 1; + while (count < limit && M->next) { + M = M->next; + count ++; + } + while (M) { + print_message (M); + M = M->prev; + } +} void do_get_history (peer_id_t id, int limit) { + if (get_peer_type (id) == PEER_ENCR_CHAT) { + do_get_local_history (id, limit); + do_mark_read (id); + return; + } clear_packet (); out_int (CODE_messages_get_history); out_peer_id (id); @@ -962,7 +989,7 @@ void do_get_history (peer_id_t id, int limit) { out_int (limit); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, (void *)*(long *)&id); } - +/* }}} */ int get_dialogs_on_answer (struct query *q UU) { unsigned x = fetch_int (); From a0ba6cc7c383c21eed7fd8dbf38644c0b92a6f80 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 5 Nov 2013 03:15:24 +0400 Subject: [PATCH 074/465] Many improvements in encrypted chats. Can not send/download encrypted messages, for example --- interface.c | 82 ++++++++++--- interface.h | 3 + mtproto-client.c | 17 ++- no-preview.h | 84 +++++++++++++ queries.c | 303 ++++++++++++++++++++++++++++++++++++++++------- queries.h | 2 + structures.c | 2 + structures.h | 2 +- 8 files changed, 434 insertions(+), 61 deletions(-) create mode 100644 no-preview.h diff --git a/interface.c b/interface.c index 536d3bc..e708db6 100644 --- a/interface.c +++ b/interface.c @@ -78,12 +78,12 @@ char *next_token (int *l) { #define NOT_FOUND (int)0x80000000 peer_id_t PEER_NOT_FOUND = {.id = NOT_FOUND}; -int next_token_int (void) { +long long next_token_int (void) { int l; char *s = next_token (&l); if (!s) { return NOT_FOUND; } char *r; - int x = strtod (s, &r); + long long x = strtoll (s, &r, 10); if (r == s + l) { return x; } else { @@ -139,6 +139,22 @@ peer_id_t next_token_chat (void) { } } +peer_id_t next_token_encr_chat (void) { + int l; + char *s = next_token (&l); + if (!s) { return PEER_NOT_FOUND; } + + int index = 0; + while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) { + index ++; + } + if (index < peer_num) { + return Peers[index]->id; + } else { + return PEER_NOT_FOUND; + } +} + peer_id_t next_token_peer (void) { int l; char *s = next_token (&l); @@ -232,6 +248,7 @@ char *commands[] = { "show_license", "search", "mark_read", + "visualize_key", 0 }; int commands_flags[] = { @@ -259,6 +276,7 @@ int commands_flags[] = { 07, 072, 072, + 075, }; int get_complete_mode (void) { @@ -322,6 +340,19 @@ int complete_chat_list (int index, const char *text, int len, char **R) { } } +int complete_encr_chat_list (int index, const char *text, int len, char **R) { + index ++; + while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) { + index ++; + } + if (index < peer_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 < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { @@ -390,6 +421,10 @@ char *command_generator (const char *text, int state) { index = complete_chat_list (index, text, len, &R); if (c) { rl_line_buffer[rl_point] = c; } return R; + case 5: + index = complete_encr_chat_list (index, text, len, &R); + if (c) { rl_line_buffer[rl_point] = c; } + return R; default: if (c) { rl_line_buffer[rl_point] = c; } return 0; @@ -446,7 +481,13 @@ void interpreter (char *line UU) { #define GET_PEER_CHAT \ id = next_token_chat (); \ if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ - printf ("Bad char id\n"); \ + printf ("Bad chat id\n"); \ + RET; \ + } +#define GET_PEER_ENCR_CHAT \ + id = next_token_encr_chat (); \ + if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ + printf ("Bad encr_chat id\n"); \ RET; \ } @@ -512,34 +553,38 @@ void interpreter (char *line UU) { } do_forward_message (id, num); } else if (IS_WORD ("load_photo")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { do_load_photo (&M->media.photo, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) { + do_load_encr_video (&M->media.encr_video, 1); // this is not a bug. } else { printf ("Bad msg id\n"); RET; } } else if (IS_WORD ("view_photo")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { do_load_photo (&M->media.photo, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) { + do_load_encr_video (&M->media.encr_video, 2); // this is not a bug. } else { printf ("Bad msg id\n"); RET; } } else if (IS_WORD ("load_video_thumb")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } @@ -551,8 +596,8 @@ void interpreter (char *line UU) { RET; } } else if (IS_WORD ("view_video_thumb")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } @@ -564,27 +609,31 @@ void interpreter (char *line UU) { RET; } } else if (IS_WORD ("load_video")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_video) { do_load_video (&M->media.video, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) { + do_load_encr_video (&M->media.encr_video, 1); } else { printf ("Bad msg id\n"); RET; } } else if (IS_WORD ("view_video")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_video) { do_load_video (&M->media.video, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) { + do_load_encr_video (&M->media.encr_video, 2); } else { printf ("Bad msg id\n"); RET; @@ -691,6 +740,9 @@ void interpreter (char *line UU) { } else if (IS_WORD ("mark_read")) { GET_PEER; do_mark_read (id); + } else if (IS_WORD ("visualize_key")) { + GET_PEER_ENCR_CHAT; + do_visualize_key (id); } #undef IS_WORD #undef RET diff --git a/interface.h b/interface.h index 1a4bd32..c9529a6 100644 --- a/interface.h +++ b/interface.h @@ -29,6 +29,9 @@ #define COLOR_BLUE "\033[34;1m" #define COLOR_MAGENTA "\033[35;1m" #define COLOR_CYAN "\033[36;1m" +#define COLOR_LCYAN "\033[0;36m" + +#define COLOR_INVERSE "\033[7m" char *get_default_prompt (void); char *complete_none (const char *text, int state); diff --git a/mtproto-client.c b/mtproto-client.c index 467d4a8..d4da57f 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1050,11 +1050,24 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_id_t id = MK_ENCR_CHAT (fetch_int ()); // chat_id fetch_int (); // max_date fetch_int (); // date + peer_t *P = user_chat_get (id); + int x = -1; + if (P && P->last) { + x = 0; + struct message *M = P->last; + while (M && (!M->out || M->unread)) { + if (M->out) { + M->unread = 0; + x ++; + } + M = M->next; + } + } print_start (); push_color (COLOR_YELLOW); - printf ("Messages in encrypted chat "); + printf ("Encrypted chat "); print_encr_chat_name_full (id, user_chat_get (id)); - printf (" marked read \n"); + printf (": %d messages marked read \n", x); pop_color (); print_end (); } diff --git a/no-preview.h b/no-preview.h new file mode 100644 index 0000000..a15eb18 --- /dev/null +++ b/no-preview.h @@ -0,0 +1,84 @@ +int thumb_file_size = (82 * 6 - 2) * 4; +int thumb_file [] = { +0xe0ffd8ff, 0x464a1000, 0x01004649, 0x64000101, 0x00006400, 0xa002e2ff, +0x5f434349, 0x464f5250, 0x00454c49, 0x00000101, 0x636c9002, 0x3004736d, +0x6e6d0000, 0x47527274, 0x59582042, 0xdd07205a, 0x04000b00, 0x1b001600, +0x63612400, 0x50417073, 0x00004c50, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x0100d6f6, 0x00000000, 0x636c2dd3, +0x0000736d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x65640b00, 0x00006373, 0x00000801, 0x70633800, 0x00007472, 0x00004001, +0x74774e00, 0x00007470, 0x00009001, 0x68631400, 0x00006461, 0x0000a401, +0x58722c00, 0x00005a59, 0x0000d001, 0x58621400, 0x00005a59, 0x0000e401, +0x58671400, 0x00005a59, 0x0000f801, 0x54721400, 0x00004352, 0x00000c02, +0x54672000, 0x00004352, 0x00002c02, 0x54622000, 0x00004352, 0x00004c02, +0x68632000, 0x00006d72, 0x00006c02, 0x6c6d2400, 0x00006375, 0x00000000, +0x00000100, 0x6e650c00, 0x00005355, 0x00001c00, 0x73001c00, 0x47005200, +0x20004200, 0x75006200, 0x6c006900, 0x2d007400, 0x6e006900, 0x6c6d0000, +0x00006375, 0x00000000, 0x00000100, 0x6e650c00, 0x00005355, 0x00003200, +0x4e001c00, 0x20006f00, 0x6f006300, 0x79007000, 0x69007200, 0x68006700, +0x2c007400, 0x75002000, 0x65007300, 0x66002000, 0x65007200, 0x6c006500, +0x00007900, 0x59580000, 0x0000205a, 0x00000000, 0x0100d6f6, 0x00000000, +0x66732dd3, 0x00003233, 0x01000000, 0x00004a0c, 0xffffe305, 0x00002af3, +0x00009b07, 0xffff87fd, 0xffffa2fb, 0x0000a3fd, 0x0000d803, 0x595894c0, +0x0000205a, 0x00000000, 0x0000946f, 0x0000ee38, 0x59589003, 0x0000205a, +0x00000000, 0x00009d24, 0x0000830f, 0x5958beb6, 0x0000205a, 0x00000000, +0x0000a562, 0x000090b7, 0x6170de18, 0x00006172, 0x03000000, 0x02000000, +0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, 0x61705b0a, 0x00006172, +0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, +0x61705b0a, 0x00006172, 0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, +0x0000590d, 0x0000d013, 0x68635b0a, 0x00006d72, 0x03000000, 0x00000000, +0x0000d7a3, 0x00007b54, 0x0000cd4c, 0x00009a99, 0x00006626, 0xdbff5c0f, +0x14004300, 0x0f120f0e, 0x1112140d, 0x14161712, 0x21331f18, 0x1f1c1c1f, +0x252f2d3f, 0x4e414a33, 0x4841494d, 0x765c5246, 0x6f575264, 0x66484658, +0x7a6f688c, 0x8485847d, 0x9b91634f, 0x769a808f, 0xff7f8481, 0x014300db, +0x1f171716, 0x213c1f1b, 0x547f3c21, 0x7f7f5448, 0x7f7f7f7f, 0x7f7f7f7f, +0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, +0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x1100c0ff, 0x005a0008, +0x2201035a, 0x01110200, 0xff011103, 0x001900c4, 0x01010101, 0x00000101, +0x00000000, 0x00000000, 0x02030400, 0xc4ff0605, 0x00103600, 0x02010401, +0x06050304, 0x00000306, 0x01000000, 0x11030200, 0x05211204, 0x13514131, +0x32146122, 0x23918171, 0x72423424, 0x432515a1, 0xa2827444, 0xc4fff0b3, +0x01011400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1400c4ff, +0x00000111, 0x00000000, 0x00000000, 0x00000000, 0xdaff0000, 0x01030c00, +0x03110200, 0x003f0011, 0x404434fb, 0xbcb4875c, 0x006b38b0, 0x03dcdb12, +0xf4637f74, 0xe519f153, 0x09d7c5c7, 0x47d29160, 0x20692f18, 0xd06d786a, +0x53f7f922, 0x17b3e260, 0x2fe8668c, 0x1786a473, 0x9775efbd, 0xe917e43a, +0x1d0a1bb0, 0x114d0f82, 0x14651110, 0x35f299ed, 0xe9b09680, 0xf5a4fc2f, +0xe975bd03, 0xb506737b, 0x04444440, 0x5c444044, 0x8e8dedbd, 0xc61adc7b, +0x689c738b, 0x92a0dc01, 0x58e2b77f, 0x7bfb37d1, 0xb5b5e79d, 0xdbf968cc, +0xead3f48d, 0x38ed1313, 0xdea77c86, 0xae089963, 0xc743435a, 0x403fe4ce, +0x392ee1b9, 0xed39e718, 0xd6517e2d, 0x7fc4aa03, 0xb7ad7590, 0x77e7e6ab, +0x34bf705d, 0x7c77ca53, 0x3dea1299, 0x7fb0bcf4, 0x241fadc5, 0x95a7a816, +0x13fbe6f3, 0x3182b135, 0xd1b4b224, 0x1b0d48a2, 0xbf9d26d8, 0x82dc3640, +0x63569a2a, 0xbbd224c3, 0xb9b4714c, 0x1680aec6, 0x3d311856, 0x9b59be91, +0x09876ca6, 0x61d86564, 0x5a9f06d2, 0x36f51b0d, 0x8682e476, 0xacb1b131, +0xd1584363, 0x00456b4d, 0x22d2053b, 0x22202202, 0xf3f30222, 0xe3e513e5, +0xf1e6e1f0, 0x2380496e, 0x5fdcdb68, 0x549b3a27, 0x825e6a6c, 0x6522028b, +0xaf91ccc8, 0x341cf26b, 0x58dbc4b5, 0xf2289add, 0x0854ddbd, 0x0b9247d5, +0xf02b5c54, 0x3f917f92, 0xaf56affd, 0xe3760637, 0x05cebde0, 0xed4c76ce, +0x3cef1b63, 0x7fd8aff8, 0xa0c902ea, 0x7e730d0a, 0x435834f3, 0x26edbb76, +0xd3ec00fd, 0x76d48efa, 0xa8560f2d, 0x0e766331, 0xd319993c, 0x20243209, +0x61b7e6c8, 0x998331d0, 0x640ee802, 0x47a3d493, 0xfab99413, 0x4fd871f1, +0xe9443792, 0x627e051c, 0xd8f3051c, 0x2f28f558, 0x64b51745, 0x1b2bfee3, +0xb8783953, 0x9900fff6, 0xd8176a65, 0x5a3bf56a, 0x1b331fdb, 0x64b3572f, +0xd59a3643, 0xaf3abce1, 0x11dd20bd, 0x01111110, 0x5c141011, 0xb3e3083f, +0xd9b19cc4, 0x17edb20e, 0xa78e9aa1, 0x4ef4de06, 0x00c0bfe7, 0x7e1e442d, +0x9221fe38, 0xedb5c7dc, 0x6338078a, 0x62495b8d, 0xc11d9b8c, 0x49e81b16, +0x51d02bea, 0x3eb86d70, 0xc8bc4f13, 0xa10ec758, 0xd40751c0, 0x5ac94710, +0xc4c8b080, 0x95492b83, 0x975ee696, 0xb7bd96b4, 0x17379cce, 0x82e856e8, +0xe4c2c82a, 0x398e935f, 0x632437ea, 0x7c9c87d2, 0xdc1ddb7c, 0x65a80a48, +0x2309f164, 0x51fab475, 0x081dc11d, 0xda45573b, 0x6622f3f3, 0x48f1b214, +0x676c4edb, 0x243468c7, 0x00ffde60, 0xf1630350, 0xa0076c1d, 0x8f2c0c8b, +0x2383c26b, 0x361a8f4e, 0xaceea6c9, 0x01dd5a5d, 0x11111011, 0xc3780c04, +0xbf093ee2, 0xc7972c0b, 0x00d99040, 0xc0c20eb7, 0x659d3bd4, 0x269ab85e, +0x468e114f, 0x11ad4fdb, 0x83d083d8, 0x8c52f4bd, 0x3c9664bf, 0xa4f9c77c, +0x22a68876, 0xadb18784, 0xf480be83, 0x885a00ea, 0x220e0a88, 0xc303e4f6, +0xc866e058, 0xdddbd661, 0xdf395db1, 0xbad64343, 0xe6e65b03, 0x668e81c3, +0xad619e98, 0xeeb94563, 0xd4d19a3c, 0x3316ce95, 0x9d65f1e1, 0x3bf324fe, +0x0e468f53, 0xc386068c, 0xa89e24f7, 0xf0c7c73b, 0xb60e391f, 0x1b8827cb, +0x58601954, 0xc54f90f9, 0x80886ec5, 0x88088888, 0x1b7bb980, 0xb4c71c23, +0xe6148e39, 0xb12358b8, 0xbd08225d, 0x0ffef085, 0x72b4f025, 0x635ce389, +0xb90277e4, 0x0d05e000, 0x9bf9dbb9, 0x8e749fbc, 0x7ee6abbf, 0x4ddbf4af, +0x728df7f3, 0x10b59adf, 0xe3c38f49, 0xb23c638a, 0xdb3d9349, 0x66899a64, +0x00004dd5, 0xf51b5adf, 0x2220a255, 0xd9ff0f22}; diff --git a/queries.c b/queries.c index b014aef..422818c 100644 --- a/queries.c +++ b/queries.c @@ -41,6 +41,9 @@ #include #include #include +#include + +#include "no-preview.h" #define sha1 SHA1 @@ -282,6 +285,16 @@ int new_dc_num; extern struct dc *DC_list[]; extern struct dc *DC_working; +void out_random (int n) { + assert (n <= 16); + static char buf[16]; + int i; + for (i = 0; i < n; i++) { + buf[i] = lrand48 () & 255; + } + out_cstring (buf, n); +} + /* {{{ Get config */ int help_get_config_on_answer (struct query *q UU) { @@ -780,6 +793,7 @@ void do_send_encr_message (peer_id_t id, const char *msg, int len) { struct message *M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); + M->flags = FLAG_ENCRYPTED; M->from_id = MK_USER (our_id); M->to_id = id; M->unread = 1; @@ -991,6 +1005,7 @@ void do_get_history (peer_id_t id, int limit) { } /* }}} */ +/* {{{ Get dialogs */ int get_dialogs_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); @@ -1067,35 +1082,11 @@ void do_get_dialog_list (void) { out_int (1000); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); } +/* }}} */ int allow_send_linux_version = 1; -void do_get_dialog_list_ex (void) { - clear_packet (); - out_int (CODE_invoke_with_layer9); - out_int (CODE_init_connection); - out_int (TG_APP_ID); - if (allow_send_linux_version) { - struct utsname st; - uname (&st); - out_string (st.machine); - static char buf[1000000]; - sprintf (buf, "%s %s %s", st.sysname, st.release, st.version); - out_string (buf); - out_string (TG_VERSION " (build " TG_BUILD ")"); - out_string ("En"); - } else { - out_string ("x86"); - out_string ("Linux"); - out_string (TG_VERSION); - out_string ("en"); - } - out_int (CODE_messages_get_dialogs); - out_int (0); - out_int (0); - out_int (100); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); -} +/* {{{ Send photo/video file */ struct send_file { int fd; long long size; @@ -1106,6 +1097,10 @@ struct send_file { peer_id_t to_id; int media_type; char *file_name; + int encr; + unsigned char *iv; + unsigned char *init_iv; + unsigned char *key; }; void out_peer_id (peer_id_t id) { @@ -1158,6 +1153,21 @@ int send_file_on_answer (struct query *q UU) { return 0; } +int send_encr_file_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_sent_encrypted_file); + struct message *M = q->extra; + M->date = fetch_int (); + assert (fetch_int () == CODE_encrypted_file); + M->media.encr_photo.id = fetch_long (); + M->media.encr_photo.access_hash = fetch_long (); + M->media.encr_photo.size = fetch_int (); + M->media.encr_photo.dc_id = fetch_int (); + assert (fetch_int () == M->media.encr_photo.key_fingerprint); + print_message (M); + message_insert (M); + return 0; +} + struct query_methods send_file_part_methods = { .on_answer = send_file_part_on_answer }; @@ -1166,6 +1176,10 @@ struct query_methods send_file_methods = { .on_answer = send_file_on_answer }; +struct query_methods send_encr_file_methods = { + .on_answer = send_encr_file_on_answer +}; + void send_part (struct send_file *f) { if (f->fd >= 0) { if (!f->part_num) { @@ -1178,9 +1192,22 @@ void send_part (struct send_file *f) { static char buf[512 << 10]; int x = read (f->fd, buf, f->part_size); assert (x > 0); - out_cstring (buf, x); f->offset += x; cur_uploaded_bytes += x; + + if (f->encr) { + if (x & 15) { + assert (f->offset == f->size); + while (x & 15) { + buf[x ++] = lrand48 () & 255; + } + } + + AES_KEY aes_key; + AES_set_encrypt_key (f->key, 256, &aes_key); + AES_ige_encrypt ((void *)buf, (void *)buf, x, &aes_key, f->iv, 1); + } + out_cstring (buf, x); if (verbosity >= 2) { logprintf ("offset=%lld size=%lld\n", f->offset, f->size); } @@ -1193,24 +1220,92 @@ void send_part (struct send_file *f) { cur_uploaded_bytes -= f->size; cur_uploading_bytes -= f->size; clear_packet (); - out_int (CODE_messages_send_media); - out_peer_id (f->to_id); assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video); - out_int (f->media_type); - out_int (CODE_input_file); - out_long (f->id); - out_int (f->part_num); - char *s = f->file_name + strlen (f->file_name); - while (s >= f->file_name && *s != '/') { s --;} - out_string (s + 1); - out_string (""); - if (f->media_type == CODE_input_media_uploaded_video) { - out_int (100); + if (!f->encr) { + out_int (CODE_messages_send_media); + out_peer_id (f->to_id); + out_int (f->media_type); + out_int (CODE_input_file); + out_long (f->id); + out_int (f->part_num); + char *s = f->file_name + strlen (f->file_name); + while (s >= f->file_name && *s != '/') { s --;} + out_string (s + 1); + out_string (""); + if (f->media_type == CODE_input_media_uploaded_video) { + out_int (100); + out_int (100); + out_int (100); + } + out_long (-lrand48 () * (1ll << 32) - lrand48 ()); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); + } else { + struct message *M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + + out_int (CODE_messages_send_encrypted_file); + out_int (CODE_input_encrypted_chat); + out_int (get_peer_id (f->to_id)); + peer_t *P = user_chat_get (f->to_id); + assert (P); + out_long (P->encr_chat.access_hash); + long long r = -lrand48 () * (1ll << 32) - lrand48 (); + out_long (r); + encr_start (); + out_int (CODE_decrypted_message); + out_long (r); + out_random (16); + out_string (""); + if (f->media_type == CODE_input_media_uploaded_photo) { + out_int (CODE_decrypted_message_media_photo); + M->media.type = CODE_decrypted_message_media_photo; + } else { + out_int (CODE_decrypted_message_media_video); + M->media.type = CODE_decrypted_message_media_video; + } + out_cstring ((void *)thumb_file, thumb_file_size); + out_int (90); + out_int (90); + if (f->media_type == CODE_input_media_uploaded_video) { + out_int (0); + } out_int (100); out_int (100); + out_int (f->size); + out_cstring ((void *)f->key, 32); + out_cstring ((void *)f->init_iv, 32); + encr_finish (&P->encr_chat); + out_int (CODE_input_encrypted_file_uploaded); + out_long (f->id); + out_int (f->part_num); + out_string (""); + + unsigned char md5[16]; + unsigned char str[64]; + memcpy (str, f->key, 32); + memcpy (str + 32, f->init_iv, 32); + MD5 (str, 64, md5); + out_int ((*(int *)md5) ^ (*(int *)(md5 + 4))); + + free (f->iv); + + M->media.encr_photo.key = f->key; + M->media.encr_photo.iv = f->init_iv; + M->media.encr_photo.key_fingerprint = (*(int *)md5) ^ (*(int *)(md5 + 4)); + + + M->flags = FLAG_ENCRYPTED; + M->from_id = MK_USER (our_id); + M->to_id = f->to_id; + M->unread = 1; + M->message = strdup (""); + M->out = 1; + M->id = r; + M->date = time (0); + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M); + } - out_long (-lrand48 () * (1ll << 32) - lrand48 ()); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); free (f->file_name); free (f); } @@ -1231,6 +1326,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { return; } struct send_file *f = malloc (sizeof (*f)); + memset (f, 0, sizeof (*f)); f->fd = fd; f->size = size; f->offset = 0; @@ -1240,6 +1336,20 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { f->to_id = to_id; f->media_type = type; f->file_name = file_name; + if (get_peer_type (f->to_id) == PEER_ENCR_CHAT) { + f->encr = 1; + f->iv = malloc (32); + int i; + for (i = 0; i < 8; i++) { + ((int *)f->iv)[i] = mrand48 (); + } + f->init_iv = malloc (32); + memcpy (f->init_iv, f->iv, 32); + f->key = malloc (32); + for (i = 0; i < 8; i++) { + ((int *)f->key)[i] = mrand48 (); + } + } if (f->part_size > (512 << 10)) { close (fd); rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); @@ -1247,7 +1357,9 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { } send_part (f); } +/* }}} */ +/* {{{ Forward */ int fwd_msg_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_stated_message); struct message *M = fetch_alloc_message (); @@ -1273,6 +1385,10 @@ struct query_methods fwd_msg_methods = { }; void do_forward_message (peer_id_t id, int n) { + if (get_peer_type (id) == PEER_ENCR_CHAT) { + rprintf ("Can not forward messages from secret chat\n"); + return; + } clear_packet (); out_int (CODE_invoke_with_layer9); out_int (CODE_messages_forward_message); @@ -1281,7 +1397,9 @@ void do_forward_message (peer_id_t id, int n) { out_long (lrand48 () * (1ll << 32) + lrand48 ()); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, 0); } +/* }}} */ +/* {{{ Rename chat */ int rename_chat_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_stated_message); struct message *M = fetch_alloc_message (); @@ -1314,7 +1432,9 @@ void do_rename_chat (peer_id_t id, char *name) { out_string (name); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, 0); } +/* }}} */ +/* {{{ Chat info */ int chat_info_on_answer (struct query *q UU) { struct chat *C = fetch_alloc_chat_full (); peer_t *U = (void *)C; @@ -1352,7 +1472,9 @@ void do_get_chat_info (peer_id_t id) { out_int (get_peer_id (id)); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0); } +/* }}} */ +/* {{{ User info */ int user_info_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user_full (); peer_t *C = (void *)U; @@ -1394,7 +1516,9 @@ void do_get_user_info (peer_id_t id) { } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0); } +/* }}} */ +/* {{{ Get user info silently */ int user_list_info_silent_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); int n = fetch_int (); @@ -1422,7 +1546,9 @@ void do_get_user_list_info_silent (int num, int *list) { } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_list_info_silent_methods, 0); } +/* }}} */ +/* {{{ Load photo/video */ struct download { int offset; int size; @@ -1435,6 +1561,8 @@ struct download { int fd; char *name; long long id; + unsigned char *iv; + unsigned char *key; }; @@ -1454,6 +1582,9 @@ void end_load (struct download *D) { logprintf ("Image is at %s\n", D->name); } } + if (D->iv) { + free (D->iv); + } free (D->name); free (D); } @@ -1503,7 +1634,16 @@ int download_on_answer (struct query *q) { assert (len >= 0); cur_downloaded_bytes += len; update_prompt (); - assert (write (D->fd, fetch_str (len), len) == len); + if (D->iv) { + unsigned char *ptr = (void *)fetch_str (len); + assert (!(len & 15)); + AES_KEY aes_key; + AES_set_decrypt_key (D->key, 256, &aes_key); + AES_ige_encrypt (ptr, ptr, len, &aes_key, D->iv, 0); + assert (write (D->fd, ptr, len) == len); + } else { + assert (write (D->fd, fetch_str (len), len) == len); + } D->offset += len; if (D->offset < D->size) { load_next_part (D); @@ -1531,7 +1671,11 @@ void load_next_part (struct download *D) { out_int (D->local_id); out_long (D->secret); } else { - out_int (CODE_input_video_file_location); + if (D->iv) { + out_int (CODE_input_encrypted_file_location); + } else { + out_int (CODE_input_video_file_location); + } out_long (D->id); out_long (D->access_hash); } @@ -1545,6 +1689,7 @@ void do_load_photo_size (struct photo_size *P, int next) { assert (P); assert (next); struct download *D = malloc (sizeof (*D)); + memset (D, 0, sizeof (*D)); D->id = 0; D->offset = 0; D->size = P->size; @@ -1580,6 +1725,7 @@ void do_load_video (struct video *V, int next) { assert (V); assert (next); struct download *D = malloc (sizeof (*D)); + memset (D, 0, sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; @@ -1591,6 +1737,34 @@ void do_load_video (struct video *V, int next) { load_next_part (D); } +void do_load_encr_video (struct encr_video *V, int next) { + assert (V); + assert (next); + struct download *D = malloc (sizeof (*D)); + memset (D, 0, sizeof (*D)); + D->offset = 0; + D->size = V->size; + D->id = V->id; + D->access_hash = V->access_hash; + D->dc = V->dc_id; + D->next = next; + D->name = 0; + D->fd = -1; + D->key = V->key; + D->iv = malloc (32); + memcpy (D->iv, V->iv, 32); + load_next_part (D); + + unsigned char md5[16]; + unsigned char str[64]; + memcpy (str, V->key, 32); + memcpy (str + 32, V->iv, 32); + MD5 (str, 64, md5); + assert (V->key_fingerprint == ((*(int *)md5) ^ (*(int *)(md5 + 4)))); +} +/* }}} */ + +/* {{{ Export auth */ char *export_auth_str; int export_auth_str_len; int is_export_auth_str (void) { @@ -1629,7 +1803,9 @@ void do_export_auth (int num) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &export_auth_methods, 0); net_loop (0, is_export_auth_str); } +/* }}} */ +/* {{{ Import auth */ int import_auth_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_auth_authorization); fetch_int (); // expires @@ -1652,7 +1828,9 @@ void do_import_auth (int num) { send_query (DC_list[num], packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, 0); net_loop (0, isn_export_auth_str); } +/* }}} */ +/* {{{ Add contact */ int add_contact_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_contacts_imported_contacts); assert (fetch_int () == CODE_vector); @@ -1720,7 +1898,9 @@ void do_add_contact (const char *phone, int phone_len, const char *first_name, i out_int (force ? CODE_bool_true : CODE_bool_false); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_contact_methods, 0); } +/* }}} */ +/* {{{ Msg search */ int msg_search_on_answer (struct query *q UU) { return get_history_on_answer (q); } @@ -1742,7 +1922,9 @@ void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) { out_int (limit); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_search_methods, 0); } +/* }}} */ +/* {{{ Encr accept */ int send_encr_accept_on_answer (struct query *q UU) { struct secret_chat *E = fetch_alloc_encrypted_chat (); @@ -1860,7 +2042,9 @@ void do_accept_encr_chat_request (struct secret_chat *E) { out_int (256); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); } +/* }}} */ +/* {{{ Get difference */ int unread_messages; int difference_got; int seq, pts, qts, last_date; @@ -1980,3 +2164,36 @@ void do_get_difference (void) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0); } } +/* }}} */ + +/* {{{ Visualize key */ +char *colors[4] = {COLOR_GREY, COLOR_GREEN, COLOR_CYAN, COLOR_BLUE}; + +void do_visualize_key (peer_id_t id) { + assert (get_peer_type (id) == PEER_ENCR_CHAT); + peer_t *P = user_chat_get (id); + assert (P); + if (P->encr_chat.state != sc_ok) { + rprintf ("Chat is not initialized yet\n"); + return; + } + unsigned char buf[20]; + SHA1 ((void *)P->encr_chat.key, 256, buf); + print_start (); + int i; + for (i = 0; i < 16; i++) { + int x = buf[i]; + int j; + for (j = 0; j < 4; j ++) { + push_color (colors[x & 3]); + push_color (COLOR_INVERSE); + printf (" "); + pop_color (); + pop_color (); + x = x >> 2; + } + if (i & 1) { printf ("\n"); } + } + print_end (); +} +/* }}} */ diff --git a/queries.h b/queries.h index beff3a8..f34f3de 100644 --- a/queries.h +++ b/queries.h @@ -80,6 +80,7 @@ void do_get_user_list_info_silent (int num, int *list); void do_get_user_info (peer_id_t id); void do_forward_message (peer_id_t id, int n); void do_rename_chat (peer_id_t id, char *name); +void do_load_encr_video (struct encr_video *V, int next); struct photo; struct video; @@ -97,5 +98,6 @@ void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s); void do_accept_encr_chat_request (struct secret_chat *E); void do_get_difference (void); void do_mark_read (peer_id_t id); +void do_visualize_key (peer_id_t id); #endif diff --git a/structures.c b/structures.c index c5a1035..e6ef4ec 100644 --- a/structures.c +++ b/structures.c @@ -818,6 +818,8 @@ void fetch_encrypted_message (struct message *M) { peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); M->to_id = chat; peer_t *P = user_chat_get (chat); + M->flags &= ~(FLAG_EMPTY | FLAG_DELETED); + M->flags |= FLAG_ENCRYPTED; if (!P) { logprintf ("Encrypted message to unknown chat. Dropping\n"); M->flags |= FLAG_EMPTY; diff --git a/structures.h b/structures.h index 5fdd8b7..fe34654 100644 --- a/structures.h +++ b/structures.h @@ -91,9 +91,9 @@ struct encr_video { int w; int h; - int duration; unsigned char *key; unsigned char *iv; + int duration; }; struct encr_file { From f4e8e8ca0c281d57b4b0f6552e7d8a404774e384 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 5 Nov 2013 03:46:12 +0400 Subject: [PATCH 075/465] Some fixes with download/upload in encrypted chats --- queries.c | 8 ++++++-- structures.c | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/queries.c b/queries.c index 422818c..4f0c498 100644 --- a/queries.c +++ b/queries.c @@ -1160,7 +1160,8 @@ int send_encr_file_on_answer (struct query *q UU) { assert (fetch_int () == CODE_encrypted_file); M->media.encr_photo.id = fetch_long (); M->media.encr_photo.access_hash = fetch_long (); - M->media.encr_photo.size = fetch_int (); + //M->media.encr_photo.size = fetch_int (); + fetch_int (); M->media.encr_photo.dc_id = fetch_int (); assert (fetch_int () == M->media.encr_photo.key_fingerprint); print_message (M); @@ -1292,7 +1293,7 @@ void send_part (struct send_file *f) { M->media.encr_photo.key = f->key; M->media.encr_photo.iv = f->init_iv; M->media.encr_photo.key_fingerprint = (*(int *)md5) ^ (*(int *)(md5 + 4)); - + M->media.encr_photo.size = f->size; M->flags = FLAG_ENCRYPTED; M->from_id = MK_USER (our_id); @@ -1640,6 +1641,9 @@ int download_on_answer (struct query *q) { AES_KEY aes_key; AES_set_decrypt_key (D->key, 256, &aes_key); AES_ige_encrypt (ptr, ptr, len, &aes_key, D->iv, 0); + if (len > D->size - D->offset) { + len = D->size - D->offset; + } assert (write (D->fd, ptr, len) == len); } else { assert (write (D->fd, fetch_str (len), len) == len); diff --git a/structures.c b/structures.c index e6ef4ec..26c6ca9 100644 --- a/structures.c +++ b/structures.c @@ -893,8 +893,9 @@ void fetch_encrypted_message_file (struct message_media *M) { assert (M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video); M->encr_photo.id = fetch_long (); M->encr_photo.access_hash = fetch_long (); + fetch_int (); //assert (M->encr_photo.size == fetch_int ()); - M->encr_photo.size = fetch_int (); // Why it is not the same? + //M->encr_photo.size = fetch_int (); // Why it is not the same? M->encr_photo.dc_id = fetch_int (); M->encr_photo.key_fingerprint = fetch_int (); From 96f180772984cbb2876b03156309350502df0136 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 5 Nov 2013 03:55:41 +0400 Subject: [PATCH 076/465] Forgot GPL header. --- no-preview.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/no-preview.h b/no-preview.h index a15eb18..ee6bc7e 100644 --- a/no-preview.h +++ b/no-preview.h @@ -1,3 +1,24 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ + +// Just sample jpg file 90x90 + int thumb_file_size = (82 * 6 - 2) * 4; int thumb_file [] = { 0xe0ffd8ff, 0x464a1000, 0x01004649, 0x64000101, 0x00006400, 0xa002e2ff, From a725c0959fd2b028b7cc8eda2feece7c3b42322c Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 6 Nov 2013 02:24:26 +0400 Subject: [PATCH 077/465] Support for chat create --- interface.c | 5 ++ loop.c | 8 ++- queries.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++- queries.h | 3 + structures.c | 7 +++ 5 files changed, 175 insertions(+), 5 deletions(-) diff --git a/interface.c b/interface.c index e708db6..52cb743 100644 --- a/interface.c +++ b/interface.c @@ -249,6 +249,7 @@ char *commands[] = { "search", "mark_read", "visualize_key", + "create_secret_chat", 0 }; int commands_flags[] = { @@ -277,6 +278,7 @@ int commands_flags[] = { 072, 072, 075, + 071, }; int get_complete_mode (void) { @@ -743,6 +745,9 @@ void interpreter (char *line UU) { } else if (IS_WORD ("visualize_key")) { GET_PEER_ENCR_CHAT; do_visualize_key (id); + } else if (IS_WORD ("create_secret_chat")) { + GET_PEER; + do_create_secret_chat (id); } #undef IS_WORD #undef RET diff --git a/loop.c b/loop.c index 0e7add0..14da472 100644 --- a/loop.c +++ b/loop.c @@ -322,9 +322,9 @@ void read_secret_chat_file (void) { if (E->state != sc_waiting) { E->g_key = malloc (256); assert (read (fd, E->g_key, 256) == 256); + E->nonce = malloc (256); + assert (read (fd, E->nonce, 256) == 256); } - E->nonce = malloc (256); - assert (read (fd, E->nonce, 256) == 256); assert (read (fd, E->key, 256) == 256); assert (read (fd, &E->key_fingerprint, 8) == 8); insert_encrypted_chat (P); @@ -368,7 +368,9 @@ void write_secret_chat_file (void) { if (Peers[i]->encr_chat.state != sc_waiting) { assert (write (fd, Peers[i]->encr_chat.g_key, 256) == 256); } - assert (write (fd, Peers[i]->encr_chat.nonce, 256) == 256); + if (Peers[i]->encr_chat.state != sc_waiting) { + assert (write (fd, Peers[i]->encr_chat.nonce, 256) == 256); + } assert (write (fd, Peers[i]->encr_chat.key, 256) == 256); assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8); } diff --git a/queries.c b/queries.c index 4f0c498..14db40a 100644 --- a/queries.c +++ b/queries.c @@ -55,6 +55,7 @@ long long cur_uploaded_bytes; long long cur_downloading_bytes; long long cur_downloaded_bytes; +void out_peer_id (peer_id_t id); #define QUERY_TIMEOUT 0.3 #define memcmp8(a,b) memcmp ((a), (b), 8) @@ -755,7 +756,6 @@ struct query_methods msg_send_encr_methods = { int out_message_num; int our_id; -void out_peer_id (peer_id_t id); void do_send_encr_message (peer_id_t id, const char *msg, int len) { peer_t *P = user_chat_get (id); @@ -1952,10 +1952,37 @@ int send_encr_accept_on_answer (struct query *q UU) { return 0; } +int send_encr_request_on_answer (struct query *q UU) { + struct secret_chat *E = fetch_alloc_encrypted_chat (); + logprintf ("state = %d\n", E->state); + if (E->state == sc_deleted) { + print_start (); + push_color (COLOR_YELLOW); + printf ("Encrypted connection with "); + print_encr_chat_name (E->id, (void *)E); + printf (" can not be established\n"); + pop_color (); + print_end (); + } else { + print_start (); + push_color (COLOR_YELLOW); + printf ("Establishing connection with "); + print_encr_chat_name (E->id, (void *)E); + printf ("\n"); + pop_color (); + print_end (); + } + return 0; +} + struct query_methods send_encr_accept_methods = { .on_answer = send_encr_accept_on_answer }; +struct query_methods send_encr_request_methods = { + .on_answer = send_encr_request_on_answer +}; + int encr_root; unsigned char *encr_prime; int encr_param_version; @@ -2010,6 +2037,94 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E); } +void do_create_keys_end (struct secret_chat *U) { + if (!encr_prime) { + rprintf (COLOR_YELLOW "Something failed in bad moment. Did not fail\n"COLOR_NORMAL); + return; + } + BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); + assert (g_b); + if (!ctx) { + ctx = BN_CTX_new (); + BN_CTX_init (ctx); + } + BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + BIGNUM *r = BN_new (); + BIGNUM *a = BN_bin2bn ((void *)U->key, 256, 0); + BN_init (r); + BN_mod_exp (r, g_b, a, p, ctx); + + memset (U->key, 0, sizeof (U->key)); + BN_bn2bin (r, (void *)U->key); + int i; + for (i = 0; i < 64; i++) { + U->key[i] ^= *(((int *)U->nonce) + i); + } + + static unsigned char sha_buffer[20]; + sha1 ((void *)U->key, 256, sha_buffer); + long long k = *(long long *)(sha_buffer + 12); + assert (k == U->key_fingerprint); + + BN_clear_free (p); + BN_clear_free (g_b); + BN_clear_free (r); + BN_clear_free (a); +} + +void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { + int i; + for (i = 0; i < 64; i++) { + *(((int *)random) + i) ^= mrand48 (); + } + if (!ctx) { + ctx = BN_CTX_new (); + BN_CTX_init (ctx); + } + BIGNUM *a = BN_bin2bn (random, 256, 0); + assert (a); + BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + + BIGNUM *g = BN_new (); + BN_init (g); + + BN_set_word (g, encr_root); + + BIGNUM *r = BN_new (); + BN_init (r); + + BN_mod_exp (r, g, a, p, ctx); + + memcpy (E->key, random, 256); + + static char g_a[256]; + memset (g_a, 0, 256); + + BN_bn2bin (r, (void *)g_a); + + clear_packet (); + out_int (CODE_messages_request_encryption); + peer_t *U = user_chat_get (MK_USER (E->user_id)); + assert (U); + if (U && U->user.access_hash) { + out_int (CODE_input_user_foreign); + out_int (E->user_id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_user_contact); + out_int (E->user_id); + } + out_int (get_peer_id (E->id)); + out_cstring (g_a, 256); + write_secret_chat_file (); + + BN_clear_free (g); + BN_clear_free (p); + BN_clear_free (r); + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E); +} + int get_dh_config_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified); @@ -2025,7 +2140,12 @@ int get_dh_config_on_answer (struct query *q UU) { assert (l == 256); unsigned char *random = (void *)fetch_str_dup (); if (q->extra) { - do_send_accept_encr_chat (q->extra, random); + struct secret_chat *E = q->extra; + if (E->state == sc_request) { + do_send_accept_encr_chat (q->extra, random); + } else if (E->state == sc_none) { + do_send_create_encr_chat (q->extra, random); + } free (random); } else { free (random); @@ -2046,6 +2166,16 @@ void do_accept_encr_chat_request (struct secret_chat *E) { out_int (256); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); } + +void do_create_encr_chat_request (struct secret_chat *E) { + assert (E->state == sc_none); + + clear_packet (); + out_int (CODE_messages_get_dh_config); + out_int (encr_param_version); + out_int (256); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); +} /* }}} */ /* {{{ Get difference */ @@ -2201,3 +2331,26 @@ void do_visualize_key (peer_id_t id) { print_end (); } /* }}} */ + +/* {{{ Create secret chat */ +char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); + +void do_create_secret_chat (peer_id_t id) { + assert (get_peer_type (id) == PEER_USER); + peer_t *U = user_chat_get (id); + if (!U) { + rprintf ("Can not create chat with unknown user\n"); + } + + peer_t *P = malloc (sizeof (*P)); + memset (P, 0, sizeof (*P)); + P->id = MK_ENCR_CHAT (lrand48 ()); + + P->encr_chat.user_id = get_peer_id (id); + + insert_encrypted_chat (P); + P->print_name = create_print_name (P->id, "!", U->user.first_name, U->user.last_name, 0); + + do_create_encr_chat_request (&P->encr_chat); +} +/* }}} */ diff --git a/queries.h b/queries.h index f34f3de..3088a12 100644 --- a/queries.h +++ b/queries.h @@ -81,6 +81,8 @@ void do_get_user_info (peer_id_t id); void do_forward_message (peer_id_t id, int n); void do_rename_chat (peer_id_t id, char *name); void do_load_encr_video (struct encr_video *V, int next); +void do_create_encr_chat_request (struct secret_chat *E); +void do_create_secret_chat (peer_id_t id); struct photo; struct video; @@ -99,5 +101,6 @@ void do_accept_encr_chat_request (struct secret_chat *E); void do_get_difference (void); void do_mark_read (peer_id_t id); void do_visualize_key (peer_id_t id); +void do_create_keys_end (struct secret_chat *U); #endif diff --git a/structures.c b/structures.c index 26c6ca9..e49e1ea 100644 --- a/structures.c +++ b/structures.c @@ -26,6 +26,7 @@ #include #include #include +#include "queries.h" #define sha1 SHA1 @@ -284,6 +285,9 @@ void fetch_encrypted_chat (struct secret_chat *U) { } else { assert (U->key_fingerprint == fetch_long ()); } + if (old_state == sc_waiting) { + do_create_keys_end (U); + } } if (U->state != old_state) { write_secret_chat_file (); @@ -799,6 +803,9 @@ int decrypt_encrypted_message (struct secret_chat *E) { AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); int x = *(decr_ptr); + if (x < 0 || (x & 3)) { + return -1; + } assert (x >= 0 && !(x & 3)); sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer); From 12c88cd27fe4e1f112a860708acfde6bd11c5f8d Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 6 Nov 2013 02:27:14 +0400 Subject: [PATCH 078/465] Deleted debug output --- queries.c | 1 - 1 file changed, 1 deletion(-) diff --git a/queries.c b/queries.c index 14db40a..d2a4d1d 100644 --- a/queries.c +++ b/queries.c @@ -1954,7 +1954,6 @@ int send_encr_accept_on_answer (struct query *q UU) { int send_encr_request_on_answer (struct query *q UU) { struct secret_chat *E = fetch_alloc_encrypted_chat (); - logprintf ("state = %d\n", E->state); if (E->state == sc_deleted) { print_start (); push_color (COLOR_YELLOW); From d7efdf515620c2c6696d748778248194a25742e8 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 6 Nov 2013 02:53:40 +0400 Subject: [PATCH 079/465] Fixed bug in restarting in starting encrypted chat --- loop.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/loop.c b/loop.c index 14da472..b7833a7 100644 --- a/loop.c +++ b/loop.c @@ -284,6 +284,10 @@ void write_state_file (void) { extern peer_t *Peers[]; extern int peer_num; +extern int encr_root; +extern unsigned char *encr_prime; +extern int encr_param_version; + void read_secret_chat_file (void) { int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); if (fd < 0) { @@ -329,6 +333,14 @@ void read_secret_chat_file (void) { assert (read (fd, &E->key_fingerprint, 8) == 8); insert_encrypted_chat (P); } + if (version >= 1) { + assert (read (fd, &encr_root, 4) == 4); + if (encr_root) { + assert (read (fd, &encr_param_version, 4) == 4); + encr_prime = malloc (256); + assert (read (fd, encr_prime, 256) == 256); + } + } close (fd); } @@ -339,7 +351,7 @@ void write_secret_chat_file (void) { } int x[2]; x[0] = SECRET_CHAT_FILE_MAGIC; - x[1] = 0; + x[1] = 1; assert (write (fd, x, 8) == 8); int i; int cc = 0; @@ -375,6 +387,11 @@ void write_secret_chat_file (void) { assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8); } } + assert (write (fd, &encr_root, 4) == 4); + if (encr_root) { + assert (write (fd, &encr_param_version, 4) == 4); + assert (write (fd, encr_prime, 256) == 256); + } close (fd); } From 2dadc03a791f02dcd5eefcb6104b9ce1d84c871c Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 6 Nov 2013 14:07:36 +0400 Subject: [PATCH 080/465] upload big file functions --- queries.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/queries.c b/queries.c index d2a4d1d..0f87906 100644 --- a/queries.c +++ b/queries.c @@ -1187,9 +1187,16 @@ void send_part (struct send_file *f) { cur_uploading_bytes += f->size; } clear_packet (); - out_int (CODE_upload_save_file_part); - out_long (f->id); - out_int (f->part_num ++); + if (f->size < (16 << 20)) { + out_int (CODE_upload_save_file_part); + out_long (f->id); + out_int (f->part_num ++); + } else { + out_int (CODE_upload_save_big_file_part); + out_long (f->id); + out_int (f->part_num ++); + out_int ((f->size + f->part_size - 1) / f->part_size); + } static char buf[512 << 10]; int x = read (f->fd, buf, f->part_size); assert (x > 0); @@ -1215,6 +1222,8 @@ void send_part (struct send_file *f) { if (f->offset == f->size) { close (f->fd); f->fd = -1; + } else { + assert (f->part_size == x); } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); } else { @@ -1226,7 +1235,11 @@ void send_part (struct send_file *f) { out_int (CODE_messages_send_media); out_peer_id (f->to_id); out_int (f->media_type); - out_int (CODE_input_file); + if (f->size < (16 << 20)) { + out_int (CODE_input_file); + } else { + out_int (CODE_input_file_big); + } out_long (f->id); out_int (f->part_num); char *s = f->file_name + strlen (f->file_name); @@ -1276,7 +1289,11 @@ void send_part (struct send_file *f) { out_cstring ((void *)f->key, 32); out_cstring ((void *)f->init_iv, 32); encr_finish (&P->encr_chat); - out_int (CODE_input_encrypted_file_uploaded); + if (f->size < (16 << 20)) { + out_int (CODE_input_encrypted_file_uploaded); + } else { + out_int (CODE_input_encrypted_file_big_uploaded); + } out_long (f->id); out_int (f->part_num); out_string (""); @@ -1332,7 +1349,13 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { f->size = size; f->offset = 0; f->part_num = 0; - f->part_size = ((size + 999) / 1000 + 0x3ff) & ~0x3ff; +/* int tmp = ((size + 1999) / 2000); + f->part_size = (1 << 10); + while (f->part_size < tmp) { + f->part_size *= 2; + }*/ + f->part_size = 256 << 10; + f->id = lrand48 () * (1ll << 32) + lrand48 (); f->to_id = to_id; f->media_type = type; @@ -1351,7 +1374,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { ((int *)f->key)[i] = mrand48 (); } } - if (f->part_size > (512 << 10)) { + if (f->part_size >= (512 << 10)) { close (fd); rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); return; From a540256a201fb8603449c9b4e1828aa1ab58bb97 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Wed, 6 Nov 2013 18:00:31 +0400 Subject: [PATCH 081/465] Changed colors in visualize key --- queries.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/queries.c b/queries.c index d2a4d1d..45b851e 100644 --- a/queries.c +++ b/queries.c @@ -2300,7 +2300,7 @@ void do_get_difference (void) { /* }}} */ /* {{{ Visualize key */ -char *colors[4] = {COLOR_GREY, COLOR_GREEN, COLOR_CYAN, COLOR_BLUE}; +char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN}; void do_visualize_key (peer_id_t id) { assert (get_peer_type (id) == PEER_ENCR_CHAT); From bb1df969fb74269a1578b1e89eb731348ae498fe Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 02:16:46 +0400 Subject: [PATCH 082/465] Some bugfixes. Add small thumb file to sent video --- interface.c | 46 +++++++++------------------------------------- mtproto-client.c | 4 +++- queries.c | 46 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 44 deletions(-) diff --git a/interface.c b/interface.c index 52cb743..e236a10 100644 --- a/interface.c +++ b/interface.c @@ -63,10 +63,14 @@ char *next_token (int *l) { } int neg = 0; char *s = line_ptr; - while (*line_ptr && (*line_ptr != ' ' || neg)) { + int in_str = 0; + while (*line_ptr && (*line_ptr != ' ' || neg || in_str)) { if (*line_ptr == '\\') { neg = 1 - neg; } else { + if (*line_ptr == '"' && !neg) { + in_str = !in_str; + } neg = 0; } line_ptr++; @@ -756,28 +760,12 @@ void interpreter (char *line UU) { int readline_active; void rprintf (const char *format, ...) { - int saved_point = 0; - char *saved_line = 0; - if (readline_active) { - saved_point = rl_point; - saved_line = rl_copy_text(0, rl_end); - rl_save_prompt(); - rl_replace_line("", 0); - rl_redisplay(); - } - + print_start (); va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); - - if (readline_active) { - rl_restore_prompt(); - rl_replace_line(saved_line, 0); - rl_point = saved_point; - rl_redisplay(); - free(saved_line); - } + print_end(); } int saved_point; @@ -833,30 +821,14 @@ void hexdump (int *in_ptr, int *in_end) { } void logprintf (const char *format, ...) { - int saved_point = 0; - char *saved_line = 0; - if (readline_active) { - saved_point = rl_point; - saved_line = rl_copy_text(0, rl_end); - rl_save_prompt(); - rl_replace_line("", 0); - rl_redisplay(); - } - + print_start (); printf (COLOR_GREY " *** "); va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); printf (COLOR_NORMAL); - - if (readline_active) { - rl_restore_prompt(); - rl_replace_line(saved_line, 0); - rl_point = saved_point; - rl_redisplay(); - free(saved_line); - } + print_end (); } int color_stack_pos; diff --git a/mtproto-client.c b/mtproto-client.c index d4da57f..2106e2d 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -708,7 +708,9 @@ void work_update (struct connection *c UU, long long msg_id UU) { int id = fetch_int (); // id int new = fetch_long (); // random_id struct message *M = message_get (new); - update_message_id (M, id); + if (M) { + update_message_id (M, id); + } } break; case CODE_update_read_messages: diff --git a/queries.c b/queries.c index 0f87906..02eaf45 100644 --- a/queries.c +++ b/queries.c @@ -1094,8 +1094,9 @@ struct send_file { int part_num; int part_size; long long id; + long long thumb_id; peer_id_t to_id; - int media_type; + unsigned media_type; char *file_name; int encr; unsigned char *iv; @@ -1225,12 +1226,14 @@ void send_part (struct send_file *f) { } else { assert (f->part_size == x); } + update_prompt (); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); } else { cur_uploaded_bytes -= f->size; cur_uploading_bytes -= f->size; + update_prompt (); clear_packet (); - assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video); + assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video); if (!f->encr) { out_int (CODE_messages_send_media); out_peer_id (f->to_id); @@ -1245,8 +1248,17 @@ void send_part (struct send_file *f) { char *s = f->file_name + strlen (f->file_name); while (s >= f->file_name && *s != '/') { s --;} out_string (s + 1); - out_string (""); - if (f->media_type == CODE_input_media_uploaded_video) { + if (f->size < (16 << 20)) { + out_string (""); + } + if (f->media_type == CODE_input_media_uploaded_thumb_video) { + out_int (CODE_input_file); + out_long (f->thumb_id); + out_int (1); + out_string ("thumb.jpg"); + out_string (""); + } + if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video) { out_int (100); out_int (100); out_int (100); @@ -1296,7 +1308,9 @@ void send_part (struct send_file *f) { } out_long (f->id); out_int (f->part_num); - out_string (""); + if (f->size < (16 << 20)) { + out_string (""); + } unsigned char md5[16]; unsigned char str[64]; @@ -1329,6 +1343,16 @@ void send_part (struct send_file *f) { } } +void send_file_thumb (struct send_file *f) { + clear_packet (); + f->thumb_id = lrand48 () * (1ll << 32) + lrand48 (); + out_int (CODE_upload_save_file_part); + out_long (f->thumb_id); + out_int (0); + out_cstring ((void *)thumb_file, thumb_file_size); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); +} + void do_send_photo (int type, peer_id_t to_id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { @@ -1379,7 +1403,12 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); return; } - send_part (f); + if (f->media_type == CODE_input_media_uploaded_video && !f->encr) { + f->media_type = CODE_input_media_uploaded_thumb_video; + send_file_thumb (f); + } else { + send_part (f); + } } /* }}} */ @@ -1713,6 +1742,11 @@ void load_next_part (struct download *D) { } void do_load_photo_size (struct photo_size *P, int next) { + if (!P->loc.dc) { + rprintf ("Bad video thumb\n"); + return; + } + assert (P); assert (next); struct download *D = malloc (sizeof (*D)); From dd3fb59dbe25014ae53c6e419237becd846d4d33 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 02:46:17 +0400 Subject: [PATCH 083/465] Add suggested contacts query --- interface.c | 4 ++++ queries.c | 42 ++++++++++++++++++++++++++++++++++++++++++ queries.h | 1 + 3 files changed, 47 insertions(+) diff --git a/interface.c b/interface.c index e236a10..82fded1 100644 --- a/interface.c +++ b/interface.c @@ -254,6 +254,7 @@ char *commands[] = { "mark_read", "visualize_key", "create_secret_chat", + "suggested_contacts", 0 }; int commands_flags[] = { @@ -283,6 +284,7 @@ int commands_flags[] = { 072, 075, 071, + 07, }; int get_complete_mode (void) { @@ -752,6 +754,8 @@ void interpreter (char *line UU) { } else if (IS_WORD ("create_secret_chat")) { GET_PEER; do_create_secret_chat (id); + } else if (IS_WORD ("suggested_contacts")) { + do_get_suggested (); } #undef IS_WORD #undef RET diff --git a/queries.c b/queries.c index 1c84565..0724a78 100644 --- a/queries.c +++ b/queries.c @@ -2388,6 +2388,48 @@ void do_visualize_key (peer_id_t id) { } /* }}} */ +/* {{{ Get suggested */ +int get_suggested_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_contacts_suggested); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + logprintf ("n = %d\n", n); + assert (n <= 200); + int l[400]; + int i; + for (i = 0; i < n; i++) { + assert (fetch_int () == CODE_contact_suggested); + l[2 * i] = fetch_int (); + l[2 * i + 1] = fetch_int (); + } + assert (fetch_int () == CODE_vector); + int m = fetch_int (); + assert (n == m); + print_start (); + push_color (COLOR_YELLOW); + for (i = 0; i < m; i++) { + peer_t *U = (void *)fetch_alloc_user (); + assert (get_peer_id (U->id) == l[2 * i]); + print_user_name (U->id, U); + printf ("phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); + } + pop_color (); + print_end (); + return 0; +} + +struct query_methods get_suggested_methods = { + .on_answer = get_suggested_on_answer +}; + +void do_get_suggested (void) { + clear_packet (); + out_int (CODE_contacts_get_suggested); + out_int (100); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_suggested_methods, 0); +} +/* }}} */ + /* {{{ Create secret chat */ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); diff --git a/queries.h b/queries.h index 3088a12..18f65d1 100644 --- a/queries.h +++ b/queries.h @@ -83,6 +83,7 @@ void do_rename_chat (peer_id_t id, char *name); void do_load_encr_video (struct encr_video *V, int next); void do_create_encr_chat_request (struct secret_chat *E); void do_create_secret_chat (peer_id_t id); +void do_get_suggested (void); struct photo; struct video; From 032755e2776c8787b48b20aaa6c83b7129e0841d Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 02:52:00 +0400 Subject: [PATCH 084/465] Fixed interface in suggested contacts query --- queries.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/queries.c b/queries.c index 0724a78..a4acb6a 100644 --- a/queries.c +++ b/queries.c @@ -2411,7 +2411,7 @@ int get_suggested_on_answer (struct query *q UU) { peer_t *U = (void *)fetch_alloc_user (); assert (get_peer_id (U->id) == l[2 * i]); print_user_name (U->id, U); - printf ("phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); + printf (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); } pop_color (); print_end (); From cd775dc273e3bfa8146d71e7452ca88d32ca0d37 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 03:12:40 +0400 Subject: [PATCH 085/465] Added global_search query --- interface.c | 19 +++++++++++++++++-- queries.c | 10 +++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/interface.c b/interface.c index 82fded1..61705c2 100644 --- a/interface.c +++ b/interface.c @@ -255,6 +255,7 @@ char *commands[] = { "visualize_key", "create_secret_chat", "suggested_contacts", + "global_search", 0 }; int commands_flags[] = { @@ -285,6 +286,7 @@ int commands_flags[] = { 075, 071, 07, + 07, }; int get_complete_mode (void) { @@ -745,6 +747,17 @@ void interpreter (char *line UU) { RET; } do_msg_search (id, from, to, limit, s); + } else if (IS_WORD ("global_search")) { + int from = 0; + int to = 0; + int limit = 40; + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty message\n"); + RET; + } + do_msg_search (PEER_NOT_FOUND, from, to, limit, s); } else if (IS_WORD ("mark_read")) { GET_PEER; do_mark_read (id); @@ -916,9 +929,11 @@ void print_user_name (peer_id_t id, peer_t *U) { if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { push_color (COLOR_REDB); } - if (!U->user.first_name) { + if ((U->flags & FLAG_DELETED) || (U->flags & FLAG_EMPTY)) { + printf ("deleted user#%d", get_peer_id (id)); + } else if (!U->user.first_name || !strlen (U->user.first_name)) { printf ("%s", U->user.last_name); - } else if (!U->user.last_name) { + } else if (!U->user.last_name || !strlen (U->user.last_name)) { printf ("%s", U->user.first_name); } else { printf ("%s %s", U->user.first_name, U->user.last_name); diff --git a/queries.c b/queries.c index a4acb6a..6bf88a3 100644 --- a/queries.c +++ b/queries.c @@ -1971,9 +1971,17 @@ struct query_methods msg_search_methods = { }; void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) { + if (get_peer_type (id) == PEER_ENCR_CHAT) { + rprintf ("Can not search in secure chat\n"); + return; + } clear_packet (); out_int (CODE_messages_search); - out_peer_id (id); + if (get_peer_type (id) == PEER_UNKNOWN) { + out_int (CODE_input_peer_empty); + } else { + out_peer_id (id); + } out_string (s); out_int (CODE_input_messages_filter_empty); out_int (from); From 2650771074e3d2738610fe5028ac835677ab324f Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 03:18:35 +0400 Subject: [PATCH 086/465] Improved help --- interface.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface.c b/interface.c index 61705c2..412ab04 100644 --- a/interface.c +++ b/interface.c @@ -724,7 +724,13 @@ void interpreter (char *line UU) { "view_photo/view_video/view_video_thumb - loads photo/video to download dir and starts system default viewer\n" "show_license - prints contents of GPLv2\n" "search pattern - searches pattern in messages with peer\n" + "global_search pattern - searches pattern in all messages\n" "mark_read - mark read all received messages with peer\n" + "add_contact - tries to add contact to contact-list by phone\n" + "create_secret_chat - creates secret chat with this user\n" + "rename_contact - tries to rename contact. If you have another device it will be a fight\n" + "suggested_contacts - print info about contacts, you have max common friends\n" + "visualize_key - prints visualization of encryption key. You should compare it to your partner's one\n" ); pop_color (); rl_on_new_line (); From d95af09b3083cd5458c7a572678756521a2ba6f6 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 04:08:16 +0400 Subject: [PATCH 087/465] Added queries to add/delete user to group --- interface.c | 14 ++++++++++++ interface.h | 1 + mtproto-client.c | 56 +++++++++++++++++++++++++++++++----------------- queries.c | 44 +++++++++++++++++++++++++++++++++++++ queries.h | 2 ++ 5 files changed, 97 insertions(+), 20 deletions(-) diff --git a/interface.c b/interface.c index 412ab04..279280e 100644 --- a/interface.c +++ b/interface.c @@ -256,6 +256,8 @@ char *commands[] = { "create_secret_chat", "suggested_contacts", "global_search", + "chat_add_user", + "chat_del_user", 0 }; int commands_flags[] = { @@ -287,6 +289,8 @@ int commands_flags[] = { 071, 07, 07, + 0724, + 0724, }; int get_complete_mode (void) { @@ -658,6 +662,16 @@ void interpreter (char *line UU) { GET_PEER; int limit = next_token_int (); do_get_history (id, limit > 0 ? limit : 40); + } else if (IS_WORD ("chat_add_user")) { + GET_PEER_CHAT; + peer_id_t chat_id = id; + GET_PEER_USER; + do_add_user_to_chat (chat_id, id, 100); + } else if (IS_WORD ("chat_del_user")) { + GET_PEER_CHAT; + peer_id_t chat_id = id; + GET_PEER_USER; + do_del_user_from_chat (chat_id, id); } else if (IS_WORD ("add_contact")) { int phone_len, first_name_len, last_name_len; char *phone, *first_name, *last_name; diff --git a/interface.h b/interface.h index c9529a6..3764446 100644 --- a/interface.h +++ b/interface.h @@ -56,6 +56,7 @@ void push_color (const char *color); void print_start (void); void print_end (void); void print_date_full (long t); +void print_date (long t); void update_prompt (void); #endif diff --git a/mtproto-client.c b/mtproto-client.c index 2106e2d..5fddd67 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -728,7 +728,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_pts (); print_start (); push_color (COLOR_YELLOW); - printf ("%d messages marked as read\n", n); + print_date (time (0)); + printf (" %d messages marked as read\n", n); pop_color (); print_end (); } @@ -739,7 +740,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *U = user_chat_get (id); print_start (); push_color (COLOR_YELLOW); - printf ("User "); + print_date (time (0)); + printf (" User "); print_user_name (id, U); printf (" is typing....\n"); pop_color (); @@ -754,7 +756,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *U = user_chat_get (id); print_start (); push_color (COLOR_YELLOW); - printf ("User "); + print_date (time (0)); + printf (" User "); print_user_name (id, U); printf (" is typing in chat "); print_chat_name (chat_id, C); @@ -771,7 +774,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_user_status (&U->user.status); print_start (); push_color (COLOR_YELLOW); - printf ("User "); + print_date (time (0)); + printf (" User "); print_user_name (user_id, U); printf (" is now "); printf ("%s\n", (U->user.status.online > 0) ? "online" : "offline"); @@ -791,7 +795,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { struct user *U = &UC->user; print_start (); push_color (COLOR_YELLOW); - printf ("User "); + 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); } @@ -835,7 +840,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { print_start (); push_color (COLOR_YELLOW); - printf ("User "); + print_date (time (0)); + printf (" User "); print_user_name (user_id, UC); printf (" updated profile photo\n"); pop_color (); @@ -867,7 +873,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { int n = fetch_int (); print_start (); push_color (COLOR_YELLOW); - printf ("Restored %d messages\n", n); + print_date (time (0)); + printf (" Restored %d messages\n", n); pop_color (); print_end (); fetch_skip (n); @@ -880,7 +887,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { int n = fetch_int (); print_start (); push_color (COLOR_YELLOW); - printf ("Deleted %d messages\n", n); + print_date (time (0)); + printf (" Deleted %d messages\n", n); pop_color (); print_end (); fetch_skip (n); @@ -899,7 +907,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *C = user_chat_get (chat_id); print_start (); push_color (COLOR_YELLOW); - printf ("Chat "); + print_date (time (0)); + printf (" Chat "); print_chat_name (chat_id, C); printf (" changed list: now %d members\n", n); pop_color (); @@ -913,7 +922,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_int (); // date print_start (); push_color (COLOR_YELLOW); - printf ("User "); + print_date (time (0)); + printf (" User "); print_user_name (user_id, U); printf (" registered\n"); pop_color (); @@ -926,7 +936,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *U = user_chat_get (user_id); print_start (); push_color (COLOR_YELLOW); - printf ("Updated link with user "); + print_date (time (0)); + printf (" Updated link with user "); print_user_name (user_id, U); printf ("\n"); pop_color (); @@ -949,7 +960,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *U = user_chat_get (user_id); print_start (); push_color (COLOR_YELLOW); - printf ("User "); + print_date (time (0)); + printf (" User "); print_user_name (user_id, U); printf (" activated\n"); pop_color (); @@ -964,7 +976,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { char *location = fetch_str_dup (); print_start (); push_color (COLOR_YELLOW); - printf ("New autorization: device='%s' location='%s'\n", + print_date (time (0)); + printf (" New autorization: device='%s' location='%s'\n", s, location); pop_color (); print_end (); @@ -994,27 +1007,28 @@ void work_update (struct connection *c UU, long long msg_id UU) { struct secret_chat *E = fetch_alloc_encrypted_chat (); print_start (); push_color (COLOR_YELLOW); + print_date (time (0)); switch (E->state) { case sc_none: assert (0); break; case sc_waiting: - printf ("Encrypted chat "); + printf (" Encrypted chat "); print_encr_chat_name (E->id, (void *)E); printf (" is now in wait state\n"); break; case sc_request: - printf ("Encrypted chat "); + printf (" Encrypted chat "); print_encr_chat_name (E->id, (void *)E); printf (" is now in request state. Sending request ok\n"); break; case sc_ok: - printf ("Encrypted chat "); + printf (" Encrypted chat "); print_encr_chat_name (E->id, (void *)E); printf (" is now in ok state\n"); break; case sc_deleted: - printf ("Encrypted chat "); + printf (" Encrypted chat "); print_encr_chat_name (E->id, (void *)E); printf (" is now in deleted state\n"); break; @@ -1033,15 +1047,16 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *P = user_chat_get (id); print_start (); push_color (COLOR_YELLOW); + print_date (time (0)); if (P) { - printf ("User "); + printf (" User "); peer_id_t user_id = MK_USER (P->encr_chat.user_id); print_user_name (user_id, user_chat_get (user_id)); printf (" typing in secret chat "); print_encr_chat_name (id, P); printf ("\n"); } else { - printf ("Some user is typing in unknown secret chat\n"); + printf (" Some user is typing in unknown secret chat\n"); } pop_color (); print_end (); @@ -1067,7 +1082,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { } print_start (); push_color (COLOR_YELLOW); - printf ("Encrypted chat "); + print_date (time (0)); + printf (" Encrypted chat "); print_encr_chat_name_full (id, user_chat_get (id)); printf (": %d messages marked read \n", x); pop_color (); diff --git a/queries.c b/queries.c index 6bf88a3..f78e6bd 100644 --- a/queries.c +++ b/queries.c @@ -2438,6 +2438,50 @@ void do_get_suggested (void) { } /* }}} */ +/* {{{ Add user to chat */ + +struct query_methods add_user_to_chat_methods = { + .on_answer = fwd_msg_on_answer +}; + +void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit) { + clear_packet (); + out_int (CODE_messages_add_chat_user); + out_int (get_peer_id (chat_id)); + + assert (get_peer_type (id) == PEER_USER); + peer_t *U = user_chat_get (id); + if (U && U->user.access_hash) { + out_int (CODE_input_user_foreign); + out_int (get_peer_id (id)); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_user_contact); + out_int (get_peer_id (id)); + } + out_int (limit); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_user_to_chat_methods, 0); +} + +void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id) { + clear_packet (); + out_int (CODE_messages_delete_chat_user); + out_int (get_peer_id (chat_id)); + + assert (get_peer_type (id) == PEER_USER); + peer_t *U = user_chat_get (id); + if (U && U->user.access_hash) { + out_int (CODE_input_user_foreign); + out_int (get_peer_id (id)); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_user_contact); + out_int (get_peer_id (id)); + } + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_user_to_chat_methods, 0); +} +/* }}} */ + /* {{{ Create secret chat */ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); diff --git a/queries.h b/queries.h index 18f65d1..e651d66 100644 --- a/queries.h +++ b/queries.h @@ -103,5 +103,7 @@ void do_get_difference (void); void do_mark_read (peer_id_t id); void do_visualize_key (peer_id_t id); void do_create_keys_end (struct secret_chat *U); +void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit); +void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); #endif From 6360eeb7ddb48f7faa741aabad479bccb40911ae Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 21:37:12 +0400 Subject: [PATCH 088/465] Fixes some bugs in network --- mtproto-client.c | 4 ++++ net.c | 7 ++++--- queries.c | 7 +++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 5fddd67..3166308 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1390,6 +1390,10 @@ int rpc_execute (struct connection *c, int op, int len) { if (verbosity) { logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); } + if (op < 0) { + assert (read_in (c, Response, Response_len) == Response_len); + return 0; + } if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); diff --git a/net.c b/net.c index b03a5c6..9c8013e 100644 --- a/net.c +++ b/net.c @@ -141,7 +141,7 @@ int read_in (struct connection *c, void *data, int len) { int x = 0; while (len) { int y = c->in_head->wptr - c->in_head->rptr; - if (y > len) { + if (y >= len) { memcpy (data, c->in_head->rptr, len); c->in_head->rptr += len; c->in_bytes -= len; @@ -164,7 +164,7 @@ int read_in (struct connection *c, void *data, int len) { } int read_in_lookup (struct connection *c, void *data, int len) { - if (!len) { return 0; } + if (!len || !c->in_bytes) { return 0; } assert (len > 0); if (len > c->in_bytes) { len = c->in_bytes; @@ -173,12 +173,13 @@ int read_in_lookup (struct connection *c, void *data, int len) { struct connection_buffer *b = c->in_head; while (len) { int y = b->wptr - b->rptr; - if (y > len) { + if (y >= len) { memcpy (data, b->rptr, len); return x + len; } else { memcpy (data, b->rptr, y); x += y; + data += y; b = b->next; } } diff --git a/queries.c b/queries.c index f78e6bd..adb99df 100644 --- a/queries.c +++ b/queries.c @@ -1373,12 +1373,11 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { f->size = size; f->offset = 0; f->part_num = 0; -/* int tmp = ((size + 1999) / 2000); + int tmp = ((size + 2999) / 3000); f->part_size = (1 << 10); while (f->part_size < tmp) { f->part_size *= 2; - }*/ - f->part_size = 256 << 10; + } f->id = lrand48 () * (1ll << 32) + lrand48 (); f->to_id = to_id; @@ -1398,7 +1397,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { ((int *)f->key)[i] = mrand48 (); } } - if (f->part_size >= (512 << 10)) { + if (f->part_size > (512 << 10)) { close (fd); rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); return; From 87a35ca58864f7a79b82c50a51d70dc65163a53e Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 7 Nov 2013 22:31:58 +0400 Subject: [PATCH 089/465] Some fixes in network --- net.c | 19 +++++++++++++++---- queries.c | 6 +++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/net.c b/net.c index 9c8013e..9ae8215 100644 --- a/net.c +++ b/net.c @@ -44,15 +44,20 @@ extern struct connection_methods auth_methods; void fail_connection (struct connection *c); +#define PING_TIMEOUT 10 + void start_ping_timer (struct connection *c); int ping_alarm (struct connection *c) { if (verbosity > 2) { logprintf ("ping alarm\n"); } - if (get_double_time () - c->last_receive_time > 20) { + if (get_double_time () - c->last_receive_time > 20 * PING_TIMEOUT) { + if (verbosity) { + logprintf ( "fail connection: reason: ping timeout\n"); + } c->state = conn_failed; fail_connection (c); - } else if (get_double_time () - c->last_receive_time > 5 && c->state == conn_ready) { + } else if (get_double_time () - c->last_receive_time > 5 * PING_TIMEOUT && c->state == conn_ready) { int x[3]; x[0] = CODE_ping; *(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 (); @@ -69,7 +74,7 @@ void stop_ping_timer (struct connection *c) { } void start_ping_timer (struct connection *c) { - c->ev.timeout = get_double_time () + 1; + c->ev.timeout = get_double_time () + PING_TIMEOUT; c->ev.alarm = (void *)ping_alarm; c->ev.self = c; insert_event_timer (&c->ev); @@ -358,6 +363,9 @@ void try_write (struct connection *c) { delete_connection_buffer (b); } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { + if (verbosity) { + logprintf ("fail_connection: write_error %m\n"); + } fail_connection (c); return; } else { @@ -459,6 +467,9 @@ void try_read (struct connection *c) { c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { + if (verbosity) { + logprintf ("fail_connection: read_error %m\n"); + } fail_connection (c); return; } else { @@ -512,7 +523,7 @@ void connections_poll_result (struct pollfd *fds, int max) { } if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) { if (verbosity) { - logprintf ( "fail connection\n"); + logprintf ("fail_connection: events_mask=0x%08x\n", fds[i].revents); } fail_connection (c); } else if (fds[i].revents & POLLOUT) { diff --git a/queries.c b/queries.c index adb99df..85b4a54 100644 --- a/queries.c +++ b/queries.c @@ -56,7 +56,7 @@ long long cur_downloading_bytes; long long cur_downloaded_bytes; void out_peer_id (peer_id_t id); -#define QUERY_TIMEOUT 0.3 +#define QUERY_TIMEOUT 6.0 #define memcmp8(a,b) memcmp ((a), (b), 8) DEFINE_TREE (query, struct query *, memcmp8, 0) ; @@ -80,6 +80,10 @@ int alarm_query (struct query *q) { q->ev.timeout = get_double_time () + QUERY_TIMEOUT; insert_event_timer (&q->ev); + if (q->session->c->out_bytes >= 100000) { + return 0; + } + clear_packet (); out_int (CODE_msg_container); out_int (1); From 92b65f2dc02a9888ce9a54ed353dd323135b8d77 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 8 Nov 2013 22:58:28 +0400 Subject: [PATCH 090/465] Added libconfig to parse config. Something fixed in net --- Makefile | 2 +- loop.c | 3 +- main.c | 189 +++++++++++++++++++++++++++++++---------------- mtproto-client.c | 7 +- net.c | 5 +- net.h | 2 +- queries.c | 56 ++++++-------- 7 files changed, 162 insertions(+), 102 deletions(-) diff --git a/Makefile b/Makefile index 11a112b..bd9b42a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC=cc CFLAGS=-c -Wall -Wextra -Werror -fPIC -ggdb -O2 -fno-omit-frame-pointer -fno-strict-aliasing -rdynamic -LDFLAGS=-lreadline -lssl -lcrypto -lrt -lz -ggdb -rdynamic +LDFLAGS=-lreadline -lssl -lcrypto -lrt -lz -lconfig -ggdb -rdynamic LD=cc SRC=main.c loop.c interface.c net.c mtproto-common.c mtproto-client.c queries.c structures.c diff --git a/loop.c b/loop.c index b7833a7..8644877 100644 --- a/loop.c +++ b/loop.c @@ -43,6 +43,7 @@ extern char *default_username; extern char *auth_token; +extern int test_dc; void set_default_username (const char *s); int default_dc_num; @@ -188,7 +189,7 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { } void empty_auth_file (void) { - struct dc *DC = alloc_dc (1, strdup (TG_SERVER), 443); + struct dc *DC = alloc_dc (1, strdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); assert (DC); dc_working_num = 1; auth_state = 0; diff --git a/main.c b/main.c index 0bd5580..bfe9e62 100644 --- a/main.c +++ b/main.c @@ -16,6 +16,7 @@ Copyright Vitaly Valtman 2013 */ +#define _GNU_SOURCE #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include "loop.h" #include "mtproto-client.h" @@ -38,12 +40,12 @@ #define PROGNAME "telegram-client" #define VERSION "0.01" -#define CONFIG_DIRECTORY ".telegram/" -#define CONFIG_FILE CONFIG_DIRECTORY "config" -#define AUTH_KEY_FILE CONFIG_DIRECTORY "auth" -#define STATE_FILE CONFIG_DIRECTORY "state" -#define SECRET_CHAT_FILE CONFIG_DIRECTORY "secret" -#define DOWNLOADS_DIRECTORY "downloads/" +#define CONFIG_DIRECTORY ".telegram" +#define CONFIG_FILE "config" +#define AUTH_KEY_FILE "auth" +#define STATE_FILE "state" +#define SECRET_CHAT_FILE "secret" +#define DOWNLOADS_DIRECTORY "downloads" #define CONFIG_DIRECTORY_MODE 0700 @@ -52,9 +54,16 @@ "# Feel free to put something here\n" char *default_username; -int setup_mode; char *auth_token; int msg_num_mode; +char *config_filename; +char *prefix; +int test_dc; +char *auth_file_name; +char *state_file_name; +char *secret_chat_file_name; +char *downloads_directory; +char *config_directory; void set_default_username (const char *s) { if (default_username) { @@ -63,11 +72,6 @@ void set_default_username (const char *s) { default_username = strdup (s); } -void set_setup_mode (void) { - setup_mode = 1; -} - - /* {{{ TERMINAL */ tcflag_t old_lflag; cc_t old_vtime; @@ -100,7 +104,7 @@ char *get_home_directory (void) { return current_passwd->pw_dir; } } - return 0; + return ""; } char *get_config_directory (void) { @@ -115,63 +119,47 @@ char *get_config_directory (void) { } char *get_config_filename (void) { - char *config_filename; - int length = strlen (get_home_directory ()) + strlen (CONFIG_FILE) + 2; - - config_filename = (char *) calloc (length, sizeof (char)); - sprintf (config_filename, "%s/" CONFIG_FILE, get_home_directory ()); return config_filename; } char *get_auth_key_filename (void) { - char *auth_key_filename; - int length = strlen (get_home_directory ()) + strlen (AUTH_KEY_FILE) + 2; - - auth_key_filename = (char *) calloc (length, sizeof (char)); - sprintf (auth_key_filename, "%s/" AUTH_KEY_FILE, get_home_directory ()); - return auth_key_filename; + return auth_file_name; } char *get_state_filename (void) { - char *state_filename; - int length = strlen (get_home_directory ()) + strlen (STATE_FILE) + 2; - - state_filename = (char *) calloc (length, sizeof (char)); - sprintf (state_filename, "%s/" STATE_FILE, get_home_directory ()); - return state_filename; + return state_file_name; } char *get_secret_chat_filename (void) { - char *secret_chat_filename; - int length = strlen (get_home_directory ()) + strlen (SECRET_CHAT_FILE) + 2; - - secret_chat_filename = (char *) calloc (length, sizeof (char)); - sprintf (secret_chat_filename, "%s/" SECRET_CHAT_FILE, get_home_directory ()); - return secret_chat_filename; + return secret_chat_file_name; } -char *get_downloads_directory (void) -{ - char *downloads_directory; - int length = strlen (get_config_directory ()) + strlen (DOWNLOADS_DIRECTORY) + 2; - - downloads_directory = (char *) calloc (length, sizeof (char)); - sprintf (downloads_directory, "%s/" DOWNLOADS_DIRECTORY, get_config_directory ()); - +char *get_downloads_directory (void) { return downloads_directory; } +char *make_full_path (char *s) { + if (*s != '/') { + char *t = s; + assert (asprintf (&s, "%s/%s", get_home_directory (), s) >= 0); + free (t); + } + return s; +} + void running_for_first_time (void) { + if (config_filename) { + return; // Do not create custom config file + } + assert (asprintf (&config_filename, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, CONFIG_FILE) >= 0); + config_filename = make_full_path (config_filename); + struct stat *config_file_stat = NULL; int config_file_fd; char *config_directory = get_config_directory (); - char *config_filename = get_config_filename (); - char *downloads_directory = get_downloads_directory (); + //char *downloads_directory = get_downloads_directory (); - if (mkdir (config_directory, CONFIG_DIRECTORY_MODE) != 0) { - return; - } else { - printf ("\nRunning " PROGNAME " for first time!!\n"); + if (!mkdir (config_directory, CONFIG_DIRECTORY_MODE)) { printf ("[%s] created\n", config_directory); } @@ -192,21 +180,92 @@ void running_for_first_time (void) { exit (EXIT_FAILURE); } close (config_file_fd); - int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); + /*int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); int x = -1; assert (write (auth_file_fd, &x, 4) == 4); close (auth_file_fd); - printf ("[%s] created\n", config_filename); + printf ("[%s] created\n", config_filename);*/ /* create downloads directory */ - if (mkdir (downloads_directory, 0755) !=0) { + /*if (mkdir (downloads_directory, 0755) !=0) { perror ("creating download directory"); exit (EXIT_FAILURE); + }*/ + } +} + +void parse_config_val (config_t *conf, char **s, char *param_name, const char *default_name, const char *path) { + static char buf[1000]; + int l = 0; + if (prefix) { + l = strlen (prefix); + memcpy (buf, prefix, l); + buf[l ++] = '.'; + } + *s = 0; + const char *r = 0; + strcpy (buf + l, param_name); + config_lookup_string (conf, buf, &r); + if (r) { + if (path) { + assert (asprintf (s, "%s/%s", path, r) >= 0); + } else { + *s = strdup (r); + } + } else { + if (path) { + assert (asprintf (s, "%s/%s", path, default_name) >= 0); + } else { + *s = strdup (default_name); } } +} - set_setup_mode (); +void parse_config (void) { + config_filename = make_full_path (config_filename); + + config_t conf; + config_init (&conf); + if (config_read_file (&conf, config_filename) != CONFIG_TRUE) { + fprintf (stderr, "Can not read config '%s': error '%s' on the line %d\n", config_filename, config_error_text (&conf), config_error_line (&conf)); + exit (2); + } + + if (!prefix) { + config_lookup_string (&conf, "default_profile", (void *)&prefix); + } + + static char buf[1000]; + int l = 0; + if (prefix) { + l = strlen (prefix); + memcpy (buf, prefix, l); + buf[l ++] = '.'; + } + test_dc = 0; + strcpy (buf + l, "test"); + config_lookup_bool (&conf, buf, &test_dc); + + if (!msg_num_mode) { + strcpy (buf + l, "msg_num"); + config_lookup_bool (&conf, buf, &msg_num_mode); + } + + parse_config_val (&conf, &config_directory, "config_directory", CONFIG_DIRECTORY, 0); + config_directory = make_full_path (config_directory); + + parse_config_val (&conf, &auth_file_name, "auth_file", AUTH_KEY_FILE, config_directory); + parse_config_val (&conf, &state_file_name, "state_file", STATE_FILE, config_directory); + parse_config_val (&conf, &secret_chat_file_name, "secret", SECRET_CHAT_FILE, config_directory); + parse_config_val (&conf, &downloads_directory, "downloads", DOWNLOADS_DIRECTORY, config_directory); + + if (!mkdir (config_directory, CONFIG_DIRECTORY_MODE)) { + printf ("[%s] created\n", config_directory); + } + if (!mkdir (downloads_directory, CONFIG_DIRECTORY_MODE)) { + printf ("[%s] created\n", downloads_directory); + } } void inner_main (void) { @@ -214,7 +273,7 @@ void inner_main (void) { } void usage (void) { - printf ("%s [-u username] [-h] [-k public key name]\n", PROGNAME); + printf ("%s [-u username] [-h] [-k public key name] [-N] [-v]\n", PROGNAME); exit (1); } @@ -224,7 +283,7 @@ extern int default_dc_num; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:N")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -235,12 +294,16 @@ void args_parse (int argc, char **argv) { case 'v': verbosity ++; break; - case 'n': - default_dc_num = atoi (optarg); - break; case 'N': msg_num_mode ++; break; + case 'c': + config_filename = strdup (optarg); + break; + case 'p': + prefix = strdup (optarg); + assert (strlen (prefix) <= 100); + break; case 'h': default: usage (); @@ -266,18 +329,20 @@ void sig_handler (int signum) { int main (int argc, char **argv) { signal (SIGSEGV, sig_handler); signal (SIGABRT, sig_handler); - running_for_first_time (); - + + args_parse (argc, argv); printf ( "Telegram-client version " TG_VERSION ", Copyright (C) 2013 Vitaly Valtman\n" "Telegram-client comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions; type `show_license' for details.\n" ); + running_for_first_time (); + parse_config (); + get_terminal_attributes (); - args_parse (argc, argv); inner_main (); diff --git a/mtproto-client.c b/mtproto-client.c index 3166308..23b4063 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1361,8 +1361,9 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, double st = get_server_time (DC); assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); - if (verbosity >= 2) { + if (verbosity >= 1) { logprintf ( "received mesage id %016llx\n", enc->msg_id); + hexdump_in (); } server_last_msg_id = enc->msg_id; @@ -1390,10 +1391,10 @@ int rpc_execute (struct connection *c, int op, int len) { if (verbosity) { logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); } - if (op < 0) { +/* if (op < 0) { assert (read_in (c, Response, Response_len) == Response_len); return 0; - } + }*/ if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); diff --git a/net.c b/net.c index 9ae8215..a17e3bb 100644 --- a/net.c +++ b/net.c @@ -146,7 +146,7 @@ int read_in (struct connection *c, void *data, int len) { int x = 0; while (len) { int y = c->in_head->wptr - c->in_head->rptr; - if (y >= len) { + if (y > len) { memcpy (data, c->in_head->rptr, len); c->in_head->rptr += len; c->in_bytes -= len; @@ -185,6 +185,7 @@ int read_in_lookup (struct connection *c, void *data, int len) { memcpy (data, b->rptr, y); x += y; data += y; + len -= y; b = b->next; } } @@ -405,7 +406,7 @@ void hexdump_buf (struct connection_buffer *b) { void try_rpc_read (struct connection *c) { assert (c->in_head); - if (verbosity >= 4) { + if (verbosity >= 1) { hexdump_buf (c->in_head); } diff --git a/net.h b/net.h index 6061e7b..343f0a7 100644 --- a/net.h +++ b/net.h @@ -23,7 +23,7 @@ struct dc; #include "queries.h" #define TG_SERVER "173.240.5.1" -//#define TG_SERVER "95.142.192.66" +#define TG_SERVER_TEST "173.240.5.253" #define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" #define TG_APP_ID 2899 #define TG_BUILD "203" diff --git a/queries.c b/queries.c index 85b4a54..bd7de57 100644 --- a/queries.c +++ b/queries.c @@ -1159,6 +1159,9 @@ int send_file_on_answer (struct query *q UU) { } int send_encr_file_on_answer (struct query *q UU) { + if (prefetch_int () != (int)CODE_messages_sent_encrypted_file) { + hexdump_in (); + } assert (fetch_int () == (int)CODE_messages_sent_encrypted_file); struct message *M = q->extra; M->date = fetch_int (); @@ -1649,40 +1652,9 @@ void load_next_part (struct download *D); int download_on_answer (struct query *q) { assert (fetch_int () == (int)CODE_upload_file); unsigned x = fetch_int (); + assert (x); struct download *D = q->extra; if (D->fd == -1) { - static char buf[100]; - sprintf (buf, "%s/tmp_%ld_%ld", get_downloads_directory (), lrand48 (), lrand48 ()); - int l = strlen (buf); - switch (x) { - case CODE_storage_file_unknown: - break; - case CODE_storage_file_jpeg: - sprintf (buf + l, "%s", ".jpg"); - break; - case CODE_storage_file_gif: - sprintf (buf + l, "%s", ".gif"); - break; - case CODE_storage_file_png: - sprintf (buf + l, "%s", ".png"); - break; - case CODE_storage_file_mp3: - sprintf (buf + l, "%s", ".mp3"); - break; - case CODE_storage_file_mov: - sprintf (buf + l, "%s", ".mov"); - break; - case CODE_storage_file_partial: - sprintf (buf + l, "%s", ".part"); - break; - case CODE_storage_file_mp4: - sprintf (buf + l, "%s", ".mp4"); - break; - case CODE_storage_file_webp: - sprintf (buf + l, "%s", ".webp"); - break; - } - D->name = strdup (buf); D->fd = open (D->name, O_CREAT | O_WRONLY, 0640); } fetch_int (); // mtime @@ -1719,7 +1691,27 @@ struct query_methods download_methods = { void load_next_part (struct download *D) { if (!D->offset) { + static char buf[1000]; + if (!D->id) { + sprintf (buf, "%s/download_%lld_%d", get_downloads_directory (), D->volume, D->local_id); + } else { + sprintf (buf, "%s/download_%lld", get_downloads_directory (), D->id); + } + D->name = strdup (buf); + struct stat st; + if (stat (buf, &st) >= 0) { + D->offset = st.st_size; + if (D->offset >= D->size) { + cur_downloading_bytes += D->size; + cur_downloaded_bytes += D->offset; + rprintf ("Already downloaded\n"); + end_load (D); + return; + } + } + cur_downloading_bytes += D->size; + cur_downloaded_bytes += D->offset; update_prompt (); } clear_packet (); From e297e2711821695722c18ccfbde74220918d76ae Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 9 Nov 2013 13:51:07 +0400 Subject: [PATCH 091/465] Added queries online/offline/contacts_search --- interface.c | 18 +++++++++++++++++ queries.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ queries.h | 2 ++ 3 files changed, 76 insertions(+) diff --git a/interface.c b/interface.c index 279280e..9e71d9e 100644 --- a/interface.c +++ b/interface.c @@ -258,6 +258,9 @@ char *commands[] = { "global_search", "chat_add_user", "chat_del_user", + "status_online", + "status_offline", + "contacts_search", 0 }; int commands_flags[] = { @@ -291,6 +294,9 @@ int commands_flags[] = { 07, 0724, 0724, + 07, + 07, + 07, }; int get_complete_mode (void) { @@ -789,6 +795,18 @@ void interpreter (char *line UU) { do_create_secret_chat (id); } else if (IS_WORD ("suggested_contacts")) { do_get_suggested (); + } else if (IS_WORD ("status_online")) { + do_update_status (1); + } else if (IS_WORD ("status_offline")) { + do_update_status (0); + } else if (IS_WORD ("contacts_search")) { + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty search query\n"); + RET; + } + do_contacts_search (100, s); } #undef IS_WORD #undef RET diff --git a/queries.c b/queries.c index bd7de57..e50bc44 100644 --- a/queries.c +++ b/queries.c @@ -1988,6 +1988,46 @@ void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) { } /* }}} */ +/* {{{ Contacts search */ +int contacts_search_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_contacts_found); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + assert (fetch_int () == (int)CODE_contact_found); + fetch_int (); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + print_start (); + push_color (COLOR_YELLOW); + for (i = 0; i < n; i++) { + struct user *U = fetch_alloc_user (); + printf ("User "); + push_color (COLOR_RED); + printf ("%s %s", U->first_name, U->last_name); + pop_color (); + printf (". Phone %s\n", U->phone); + } + pop_color (); + print_end (); + return 0; +} + +struct query_methods contacts_search_methods = { + .on_answer = contacts_search_on_answer +}; + +void do_contacts_search (int limit, const char *s) { + clear_packet (); + out_int (CODE_contacts_search); + out_string (s); + out_int (limit); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &contacts_search_methods, 0); +} +/* }}} */ + /* {{{ Encr accept */ int send_encr_accept_on_answer (struct query *q UU) { struct secret_chat *E = fetch_alloc_encrypted_chat (); @@ -2499,3 +2539,19 @@ void do_create_secret_chat (peer_id_t id) { do_create_encr_chat_request (&P->encr_chat); } /* }}} */ + +int update_status_on_answer (struct query *q UU) { + fetch_bool (); + return 0; +} + +struct query_methods update_status_methods = { + .on_answer = update_status_on_answer +}; + +void do_update_status (int online UU) { + clear_packet (); + out_int (CODE_account_update_status); + out_int (online ? CODE_bool_false : CODE_bool_true); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &update_status_methods, 0); +} diff --git a/queries.h b/queries.h index e651d66..ef727ab 100644 --- a/queries.h +++ b/queries.h @@ -105,5 +105,7 @@ void do_visualize_key (peer_id_t id); void do_create_keys_end (struct secret_chat *U); void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit); void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); +void do_update_status (int online UU); +void do_contacts_search (int limit, const char *s); #endif From f16fdbe5c86154d39fbe3ef1578f916544ad1f6e Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 9 Nov 2013 14:00:51 +0400 Subject: [PATCH 092/465] Fixed CE --- queries.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/queries.h b/queries.h index ef727ab..49b10c0 100644 --- a/queries.h +++ b/queries.h @@ -105,7 +105,7 @@ void do_visualize_key (peer_id_t id); void do_create_keys_end (struct secret_chat *U); void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit); void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); -void do_update_status (int online UU); +void do_update_status (int online); void do_contacts_search (int limit, const char *s); #endif From b8dde029c9ac2439d57893f6b68ff75e27a8803e Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 9 Nov 2013 22:23:11 +0400 Subject: [PATCH 093/465] Added quit comman --- interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface.c b/interface.c index 9e71d9e..31ed3c5 100644 --- a/interface.c +++ b/interface.c @@ -261,6 +261,7 @@ char *commands[] = { "status_online", "status_offline", "contacts_search", + "quit", 0 }; int commands_flags[] = { @@ -297,6 +298,7 @@ int commands_flags[] = { 07, 07, 07, + 07, }; int get_complete_mode (void) { @@ -807,6 +809,8 @@ void interpreter (char *line UU) { RET; } do_contacts_search (100, s); + } else if (IS_WORD ("quit")) { + exit (0); } #undef IS_WORD #undef RET From 84f119e900e078f13d62bc66a0391858889f9f9a Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 9 Nov 2013 22:27:08 +0400 Subject: [PATCH 094/465] Committed sample config --- config.sample | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 config.sample diff --git a/config.sample b/config.sample new file mode 100755 index 0000000..4415c46 --- /dev/null +++ b/config.sample @@ -0,0 +1,22 @@ +# This is my real config +# Feel free to edit it + +default_profile = "tele2" + +mts = { + test = false + config_directory = ".telegram/mts" + msg_num = true +} + +tele2 = { + test = false + config_directory = ".telegram/tele2" + msg_num = true +} + +test = { + test = true + config_directory = ".telegram/test" + msg_num = true +} From 728fe454288f75ddb5af7a757219c1b1ee5b363e Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 9 Nov 2013 22:28:52 +0400 Subject: [PATCH 095/465] Fixed permissions for config --- config.sample | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 config.sample diff --git a/config.sample b/config.sample old mode 100755 new mode 100644 From 8c30413d6ccc05933d025dfa333d45a31b985af4 Mon Sep 17 00:00:00 2001 From: vysheng Date: Sun, 10 Nov 2013 02:47:19 +0400 Subject: [PATCH 096/465] Added configure script. Some interface fixes --- Makefile | 45 +- Makefile.in | 35 + config.h | 106 ++ config.h.in | 105 ++ configure | 5089 ++++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 57 + interface.c | 66 +- interface.h | 1 + loop.c | 44 +- main.c | 14 +- net.h | 2 +- structures.c | 3 + 12 files changed, 5509 insertions(+), 58 deletions(-) create mode 100644 Makefile.in create mode 100644 config.h create mode 100644 config.h.in create mode 100755 configure create mode 100644 configure.ac diff --git a/Makefile b/Makefile index bd9b42a..52d0e3e 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,35 @@ -CC=cc -CFLAGS=-c -Wall -Wextra -Werror -fPIC -ggdb -O2 -fno-omit-frame-pointer -fno-strict-aliasing -rdynamic -LDFLAGS=-lreadline -lssl -lcrypto -lrt -lz -lconfig -ggdb -rdynamic -LD=cc +srcdir=. -SRC=main.c loop.c interface.c net.c mtproto-common.c mtproto-client.c queries.c structures.c -OBJ=$(SRC:.c=.o) -EXE=telegram -HDRS=include.h interface.h loop.h mtproto-client.h mtproto-common.h net.h queries.h structures.h telegram.h tree.h +CFLAGS=-g -O2 +LDFLAGS= +CPPFLAGS= +DEFS=-DHAVE_CONFIG_H +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -all: $(SRC) $(EXE) - -$(EXE): $(OBJ) - $(LD) $(OBJ) $(LDFLAGS) -o $@ +EXTRA_LIBS= -lreadline -lconfig +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -lrt ${EXTRA_LIBS} +LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} + +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h +INCLUDE=-I. -I${srcdir} +CC=gcc +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o + +.SUFFIXES: + +.SUFFIXES: .c .h .o + +all: telegram + +${OBJECTS}: ${HEADERS} + +telegram: ${OBJECTS} + ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ + +.c.o : + ${CC} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ -.c.o: - $(CC) $(CFLAGS) $< -o $@ clean: - rm *.o telegram || true + rm -rf *.o telegram > /dev/null || echo "all clean" + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..89a0ab9 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,35 @@ +srcdir=@srcdir@ + +CFLAGS=@CFLAGS@ +LDFLAGS=@LDFLAGS@ +CPPFLAGS=@CPPFLAGS@ +DEFS=@DEFS@ +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb + +EXTRA_LIBS=@EXTRA_LIBS@ +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -lrt ${EXTRA_LIBS} +LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} + +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h +INCLUDE=-I. -I${srcdir} +CC=@CC@ +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o + +.SUFFIXES: + +.SUFFIXES: .c .h .o + +all: telegram + +${OBJECTS}: ${HEADERS} + +telegram: ${OBJECTS} + ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ + +.c.o : + ${CC} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ + + +clean: + rm -rf *.o telegram > /dev/null || echo "all clean" + diff --git a/config.h b/config.h new file mode 100644 index 0000000..73aaaf3 --- /dev/null +++ b/config.h @@ -0,0 +1,106 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* enable libconfig */ +#define ENABLE_LIBCONFIG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define to 1 if you have the `edit' library (-ledit). */ +/* #undef HAVE_LIBEDIT */ + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "telegram" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "telegram 0.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "telegram" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.1" + +/* Use libedit */ +/* #undef READLINE_EDIT */ + +/* Use gnu libreadline */ +#define READLINE_GNU 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..ce8b6b2 --- /dev/null +++ b/config.h.in @@ -0,0 +1,105 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* enable libconfig */ +#undef ENABLE_LIBCONFIG + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + +/* Define to 1 if you have the `edit' library (-ledit). */ +#undef HAVE_LIBEDIT + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strndup' function. */ +#undef HAVE_STRNDUP + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Use libedit */ +#undef READLINE_EDIT + +/* Use gnu libreadline */ +#undef READLINE_GNU + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/configure b/configure new file mode 100755 index 0000000..4bb34ea --- /dev/null +++ b/configure @@ -0,0 +1,5089 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for telegram 0.1. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='telegram' +PACKAGE_TARNAME='telegram' +PACKAGE_VERSION='0.1' +PACKAGE_STRING='telegram 0.1' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="config.h.in" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +EXTRA_LIBS +LIBOBJS +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_libconfig +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures telegram 0.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/telegram] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of telegram 0.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] +--enable-libconfig/--disable-libconfig + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +telegram configure 0.1 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by telegram $as_me 0.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_config_headers="$ac_config_headers config.h" + + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Checks for libraries. + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 +$as_echo_n "checking for sqrt in -lm... " >&6; } +if ${ac_cv_lib_m_sqrt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sqrt (); +int +main () +{ +return sqrt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_sqrt=yes +else + ac_cv_lib_m_sqrt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5 +$as_echo "$ac_cv_lib_m_sqrt" >&6; } +if test "x$ac_cv_lib_m_sqrt" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBM 1 +_ACEOF + + LIBS="-lm $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for AES_set_encrypt_key in -lcrypto" >&5 +$as_echo_n "checking for AES_set_encrypt_key in -lcrypto... " >&6; } +if ${ac_cv_lib_crypto_AES_set_encrypt_key+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char AES_set_encrypt_key (); +int +main () +{ +return AES_set_encrypt_key (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_crypto_AES_set_encrypt_key=yes +else + ac_cv_lib_crypto_AES_set_encrypt_key=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_AES_set_encrypt_key" >&5 +$as_echo "$ac_cv_lib_crypto_AES_set_encrypt_key" >&6; } +if test "x$ac_cv_lib_crypto_AES_set_encrypt_key" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCRYPTO 1 +_ACEOF + + LIBS="-lcrypto $LIBS" + +fi + + +EXTRA_LIBS="" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_save_prompt in -lreadline" >&5 +$as_echo_n "checking for rl_save_prompt in -lreadline... " >&6; } +if ${ac_cv_lib_readline_rl_save_prompt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lreadline $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char rl_save_prompt (); +int +main () +{ +return rl_save_prompt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_readline_rl_save_prompt=yes +else + ac_cv_lib_readline_rl_save_prompt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_save_prompt" >&5 +$as_echo "$ac_cv_lib_readline_rl_save_prompt" >&6; } +if test "x$ac_cv_lib_readline_rl_save_prompt" = xyes; then : + + +$as_echo "#define READLINE_GNU 1" >>confdefs.h + + EXTRA_LIBS+=" -lreadline" ; + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_set_prompt in -ledit" >&5 +$as_echo_n "checking for rl_set_prompt in -ledit... " >&6; } +if ${ac_cv_lib_edit_rl_set_prompt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ledit $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char rl_set_prompt (); +int +main () +{ +return rl_set_prompt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_edit_rl_set_prompt=yes +else + ac_cv_lib_edit_rl_set_prompt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_rl_set_prompt" >&5 +$as_echo "$ac_cv_lib_edit_rl_set_prompt" >&6; } +if test "x$ac_cv_lib_edit_rl_set_prompt" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBEDIT 1 +_ACEOF + + LIBS="-ledit $LIBS" + +fi + + +$as_echo "#define READLINE_EDIT 1" >>confdefs.h + + EXTRA_LIBS+=" -ledit" ; + + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Checking for libconfig" >&5 +$as_echo_n "checking Checking for libconfig... " >&6; } +# Check whether --enable-libconfig was given. +if test "${enable_libconfig+set}" = set; then : + enableval=$enable_libconfig; + if test "x$enableval" = "xno" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 +$as_echo "disabled" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 +$as_echo "enabled" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for config_init in -lconfig" >&5 +$as_echo_n "checking for config_init in -lconfig... " >&6; } +if ${ac_cv_lib_config_config_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lconfig $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char config_init (); +int +main () +{ +return config_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_config_config_init=yes +else + ac_cv_lib_config_config_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_config_config_init" >&5 +$as_echo "$ac_cv_lib_config_config_init" >&6; } +if test "x$ac_cv_lib_config_config_init" = xyes; then : + +$as_echo "#define ENABLE_LIBCONFIG 1" >>confdefs.h + +else + as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 +fi + + EXTRA_LIBS+=" -lconfig" ; + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 +$as_echo "enabled" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for config_init in -lconfig" >&5 +$as_echo_n "checking for config_init in -lconfig... " >&6; } +if ${ac_cv_lib_config_config_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lconfig $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char config_init (); +int +main () +{ +return config_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_config_config_init=yes +else + ac_cv_lib_config_config_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_config_config_init" >&5 +$as_echo "$ac_cv_lib_config_config_init" >&6; } +if test "x$ac_cv_lib_config_config_init" = xyes; then : + +$as_echo "#define ENABLE_LIBCONFIG 1" >>confdefs.h + +else + as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 +fi + + EXTRA_LIBS+=" -lconfig" ; + +fi + + +# Checks for header files. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in fcntl.h malloc.h stdlib.h string.h sys/socket.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for typedefs, structures, and compiler characteristics. +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + + +# Checks for library functions. +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 +$as_echo_n "checking for GNU libc compatible malloc... " >&6; } +if ${ac_cv_func_malloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_malloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *malloc (); +#endif + +int +main () +{ +return ! malloc (0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_malloc_0_nonnull=yes +else + ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } +if test $ac_cv_func_malloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_MALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_MALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" + ;; +esac + + +$as_echo "#define malloc rpl_malloc" >>confdefs.h + +fi + + +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 +$as_echo_n "checking for GNU libc compatible realloc... " >&6; } +if ${ac_cv_func_realloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_realloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include +#else +char *realloc (); +#endif + +int +main () +{ +return ! realloc (0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_realloc_0_nonnull=yes +else + ac_cv_func_realloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } +if test $ac_cv_func_realloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_REALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_REALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" realloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS realloc.$ac_objext" + ;; +esac + + +$as_echo "#define realloc rpl_realloc" >>confdefs.h + +fi + + +for ac_func in memset select strdup strndup +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by telegram $as_me 0.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +telegram config.status 0.1 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f319a33 --- /dev/null +++ b/configure.ac @@ -0,0 +1,57 @@ +AC_PREREQ([2.68]) +AC_INIT([telegram], [0.1]) +AC_CONFIG_SRCDIR([config.h.in]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. +AC_CHECK_LIB([m], [sqrt]) +AC_CHECK_LIB([crypto], [AES_set_encrypt_key]) + +EXTRA_LIBS="" + +AC_CHECK_LIB([readline], [rl_save_prompt], + [ + AC_DEFINE([READLINE_GNU], [1], [Use gnu libreadline]) + [ EXTRA_LIBS+=" -lreadline" ; ] + ], + [ + AC_CHECK_LIB([edit], [rl_set_prompt]) + AC_DEFINE([READLINE_EDIT], [1], [Use libedit]) + [ EXTRA_LIBS+=" -ledit" ; ] + ] +) + +AC_MSG_CHECKING([Checking for libconfig]) +AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], + [ + if test "x$enableval" = "xno" ; then + AC_MSG_RESULT([disabled]) + else + AC_MSG_RESULT([enabled]) + AC_CHECK_LIB([config],[config_init],AC_DEFINE(ENABLE_LIBCONFIG,1,[enable libconfig]),AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) + [EXTRA_LIBS+=" -lconfig" ; ] + fi + ],[ + AC_MSG_RESULT([enabled]) + AC_CHECK_LIB([config],[config_init],AC_DEFINE(ENABLE_LIBCONFIG,1,[enable libconfig]),AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) + [EXTRA_LIBS+=" -lconfig" ; ] + ]) + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h malloc.h stdlib.h string.h sys/socket.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIZE_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([memset select strdup strndup]) + +AC_SUBST(EXTRA_LIBS) +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT + diff --git a/interface.c b/interface.c index 31ed3c5..28cc5dd 100644 --- a/interface.c +++ b/interface.c @@ -17,15 +17,22 @@ Copyright Vitaly Valtman 2013 */ +#include "config.h" #define _GNU_SOURCE + #include #include #include #include #include +#ifdef READLINE_GNU #include #include +#else +#include +#include +#endif #include "include.h" #include "queries.h" @@ -51,6 +58,7 @@ char *line_ptr; extern peer_t *Peers[]; extern int peer_num; + int is_same_word (const char *s, size_t l, const char *word) { return s && word && strlen (word) == l && !memcmp (s, word, l); } @@ -220,9 +228,14 @@ char *complete_none (const char *text UU, int state UU) { return 0; } + +void set_prompt (const char *s) { + rl_set_prompt (s); +} + void update_prompt (void) { print_start (); - rl_set_prompt (get_default_prompt ()); + set_prompt (get_default_prompt ()); rl_redisplay (); print_end (); } @@ -755,9 +768,6 @@ void interpreter (char *line UU) { "visualize_key - prints visualization of encryption key. You should compare it to your partner's one\n" ); pop_color (); - rl_on_new_line (); - //print_end (); - printf ("\033[1K\033H"); } else if (IS_WORD ("show_license")) { char *b = #include "LICENSE.h" @@ -835,20 +845,32 @@ void print_start (void) { assert (!prompt_was); if (readline_active) { saved_point = rl_point; - saved_line = rl_copy_text(0, rl_end); +#ifdef READLINE_GNU + saved_line = rl_copy_text(0, rl_end); rl_save_prompt(); rl_replace_line("", 0); +#else + assert (rl_end >= 0); + saved_line = malloc (rl_end + 1); + memcpy (saved_line, rl_line_buffer, rl_end + 1); + rl_line_buffer[0] = 0; + set_prompt (""); +#endif rl_redisplay(); } prompt_was = 1; } + void print_end (void) { if (in_readline) { return; } assert (prompt_was); if (readline_active) { - rl_set_prompt (get_default_prompt ()); - rl_redisplay(); + set_prompt (get_default_prompt ()); +#if READLINE_GNU rl_replace_line(saved_line, 0); +#else + memcpy (rl_line_buffer, saved_line, rl_end + 1); // not safe, but I hope this would work. +#endif rl_point = saved_point; rl_redisplay(); free(saved_line); @@ -857,26 +879,11 @@ void print_end (void) { } void hexdump (int *in_ptr, int *in_end) { - int saved_point = 0; - char *saved_line = 0; - if (readline_active) { - saved_point = rl_point; - saved_line = rl_copy_text(0, rl_end); - rl_save_prompt(); - rl_replace_line("", 0); - rl_redisplay(); - } + print_start (); int *ptr = in_ptr; - while (ptr < in_end) { fprintf (stdout, " %08x", *(ptr ++)); } - fprintf (stdout, "\n"); - - if (readline_active) { - rl_restore_prompt(); - rl_replace_line(saved_line, 0); - rl_point = saved_point; - rl_redisplay(); - free(saved_line); - } + while (ptr < in_end) { printf (" %08x", *(ptr ++)); } + printf ("\n"); + print_end (); } void logprintf (const char *format, ...) { @@ -1204,3 +1211,10 @@ void print_message (struct message *M) { printf ("\n"); print_end(); } + +void set_interface_callbacks (void) { + readline_active = 1; + rl_callback_handler_install (get_default_prompt (), interpreter); + rl_attempted_completion_function = (CPPFunction *) complete_text; + rl_completion_entry_function = (void *)complete_none; +} diff --git a/interface.h b/interface.h index 3764446..a61f968 100644 --- a/interface.h +++ b/interface.h @@ -59,4 +59,5 @@ void print_date_full (long t); void print_date (long t); void update_prompt (void); +void set_interface_callbacks (void); #endif diff --git a/loop.c b/loop.c index 8644877..15821f1 100644 --- a/loop.c +++ b/loop.c @@ -17,14 +17,20 @@ Copyright Vitaly Valtman 2013 */ #define READLINE_CALLBACKS +#include "config.h" #include #include #include #include +#ifdef READLINE_GNU #include #include +#else +#include +#include +#endif #include #include @@ -51,11 +57,12 @@ extern int unknown_user_list_pos; extern int unknown_user_list[]; int unread_messages; +void got_it (char *line, int len); void net_loop (int flags, int (*is_end)(void)) { while (!is_end ()) { struct pollfd fds[101]; int cc = 0; - if (flags & 1) { + if (flags & 3) { fds[0].fd = 0; fds[0].events = POLLIN; cc ++; @@ -70,9 +77,16 @@ void net_loop (int flags, int (*is_end)(void)) { continue; } work_timers (); - if ((flags & 1) && (fds[0].revents & POLLIN)) { + if ((flags & 3) && (fds[0].revents & POLLIN)) { unread_messages = 0; - rl_callback_read_char (); + if (flags & 1) { + rl_callback_read_char (); + } else { + char *line = 0; + size_t len = 0; + assert (getline (&line, &len, stdin) >= 0); + got_it (line, strlen (line)); + } } connections_poll_result (fds + cc, x - cc); if (unknown_user_list_pos) { @@ -86,9 +100,10 @@ char **_s; size_t *_l; int got_it_ok; -void got_it (char *line) { - *_s = strdup (line); - *_l = strlen (line); +void got_it (char *line, int len) { + line[-- len] = 0; // delete end of line + *_s = line; + *_l = len; got_it_ok = 1; } @@ -97,12 +112,13 @@ int is_got_it (void) { } int net_getline (char **s, size_t *l) { - rl_already_prompted = 1; + fflush (stdout); +// rl_already_prompted = 1; got_it_ok = 0; _s = s; _l = l; - rl_callback_handler_install (0, got_it); - net_loop (1, is_got_it); +// rl_callback_handler_install (0, got_it); + net_loop (2, is_got_it); return 0; } @@ -411,8 +427,7 @@ int new_dc_num; int loop (void) { on_start (); read_auth_file (); - readline_active = 1; - rl_set_prompt (""); + update_prompt (); assert (DC_list[dc_working_num]); if (auth_state == 0) { @@ -534,12 +549,11 @@ int loop (void) { fflush (stdout); fflush (stderr); - rl_callback_handler_install (get_default_prompt (), interpreter); - rl_attempted_completion_function = (CPPFunction *) complete_text; - rl_completion_entry_function = complete_none; - read_state_file (); read_secret_chat_file (); + + set_interface_callbacks (); + do_get_difference (); net_loop (0, dgot); do_get_dialog_list (); diff --git a/main.c b/main.c index bfe9e62..619d488 100644 --- a/main.c +++ b/main.c @@ -17,6 +17,7 @@ Copyright Vitaly Valtman 2013 */ #define _GNU_SOURCE +#include "config.h" #include #include @@ -26,7 +27,12 @@ #include #include #include +#if (READLINE == GNU) #include +#else +#include +#endif + #include #include #include @@ -195,6 +201,7 @@ void running_for_first_time (void) { } } +#ifdef ENABLE_LIBCONFIG void parse_config_val (config_t *conf, char **s, char *param_name, const char *default_name, const char *path) { static char buf[1000]; int l = 0; @@ -267,6 +274,11 @@ void parse_config (void) { printf ("[%s] created\n", downloads_directory); } } +#else +void parse_config (void) { + printf ("libconfig not enabled\n"); +} +#endif void inner_main (void) { loop (); @@ -321,7 +333,7 @@ void print_backtrace (void) { void sig_handler (int signum) { set_terminal_attributes (); - printf ("signal %d received\n", signum); + printf ("Signal %d received\n", signum); print_backtrace (); } diff --git a/net.h b/net.h index 343f0a7..1fda52a 100644 --- a/net.h +++ b/net.h @@ -26,7 +26,7 @@ struct dc; #define TG_SERVER_TEST "173.240.5.253" #define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" #define TG_APP_ID 2899 -#define TG_BUILD "203" +#define TG_BUILD "209" #define TG_VERSION "0.01-beta" diff --git a/structures.c b/structures.c index e49e1ea..bad5cc3 100644 --- a/structures.c +++ b/structures.c @@ -16,6 +16,9 @@ Copyright Vitaly Valtman 2013 */ + +#include "config.h" + #include #include #include "structures.h" From 25541385eed36a2b1251227e6493f2f7e8ce5fa6 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 11 Nov 2013 00:35:08 +0400 Subject: [PATCH 097/465] Fixed CE without libconfig --- main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.c b/main.c index 619d488..4fbc5fb 100644 --- a/main.c +++ b/main.c @@ -38,7 +38,9 @@ #include #include #include +#ifdef ENABLE_LIBCONFIG #include +#endif #include "loop.h" #include "mtproto-client.h" From 70f14b4f45926b15f10260c2888d731f5feb5d86 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 11 Nov 2013 02:33:03 +0400 Subject: [PATCH 098/465] fixed small bug in msg send to not a contact --- queries.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/queries.c b/queries.c index e50bc44..74b01c9 100644 --- a/queries.c +++ b/queries.c @@ -738,7 +738,8 @@ int msg_send_encr_on_answer (struct query *q UU) { } int msg_send_on_answer (struct query *q UU) { - assert (fetch_int () == (int)CODE_messages_sent_message); + unsigned x = fetch_int (); + assert (x == CODE_messages_sent_message || x == CODE_messages_sent_message_link); int id = fetch_int (); // id fetch_date (); fetch_pts (); @@ -746,6 +747,45 @@ int msg_send_on_answer (struct query *q UU) { struct message *M = q->extra; M->id = id; message_insert (M); + if (x == CODE_messages_sent_message_link) { + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + unsigned a, b; + for (i = 0; i < n; i++) { + assert (fetch_int () == (int)CODE_contacts_link); + a = fetch_int (); + assert (a == CODE_contacts_my_link_empty || a == CODE_contacts_my_link_requested || a == CODE_contacts_my_link_contact); + if (a == CODE_contacts_my_link_requested) { + fetch_bool (); + } + b = fetch_int (); + assert (b == CODE_contacts_foreign_link_unknown || b == CODE_contacts_foreign_link_requested || b == CODE_contacts_foreign_link_mutual); + if (b == CODE_contacts_foreign_link_requested) { + fetch_bool (); + } + struct user *U = fetch_alloc_user (); + + U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); + if (a == CODE_contacts_my_link_contact) { + U->flags |= FLAG_USER_IN_CONTACT; + } + U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); + if (b == CODE_contacts_foreign_link_mutual) { + U->flags |= FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT; + } + if (b == CODE_contacts_foreign_link_requested) { + U->flags |= FLAG_USER_OUT_CONTACT; + } + print_start (); + push_color (COLOR_YELLOW); + printf ("Link with user "); + print_user_name (U->id, (void *)U); + printf (" changed\n"); + pop_color (); + print_end (); + } + } logprintf ("Sent: id = %d\n", id); return 0; } From 4fdb69a85f45d8a38f15f896c6d0542ac48bc599 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 11 Nov 2013 15:34:45 +0400 Subject: [PATCH 099/465] Maybe it would compile on mac now --- Makefile | 6 +++--- Makefile.in | 4 ++-- configure | 43 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 8 ++++++++ interface.c | 9 ++++++--- loop.c | 4 ++-- mtproto-client.c | 22 ++++++++++++++++------ mtproto-common.c | 24 +++++++++++++++++++++++- mtproto-common.h | 6 ++++++ net.c | 4 ++++ queries.c | 2 +- tree.h | 2 ++ 12 files changed, 116 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 52d0e3e..8d7759a 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,10 @@ CFLAGS=-g -O2 LDFLAGS= CPPFLAGS= DEFS=-DHAVE_CONFIG_H -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -EXTRA_LIBS= -lreadline -lconfig -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -lrt ${EXTRA_LIBS} +EXTRA_LIBS= -lreadline -lrt -lconfig +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h diff --git a/Makefile.in b/Makefile.in index 89a0ab9..cf92f28 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,10 +4,10 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@EXTRA_LIBS@ -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -lrt ${EXTRA_LIBS} +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h diff --git a/configure b/configure index 4bb34ea..49c45d3 100755 --- a/configure +++ b/configure @@ -3127,6 +3127,49 @@ $as_echo "#define READLINE_EDIT 1" >>confdefs.h fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + + EXTRA_LIBS+=" -lrt" ; + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Checking for libconfig" >&5 $as_echo_n "checking Checking for libconfig... " >&6; } # Check whether --enable-libconfig was given. diff --git a/configure.ac b/configure.ac index f319a33..a1d2d47 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,14 @@ AC_CHECK_LIB([readline], [rl_save_prompt], ] ) +AC_CHECK_LIB([rt], [clock_gettime], + [ + [ EXTRA_LIBS+=" -lrt" ; ] + ], + [ + ] +) + AC_MSG_CHECKING([Checking for libconfig]) AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], [ diff --git a/interface.c b/interface.c index 28cc5dd..3d87912 100644 --- a/interface.c +++ b/interface.c @@ -30,8 +30,8 @@ #include #include #else -#include -#include +#include +#include #endif #include "include.h" @@ -48,6 +48,7 @@ int unread_messages; int msg_num_mode; int in_readline; +int readline_active; long long cur_uploading_bytes; long long cur_uploaded_bytes; @@ -236,7 +237,9 @@ void set_prompt (const char *s) { void update_prompt (void) { print_start (); set_prompt (get_default_prompt ()); - rl_redisplay (); + if (readline_active) { + rl_redisplay (); + } print_end (); } diff --git a/loop.c b/loop.c index 15821f1..4bb3515 100644 --- a/loop.c +++ b/loop.c @@ -28,8 +28,8 @@ #include #include #else -#include -#include +#include +#include #endif #include diff --git a/mtproto-client.c b/mtproto-client.c index 23b4063..c538e44 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -72,13 +72,8 @@ long long precise_time; long long precise_time_rdtsc; double get_utime (int clock_id) { struct timespec T; - #if _POSIX_TIMERS - assert (clock_gettime (clock_id, &T) >= 0); + my_clock_gettime (clock_id, &T); double res = T.tv_sec + (double) T.tv_nsec * 1e-9; - #else - #error "No high-precision clock" - double res = time (); - #endif if (clock_id == CLOCK_REALTIME) { precise_time = (long long) (res * (1LL << 32)); precise_time_rdtsc = rdtsc (); @@ -835,6 +830,7 @@ 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) { struct user *U = &UC->user; @@ -852,6 +848,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { U->photo_small.dc = -2; } else { assert (y == CODE_user_profile_photo); + fetch_long (); // photo_id fetch_file_location (&U->photo_small); fetch_file_location (&U->photo_big); } @@ -865,6 +862,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_file_location (&t); } } + fetch_bool (); } break; case CODE_update_restore_messages: @@ -1412,25 +1410,35 @@ int rpc_execute (struct connection *c, int op, int len) { logprintf ( "have %d Response bytes\n", Response_len); } +#ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); +#endif int o = c_state; if (GET_DC(c)->flags & 1) { o = st_authorized;} switch (o) { case st_reqpq_sent: process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); +#ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); +#endif return 0; case st_reqdh_sent: process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); +#ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); +#endif return 0; case st_client_dh_sent: process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); +#ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); +#endif return 0; case st_authorized: process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); +#ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); +#endif return 0; default: logprintf ( "fatal: cannot receive answer in state %d\n", c_state); @@ -1456,7 +1464,9 @@ int tc_becomes_ready (struct connection *c) { assert (write_out (c, &byte, 1) == 1); flush_out (c); +#ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); +#endif int o = c_state; if (GET_DC(c)->flags & 1) { o = st_authorized; } switch (o) { diff --git a/mtproto-common.c b/mtproto-common.c index 201ab68..ab3614e 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -36,6 +36,13 @@ #include "mtproto-common.h" #include "interface.h" +#include "include.h" + +#ifdef __MACH__ +#include +#include +#endif + int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr; int *packet_buffer = __packet_buffer + 16; @@ -78,13 +85,28 @@ int get_random_bytes (void *buf, int n) { return r; } +void my_clock_gettime (int clock_id UU, struct timespec *T) { +#ifdef __MACH__ + // We are ignoring MONOTONIC and hope time doesn't go back to often + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + T->tv_sec = mts.tv_sec; + T->tv_nsec = mts.tv_nsec; +#else + assert (clock_gettime(clock_id, T) >= 0); +#endif +} + void prng_seed (const char *password_filename, int password_length) { unsigned char *a = calloc (64 + password_length, 1); assert (a != NULL); long long r = rdtsc (); struct timespec T; - assert (clock_gettime(CLOCK_REALTIME, &T) >= 0); + my_clock_gettime (CLOCK_REALTIME, &T); memcpy (a, &T.tv_sec, 4); memcpy (a+4, &T.tv_nsec, 4); memcpy (a+8, &r, 8); diff --git a/mtproto-common.h b/mtproto-common.h index 94c97ac..df696cc 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -385,4 +385,10 @@ static inline void hexdump_in (void) { static inline void hexdump_out (void) { hexdump (packet_buffer, packet_ptr); } + +#ifdef __MACH__ +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#endif +void my_clock_gettime (int clock_id, struct timespec *T); #endif diff --git a/net.c b/net.c index a17e3bb..4db2677 100644 --- a/net.c +++ b/net.c @@ -37,6 +37,10 @@ #include "tree.h" #include "interface.h" +#ifdef __MACH__ +#define POLLRDHUP 0 +#endif + DEFINE_TREE(int,int,int_cmp,0) int verbosity; diff --git a/queries.c b/queries.c index 74b01c9..61664b8 100644 --- a/queries.c +++ b/queries.c @@ -64,7 +64,7 @@ struct tree_query *queries_tree; double get_double_time (void) { struct timespec tv; - clock_gettime (CLOCK_REALTIME, &tv); + my_clock_gettime (CLOCK_REALTIME, &tv); return tv.tv_sec + 1e-9 * tv.tv_nsec; } diff --git a/tree.h b/tree.h index 8f38e17..d5cdb73 100644 --- a/tree.h +++ b/tree.h @@ -21,7 +21,9 @@ #include #include +#ifdef HAVE_MALLOC_H #include +#endif #include #define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ From 1c6e84b999800ca53cb8601a79ec1bca4205ca89 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 11 Nov 2013 22:35:31 +0400 Subject: [PATCH 100/465] Fixed bug in read config --- config.sample | 26 +++++++++++++------------- main.c | 9 +++------ mtproto-client.c | 2 +- queries.c | 2 +- structures.c | 6 ++++-- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/config.sample b/config.sample index 4415c46..588090f 100644 --- a/config.sample +++ b/config.sample @@ -1,22 +1,22 @@ # This is my real config # Feel free to edit it -default_profile = "tele2" +default_profile = "tele2"; mts = { - test = false - config_directory = ".telegram/mts" - msg_num = true -} + test = false; + config_directory = ".telegram/mts"; + msg_num = true; +}; tele2 = { - test = false - config_directory = ".telegram/tele2" - msg_num = true -} + test = false; + config_directory = ".telegram/tele2"; + msg_num = true; +}; test = { - test = true - config_directory = ".telegram/test" - msg_num = true -} + test = true; + config_directory = ".telegram/test"; + msg_num = true; +}; diff --git a/main.c b/main.c index 4fbc5fb..7873210 100644 --- a/main.c +++ b/main.c @@ -44,6 +44,7 @@ #include "loop.h" #include "mtproto-client.h" +#include "interface.h" #define PROGNAME "telegram-client" #define VERSION "0.01" @@ -162,7 +163,7 @@ void running_for_first_time (void) { assert (asprintf (&config_filename, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, CONFIG_FILE) >= 0); config_filename = make_full_path (config_filename); - struct stat *config_file_stat = NULL; + static struct stat config_file_stat; int config_file_fd; char *config_directory = get_config_directory (); //char *downloads_directory = get_downloads_directory (); @@ -172,17 +173,13 @@ void running_for_first_time (void) { } // see if config file is there - if (stat (config_filename, config_file_stat) != 0) { + if (stat (config_filename, &config_file_stat) != 0) { // config file missing, so touch it config_file_fd = open (config_filename, O_CREAT | O_RDWR, 0600); if (config_file_fd == -1) { perror ("open[config_file]"); exit (EXIT_FAILURE); } - if (fchmod (config_file_fd, CONFIG_DIRECTORY_MODE) != 0) { - perror ("fchmod[" CONFIG_FILE "]"); - exit (EXIT_FAILURE); - } if (write (config_file_fd, DEFAULT_CONFIG_CONTENTS, strlen (DEFAULT_CONFIG_CONTENTS)) <= 0) { perror ("write[config_file]"); exit (EXIT_FAILURE); diff --git a/mtproto-client.c b/mtproto-client.c index c538e44..8435e34 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1207,7 +1207,7 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { } } -#define MAX_PACKED_SIZE (1 << 20) +#define MAX_PACKED_SIZE (1 << 24) void work_packed (struct connection *c, long long msg_id) { assert (fetch_int () == CODE_gzip_packed); static int in_gzip; diff --git a/queries.c b/queries.c index 61664b8..33c2166 100644 --- a/queries.c +++ b/queries.c @@ -179,7 +179,7 @@ void query_error (long long id) { } } -#define MAX_PACKED_SIZE (1 << 20) +#define MAX_PACKED_SIZE (1 << 24) static int packed_buffer[MAX_PACKED_SIZE / 4]; void query_result (long long id UU) { diff --git a/structures.c b/structures.c index bad5cc3..2e7788f 100644 --- a/structures.c +++ b/structures.c @@ -456,8 +456,10 @@ void fetch_photo_size (struct photo_size *S) { S->size = fetch_int (); } else { S->size = prefetch_strlen (); - S->data = malloc (S->size); - memcpy (S->data, fetch_str (S->size), S->size); +// S->data = malloc (S->size); +// assert (S->data); + fetch_str (S->size); +// memcpy (S->data, fetch_str (S->size), S->size); } } } From 5c937ee8c6cc04e6fcbc1fe6c318dc46898fbec2 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 12 Nov 2013 01:59:36 +0400 Subject: [PATCH 101/465] started to add binlog --- main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.c b/main.c index 4fbc5fb..8a1864e 100644 --- a/main.c +++ b/main.c @@ -72,6 +72,7 @@ char *state_file_name; char *secret_chat_file_name; char *downloads_directory; char *config_directory; +int binlog_enabled; void set_default_username (const char *s) { if (default_username) { @@ -269,6 +270,9 @@ void parse_config (void) { parse_config_val (&conf, &secret_chat_file_name, "secret", SECRET_CHAT_FILE, config_directory); parse_config_val (&conf, &downloads_directory, "downloads", DOWNLOADS_DIRECTORY, config_directory); + strcpy (buf + l, "binlog_enabled"); + config_lookup_bool (&conf, buf, &binlog_enabled); + if (!mkdir (config_directory, CONFIG_DIRECTORY_MODE)) { printf ("[%s] created\n", config_directory); } From 22e3367fd177a4a61dcc05a1ca83f28297a391fb Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 12 Nov 2013 15:58:16 +0400 Subject: [PATCH 102/465] Fixed errors without libconfig --- main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.c b/main.c index 7873210..d48e698 100644 --- a/main.c +++ b/main.c @@ -276,6 +276,10 @@ void parse_config (void) { #else void parse_config (void) { printf ("libconfig not enabled\n"); + assert (asprintf (&auth_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, AUTH_KEY_FILE) >= 0); + assert (asprintf (&state_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, STATE_FILE) >= 0); + assert (asprintf (&secret_chat_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, SECRET_CHAT_FILE) >= 0); + assert (asprintf (&downloads_directory, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, DOWNLOADS_DIRECTORY) >= 0); } #endif From fab86252e12c83f798f9ef283a9350b9e7001ffc Mon Sep 17 00:00:00 2001 From: Vysheng Date: Tue, 12 Nov 2013 19:47:41 +0400 Subject: [PATCH 103/465] Supoort for layer 10 --- constants.h | 6 ++++++ mtproto-client.c | 40 ++++++++++++++++++++++++++++++++++++++++ queries.c | 3 +-- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/constants.h b/constants.h index 419f1f9..7998efc 100644 --- a/constants.h +++ b/constants.h @@ -203,6 +203,8 @@ #define CODE_dc_option 0x2ec2a43c #define CODE_config 0x232d5905 #define CODE_nearest_dc 0x8e1a1775 +#define CODE_help_app_update 0x8987f311 +#define CODE_help_no_app_update 0xc45a6536 #define CODE_help_invite_text 0x18cb9f78 #define CODE_messages_stated_messages_links 0x3e74f5c6 #define CODE_messages_stated_message_link 0xa9af2881 @@ -254,6 +256,8 @@ #define CODE_messages_sent_encrypted_file 0x9493ff32 #define CODE_input_file_big 0xfa4f0bb5 #define CODE_input_encrypted_file_big_uploaded 0x2dc173c8 +#define CODE_update_chat_participant_add 0x3a0eeb22 +#define CODE_update_chat_participant_delete 0x6e5f8c22 #define CODE_invoke_after_msg 0xcb9f372d #define CODE_invoke_after_msgs 0x3dc4b4f0 #define CODE_invoke_with_layer1 0x53835315 @@ -315,6 +319,7 @@ #define CODE_upload_get_file 0xe3a6cfb5 #define CODE_help_get_config 0xc4f9186b #define CODE_help_get_nearest_dc 0x1fb33026 +#define CODE_help_get_app_update 0xc812ac7e #define CODE_help_save_app_log 0x6f02f748 #define CODE_help_get_invite_text 0xa4a95186 #define CODE_photos_get_user_photos 0xb7ee553c @@ -352,4 +357,5 @@ #define CODE_upload_save_big_file_part 0xde7b673d #define CODE_init_connection 0x69796de9 #define CODE_invoke_with_layer9 0x76715a63 +#define CODE_invoke_with_layer10 0x39620c41 #endif diff --git a/mtproto-client.c b/mtproto-client.c index 8435e34..32e9567 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1088,6 +1088,45 @@ void work_update (struct connection *c UU, long long msg_id UU) { print_end (); } break; + case CODE_update_chat_participant_add: + { + 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 + + print_start (); + push_color (COLOR_YELLOW); + print_date (time (0)); + printf (" Chat "); + print_chat_name (chat_id, user_chat_get (chat_id)); + printf (": user "); + print_user_name (user_id, user_chat_get (user_id)); + printf (" added by user "); + print_user_name (inviter_id, user_chat_get (inviter_id)); + printf ("\n"); + pop_color (); + print_end (); + } + break; + case CODE_update_chat_participant_delete: + { + peer_id_t chat_id = MK_CHAT (fetch_int ()); + peer_id_t user_id = MK_USER (fetch_int ()); + fetch_int (); // version + + print_start (); + push_color (COLOR_YELLOW); + print_date (time (0)); + printf (" Chat "); + print_chat_name (chat_id, user_chat_get (chat_id)); + printf (": user "); + print_user_name (user_id, user_chat_get (user_id)); + printf (" deleted\n"); + pop_color (); + print_end (); + } + break; default: logprintf ("Unknown update type %08x\n", op); } @@ -1273,6 +1312,7 @@ void work_detained_info (struct connection *c UU, long long msg_id UU) { void work_updates_to_long (struct connection *c UU, long long msg_id UU) { assert (fetch_int () == (int)CODE_updates_too_long); + logprintf ("updates to long... Getting difference\n"); do_get_difference (); } void rpc_execute_answer (struct connection *c, long long msg_id UU) { diff --git a/queries.c b/queries.c index 33c2166..ed3fb47 100644 --- a/queries.c +++ b/queries.c @@ -1489,7 +1489,6 @@ void do_forward_message (peer_id_t id, int n) { return; } clear_packet (); - out_int (CODE_invoke_with_layer9); out_int (CODE_messages_forward_message); out_peer_id (id); out_int (n); @@ -2408,7 +2407,7 @@ struct query_methods get_difference_methods = { void do_get_difference (void) { difference_got = 0; clear_packet (); - out_int (CODE_invoke_with_layer9); + out_int (CODE_invoke_with_layer10); out_int (CODE_init_connection); out_int (TG_APP_ID); if (allow_send_linux_version) { From 2bf075b239d85dbea8fc5d32058dab7819ced302 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Tue, 12 Nov 2013 21:15:48 +0300 Subject: [PATCH 104/465] Update README.md --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 29ef917..d4301e0 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,30 @@ Documentation for MTproto protocol is available here: http://core.telegram.org/m ### Installation -Just run `make` +#### Linux -#### Requirements +Just run + + $ ./configure + $ make + + +#### Mac OS X + +The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) and [libconfig](http://www.hyperrealm.com/libconfig/), which are not included in OS X by default. You have to install these libraries manually, e.g. using [Homebrew](http://brew.sh/). + + $ brew install libconfig + $ brew install readline + $ export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" + $ export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" + $ ./configure && make + +Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. + +#### Other UNIX + +If you manage to launch it on other UNIX, please let me know. -Currently only Linux OS is supported. But if you manage to launch it on OS X or other UNIX, please let me know. ### Usage @@ -26,14 +45,27 @@ By default public key is stored in the same folder named tg.pub: #### Supported commands: -* chat_info -* contact_list -* dialog_list -* help -* history -* msg -* send_photo -* send_text -* send_video -* stats - +* **msg** \ Text - sends message to this peer +* **contact_list** - prints info about users in your contact list +* **stats** - just for debugging +* **history** \ [limit] - prints history (and marks it as read). Default limit = 40 +* **dialog_list** - prints info about your dialogs +* **send_photo** \ \ - sends photo to peer +* **send_video** \ \ - sends video to peer +* **send_text** \ \ - sends text file as plain messages +* **chat_info** \ - prints info about chat +* **user_info** \ - prints info about user +* **fwd** \ \ - forward message to user. You can see message numbers starting client with -N +* **rename_chat** \ \ +* **load_photo**/load_video/load_video_thumb \ - loads photo/video to download dir +* **view_photo**/view_video/view_video_thumb \ - loads photo/video to download dir and starts system default viewer +* **search** \ pattern - searches pattern in messages with peer +* **global_search** pattern - searches pattern in all messages +* **mark_read** \ - mark read all received messages with peer +* **add_contact** \ \ \ - tries to add contact to contact-list by phone +* **create_secret_chat** \ - creates secret chat with this user +* **rename_contact** \ \ \ - tries to rename contact. If you have another device it will be a fight +* **suggested_contacts** - print info about contacts, you have max common friends +* **visualize_key** \ - prints visualization of encryption key. You should compare it to your partner's one +* **show_license** - prints contents of GPLv2 +* **help** - prints this help From 899b02784e8006533c0d719bacbb0eeb090bb147 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 13 Nov 2013 01:43:42 +0400 Subject: [PATCH 105/465] Start add of binlog support --- main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.c b/main.c index 3181c49..ca2282c 100644 --- a/main.c +++ b/main.c @@ -55,6 +55,7 @@ #define STATE_FILE "state" #define SECRET_CHAT_FILE "secret" #define DOWNLOADS_DIRECTORY "downloads" +#define BINLOG_FILE "binlog" #define CONFIG_DIRECTORY_MODE 0700 @@ -266,6 +267,7 @@ void parse_config (void) { parse_config_val (&conf, &state_file_name, "state_file", STATE_FILE, config_directory); parse_config_val (&conf, &secret_chat_file_name, "secret", SECRET_CHAT_FILE, config_directory); parse_config_val (&conf, &downloads_directory, "downloads", DOWNLOADS_DIRECTORY, config_directory); + parse_config_val (&conf, &binlog_file_name, "binlog", BINLOG_FILE, config_directory); strcpy (buf + l, "binlog_enabled"); config_lookup_bool (&conf, buf, &binlog_enabled); From c25fa47660df5d6da23e7ed088d8864ad3fe2f98 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 13 Nov 2013 01:52:30 +0400 Subject: [PATCH 106/465] Another binlog commit --- main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main.c b/main.c index 5109469..e1cd504 100644 --- a/main.c +++ b/main.c @@ -74,6 +74,7 @@ char *state_file_name; char *secret_chat_file_name; char *downloads_directory; char *config_directory; +char *binlog_file_name; int binlog_enabled; void set_default_username (const char *s) { @@ -149,6 +150,10 @@ char *get_downloads_directory (void) { return downloads_directory; } +char *get_binlog_file_name (void) { + return binlog_file_name; +} + char *make_full_path (char *s) { if (*s != '/') { char *t = s; @@ -286,6 +291,7 @@ void parse_config (void) { assert (asprintf (&state_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, STATE_FILE) >= 0); assert (asprintf (&secret_chat_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, SECRET_CHAT_FILE) >= 0); assert (asprintf (&downloads_directory, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, DOWNLOADS_DIRECTORY) >= 0); + assert (asprintf (&binlog_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, BINLOG_FILE) >= 0); } #endif From b93c9549f2e6ed83fae163a94c06bb457a1b49e1 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 13 Nov 2013 04:11:25 +0400 Subject: [PATCH 107/465] Added files for binlog --- Makefile | 4 +- Makefile.in | 4 +- binlog.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++ binlog.h | 6 +++ binlog.tl | 10 +++++ loop.c | 5 +++ queries.c | 32 ++++++++------ queries.h | 4 ++ 8 files changed, 169 insertions(+), 18 deletions(-) create mode 100644 binlog.c create mode 100644 binlog.h create mode 100644 binlog.tl diff --git a/Makefile b/Makefile index 8d7759a..3765171 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,10 @@ EXTRA_LIBS= -lreadline -lrt -lconfig LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h INCLUDE=-I. -I${srcdir} CC=gcc -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o .SUFFIXES: diff --git a/Makefile.in b/Makefile.in index cf92f28..ba23e05 100644 --- a/Makefile.in +++ b/Makefile.in @@ -10,10 +10,10 @@ EXTRA_LIBS=@EXTRA_LIBS@ LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o .SUFFIXES: diff --git a/binlog.c b/binlog.c new file mode 100644 index 0000000..ec905d8 --- /dev/null +++ b/binlog.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "binlog.h" +#include "mtproto-common.h" +#include "net.h" + +#define LOG_START 0x8948329a +#define LOG_AUTH_KEY 0x984932aa +#define LOG_DEFAULT_DC 0x95382908 + +#define BINLOG_BUFFER_SIZE (1 << 20) +int binlog_buffer[BINLOG_BUFFER_SIZE]; +int *rptr; +int *wptr; +extern int test_dc; + +#define MAX_LOG_EVENT_SIZE (1 << 17) + +char *get_binlog_file_name (void); +extern struct dc *DC_list[]; +extern struct dc *DC_working; +extern int dc_working_num; + +void replay_log_event (void) { + assert (rptr < wptr); + int op = *rptr; + + in_ptr = rptr; + in_end = wptr; + switch (op) { + case LOG_START: + rptr ++; + return; + case CODE_dc_option: + fetch_dc_option (); + return; + case LOG_AUTH_KEY: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + assert (DC_list[num]); + DC_list[num]->auth_key_id = *(long long *)rptr; + rptr += 2; + memcpy (DC_list[num]->auth_key, rptr, 256); + rptr += 64; + }; + return; + case LOG_DEFAULT_DC: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + DC_working = DC_list[num]; + dc_working_num = num; + } + return; + } +} + +void create_new_binlog (void) { + static int s[1000]; + packet_ptr = s; + out_int (LOG_START); + out_int (CODE_dc_option); + out_int (0); + out_string (""); + out_string (test_dc ? TG_SERVER_TEST : TG_SERVER); + out_int (443); + + int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL); + assert (write (fd, s, (packet_ptr - s) * 4) == (packet_ptr - s) * 4); + close (fd); +} + + +void replay_log (void) { + if (access (get_binlog_file_name (), F_OK) < 0) { + printf ("No binlog found. Creating new one"); + create_new_binlog (); + } + int fd = open (get_binlog_file_name (), O_RDONLY); + if (fd < 0) { + perror ("binlog open"); + exit (2); + } + int end; + while (1) { + if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) { + if (wptr == rptr) { + wptr = rptr = binlog_buffer; + } else { + int x = wptr - rptr; + memcpy (binlog_buffer, rptr, 4 * x); + wptr -= x; + rptr -= x; + } + int l = (binlog_buffer + BINLOG_BUFFER_SIZE - wptr) * 4; + int k = read (fd, wptr, l); + if (k < 0) { + perror ("read binlog"); + exit (2); + } + assert (!(k & 3)); + if (k < l) { + end = 1; + } + wptr += (k / 4); + } + if (wptr == rptr) { break; } + replay_log_event (); + } + close (fd); +} diff --git a/binlog.h b/binlog.h new file mode 100644 index 0000000..a950682 --- /dev/null +++ b/binlog.h @@ -0,0 +1,6 @@ +#ifndef __BINLOG_H__ +#define __BINLOG_H__ + +void *alloc_log_event (int l); +void replay_log (void); +#endif diff --git a/binlog.tl b/binlog.tl new file mode 100644 index 0000000..c7c80b7 --- /dev/null +++ b/binlog.tl @@ -0,0 +1,10 @@ +log.peer peer_type:int peer_id:int = log.Peer; + +log.dc num:int hostname:string ip:string port:int = log.Event; +log.dcRenum old_num:int new_num:int = log.Event; +log.authKey dc:int key:bytes key_id:long = log.Event; +log.signIn dc:int id:int = log.Event; + + +log.user id:int flags:int access_hash:long first_name:string last_name:string real_first_name:string real_last_name:string phone:string photo:log.Photo photo_id:long photo_big:log.FileLocation photo_small:long.FileLocation = log.Event; + diff --git a/loop.c b/loop.c index 4bb3515..5cfcdb3 100644 --- a/loop.c +++ b/loop.c @@ -46,12 +46,14 @@ #include "queries.h" #include "telegram.h" #include "loop.h" +#include "binlog.h" extern char *default_username; extern char *auth_token; extern int test_dc; void set_default_username (const char *s); int default_dc_num; +extern int binlog_enabled; extern int unknown_user_list_pos; extern int unknown_user_list[]; @@ -426,6 +428,9 @@ int readline_active; int new_dc_num; int loop (void) { on_start (); + if (binlog_enabled) { + replay_log (); + } read_auth_file (); update_prompt (); diff --git a/queries.c b/queries.c index ed3fb47..7b58fb2 100644 --- a/queries.c +++ b/queries.c @@ -302,6 +302,23 @@ void out_random (int n) { /* {{{ Get config */ +void fetch_dc_option (void) { + assert (fetch_int () == CODE_dc_option); + int id = fetch_int (); + int l1 = prefetch_strlen (); + char *name = fetch_str (l1); + int l2 = prefetch_strlen (); + char *ip = fetch_str (l2); + int port = fetch_int (); + if (verbosity) { + logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + } + if (!DC_list[id]) { + alloc_dc (id, strndup (ip, l2), port); + new_dc_num ++; + } +} + int help_get_config_on_answer (struct query *q UU) { assert (fetch_int () == CODE_config); fetch_int (); @@ -318,20 +335,7 @@ int help_get_config_on_answer (struct query *q UU) { assert (n <= 10); int i; for (i = 0; i < n; i++) { - assert (fetch_int () == CODE_dc_option); - int id = fetch_int (); - int l1 = prefetch_strlen (); - char *name = fetch_str (l1); - int l2 = prefetch_strlen (); - char *ip = fetch_str (l2); - int port = fetch_int (); - if (verbosity) { - logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - } - if (!DC_list[id]) { - alloc_dc (id, strndup (ip, l2), port); - new_dc_num ++; - } + fetch_dc_option (); } max_chat_size = fetch_int (); if (verbosity >= 2) { diff --git a/queries.h b/queries.h index 49b10c0..32a613e 100644 --- a/queries.h +++ b/queries.h @@ -108,4 +108,8 @@ void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); void do_update_status (int online); void do_contacts_search (int limit, const char *s); + +// For binlog + +void fetch_dc_option (void); #endif From f3edaaa34624c21081ecf5faeda7bc19f5e538eb Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 15 Nov 2013 04:08:24 +0400 Subject: [PATCH 108/465] Partial support for binlog. It now can track user, secret chat and auth updates. --- Makefile | 2 +- Makefile.in | 2 +- binlog.c | 220 +++++++++++++++++++++++++++++++++++++++++++++-- binlog.h | 17 ++++ loop.c | 19 +++- mtproto-client.c | 48 ++++++++++- mtproto-common.h | 47 ++++++++++ queries.c | 111 +++++++++++++++++++++--- queries.h | 1 + structures.c | 205 ++++++++++++++++++++++++++++--------------- structures.h | 13 ++- 11 files changed, 589 insertions(+), 96 deletions(-) diff --git a/Makefile b/Makefile index 3765171..c7e68f3 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DEFS=-DHAVE_CONFIG_H COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS= -lreadline -lrt -lconfig -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h diff --git a/Makefile.in b/Makefile.in index ba23e05..1bf9014 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,7 +7,7 @@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@EXTRA_LIBS@ -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h diff --git a/binlog.c b/binlog.c index ec905d8..73d543c 100644 --- a/binlog.c +++ b/binlog.c @@ -11,10 +11,7 @@ #include "binlog.h" #include "mtproto-common.h" #include "net.h" - -#define LOG_START 0x8948329a -#define LOG_AUTH_KEY 0x984932aa -#define LOG_DEFAULT_DC 0x95382908 +#include "include.h" #define BINLOG_BUFFER_SIZE (1 << 20) int binlog_buffer[BINLOG_BUFFER_SIZE]; @@ -28,6 +25,14 @@ char *get_binlog_file_name (void); extern struct dc *DC_list[]; extern struct dc *DC_working; extern int dc_working_num; +extern int our_id; +extern int binlog_enabled; + +int in_replay_log; + +void *alloc_log_event (int l UU) { + return binlog_buffer; +} void replay_log_event (void) { assert (rptr < wptr); @@ -41,6 +46,7 @@ void replay_log_event (void) { return; case CODE_dc_option: fetch_dc_option (); + rptr = in_ptr; return; case LOG_AUTH_KEY: rptr ++; @@ -52,6 +58,7 @@ void replay_log_event (void) { rptr += 2; memcpy (DC_list[num]->auth_key, rptr, 256); rptr += 64; + DC_list[num]->flags |= 1; }; return; case LOG_DEFAULT_DC: @@ -63,6 +70,180 @@ void replay_log_event (void) { dc_working_num = num; } return; + case LOG_OUR_ID: + rptr ++; + { + our_id = *(rptr ++); + } + break; + case LOG_DC_SIGNED: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + assert (DC_list[num]); + DC_list[num]->has_auth = 1; + } + break; + case LOG_DC_SALT: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + assert (DC_list[num]); + DC_list[num]->server_salt = *(long long *)rptr; + rptr += 2; + }; + break; + case CODE_user_empty: + case CODE_user_self: + case CODE_user_contact: + case CODE_user_request: + case CODE_user_foreign: + case CODE_user_deleted: + fetch_alloc_user (); + rptr = in_ptr; + return; + case LOG_DH_CONFIG: + get_dh_config_on_answer (0); + rptr = in_ptr; + return; + case LOG_ENCR_CHAT_KEY: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->key_fingerprint = *(long long *)rptr; + rptr += 2; + memcpy (U->key, rptr, 256); + rptr += 64; + }; + return; + case LOG_ENCR_CHAT_SEND_ACCEPT: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->key_fingerprint = *(long long *)rptr; + rptr += 2; + memcpy (U->key, rptr, 256); + rptr += 64; + if (!U->g_key) { + U->g_key = malloc (256); + } + memcpy (U->g_key, rptr, 256); + rptr += 64; + }; + return; + case LOG_ENCR_CHAT_SEND_CREATE: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (!U || (U->flags & FLAG_EMPTY)); + if (!U) { + U = malloc (sizeof (peer_t)); + memset (U, 0, sizeof (peer_t)); + U->id = id; + insert_encrypted_chat ((void *)U); + } else { + U->flags &= ~FLAG_EMPTY; + } + U->flags |= FLAG_CREATED; + U->user_id = *(rptr ++); + memcpy (U->key, rptr, 256); + rptr += 64; + if (!U->print_name) { + peer_t *P = user_chat_get (MK_USER (U->user_id)); + if (P) { + U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + } else { + static char buf[100]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (U->id, "!", buf, 0, 0); + } + } + }; + return; + case LOG_ENCR_CHAT_DELETED: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + if (!U) { + U = malloc (sizeof (peer_t)); + memset (U, 0, sizeof (peer_t)); + U->id = id; + insert_encrypted_chat ((void *)U); + } else { + U->flags &= ~FLAG_EMPTY; + } + U->flags |= FLAG_CREATED; + U->state = sc_deleted; + }; + return; + case LOG_ENCR_CHAT_WAITING: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->state = sc_waiting; + U->date = *(rptr ++); + U->admin_id = *(rptr ++); + U->user_id = *(rptr ++); + U->access_hash = *(long long *)rptr; + rptr += 2; + }; + return; + case LOG_ENCR_CHAT_REQUESTED: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + if (!U) { + U = malloc (sizeof (peer_t)); + memset (U, 0, sizeof (peer_t)); + U->id = id; + insert_encrypted_chat ((void *)U); + } else { + U->flags &= ~FLAG_EMPTY; + } + U->flags |= FLAG_CREATED; + U->state = sc_request; + U->date = *(rptr ++); + U->admin_id = *(rptr ++); + U->user_id = *(rptr ++); + U->access_hash = *(long long *)rptr; + if (!U->print_name) { + peer_t *P = user_chat_get (MK_USER (U->user_id)); + if (P) { + U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + } else { + static char buf[100]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (U->id, "!", buf, 0, 0); + } + } + rptr += 2; + }; + return; + case LOG_ENCR_CHAT_OK: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->state = sc_ok; + } + return; + + default: + logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x]\n", *(rptr - 1), op, *(rptr + 1)); + + assert (0); } } @@ -71,20 +252,27 @@ void create_new_binlog (void) { packet_ptr = s; out_int (LOG_START); out_int (CODE_dc_option); - out_int (0); + out_int (1); out_string (""); out_string (test_dc ? TG_SERVER_TEST : TG_SERVER); out_int (443); + out_int (LOG_DEFAULT_DC); + out_int (1); - int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL); + int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL | O_CREAT, 0600); + if (fd < 0) { + perror ("Write new binlog"); + exit (2); + } assert (write (fd, s, (packet_ptr - s) * 4) == (packet_ptr - s) * 4); close (fd); } void replay_log (void) { + in_replay_log = 1; if (access (get_binlog_file_name (), F_OK) < 0) { - printf ("No binlog found. Creating new one"); + printf ("No binlog found. Creating new one\n"); create_new_binlog (); } int fd = open (get_binlog_file_name (), O_RDONLY); @@ -92,7 +280,7 @@ void replay_log (void) { perror ("binlog open"); exit (2); } - int end; + int end = 0; while (1) { if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) { if (wptr == rptr) { @@ -119,4 +307,20 @@ void replay_log (void) { replay_log_event (); } close (fd); + in_replay_log = 0; +} + +int binlog_fd; +void write_binlog (void) { + binlog_fd = open (get_binlog_file_name (), O_WRONLY); + if (binlog_fd < 0) { + perror ("binlog open"); + exit (2); + } + lseek (binlog_fd, 0, SEEK_END); +} + +void add_log_event (const int *data, int len) { + if (in_replay_log) { return; } + assert (write (binlog_fd, data, len) == len); } diff --git a/binlog.h b/binlog.h index a950682..9c77d78 100644 --- a/binlog.h +++ b/binlog.h @@ -1,6 +1,23 @@ #ifndef __BINLOG_H__ #define __BINLOG_H__ +#define LOG_START 0x8948329a +#define LOG_AUTH_KEY 0x984932aa +#define LOG_DEFAULT_DC 0x95382908 +#define LOG_OUR_ID 0x8943211a +#define LOG_DC_SIGNED 0x234f9893 +#define LOG_DC_SALT 0x92192ffa +#define LOG_DH_CONFIG 0x8983402b +#define LOG_ENCR_CHAT_KEY 0x894320aa +#define LOG_ENCR_CHAT_SEND_ACCEPT 0x12ab01c4 +#define LOG_ENCR_CHAT_SEND_CREATE 0xab091e24 +#define LOG_ENCR_CHAT_DELETED 0x99481230 +#define LOG_ENCR_CHAT_WAITING 0x7102100a +#define LOG_ENCR_CHAT_REQUESTED 0x9011011a +#define LOG_ENCR_CHAT_OK 0x7612ce13 + void *alloc_log_event (int l); void replay_log (void); +void add_log_event (const int *data, int l); +void write_binlog (void); #endif diff --git a/loop.c b/loop.c index 5cfcdb3..fa93451 100644 --- a/loop.c +++ b/loop.c @@ -160,6 +160,7 @@ void write_dc (int auth_file_fd, struct dc *DC) { int our_id; void write_auth_file (void) { + if (binlog_enabled) { return; } int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); int x = DC_SERIALIZED_MAGIC_V2; @@ -216,6 +217,7 @@ void empty_auth_file (void) { int need_dc_list_update; void read_auth_file (void) { + if (binlog_enabled) { return; } int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); if (auth_file_fd < 0) { empty_auth_file (); @@ -308,6 +310,7 @@ extern unsigned char *encr_prime; extern int encr_param_version; void read_secret_chat_file (void) { + if (binlog_enabled) { return; } int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); if (fd < 0) { return; @@ -364,6 +367,7 @@ void read_secret_chat_file (void) { } void write_secret_chat_file (void) { + if (binlog_enabled) { return; } int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); if (fd < 0) { return; @@ -430,12 +434,15 @@ int loop (void) { on_start (); if (binlog_enabled) { replay_log (); + write_binlog (); + } else { + read_auth_file (); } - read_auth_file (); update_prompt (); assert (DC_list[dc_working_num]); - if (auth_state == 0) { + if (!DC_working || !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); @@ -459,7 +466,7 @@ int loop (void) { write_auth_file (); } - if (auth_state == 100) { + if (auth_state == 100 || !(DC_working->has_auth)) { if (!default_username) { size_t size = 0; char *user = 0; @@ -546,6 +553,12 @@ int loop (void) { do_export_auth (i); do_import_auth (i); DC_list[i]->has_auth = 1; + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DC_SIGNED; + ev[1] = i; + add_log_event (ev, 8); + } write_auth_file (); } write_auth_file (); diff --git a/mtproto-client.c b/mtproto-client.c index 32e9567..4c1c1c0 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -44,6 +44,7 @@ #include "loop.h" #include "interface.h" #include "structures.h" +#include "binlog.h" #define sha1 SHA1 @@ -57,6 +58,7 @@ enum dc_state c_state; char nonce[256]; char new_nonce[256]; char server_nonce[256]; +extern int binlog_enabled; int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); @@ -509,6 +511,13 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { sha1 (tmp, 41, sha1_buffer); assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->server_salt; + add_log_event (ev, 16); + }*/ if (verbosity >= 3) { logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); } @@ -525,6 +534,15 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { auth_success ++; GET_DC(c)->flags |= 1; write_auth_file (); + if (binlog_enabled) { + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_AUTH_KEY; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->auth_key_id; + memcpy (ev + 4, GET_DC(c)->auth_key, 256); + add_log_event (ev, 8 + 8 + 256); + } + return 1; } @@ -559,7 +577,7 @@ void init_enc_msg (struct session *S, int useful) { struct dc *DC = S->dc; assert (DC->auth_key_id); enc_msg.auth_key_id = DC->auth_key_id; - assert (DC->server_salt); +// assert (DC->server_salt); enc_msg.server_salt = DC->server_salt; if (!S->session_id) { assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); @@ -1213,6 +1231,14 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { //DC->session_id = fetch_long (); fetch_long (); // unique_id GET_DC(c)->server_salt = fetch_long (); + +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->server_salt; + add_log_event (ev, 16); + }*/ } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { @@ -1294,6 +1320,13 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { fetch_int (); // error_code long long new_server_salt = fetch_long (); GET_DC(c)->server_salt = new_server_salt; +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->server_salt; + add_log_event (ev, 16); + }*/ } void work_pong (struct connection *c UU, long long msg_id UU) { @@ -1389,6 +1422,13 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, if (DC->server_salt != enc->server_salt) { DC->server_salt = enc->server_salt; write_auth_file (); +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = DC->id; + *(long long *)(ev + 2) = DC->server_salt; + add_log_event (ev, 16); + }*/ } int this_server_time = enc->msg_id >> 32LL; @@ -1475,7 +1515,11 @@ int rpc_execute (struct connection *c, int op, int len) { #endif return 0; case st_authorized: - process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); + if (op < 0 && op >= -999) { + logprintf ("Server error %d\n", op); + } else { + process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); + } #ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif diff --git a/mtproto-common.h b/mtproto-common.h index df696cc..ee6cf9d 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -307,6 +307,53 @@ static inline char *fetch_str_dup (void) { return s; } +static inline int fetch_update_str (char **s) { + if (!*s) { + *s = fetch_str_dup (); + return 1; + } + int l = prefetch_strlen (); + char *r = fetch_str (l); + if (memcmp (*s, r, l) || (*s)[l]) { + free (*s); + *s = malloc (l + 1); + memcpy (*s, r, l); + (*s)[l] = 0; + return 1; + } + return 0; +} + +static inline int fetch_update_int (int *value) { + if (*value == *in_ptr) { + in_ptr ++; + return 0; + } else { + *value = *(in_ptr ++); + return 1; + } +} + +static inline int fetch_update_long (long long *value) { + if (*value == *(long long *)in_ptr) { + in_ptr += 2; + return 0; + } else { + *value = *(long long *)(in_ptr); + in_ptr += 2; + return 1; + } +} + +static inline int set_update_int (int *value, int new_value) { + if (*value == new_value) { + return 0; + } else { + *value = new_value; + return 1; + } +} + static inline void fetch_skip (int n) { in_ptr += n; } diff --git a/queries.c b/queries.c index 7b58fb2..8c91003 100644 --- a/queries.c +++ b/queries.c @@ -44,6 +44,7 @@ #include #include "no-preview.h" +#include "binlog.h" #define sha1 SHA1 @@ -55,6 +56,8 @@ long long cur_uploaded_bytes; long long cur_downloading_bytes; long long cur_downloaded_bytes; +extern int binlog_enabled; + void out_peer_id (peer_id_t id); #define QUERY_TIMEOUT 6.0 @@ -303,6 +306,7 @@ void out_random (int n) { /* {{{ Get config */ void fetch_dc_option (void) { + int *start = in_ptr; assert (fetch_int () == CODE_dc_option); int id = fetch_int (); int l1 = prefetch_strlen (); @@ -316,6 +320,9 @@ void fetch_dc_option (void) { if (!DC_list[id]) { alloc_dc (id, strndup (ip, l2), port); new_dc_num ++; + if (binlog_enabled) { + add_log_event (start, 4 * (in_ptr - start)); + } } } @@ -424,6 +431,13 @@ void do_send_code (const char *user) { dc_create_session (DC_working); } dc_working_num = want_dc_num; + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = dc_working_num; + add_log_event (ev, 8); + } + logprintf ("send_code: dc_num = %d\n", dc_working_num); want_dc_num = 0; clear_packet (); @@ -463,11 +477,27 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error dc_working_num = i; DC_working = DC_list[i]; write_auth_file (); + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = i; + add_log_event (ev, 8); + } + check_phone_result = 1; } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { int i = error[s2] - '0'; assert (DC_list[i]); dc_working_num = i; + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = i; + add_log_event (ev, 8); + } + DC_working = DC_list[i]; write_auth_file (); check_phone_result = 1; @@ -536,6 +566,7 @@ int do_get_nearest_dc (void) { /* {{{ Sign in / Sign up */ int sign_in_ok; +int our_id; int sign_in_is_ok (void) { return sign_in_ok; } @@ -546,11 +577,28 @@ int sign_in_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_auth_authorization); int expires = fetch_int (); fetch_user (&User); + if (!our_id) { + our_id = get_peer_id (User.id); + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_OUR_ID; + ev[1] = our_id; + add_log_event (ev, 8); + } + } sign_in_ok = 1; 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; + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DC_SIGNED; + ev[1] = DC_working->id; + add_log_event (ev, 8); + } + return 0; } @@ -734,7 +782,7 @@ void encr_finish (struct secret_chat *E) { /* {{{ Seng msg (plain text) */ int msg_send_encr_on_answer (struct query *q UU) { assert (fetch_int () == CODE_messages_sent_encrypted_message); - logprintf ("Sent\n"); + rprintf ("Sent\n"); struct message *M = q->extra; M->date = fetch_int (); message_insert (M); @@ -790,7 +838,7 @@ int msg_send_on_answer (struct query *q UU) { print_end (); } } - logprintf ("Sent: id = %d\n", id); + rprintf ("Sent: id = %d\n", id); return 0; } @@ -2113,6 +2161,8 @@ int send_encr_request_on_answer (struct query *q UU) { printf ("\n"); pop_color (); print_end (); + + assert (E->state == sc_waiting); } return 0; } @@ -2156,10 +2206,18 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { sha1 ((void *)E->key, 256, sha_buffer); E->key_fingerprint = *(long long *)(sha_buffer + 12); + if (binlog_enabled) { + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_ENCR_CHAT_KEY; + ev[1] = get_peer_id (E->id); + *(long long *)(ev + 2) = E->key_fingerprint; + memcpy (ev + 4, E->key, 256); + add_log_event (ev, 8 + 8 + 256); + } + clear_packet (); out_int (CODE_messages_accept_encryption); out_int (CODE_input_encrypted_chat); - logprintf ("id = %d\n", get_peer_id (E->id)); out_int (get_peer_id (E->id)); out_long (E->access_hash); @@ -2175,15 +2233,22 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (g_a); BN_clear_free (p); BN_clear_free (r); + + if (binlog_enabled) { + int *ev = alloc_log_event (16 + 512); + ev[0] = LOG_ENCR_CHAT_SEND_ACCEPT; + ev[1] = get_peer_id (E->id); + *(long long *)(ev + 2) = E->key_fingerprint; + memcpy (ev + 4, E->key, 256); + memcpy (ev + 68, buf, 256); + add_log_event (ev, 16 + 512); + } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E); } void do_create_keys_end (struct secret_chat *U) { - if (!encr_prime) { - rprintf (COLOR_YELLOW "Something failed in bad moment. Did not fail\n"COLOR_NORMAL); - return; - } + assert (encr_prime); BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); assert (g_b); if (!ctx) { @@ -2212,6 +2277,15 @@ void do_create_keys_end (struct secret_chat *U) { BN_clear_free (g_b); BN_clear_free (r); BN_clear_free (a); + + if (binlog_enabled) { + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_ENCR_CHAT_KEY; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = U->key_fingerprint; + memcpy (ev + 4, U->key, 256); + add_log_event (ev, 8 + 8 + 256); + } } void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { @@ -2264,20 +2338,36 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (p); BN_clear_free (r); + if (binlog_enabled) { + int *ev = alloc_log_event (12 + 256); + ev[0] = LOG_ENCR_CHAT_SEND_CREATE; + ev[1] = get_peer_id (E->id); + ev[2] = E->user_id; + memcpy (ev + 3, E->key, 256); + add_log_event (ev, 12 + 256); + } + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E); } int get_dh_config_on_answer (struct query *q UU) { + int *start = in_ptr; unsigned x = fetch_int (); - assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified); - if (x == CODE_messages_dh_config) { + assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); + if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { encr_root = fetch_int (); if (encr_prime) { free (encr_prime); } int l = prefetch_strlen (); assert (l == 256); encr_prime = (void *)fetch_str_dup (); encr_param_version = fetch_int (); + if (binlog_enabled) { + *start = LOG_DH_CONFIG; + add_log_event (start, 4 * (in_ptr - start)); + *start = CODE_messages_dh_config; + } } + if (x == LOG_DH_CONFIG) { return 0; } int l = prefetch_strlen (); assert (l == 256); unsigned char *random = (void *)fetch_str_dup (); @@ -2411,7 +2501,7 @@ struct query_methods get_difference_methods = { void do_get_difference (void) { difference_got = 0; clear_packet (); - out_int (CODE_invoke_with_layer10); + out_int (CODE_invoke_with_layer9); out_int (CODE_init_connection); out_int (TG_APP_ID); if (allow_send_linux_version) { @@ -2568,6 +2658,7 @@ void do_create_secret_chat (peer_id_t id) { peer_t *U = user_chat_get (id); if (!U) { rprintf ("Can not create chat with unknown user\n"); + return; } peer_t *P = malloc (sizeof (*P)); diff --git a/queries.h b/queries.h index 32a613e..20015ca 100644 --- a/queries.h +++ b/queries.h @@ -111,5 +111,6 @@ void do_contacts_search (int limit, const char *s); // For binlog +int get_dh_config_on_answer (struct query *q); void fetch_dc_option (void); #endif diff --git a/structures.c b/structures.c index 2e7788f..334d65b 100644 --- a/structures.c +++ b/structures.c @@ -30,6 +30,7 @@ #include #include #include "queries.h" +#include "binlog.h" #define sha1 SHA1 @@ -40,24 +41,37 @@ int peer_num; int encr_chats_allocated; int geo_chats_allocated; -void fetch_file_location (struct file_location *loc) { - int x = fetch_int (); - if (x == CODE_file_location_unavailable) { - loc->dc = -1; - loc->volume = fetch_long (); - loc->local_id = fetch_int (); - loc->secret = fetch_long (); - } else { - assert (x == CODE_file_location); - loc->dc = fetch_int ();; - loc->volume = fetch_long (); - loc->local_id = fetch_int (); - loc->secret = fetch_long (); +extern int binlog_enabled; + +void fetch_add_alloc_log_event (void *obj, int (*f)(void *)) { + int *start = in_ptr; + int r = f (obj); + if (binlog_enabled && r) { + add_log_event (start, 4 * (in_ptr - start)); } } -void fetch_user_status (struct user_status *S) { +int fetch_file_location (struct file_location *loc) { int x = fetch_int (); + int new = 0; + if (x == CODE_file_location_unavailable) { + new |= set_update_int (&loc->dc, -1); + new |= fetch_update_long (&loc->volume); + new |= fetch_update_int (&loc->local_id); + new |= fetch_update_long (&loc->secret); + } else { + assert (x == CODE_file_location); + new |= fetch_update_int (&loc->dc); + new |= fetch_update_long (&loc->volume); + new |= fetch_update_int (&loc->local_id); + new |= fetch_update_long (&loc->secret); + } + return new; +} + +int fetch_user_status (struct user_status *S) { + int x = fetch_int (); + int old = S->online; switch (x) { case CODE_user_status_empty: S->online = 0; @@ -73,6 +87,7 @@ void fetch_user_status (struct user_status *S) { default: assert (0); } + return (old == S->online); } int our_id; @@ -134,72 +149,83 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha return strdup (s); } -void fetch_user (struct user *U) { +int fetch_user (struct user *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 = MK_USER (fetch_int ()); - U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT); + if ((U->flags & FLAG_CREATED) && x == CODE_user_empty) { + return 0; + } + int old_flags = U->flags; + U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT | FLAG_CREATED); if (x == CODE_user_empty) { U->flags |= FLAG_EMPTY; - return; + return 0; } + U->flags |= FLAG_CREATED; if (x == CODE_user_self) { assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { our_id = get_peer_id (U->id); write_auth_file (); + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_OUR_ID; + ev[1] = our_id; + add_log_event (ev, 8); + } } } - 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); + int need_update = 0; + need_update |= fetch_update_str (&U->first_name); + need_update |= fetch_update_str (&U->last_name); + if (need_update) { + if (U->print_name) { free (U->print_name); } + U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); + } if (x == CODE_user_deleted) { U->flags |= FLAG_DELETED; - return; - } - if (x == CODE_user_self) { - U->flags |= FLAG_USER_SELF; } else { - U->access_hash = fetch_long (); - } - if (x == CODE_user_foreign) { - U->flags |= FLAG_USER_FOREIGN; - U->phone = 0; - } else { - if (U->phone) { free (U->phone); } - U->phone = fetch_str_dup (); - } - //logprintf ("name = %s, surname = %s, phone = %s\n", U->first_name, U->last_name, U->phone); - unsigned y = fetch_int (); - //fprintf (stderr, "y = 0x%08x\n", y); - if (y == CODE_user_profile_photo_empty) { - U->photo_small.dc = -2; - U->photo_big.dc = -2; - } else { - assert (y == CODE_user_profile_photo || y == 0x990d1493); - if (y == CODE_user_profile_photo) { - fetch_long (); + if (x == CODE_user_self) { + U->flags |= FLAG_USER_SELF; + } else { + need_update |= fetch_update_long (&U->access_hash); + } + if (x == CODE_user_foreign) { + U->flags |= FLAG_USER_FOREIGN; + } else { + need_update |= fetch_update_str (&U->phone); + } + unsigned y = fetch_int (); + if (y == CODE_user_profile_photo_empty) { + need_update |= set_update_int (&U->photo_small.dc, -2); + need_update |= set_update_int (&U->photo_big.dc, -2); + } else { + assert (y == CODE_user_profile_photo); + fetch_long (); + need_update |= fetch_file_location (&U->photo_small); + need_update |= fetch_file_location (&U->photo_big); + } + fetch_user_status (&U->status); + if (x == CODE_user_self) { + fetch_bool (); + } + if (x == CODE_user_contact) { + U->flags |= FLAG_USER_CONTACT; } - fetch_file_location (&U->photo_small); - fetch_file_location (&U->photo_big); - } - fetch_user_status (&U->status); - if (x == CODE_user_self) { - fetch_bool (); - } - if (x == CODE_user_contact) { - U->flags |= FLAG_USER_CONTACT; } + need_update |= (old_flags != U->flags); + return need_update; } void fetch_encrypted_chat (struct secret_chat *U) { unsigned x = fetch_int (); assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); U->id = MK_ENCR_CHAT (fetch_int ()); + if ((U->flags & FLAG_CREATED) && x == CODE_encrypted_chat_empty) { + return; + } U->flags &= ~(FLAG_EMPTY | FLAG_DELETED); enum secret_chat_state old_state = U->state; if (x == CODE_encrypted_chat_empty) { @@ -210,11 +236,18 @@ void fetch_encrypted_chat (struct secret_chat *U) { } return; } + U->flags |= FLAG_CREATED; if (x == CODE_encrypted_chat_discarded) { U->state = sc_deleted; U->flags |= FLAG_DELETED; if (U->state != old_state) { write_secret_chat_file (); + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_ENCR_CHAT_DELETED; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); + } } return; } @@ -222,19 +255,31 @@ void fetch_encrypted_chat (struct secret_chat *U) { U->date = fetch_int (); U->admin_id = fetch_int (); U->user_id = fetch_int () + U->admin_id - our_id; - if (U->print_name) { free (U->print_name); } - - peer_t *P = user_chat_get (MK_USER (U->user_id)); - if (P) { - U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); - } else { - static char buf[100]; - sprintf (buf, "user#%d", U->user_id); - U->print_name = create_print_name (U->id, "!", buf, 0, 0); + if (!U->print_name) { + peer_t *P = user_chat_get (MK_USER (U->user_id)); + if (P) { + U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + } else { + static char buf[100]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (U->id, "!", buf, 0, 0); + } } if (x == CODE_encrypted_chat_waiting) { U->state = sc_waiting; + if (old_state != sc_waiting) { + if (binlog_enabled) { + int *ev = alloc_log_event (28); + ev[0] = LOG_ENCR_CHAT_WAITING; + ev[1] = get_peer_id (U->id); + ev[2] = U->date; + ev[3] = U->admin_id; + ev[4] = U->user_id; + *(long long *)(ev + 5) = U->access_hash; + add_log_event (ev, 28); + } + } } else if (x == CODE_encrypted_chat_requested) { U->state = sc_request; if (!U->g_key) { @@ -259,6 +304,18 @@ void fetch_encrypted_chat (struct secret_chat *U) { } else { memcpy (U->nonce, s + (l - 256), 256); } + if (old_state != sc_request) { + if (binlog_enabled) { + int *ev = alloc_log_event (28); + ev[0] = LOG_ENCR_CHAT_REQUESTED; + ev[1] = get_peer_id (U->id); + ev[2] = U->date; + ev[3] = U->admin_id; + ev[4] = U->user_id; + *(long long *)(ev + 5) = U->access_hash; + add_log_event (ev, 28); + } + } } else { U->state = sc_ok; if (!U->g_key) { @@ -291,6 +348,18 @@ void fetch_encrypted_chat (struct secret_chat *U) { if (old_state == sc_waiting) { do_create_keys_end (U); } + free (U->g_key); + U->g_key = 0; + free (U->nonce); + U->nonce = 0; + if (old_state != sc_ok) { + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_ENCR_CHAT_OK; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); + } + } } if (U->state != old_state) { write_secret_chat_file (); @@ -941,13 +1010,13 @@ struct user *fetch_alloc_user (void) { prefetch_data (data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); if (U) { - fetch_user (&U->user); + fetch_add_alloc_log_event (&U->user, (void *)fetch_user); return &U->user; } else { users_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - fetch_user (&U->user); + fetch_add_alloc_log_event (&U->user, (void *)fetch_user); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[peer_num ++] = U; return &U->user; @@ -1343,7 +1412,7 @@ int print_stat (char *s, int len) { } peer_t *user_chat_get (peer_id_t id) { - peer_t U; + static peer_t U; U.id = id; return tree_lookup_peer (peer_tree, &U); } diff --git a/structures.h b/structures.h index fe34654..a06627a 100644 --- a/structures.h +++ b/structures.h @@ -26,6 +26,7 @@ typedef struct { int type; int id; } peer_id_t; #define FLAG_DELETED 2 #define FLAG_FORBIDDEN 4 #define FLAG_HAS_PHOTO 8 +#define FLAG_CREATED 16 #define FLAG_USER_SELF 128 #define FLAG_USER_FOREIGN 256 @@ -113,6 +114,7 @@ struct user { int flags; struct message *last; char *print_name; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -137,6 +139,7 @@ struct chat { int flags; struct message *last; char *print_title; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -161,6 +164,7 @@ struct secret_chat { int flags; struct message *last; char *print_name; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -183,6 +187,7 @@ typedef union peer { int flags; struct message *last; char *print_name; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -262,9 +267,9 @@ struct message { }; }; -void fetch_file_location (struct file_location *loc); -void fetch_user_status (struct user_status *S); -void fetch_user (struct user *U); +int fetch_file_location (struct file_location *loc); +int fetch_user_status (struct user_status *S); +int fetch_user (struct user *U); struct user *fetch_alloc_user (void); struct user *fetch_alloc_user_full (void); struct chat *fetch_alloc_chat (void); @@ -281,6 +286,8 @@ peer_id_t fetch_peer_id (void); void free_user (struct user *U); void free_chat (struct chat *U); +char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); + int print_stat (char *s, int len); peer_t *user_chat_get (peer_id_t id); struct message *message_get (long long id); From a1ea8bd69caccc357ea9eb8f2b054047fd6d0811 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 15 Nov 2013 14:37:14 +0400 Subject: [PATCH 109/465] Added full support for layer 10 --- constants.h | 19 ++++++ gen_constants_h.awk | 18 ++++++ interface.c | 141 +++++++++++++++++++++++++++++++++++++++++++- net.c | 3 +- queries.c | 46 ++++++++++++--- structures.c | 110 ++++++++++++++++++++++++++++++++-- structures.h | 62 +++++++++++++++++-- 7 files changed, 379 insertions(+), 20 deletions(-) diff --git a/constants.h b/constants.h index 7998efc..fbd674f 100644 --- a/constants.h +++ b/constants.h @@ -258,6 +258,25 @@ #define CODE_input_encrypted_file_big_uploaded 0x2dc173c8 #define CODE_update_chat_participant_add 0x3a0eeb22 #define CODE_update_chat_participant_delete 0x6e5f8c22 +#define CODE_input_media_uploaded_audio 0x61a6d436 +#define CODE_input_media_audio 0x89938781 +#define CODE_input_media_uploaded_document 0x34e794bd +#define CODE_input_media_uploaded_thumb_document 0x3e46de5d +#define CODE_input_media_document 0xd184e841 +#define CODE_message_media_document 0x2fda2204 +#define CODE_message_media_audio 0xc6b68300 +#define CODE_input_audio_empty 0xd95adc84 +#define CODE_input_audio 0x77d440ff +#define CODE_input_document_empty 0x72f0eaae +#define CODE_input_document 0x18798952 +#define CODE_input_audio_file_location 0x74dc404d +#define CODE_input_document_file_location 0x4e45abe9 +#define CODE_decrypted_message_media_document 0xb095434b +#define CODE_decrypted_message_media_audio 0x6080758f +#define CODE_audio_empty 0x586988d8 +#define CODE_audio 0x427425e7 +#define CODE_document_empty 0x36f8c871 +#define CODE_document 0x9efc6326 #define CODE_invoke_after_msg 0xcb9f372d #define CODE_invoke_after_msgs 0x3dc4b4f0 #define CODE_invoke_with_layer1 0x53835315 diff --git a/gen_constants_h.awk b/gen_constants_h.awk index 5088914..06e6835 100644 --- a/gen_constants_h.awk +++ b/gen_constants_h.awk @@ -1,4 +1,22 @@ BEGIN { + print "/*"; + print " This file is part of telegram-client."; + print ""; + print " Telegram-client is free software: you can redistribute it and/or modify"; + print " it under the terms of the GNU General Public License as published by"; + print " the Free Software Foundation, either version 2 of the License, or"; + print " (at your option) any later version."; + print ""; + print " Telegram-client is distributed in the hope that it will be useful,"; + print " but WITHOUT ANY WARRANTY; without even the implied warranty of"; + print " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"; + print " GNU General Public License for more details."; + print ""; + print " You should have received a copy of the GNU General Public License"; + print " along with this telegram-client. If not, see ."; + print ""; + print " Copyright Vitaly Valtman 2013"; + print "*/"; print "#ifndef CONSTANTS_H"; print "#define CONSTANTS_H"; } diff --git a/interface.c b/interface.c index 3d87912..65889d3 100644 --- a/interface.c +++ b/interface.c @@ -278,6 +278,14 @@ char *commands[] = { "status_offline", "contacts_search", "quit", + "send_audio", + "load_audio", + "view_audio", + "send_document", + "load_document_thumb", + "view_document_thumb", + "load_document", + "view_document", 0 }; int commands_flags[] = { @@ -315,6 +323,10 @@ int commands_flags[] = { 07, 07, 07, + 0732, + 07, + 07, + 0732, }; int get_complete_mode (void) { @@ -822,6 +834,110 @@ void interpreter (char *line UU) { RET; } do_contacts_search (100, s); + } else if (IS_WORD("send_audio")) { + GET_PEER; + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty file name\n"); + RET; + } + do_send_photo (CODE_input_media_uploaded_audio, id, strndup (s, t)); + } else if (IS_WORD("send_document")) { + GET_PEER; + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty file name\n"); + RET; + } + do_send_photo (CODE_input_media_uploaded_document, id, strndup (s, t)); + } else if (IS_WORD ("load_audio")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { + do_load_video (&M->media.video, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { + do_load_encr_video (&M->media.encr_video, 1); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("view_audio")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { + do_load_video (&M->media.video, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { + do_load_encr_video (&M->media.encr_video, 2); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("load_document_thumb")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video_thumb (&M->media.video, 1); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("view_document_thumb")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video_thumb (&M->media.video, 2); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("load_document")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video (&M->media.video, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { + do_load_encr_video (&M->media.encr_video, 1); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("view_document")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video (&M->media.video, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { + do_load_encr_video (&M->media.encr_video, 2); + } else { + printf ("Bad msg id\n"); + RET; + } } else if (IS_WORD ("quit")) { exit (0); } @@ -933,12 +1049,28 @@ void print_media (struct message_media *M) { case CODE_message_media_video: printf ("[video]"); return; + case CODE_message_media_audio: + printf ("[audio]"); + return; + case CODE_message_media_document: + if (M->document.mime_type && M->document.caption) { + printf ("[document %s: type %s]", M->document.caption, M->document.mime_type); + } else { + printf ("[document]"); + } + return; case CODE_decrypted_message_media_photo: printf ("[photo]"); return; case CODE_decrypted_message_media_video: printf ("[video]"); return; + case CODE_decrypted_message_media_audio: + printf ("[audio]"); + return; + case CODE_decrypted_message_media_document: + printf ("[document]"); + return; case CODE_message_media_geo: printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude); return; @@ -1055,7 +1187,11 @@ void print_service_message (struct message *M) { print_date (M->date); pop_color (); printf (" "); - print_chat_name (M->to_id, user_chat_get (M->to_id)); + if (get_peer_type (M->to_id) == PEER_CHAT) { + print_chat_name (M->to_id, user_chat_get (M->to_id)); + } else { + print_encr_chat_name (M->to_id, user_chat_get (M->to_id)); + } printf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); @@ -1086,6 +1222,9 @@ void print_service_message (struct message *M) { print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); printf ("\n"); break; + case CODE_decrypted_message_action_set_message_t_t_l: + printf (" set ttl to %d seconds. Unsupported yet\n", M->action.ttl); + break; default: assert (0); } diff --git a/net.c b/net.c index 4db2677..546f48d 100644 --- a/net.c +++ b/net.c @@ -240,6 +240,7 @@ struct connection *create_connection (const char *host, int port, struct session struct pollfd s; s.fd = fd; s.events = POLLOUT | POLLERR | POLLRDHUP | POLLHUP; + errno = 0; while (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { if (errno == EINTR) { continue; } @@ -247,7 +248,7 @@ struct connection *create_connection (const char *host, int port, struct session logprintf ("Problems in poll: %m\n"); exit (1); } - logprintf ("Connect timeout\n"); + logprintf ("Connect with %s:%d timeout\n", host, port); close (fd); free (c); return 0; diff --git a/queries.c b/queries.c index 7b58fb2..a470e49 100644 --- a/queries.c +++ b/queries.c @@ -1284,7 +1284,7 @@ void send_part (struct send_file *f) { cur_uploading_bytes -= f->size; update_prompt (); clear_packet (); - assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video); + assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_audio || f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document); if (!f->encr) { out_int (CODE_messages_send_media); out_peer_id (f->to_id); @@ -1302,7 +1302,7 @@ void send_part (struct send_file *f) { if (f->size < (16 << 20)) { out_string (""); } - if (f->media_type == CODE_input_media_uploaded_thumb_video) { + if (f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_thumb_document) { out_int (CODE_input_file); out_long (f->thumb_id); out_int (1); @@ -1314,6 +1314,14 @@ void send_part (struct send_file *f) { out_int (100); out_int (100); } + if (f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document) { + out_string (s + 1); + out_string ("text"); + } + if (f->media_type == CODE_input_media_uploaded_audio) { + out_int (60); + } + out_long (-lrand48 () * (1ll << 32) - lrand48 ()); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); } else { @@ -1336,18 +1344,37 @@ void send_part (struct send_file *f) { if (f->media_type == CODE_input_media_uploaded_photo) { out_int (CODE_decrypted_message_media_photo); M->media.type = CODE_decrypted_message_media_photo; - } else { + } else if (f->media_type == CODE_input_media_uploaded_video) { out_int (CODE_decrypted_message_media_video); M->media.type = CODE_decrypted_message_media_video; + } else if (f->media_type == CODE_input_media_uploaded_audio) { + out_int (CODE_decrypted_message_media_audio); + M->media.type = CODE_decrypted_message_media_audio; + } else if (f->media_type == CODE_input_media_uploaded_document) { + out_int (CODE_decrypted_message_media_document); + M->media.type = CODE_decrypted_message_media_document;; + } else { + assert (0); + } + if (f->media_type != CODE_input_media_uploaded_audio) { + out_cstring ((void *)thumb_file, thumb_file_size); + out_int (90); + out_int (90); } - out_cstring ((void *)thumb_file, thumb_file_size); - out_int (90); - out_int (90); if (f->media_type == CODE_input_media_uploaded_video) { out_int (0); } - out_int (100); - out_int (100); + if (f->media_type == CODE_input_media_uploaded_document) { + out_string (f->file_name); + out_string ("text"); + } + if (f->media_type == CODE_input_media_uploaded_audio) { + out_int (60); + } + if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_photo) { + out_int (100); + out_int (100); + } out_int (f->size); out_cstring ((void *)f->key, 32); out_cstring ((void *)f->init_iv, 32); @@ -1456,6 +1483,9 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { if (f->media_type == CODE_input_media_uploaded_video && !f->encr) { f->media_type = CODE_input_media_uploaded_thumb_video; send_file_thumb (f); + } else if (f->media_type == CODE_input_media_uploaded_document && !f->encr) { + f->media_type = CODE_input_media_uploaded_thumb_document; + send_file_thumb (f); } else { send_part (f); } diff --git a/structures.c b/structures.c index 2e7788f..08561c9 100644 --- a/structures.c +++ b/structures.c @@ -513,6 +513,34 @@ void fetch_video (struct video *V) { V->h = fetch_int (); } +void fetch_audio (struct audio *V) { + memset (V, 0, sizeof (*V)); + unsigned x = fetch_int (); + V->id = fetch_long (); + if (x == CODE_audio_empty) { return; } + V->access_hash = fetch_long (); + V->user_id = fetch_int (); + V->date = fetch_int (); + V->duration = fetch_int (); + V->size = fetch_int (); + V->dc_id = fetch_int (); +} + +void fetch_document (struct document *V) { + memset (V, 0, sizeof (*V)); + unsigned x = fetch_int (); + V->id = fetch_long (); + if (x == CODE_document_empty) { return; } + V->access_hash = fetch_long (); + V->user_id = fetch_int (); + V->date = fetch_int (); + V->caption = fetch_str_dup (); + V->mime_type = fetch_str_dup (); + V->size = fetch_int (); + fetch_photo_size (&V->thumb); + V->dc_id = fetch_int (); +} + void fetch_message_action (struct message_action *M) { memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); @@ -585,6 +613,12 @@ void fetch_message_media (struct message_media *M) { case CODE_message_media_video: fetch_video (&M->video); break; + case CODE_message_media_audio: + fetch_audio (&M->audio); + break; + case CODE_message_media_document: + fetch_document (&M->document); + break; case CODE_message_media_geo: fetch_geo (&M->geo); break; @@ -646,10 +680,63 @@ void fetch_message_media_encrypted (struct message_media *M) { fetch_str (l); // thumb fetch_int (); // thumb_w fetch_int (); // thumb_h + M->encr_video.duration = fetch_int (); M->encr_video.w = fetch_int (); M->encr_video.h = fetch_int (); M->encr_video.size = fetch_int (); - M->encr_video.duration = fetch_int (); + + l = prefetch_strlen (); + assert (l > 0); + M->encr_video.key = malloc (32); + memset (M->encr_photo.key, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + } + M->encr_video.iv = malloc (32); + l = prefetch_strlen (); + assert (l > 0); + memset (M->encr_video.iv, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + } + break; + case CODE_decrypted_message_media_audio: + M->type = x; + M->encr_audio.duration = fetch_int (); + M->encr_audio.size = fetch_int (); + + l = prefetch_strlen (); + assert (l > 0); + M->encr_video.key = malloc (32); + memset (M->encr_photo.key, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + } + M->encr_video.iv = malloc (32); + l = prefetch_strlen (); + assert (l > 0); + memset (M->encr_video.iv, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + } + break; + case CODE_decrypted_message_media_document: + M->type = x; + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_int (); // thumb_w + fetch_int (); // thumb_h + M->encr_document.file_name = fetch_str_dup (); + M->encr_document.mime_type = fetch_str_dup (); + M->encr_video.size = fetch_int (); l = prefetch_strlen (); assert (l > 0); @@ -828,6 +915,7 @@ void fetch_encrypted_message (struct message *M) { unsigned sx = x; M->id = fetch_long (); peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); + M->from_id = MK_USER (our_id); M->to_id = chat; peer_t *P = user_chat_get (chat); M->flags &= ~(FLAG_EMPTY | FLAG_DELETED); @@ -874,7 +962,9 @@ void fetch_encrypted_message (struct message *M) { fetch_message_media_encrypted (&M->media); } else { assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l); + M->action.type = CODE_decrypted_message_action_set_message_t_t_l; P->encr_chat.ttl = fetch_int (); + M->action.ttl = P->encr_chat.ttl; M->service = 1; } in_ptr = save_in_ptr; @@ -1029,10 +1119,18 @@ void free_video (struct video *V) { free_photo_size (&V->thumb); } +void free_document (struct document *D) { + if (!D->access_hash) { return; } + free (D->caption); + free (D->mime_type); + free_photo_size (&D->thumb); +} + void free_message_media (struct message_media *M) { switch (M->type) { case CODE_message_media_empty: case CODE_message_media_geo: + case CODE_message_media_audio: return; case CODE_message_media_photo: free_photo (&M->photo); @@ -1045,17 +1143,19 @@ void free_message_media (struct message_media *M) { free (M->first_name); free (M->last_name); return; + case CODE_message_media_document: + free_document (&M->document); + return; case CODE_message_media_unsupported: free (M->data); return; case CODE_decrypted_message_media_photo: + case CODE_decrypted_message_media_video: + case CODE_decrypted_message_media_audio: + case CODE_decrypted_message_media_document: free (M->encr_photo.key); free (M->encr_photo.iv); return; - case CODE_decrypted_message_media_video: - free (M->encr_video.key); - free (M->encr_video.iv); - return; case 0: break; default: diff --git a/structures.h b/structures.h index fe34654..5474c4e 100644 --- a/structures.h +++ b/structures.h @@ -76,10 +76,10 @@ struct encr_photo { int size; int key_fingerprint; - int w; - int h; unsigned char *key; unsigned char *iv; + int w; + int h; }; struct encr_video { @@ -89,13 +89,38 @@ struct encr_video { int size; int key_fingerprint; + unsigned char *key; + unsigned char *iv; int w; int h; + int duration; +}; + +struct encr_audio { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + unsigned char *key; unsigned char *iv; int duration; }; +struct encr_document { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + + unsigned char *key; + unsigned char *iv; + char *file_name; + char *mime_type; +}; + struct encr_file { char *filename; unsigned char *key; @@ -197,15 +222,37 @@ struct video { long long access_hash; int user_id; int date; + int size; + int dc_id; + struct photo_size thumb; char *caption; int duration; - int size; - struct photo_size thumb; - int dc_id; int w; int h; }; +struct audio { + long long id; + long long access_hash; + int user_id; + int date; + int size; + int dc_id; + int duration; +}; + +struct document { + long long id; + long long access_hash; + int user_id; + int date; + int size; + int dc_id; + struct photo_size thumb; + char *caption; + char *mime_type; +}; + struct message_action { int type; union { @@ -217,6 +264,7 @@ struct message_action { char *new_title; struct photo photo; int user; + int ttl; }; }; @@ -225,6 +273,8 @@ struct message_media { union { struct photo photo; struct video video; + struct audio audio; + struct document document; struct geo geo; struct { char *phone; @@ -234,6 +284,8 @@ struct message_media { }; struct encr_photo encr_photo; struct encr_video encr_video; + struct encr_audio encr_audio; + struct encr_document encr_document; struct encr_file encr_file; void *data; }; From 9f070a27a44322c237697f89ce4afc20394f5b0b Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 15 Nov 2013 16:59:06 +0400 Subject: [PATCH 110/465] Fixed assert on profile photo update --- interface.c | 1 + mtproto-client.c | 1 + 2 files changed, 2 insertions(+) diff --git a/interface.c b/interface.c index 3d87912..12b02ff 100644 --- a/interface.c +++ b/interface.c @@ -827,6 +827,7 @@ void interpreter (char *line UU) { } #undef IS_WORD #undef RET + update_prompt (); in_readline = 0; } diff --git a/mtproto-client.c b/mtproto-client.c index 4c1c1c0..dbd4152 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -876,6 +876,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { if (y == CODE_user_profile_photo_empty) { } else { assert (y == CODE_user_profile_photo); + fetch_long (); // photo_id fetch_file_location (&t); fetch_file_location (&t); } From f85f248a860119154e80becaaaa2203fb2261389 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 15 Nov 2013 20:14:25 +0400 Subject: [PATCH 111/465] Added log level param --- interface.c | 25 +++++++++++++ main.c | 13 +++++-- mtproto-client.c | 93 +++++++++++++++++++++++++++--------------------- 3 files changed, 88 insertions(+), 43 deletions(-) diff --git a/interface.c b/interface.c index 12b02ff..1663669 100644 --- a/interface.c +++ b/interface.c @@ -50,6 +50,8 @@ int msg_num_mode; int in_readline; int readline_active; +int log_level; + long long cur_uploading_bytes; long long cur_uploaded_bytes; long long cur_downloading_bytes; @@ -278,6 +280,7 @@ char *commands[] = { "status_offline", "contacts_search", "quit", + "set", 0 }; int commands_flags[] = { @@ -315,6 +318,7 @@ int commands_flags[] = { 07, 07, 07, + 07, }; int get_complete_mode (void) { @@ -769,6 +773,13 @@ void interpreter (char *line UU) { "rename_contact - tries to rename contact. If you have another device it will be a fight\n" "suggested_contacts - print info about contacts, you have max common friends\n" "visualize_key - prints visualization of encryption key. You should compare it to your partner's one\n" + "set . Possible values are:\n" + "\tdebug_verbosity - just as it sounds. Debug verbosity\n" + "\tlog_level - level of logging of new events. Lower is less verbose:\n" + "\t\tLevel 1: prints info about read messages\n" + "\t\tLevel 2: prints line, when somebody is typing in chat\n" + "\t\tLevel 3: prints line, when somebody changes online status\n" + "\tmsg_num - enables/disables numeration of messages\n" ); pop_color (); } else if (IS_WORD ("show_license")) { @@ -822,6 +833,20 @@ void interpreter (char *line UU) { RET; } do_contacts_search (100, s); + } else if (IS_WORD ("set")) { + command = next_token (&l); + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + if (IS_WORD ("debug_verbosity")) { + verbosity = num; + } else if (IS_WORD ("log_level")) { + log_level = num; + } else if (IS_WORD ("msg_num")) { + msg_num_mode = num; + } } else if (IS_WORD ("quit")) { exit (0); } diff --git a/main.c b/main.c index e1cd504..b17410e 100644 --- a/main.c +++ b/main.c @@ -76,6 +76,7 @@ char *downloads_directory; char *config_directory; char *binlog_file_name; int binlog_enabled; +extern int log_level; void set_default_username (const char *s) { if (default_username) { @@ -260,6 +261,9 @@ void parse_config (void) { strcpy (buf + l, "test"); config_lookup_bool (&conf, buf, &test_dc); + strcpy (buf + l, "log_level"); + config_lookup_int (&conf, buf, &log_level); + if (!msg_num_mode) { strcpy (buf + l, "msg_num"); config_lookup_bool (&conf, buf, &msg_num_mode); @@ -300,7 +304,7 @@ void inner_main (void) { } void usage (void) { - printf ("%s [-u username] [-h] [-k public key name] [-N] [-v]\n", PROGNAME); + printf ("%s [-u username] [-h] [-k public key name] [-N] [-v] [-l log_level]\n", PROGNAME); exit (1); } @@ -310,7 +314,7 @@ extern int default_dc_num; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -331,6 +335,9 @@ void args_parse (int argc, char **argv) { prefix = strdup (optarg); assert (strlen (prefix) <= 100); break; + case 'l': + log_level = atoi (optarg); + break; case 'h': default: usage (); @@ -356,6 +363,8 @@ void sig_handler (int signum) { int main (int argc, char **argv) { signal (SIGSEGV, sig_handler); signal (SIGABRT, sig_handler); + + log_level = 10; args_parse (argc, argv); printf ( diff --git a/mtproto-client.c b/mtproto-client.c index dbd4152..91f0404 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -51,6 +51,7 @@ #include "mtproto-common.h" #define MAX_NET_RES (1L << 16) +extern int log_level; int verbosity; int auth_success; @@ -739,26 +740,30 @@ void work_update (struct connection *c UU, long long msg_id UU) { } } fetch_pts (); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); - printf (" %d messages marked as read\n", n); - pop_color (); - print_end (); + if (log_level >= 1) { + print_start (); + push_color (COLOR_YELLOW); + print_date (time (0)); + printf (" %d messages marked as read\n", n); + pop_color (); + print_end (); + } } break; case CODE_update_user_typing: { peer_id_t id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (id); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); - printf (" User "); - print_user_name (id, U); - printf (" is typing....\n"); - pop_color (); - print_end (); + if (log_level >= 2) { + print_start (); + push_color (COLOR_YELLOW); + print_date (time (0)); + printf (" User "); + print_user_name (id, U); + printf (" is typing....\n"); + pop_color (); + print_end (); + } } break; case CODE_update_chat_user_typing: @@ -767,16 +772,18 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_id_t id = MK_USER (fetch_int ()); peer_t *C = user_chat_get (chat_id); peer_t *U = user_chat_get (id); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); - printf (" User "); - print_user_name (id, U); - printf (" is typing in chat "); - print_chat_name (chat_id, C); - printf ("....\n"); - pop_color (); - print_end (); + if (log_level >= 2) { + print_start (); + push_color (COLOR_YELLOW); + print_date (time (0)); + printf (" User "); + print_user_name (id, U); + printf (" is typing in chat "); + print_chat_name (chat_id, C); + printf ("....\n"); + pop_color (); + print_end (); + } } break; case CODE_update_user_status: @@ -785,15 +792,17 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *U = user_chat_get (user_id); if (U) { fetch_user_status (&U->user.status); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); - printf (" User "); - print_user_name (user_id, U); - printf (" is now "); - printf ("%s\n", (U->user.status.online > 0) ? "online" : "offline"); - pop_color (); - print_end (); + if (log_level >= 3) { + print_start (); + push_color (COLOR_YELLOW); + print_date (time (0)); + printf (" User "); + print_user_name (user_id, U); + printf (" is now "); + printf ("%s\n", (U->user.status.online > 0) ? "online" : "offline"); + pop_color (); + print_end (); + } } else { struct user_status t; fetch_user_status (&t); @@ -1097,14 +1106,16 @@ void work_update (struct connection *c UU, long long msg_id UU) { M = M->next; } } - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); - printf (" Encrypted chat "); - print_encr_chat_name_full (id, user_chat_get (id)); - printf (": %d messages marked read \n", x); - pop_color (); - print_end (); + if (log_level >= 1) { + print_start (); + push_color (COLOR_YELLOW); + print_date (time (0)); + printf (" Encrypted chat "); + print_encr_chat_name_full (id, user_chat_get (id)); + printf (": %d messages marked read \n", x); + pop_color (); + print_end (); + } } break; case CODE_update_chat_participant_add: From c41a38924a04b7903f7fd57a1492af3eb4d1b42b Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 16 Nov 2013 17:04:53 +0400 Subject: [PATCH 112/465] Fixed small bugs. Fixed login --- mtproto-common.h | 1 + queries.c | 45 +++++++++++++++++++++++++-------------------- structures.c | 7 +++++-- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/mtproto-common.h b/mtproto-common.h index ee6cf9d..9aec485 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -76,6 +76,7 @@ #define CODE_input_peer_notify_settings_old 0x3cf4b1be #define CODE_peer_notify_settings_old 0xddbcd4a5 +#define CODE_user_profile_photo_old 0x990d1493 #define CODE_msg_detained_info 0x276d3ec6 /* not really a limit, for struct encrypted_message only */ diff --git a/queries.c b/queries.c index 8c91003..429f04c 100644 --- a/queries.c +++ b/queries.c @@ -303,6 +303,28 @@ void out_random (int n) { out_cstring (buf, n); } +int allow_send_linux_version; +void do_insert_header (void) { + out_int (CODE_invoke_with_layer9); + out_int (CODE_init_connection); + out_int (TG_APP_ID); + if (allow_send_linux_version) { + struct utsname st; + uname (&st); + out_string (st.machine); + static char buf[1000000]; + sprintf (buf, "%s %s %s", st.sysname, st.release, st.version); + out_string (buf); + out_string (TG_VERSION " (build " TG_BUILD ")"); + out_string ("En"); + } else { + out_string ("x86"); + out_string ("Linux"); + out_string (TG_VERSION); + out_string ("en"); + } +} + /* {{{ Get config */ void fetch_dc_option (void) { @@ -413,7 +435,7 @@ void do_send_code (const char *user) { suser = strdup (user); want_dc_num = 0; clear_packet (); - out_int (CODE_invoke_with_layer6); + do_insert_header (); out_int (CODE_auth_send_code); out_string (user); out_int (0); @@ -441,7 +463,7 @@ void do_send_code (const char *user) { logprintf ("send_code: dc_num = %d\n", dc_working_num); want_dc_num = 0; clear_packet (); - out_int (CODE_invoke_with_layer6); + do_insert_header (); out_int (CODE_auth_send_code); out_string (user); out_int (0); @@ -2501,24 +2523,7 @@ struct query_methods get_difference_methods = { void do_get_difference (void) { difference_got = 0; clear_packet (); - out_int (CODE_invoke_with_layer9); - out_int (CODE_init_connection); - out_int (TG_APP_ID); - if (allow_send_linux_version) { - struct utsname st; - uname (&st); - out_string (st.machine); - static char buf[1000000]; - sprintf (buf, "%s %s %s", st.sysname, st.release, st.version); - out_string (buf); - out_string (TG_VERSION " (build " TG_BUILD ")"); - out_string ("En"); - } else { - out_string ("x86"); - out_string ("Linux"); - out_string (TG_VERSION); - out_string ("en"); - } + do_insert_header (); if (seq > 0) { out_int (CODE_updates_get_difference); out_int (pts); diff --git a/structures.c b/structures.c index 334d65b..9a48a42 100644 --- a/structures.c +++ b/structures.c @@ -202,8 +202,10 @@ int fetch_user (struct user *U) { need_update |= set_update_int (&U->photo_small.dc, -2); need_update |= set_update_int (&U->photo_big.dc, -2); } else { - assert (y == CODE_user_profile_photo); - fetch_long (); + assert (y == CODE_user_profile_photo || y == CODE_user_profile_photo_old); + if (y == CODE_user_profile_photo) { + fetch_long (); + } need_update |= fetch_file_location (&U->photo_small); need_update |= fetch_file_location (&U->photo_big); } @@ -396,6 +398,7 @@ void fetch_user_full (struct user *U) { free_photo (&U->photo); } fetch_photo (&U->photo); + U->flags |= FLAG_HAS_PHOTO; fetch_notify_settings (); U->blocked = fetch_int (); if (U->real_first_name) { free (U->real_first_name); } From 31440ea3874dfbd6f3a4947e0181e20f726cb720 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 19 Nov 2013 21:02:02 +0400 Subject: [PATCH 113/465] Updated: layer10 --- queries.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/queries.c b/queries.c index 2cef723..6731e46 100644 --- a/queries.c +++ b/queries.c @@ -305,7 +305,7 @@ void out_random (int n) { int allow_send_linux_version; void do_insert_header (void) { - out_int (CODE_invoke_with_layer9); + out_int (CODE_invoke_with_layer10); out_int (CODE_init_connection); out_int (TG_APP_ID); if (allow_send_linux_version) { From 849d6a33a62938343330361ac77f8300de773000 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 21 Nov 2013 23:35:49 +0400 Subject: [PATCH 114/465] Sometimes new binlog works --- binlog.c | 636 +++++++++++++++++++++++++++++++++++++++++++++-- binlog.h | 49 ++++ interface.c | 16 +- loop.c | 11 +- main.c | 6 +- mtproto-client.c | 76 ++---- queries.c | 160 ++++-------- queries.h | 2 +- structures.c | 494 +++++++++++++++++++----------------- structures.h | 7 +- 10 files changed, 1023 insertions(+), 434 deletions(-) diff --git a/binlog.c b/binlog.c index 73d543c..ef46b8b 100644 --- a/binlog.c +++ b/binlog.c @@ -12,6 +12,9 @@ #include "mtproto-common.h" #include "net.h" #include "include.h" +#include "mtproto-client.h" + +#include #define BINLOG_BUFFER_SIZE (1 << 20) int binlog_buffer[BINLOG_BUFFER_SIZE]; @@ -27,6 +30,9 @@ extern struct dc *DC_working; extern int dc_working_num; extern int our_id; extern int binlog_enabled; +extern int encr_root; +extern unsigned char *encr_prime; +extern int encr_param_version; int in_replay_log; @@ -34,20 +40,39 @@ void *alloc_log_event (int l UU) { return binlog_buffer; } +long long binlog_pos; + void replay_log_event (void) { + int *start = rptr; + in_replay_log = 1; assert (rptr < wptr); int op = *rptr; in_ptr = rptr; in_end = wptr; + if (verbosity >= 2) { + logprintf ("event = 0x%08x. pos = %lld\n", op, binlog_pos); + } switch (op) { case LOG_START: rptr ++; - return; - case CODE_dc_option: - fetch_dc_option (); + break; + case CODE_binlog_dc_option: + in_ptr ++; + { + int id = fetch_int (); + int l1 = prefetch_strlen (); + char *name = fetch_str (l1); + int l2 = prefetch_strlen (); + char *ip = fetch_str (l2); + int port = fetch_int (); + if (verbosity) { + logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + } + alloc_dc (id, strndup (ip, l2), port); + } rptr = in_ptr; - return; + break; case LOG_AUTH_KEY: rptr ++; { @@ -60,7 +85,7 @@ void replay_log_event (void) { rptr += 64; DC_list[num]->flags |= 1; }; - return; + break; case LOG_DEFAULT_DC: rptr ++; { @@ -69,7 +94,7 @@ void replay_log_event (void) { DC_working = DC_list[num]; dc_working_num = num; } - return; + break; case LOG_OUR_ID: rptr ++; { @@ -95,7 +120,7 @@ void replay_log_event (void) { rptr += 2; }; break; - case CODE_user_empty: +/* case CODE_user_empty: case CODE_user_self: case CODE_user_contact: case CODE_user_request: @@ -103,11 +128,11 @@ void replay_log_event (void) { case CODE_user_deleted: fetch_alloc_user (); rptr = in_ptr; - return; + break;*/ case LOG_DH_CONFIG: get_dh_config_on_answer (0); rptr = in_ptr; - return; + break; case LOG_ENCR_CHAT_KEY: rptr ++; { @@ -119,7 +144,7 @@ void replay_log_event (void) { memcpy (U->key, rptr, 256); rptr += 64; }; - return; + break; case LOG_ENCR_CHAT_SEND_ACCEPT: rptr ++; { @@ -136,20 +161,18 @@ void replay_log_event (void) { memcpy (U->g_key, rptr, 256); rptr += 64; }; - return; + break; case LOG_ENCR_CHAT_SEND_CREATE: rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); - assert (!U || (U->flags & FLAG_EMPTY)); + assert (!U || !(U->flags & FLAG_CREATED)); if (!U) { U = malloc (sizeof (peer_t)); memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); - } else { - U->flags &= ~FLAG_EMPTY; } U->flags |= FLAG_CREATED; U->user_id = *(rptr ++); @@ -166,7 +189,7 @@ void replay_log_event (void) { } } }; - return; + break; case LOG_ENCR_CHAT_DELETED: rptr ++; { @@ -177,13 +200,11 @@ void replay_log_event (void) { memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); - } else { - U->flags &= ~FLAG_EMPTY; } U->flags |= FLAG_CREATED; U->state = sc_deleted; }; - return; + break; case LOG_ENCR_CHAT_WAITING: rptr ++; { @@ -197,7 +218,7 @@ void replay_log_event (void) { U->access_hash = *(long long *)rptr; rptr += 2; }; - return; + break; case LOG_ENCR_CHAT_REQUESTED: rptr ++; { @@ -208,8 +229,6 @@ void replay_log_event (void) { memset (U, 0, sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); - } else { - U->flags &= ~FLAG_EMPTY; } U->flags |= FLAG_CREATED; U->state = sc_request; @@ -229,7 +248,7 @@ void replay_log_event (void) { } rptr += 2; }; - return; + break; case LOG_ENCR_CHAT_OK: rptr ++; { @@ -238,20 +257,293 @@ void replay_log_event (void) { assert (U); U->state = sc_ok; } - return; + break; + case CODE_binlog_new_user: + in_ptr ++; + { + peer_id_t id = MK_USER (fetch_int ()); + peer_t *_U = user_chat_get (id); + if (!_U) { + _U = malloc (sizeof (*_U)); + memset (_U, 0, sizeof (*_U)); + _U->id = id; + insert_user (_U); + } else { + assert (!(_U->flags & FLAG_CREATED)); + } + struct user *U = (void *)_U; + U->flags |= FLAG_CREATED; + if (get_peer_id (id) == our_id) { + U->flags |= FLAG_USER_SELF; + } + 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); + U->access_hash = fetch_long (); + U->phone = fetch_str_dup (); + if (fetch_int ()) { + U->flags |= FLAG_USER_CONTACT; + } + } + rptr = in_ptr; + break; + case CODE_binlog_user_delete: + rptr ++; + { + peer_id_t id = MK_USER (*(rptr ++)); + peer_t *U = user_chat_get (id); + assert (U); + U->flags |= FLAG_DELETED; + } + break; + case CODE_binlog_set_user_access_token: + rptr ++; + { + peer_id_t id = MK_USER (*(rptr ++)); + peer_t *U = user_chat_get (id); + assert (U); + U->user.access_hash = *(long long *)rptr; + rptr += 2; + } + break; + case CODE_binlog_set_user_phone: + in_ptr ++; + { + peer_id_t id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (id); + assert (U); + if (U->user.phone) { free (U->user.phone); } + U->user.phone = fetch_str_dup (); + } + rptr = in_ptr; + break; + case CODE_binlog_set_user_friend: + rptr ++; + { + peer_id_t id = MK_USER (*(rptr ++)); + peer_t *U = user_chat_get (id); + assert (U); + int friend = *(rptr ++); + if (friend) { U->flags |= FLAG_USER_CONTACT; } + else { U->flags &= ~FLAG_USER_CONTACT; } + } + break; + case CODE_binlog_user_full_photo: + in_ptr ++; + { + peer_id_t id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (id); + assert (U); + if (U->flags & FLAG_HAS_PHOTO) { + free_photo (&U->user.photo); + } + fetch_photo (&U->user.photo); + } + rptr = in_ptr; + break; + case CODE_binlog_user_blocked: + rptr ++; + { + peer_id_t id = MK_USER (*(rptr ++)); + peer_t *U = user_chat_get (id); + assert (U); + U->user.blocked = *(rptr ++); + } + break; + case CODE_binlog_set_user_full_name: + in_ptr ++; + { + peer_id_t id = MK_USER (fetch_int ()); + peer_t *U = user_chat_get (id); + assert (U); + if (U->user.real_first_name) { free (U->user.real_first_name); } + if (U->user.real_last_name) { free (U->user.real_last_name); } + U->user.real_first_name = fetch_str_dup (); + U->user.real_last_name = fetch_str_dup (); + } + rptr = in_ptr; + break; + case CODE_binlog_encr_chat_delete: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_t *_U = user_chat_get (id); + assert (_U); + struct secret_chat *U = &_U->encr_chat; + memset (U->key, 0, sizeof (U->key)); + U->flags |= FLAG_DELETED; + U->state = sc_deleted; + if (U->nonce) { + memset (U->nonce, 0, 256); + free (U->nonce); + U->nonce = 0; + } + if (U->g_key) { + memset (U->g_key, 0, 256); + free (U->g_key); + U->g_key = 0; + } + } + break; + case CODE_binlog_encr_chat_requested: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_t *_U = user_chat_get (id); + if (!_U) { + _U = malloc (sizeof (*_U)); + memset (_U, 0, sizeof (*_U)); + _U->id = id; + insert_encrypted_chat (_U); + } else { + assert (!(_U->flags & FLAG_CREATED)); + } + struct secret_chat *U = (void *)_U; + U->access_hash = *(long long *)rptr; + rptr += 2; + U->date = *(rptr ++); + U->admin_id = *(rptr ++); + U->user_id = *(rptr ++); + peer_t *Us = user_chat_get (MK_USER (U->user_id)); + if (Us) { + U->print_name = create_print_name (id, "!", Us->user.first_name, Us->user.last_name, 0); + } else { + static char buf[20]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (id, "!", buf, 0, 0); + } + U->g_key = malloc (256); + U->nonce = malloc (256); + memcpy (U->g_key, rptr, 256); + rptr += 64; + memcpy (U->nonce, rptr, 256); + rptr += 64; + + U->flags |= FLAG_CREATED; + U->state = sc_request; + } + break; + case CODE_binlog_set_encr_chat_access_hash: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_t *U = user_chat_get (id); + assert (U); + U->encr_chat.access_hash = *(long long *)rptr; + rptr += 2; + } + break; + case CODE_binlog_set_encr_chat_date: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_t *U = user_chat_get (id); + assert (U); + U->encr_chat.date = *(rptr ++); + } + break; + case CODE_binlog_set_encr_chat_state: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_t *U = user_chat_get (id); + assert (U); + U->encr_chat.state = *(rptr ++); + } + break; + case CODE_binlog_encr_chat_accepted: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_t *_U = user_chat_get (id); + assert (_U); + struct secret_chat *U = &_U->encr_chat; + if (!U->g_key) { + U->g_key = malloc (256); + } + if (!U->nonce) { + U->nonce = malloc (256); + } + memcpy (rptr, U->g_key, 256); + rptr += 64; + memcpy (rptr, U->nonce, 256); + rptr += 64; + U->key_fingerprint = *(long long *)rptr; + rptr += 2; + if (U->state == sc_waiting) { + do_create_keys_end (U); + } + U->state = sc_ok; + } + break; + case CODE_binlog_set_encr_chat_key: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_t *_U = user_chat_get (id); + assert (_U); + struct secret_chat *U = &_U->encr_chat; + memcpy (U->key, rptr, 256); + rptr += 64; + U->key_fingerprint = *(long long *)rptr; + rptr += 2; + } + break; + case CODE_binlog_set_dh_params: + rptr ++; + { + if (encr_prime) { free (encr_prime); } + encr_root = *(rptr ++); + encr_prime = malloc (256); + memcpy (encr_prime, rptr, 256); + rptr += 64; + encr_param_version = *(rptr ++); + } + break; + case CODE_binlog_encr_chat_init: + rptr ++; + { + peer_t *P = malloc (sizeof (*P)); + memset (P, 0, sizeof (*P)); + P->id = MK_ENCR_CHAT (*(rptr ++)); + assert (!user_chat_get (P->id)); + P->encr_chat.user_id = *(rptr ++); + P->encr_chat.admin_id = our_id; + insert_encrypted_chat (P); + peer_t *Us = user_chat_get (MK_USER (P->encr_chat.user_id)); + assert (Us); + P->print_name = create_print_name (P->id, "!", Us->user.first_name, Us->user.last_name, 0); + memcpy (P->encr_chat.key, rptr, 256); + rptr += 64; + P->encr_chat.g_key = malloc (256); + memcpy (P->encr_chat.g_key, rptr, 256); + rptr += 64; + P->flags |= FLAG_CREATED; + } + break; + case CODE_update_user_photo: + case CODE_update_user_name: + work_update (0, 0); + rptr = in_ptr; + break; default: logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x]\n", *(rptr - 1), op, *(rptr + 1)); assert (0); } + if (verbosity >= 2) { + logprintf ("Event end\n"); + } + in_replay_log = 0; + binlog_pos += (rptr - start) * 4; } void create_new_binlog (void) { static int s[1000]; packet_ptr = s; out_int (LOG_START); - out_int (CODE_dc_option); + out_int (CODE_binlog_dc_option); out_int (1); out_string (""); out_string (test_dc ? TG_SERVER_TEST : TG_SERVER); @@ -270,7 +562,6 @@ void create_new_binlog (void) { void replay_log (void) { - in_replay_log = 1; if (access (get_binlog_file_name (), F_OK) < 0) { printf ("No binlog found. Creating new one\n"); create_new_binlog (); @@ -307,7 +598,6 @@ void replay_log (void) { replay_log_event (); } close (fd); - in_replay_log = 0; } int binlog_fd; @@ -321,6 +611,298 @@ void write_binlog (void) { } void add_log_event (const int *data, int len) { + if (verbosity) { + logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); + } + assert (!(len & 3)); if (in_replay_log) { return; } - assert (write (binlog_fd, data, len) == len); + rptr = (void *)data; + wptr = rptr + (len / 4); + int *in = in_ptr; + int *end = in_end; + replay_log_event (); + if (rptr != wptr) { + logprintf ("Unread %ld ints. Len = %d\n", wptr - rptr, len); + assert (rptr == wptr); + } + if (binlog_enabled) { + assert (write (binlog_fd, data, len) == len); + } + in_ptr = in; + in_end = end; +} + +void bl_do_set_auth_key_id (int num, unsigned char *buf) { + static unsigned char sha1_buffer[20]; + SHA1 (buf, 256, sha1_buffer); + long long fingerprint = *(long long *)(sha1_buffer + 12); + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_AUTH_KEY; + ev[1] = num; + *(long long *)(ev + 2) = fingerprint; + memcpy (ev + 4, buf, 256); + add_log_event (ev, 8 + 8 + 256); +} + +void bl_do_set_our_id (int id) { + int *ev = alloc_log_event (8); + ev[0] = LOG_OUR_ID; + ev[1] = id; + add_log_event (ev, 8); +} + +void bl_do_new_user (int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact) { + clear_packet (); + out_int (CODE_binlog_new_user); + out_int (id); + out_cstring (f ? f : "", fl); + out_cstring (l ? l : "", ll); + out_long (access_token); + out_cstring (p ? p : "", pl); + out_int (contact); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_user_delete (struct user *U) { + if (U->flags & FLAG_DELETED) { return; } + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_user_delete; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); +} + +extern int last_date; +void bl_do_set_user_profile_photo (struct user *U, long long photo_id, struct file_location *big, struct file_location *small) { + if (photo_id == U->photo_id) { return; } + if (!photo_id) { + int *ev = alloc_log_event (20); + ev[0] = CODE_update_user_photo; + ev[1] = get_peer_id (U->id); + ev[2] = last_date; + ev[3] = CODE_user_profile_photo_empty; + ev[4] = CODE_bool_false; + add_log_event (ev, 20); + } else { + clear_packet (); + out_int (CODE_update_user_photo); + out_int (get_peer_id (U->id)); + out_int (last_date); + out_int (CODE_user_profile_photo); + out_long (photo_id); + if (small->dc >= 0) { + out_int (CODE_file_location); + out_int (small->dc); + out_long (small->volume); + out_int (small->local_id); + out_long (small->secret); + } else { + out_int (CODE_file_location_unavailable); + out_long (small->volume); + out_int (small->local_id); + out_long (small->secret); + } + if (big->dc >= 0) { + out_int (CODE_file_location); + out_int (big->dc); + out_long (big->volume); + out_int (big->local_id); + out_long (big->secret); + } else { + out_int (CODE_file_location_unavailable); + out_long (big->volume); + out_int (big->local_id); + out_long (big->secret); + } + out_int (CODE_bool_false); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + } +} + +void bl_do_set_user_name (struct user *U, const char *f, int fl, const char *l, int ll) { + if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) && + (U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) { + return; + } + clear_packet (); + out_int (CODE_update_user_name); + out_int (get_peer_id (U->id)); + out_cstring (f, fl); + out_cstring (l, ll); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_user_access_token (struct user *U, long long access_token) { + if (U->access_hash == access_token) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_set_user_access_token; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = access_token; + add_log_event (ev, 16); +} + +void bl_do_set_user_phone (struct user *U, const char *p, int pl) { + if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) { + return; + } + clear_packet (); + out_int (CODE_binlog_set_user_phone); + out_int (get_peer_id (U->id)); + out_cstring (p, pl); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_user_friend (struct user *U, int friend) { + if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_user_friend; + ev[1] = get_peer_id (U->id); + ev[2] = friend; + add_log_event (ev, 12); +} + +void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port) { + struct dc *DC = DC_list[id]; + if (DC) { return; } + + clear_packet (); + out_int (CODE_binlog_dc_option); + out_int (id); + out_cstring (name, l1); + out_cstring (ip, l2); + out_int (port); + + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_dc_signed (int id) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DC_SIGNED; + ev[1] = id; + add_log_event (ev, 8); +} + +void bl_do_set_working_dc (int num) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = num; + add_log_event (ev, 8); +} + +void bl_do_set_user_full_photo (struct user *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_user_full_photo; + ev[1] = get_peer_id (U->id); + memcpy (ev + 2, start, len); + add_log_event (ev, len + 8); +} + +void bl_do_set_user_blocked (struct user *U, int blocked) { + if (U->blocked == blocked) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_user_blocked; + ev[1] = get_peer_id (U->id); + ev[2] = blocked; + add_log_event (ev, 12); +} + +void bl_do_set_user_real_name (struct user *U, const char *f, int fl, const char *l, int ll) { + if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) && + (U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) { + return; + } + clear_packet (); + out_int (CODE_binlog_set_user_full_name); + out_int (get_peer_id (U->id)); + out_cstring (f, fl); + out_cstring (l, ll); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_encr_chat_delete (struct secret_chat *U) { + if (!(U->flags & FLAG_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; } + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_encr_chat_delete; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); +} + +void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]) { + int *ev = alloc_log_event (540); + ev[0] = CODE_binlog_encr_chat_requested; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = access_hash; + ev[4] = date; + ev[5] = admin_id; + ev[6] = user_id; + logprintf ("user_id = %d, admin_id = %d, our_id = %d\n", user_id, admin_id, our_id); + memcpy (ev + 7, g_key, 256); + memcpy (ev + 7 + 64, nonce, 256); + add_log_event (ev, 540); +} + +void bl_do_set_encr_chat_access_hash (struct secret_chat *U, long long access_hash) { + if (U->access_hash == access_hash) { return; } + int *ev = alloc_log_event (16); + ev[0] = CODE_binlog_set_encr_chat_access_hash; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = access_hash; + add_log_event (ev, 16); +} + +void bl_do_set_encr_chat_date (struct secret_chat *U, int date) { + if (U->date == date) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_encr_chat_date; + ev[1] = get_peer_id (U->id); + ev[2] = date; + add_log_event (ev, 12); +} + +void bl_do_set_encr_chat_state (struct secret_chat *U, enum secret_chat_state state) { + if (U->state == state) { return; } + int *ev = alloc_log_event (12); + ev[0] = CODE_binlog_set_encr_chat_state; + ev[1] = get_peer_id (U->id); + ev[2] = state; + add_log_event (ev, 12); +} + +void bl_do_encr_chat_accepted (struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) { + if (U->state != sc_waiting && U->state != sc_request) { return; } + int *ev = alloc_log_event (528); + ev[0] = CODE_binlog_encr_chat_accepted; + ev[1] = get_peer_id (U->id); + memcpy (ev + 2, g_key, 256); + memcpy (ev + 66, nonce, 256); + *(long long *)(ev + 130) = key_fingerprint; + add_log_event (ev, 528); +} + +void bl_do_set_encr_chat_key (struct secret_chat *E, unsigned char key[], long long key_fingerprint) { + int *ev = alloc_log_event (272); + ev[0] = CODE_binlog_set_encr_chat_key; + ev[1] = get_peer_id (E->id); + memcpy (ev + 2, key, 256); + *(long long *)(ev + 66) = key_fingerprint; + add_log_event (ev, 272); +} + +void bl_do_set_dh_params (int root, unsigned char prime[], int version) { + int *ev = alloc_log_event (268); + ev[0] = CODE_binlog_set_dh_params; + ev[1] = root; + memcpy (ev + 2, prime, 256); + ev[66] = version; + add_log_event (ev, 268); +} + +void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned char g_a[]) { + int *ev = alloc_log_event (524); + ev[0] = CODE_binlog_encr_chat_init; + ev[1] = id; + ev[2] = user_id; + memcpy (ev + 3, random, 256); + memcpy (ev + 67, g_a, 256); + add_log_event (ev, 524); } diff --git a/binlog.h b/binlog.h index 9c77d78..1ce2a37 100644 --- a/binlog.h +++ b/binlog.h @@ -1,6 +1,8 @@ #ifndef __BINLOG_H__ #define __BINLOG_H__ +#include "structures.h" + #define LOG_START 0x8948329a #define LOG_AUTH_KEY 0x984932aa #define LOG_DEFAULT_DC 0x95382908 @@ -16,8 +18,55 @@ #define LOG_ENCR_CHAT_REQUESTED 0x9011011a #define LOG_ENCR_CHAT_OK 0x7612ce13 +#define CODE_binlog_new_user 0xe04f30de +#define CODE_binlog_user_delete 0xf7a27c79 +#define CODE_binlog_set_user_access_token 0x1349f615 +#define CODE_binlog_set_user_phone 0x5d3afde2 +#define CODE_binlog_set_user_friend 0x75a7ec5a +#define CODE_binlog_dc_option 0x08c0ef19 +#define CODE_binlog_user_full_photo 0xfaa35824 +#define CODE_binlog_user_blocked 0xb2dea7cd +#define CODE_binlog_set_user_full_name 0x4ceb4cf0 +#define CODE_binlog_encr_chat_delete 0xb9d33f87 +#define CODE_binlog_encr_chat_requested 0xf57d1ea2 +#define CODE_binlog_set_encr_chat_access_hash 0xe5612bb3 +#define CODE_binlog_set_encr_chat_date 0x54f16911 +#define CODE_binlog_set_encr_chat_state 0x76a6e45b +#define CODE_binlog_encr_chat_accepted 0x4627e926 +#define CODE_binlog_set_encr_chat_key 0x179df2d4 +#define CODE_binlog_set_dh_params 0x20ba46bc +#define CODE_binlog_encr_chat_init 0x939cd1c7 + void *alloc_log_event (int l); void replay_log (void); void add_log_event (const int *data, int l); void write_binlog (void); +void bl_do_set_auth_key_id (int num, unsigned char *buf); + +void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port); + +void bl_do_set_our_id (int id); +void bl_do_new_user (int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); +void bl_do_user_delete (struct user *U); +void bl_do_set_user_profile_photo (struct user *U, long long photo_id, struct file_location *big, struct file_location *small); +void bl_do_set_user_name (struct user *U, const char *f, int fl, const char *l, int ll); +void bl_do_set_user_access_token (struct user *U, long long access_token); +void bl_do_set_user_phone (struct user *U, const char *p, int pl); +void bl_do_set_user_friend (struct user *U, int friend); +void bl_do_set_user_full_photo (struct user *U, const int *start, int len); +void bl_do_set_user_blocked (struct user *U, int blocked); +void bl_do_set_user_real_name (struct user *U, const char *f, int fl, const char *l, int ll); + +void bl_do_encr_chat_delete (struct secret_chat *U); +void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); +void bl_do_set_encr_chat_access_hash (struct secret_chat *U, long long access_hash); +void bl_do_set_encr_chat_date (struct secret_chat *U, int date); +void bl_do_set_encr_chat_state (struct secret_chat *U, enum secret_chat_state state); +void bl_do_encr_chat_accepted (struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint); +void bl_do_set_encr_chat_key (struct secret_chat *E, unsigned char key[], long long key_fingerprint); +void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned char g_a[]); + +void bl_do_dc_signed (int id); +void bl_do_set_working_dc (int num); +void bl_do_set_dh_params (int root, unsigned char prime[], int version); #endif diff --git a/interface.c b/interface.c index 1663669..a089988 100644 --- a/interface.c +++ b/interface.c @@ -916,14 +916,20 @@ void hexdump (int *in_ptr, int *in_end) { } void logprintf (const char *format, ...) { - print_start (); + int x = 0; + if (!prompt_was) { + x = 1; + print_start (); + } printf (COLOR_GREY " *** "); va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); printf (COLOR_NORMAL); - print_end (); + if (x) { + print_end (); + } } int color_stack_pos; @@ -1007,8 +1013,10 @@ void print_user_name (peer_id_t id, peer_t *U) { if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { push_color (COLOR_REDB); } - if ((U->flags & FLAG_DELETED) || (U->flags & FLAG_EMPTY)) { + if ((U->flags & FLAG_DELETED)) { printf ("deleted user#%d", get_peer_id (id)); + } else if (!(U->flags & FLAG_CREATED)) { + printf ("empty user#%d", get_peer_id (id)); } else if (!U->user.first_name || !strlen (U->user.first_name)) { printf ("%s", U->user.last_name); } else if (!U->user.last_name || !strlen (U->user.last_name)) { @@ -1123,7 +1131,7 @@ peer_id_t last_from_id; peer_id_t last_to_id; void print_message (struct message *M) { - if (M->flags & (FLAG_EMPTY | FLAG_DELETED)) { + if (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED)) { return; } if (M->service) { diff --git a/loop.c b/loop.c index fa93451..8680850 100644 --- a/loop.c +++ b/loop.c @@ -57,6 +57,7 @@ extern int binlog_enabled; extern int unknown_user_list_pos; extern int unknown_user_list[]; +int register_mode; int unread_messages; void got_it (char *line, int len); @@ -483,7 +484,7 @@ int loop (void) { int res = do_auth_check_phone (default_username); assert (res >= 0); logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); - if (res > 0) { + if (res > 0 && !register_mode) { do_send_code (default_username); char *code = 0; size_t size = 0; @@ -552,13 +553,7 @@ int loop (void) { 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; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DC_SIGNED; - ev[1] = i; - add_log_event (ev, 8); - } + bl_do_dc_signed (i); write_auth_file (); } write_auth_file (); diff --git a/main.c b/main.c index b17410e..3d9c4a1 100644 --- a/main.c +++ b/main.c @@ -312,9 +312,10 @@ extern char *rsa_public_key_name; extern int verbosity; extern int default_dc_num; +int register_mode; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:R")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -338,6 +339,9 @@ void args_parse (int argc, char **argv) { case 'l': log_level = atoi (optarg); break; + case 'R': + register_mode = 1; + break; case 'h': default: usage (); diff --git a/mtproto-client.c b/mtproto-client.c index 91f0404..da1ca8a 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -61,6 +61,11 @@ char new_nonce[256]; char server_nonce[256]; extern int binlog_enabled; + +int total_packets_sent; +long long total_data_sent; + + int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); int rpc_close (struct connection *c); @@ -183,6 +188,9 @@ int rpc_send_packet (struct connection *c) { write_out (c, &unenc_msg_header, 20); write_out (c, packet_buffer, len); flush_out (c); + + total_packets_sent ++; + total_data_sent += total_len; return 1; } @@ -198,6 +206,9 @@ int rpc_send_message (struct connection *c, void *data, int len) { c->out_packet_num ++; write_out (c, data, len); flush_out (c); + + total_packets_sent ++; + total_data_sent += total_len; return 1; } @@ -506,19 +517,16 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { static unsigned char tmp[44], sha1_buffer[20]; memcpy (tmp, new_nonce, 32); tmp[32] = 1; + //GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); + + bl_do_set_auth_key_id (GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); - GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); + memcpy (tmp + 33, sha1_buffer, 8); sha1 (tmp, 41, sha1_buffer); assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->server_salt; - add_log_event (ev, 16); - }*/ + if (verbosity >= 3) { logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); } @@ -535,14 +543,6 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { auth_success ++; GET_DC(c)->flags |= 1; write_auth_file (); - if (binlog_enabled) { - int *ev = alloc_log_event (8 + 8 + 256); - ev[0] = LOG_AUTH_KEY; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->auth_key_id; - memcpy (ev + 4, GET_DC(c)->auth_key, 256); - add_log_event (ev, 8 + 8 + 256); - } return 1; } @@ -825,25 +825,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { 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"); pop_color (); print_end (); - if (!strlen (U->first_name)) { - if (!strlen (U->last_name)) { - U->print_name = strdup ("none"); - } else { - U->print_name = strdup (U->last_name); - } - } else { - if (!strlen (U->last_name)) { - U->print_name = strdup (U->first_name); - } else { - U->print_name = malloc (strlen (U->first_name) + strlen (U->last_name) + 2); - sprintf (U->print_name, "%s_%s", U->first_name, U->last_name); - } - } } else { int l; l = prefetch_strlen (); @@ -871,11 +858,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { 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); - fetch_long (); // photo_id + U->photo_id = fetch_long (); fetch_file_location (&U->photo_small); fetch_file_location (&U->photo_big); } @@ -1031,12 +1019,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { case CODE_update_encryption: { struct secret_chat *E = fetch_alloc_encrypted_chat (); + if (verbosity >= 2) { + logprintf ("Secret chat state = %d\n", E->state); + } print_start (); push_color (COLOR_YELLOW); print_date (time (0)); switch (E->state) { case sc_none: - assert (0); break; case sc_waiting: printf (" Encrypted chat "); @@ -1159,6 +1149,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; default: logprintf ("Unknown update type %08x\n", op); + ; } } @@ -1244,13 +1235,6 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { fetch_long (); // unique_id GET_DC(c)->server_salt = fetch_long (); -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->server_salt; - add_log_event (ev, 16); - }*/ } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { @@ -1332,13 +1316,6 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { fetch_int (); // error_code long long new_server_salt = fetch_long (); GET_DC(c)->server_salt = new_server_salt; -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = GET_DC(c)->id; - *(long long *)(ev + 2) = GET_DC(c)->server_salt; - add_log_event (ev, 16); - }*/ } void work_pong (struct connection *c UU, long long msg_id UU) { @@ -1434,13 +1411,6 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, if (DC->server_salt != enc->server_salt) { DC->server_salt = enc->server_salt; write_auth_file (); -/* if (binlog_enabled) { - int *ev = alloc_log_event (16); - ev[0] = LOG_DC_SALT; - ev[1] = DC->id; - *(long long *)(ev + 2) = DC->server_salt; - add_log_event (ev, 16); - }*/ } int this_server_time = enc->msg_id >> 32LL; diff --git a/queries.c b/queries.c index 429f04c..1fb4d82 100644 --- a/queries.c +++ b/queries.c @@ -328,7 +328,6 @@ void do_insert_header (void) { /* {{{ Get config */ void fetch_dc_option (void) { - int *start = in_ptr; assert (fetch_int () == CODE_dc_option); int id = fetch_int (); int l1 = prefetch_strlen (); @@ -339,13 +338,8 @@ void fetch_dc_option (void) { if (verbosity) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } - if (!DC_list[id]) { - alloc_dc (id, strndup (ip, l2), port); - new_dc_num ++; - if (binlog_enabled) { - add_log_event (start, 4 * (in_ptr - start)); - } - } + + bl_do_dc_option (id, l1, name, l2, ip, port); } int help_get_config_on_answer (struct query *q UU) { @@ -453,12 +447,8 @@ void do_send_code (const char *user) { dc_create_session (DC_working); } dc_working_num = want_dc_num; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = dc_working_num; - add_log_event (ev, 8); - } + + bl_do_set_working_dc (dc_working_num); logprintf ("send_code: dc_num = %d\n", dc_working_num); want_dc_num = 0; @@ -496,16 +486,12 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error 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 (); - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = i; - add_log_event (ev, 8); - } + bl_do_set_working_dc (i); check_phone_result = 1; } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { @@ -513,12 +499,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error assert (DC_list[i]); dc_working_num = i; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = i; - add_log_event (ev, 8); - } + bl_do_set_working_dc (i); DC_working = DC_list[i]; write_auth_file (); @@ -602,24 +583,15 @@ int sign_in_on_answer (struct query *q UU) { if (!our_id) { our_id = get_peer_id (User.id); - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_OUR_ID; - ev[1] = our_id; - add_log_event (ev, 8); - } + bl_do_set_our_id (our_id); } sign_in_ok = 1; 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; - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_DC_SIGNED; - ev[1] = DC_working->id; - add_log_event (ev, 8); - } + + bl_do_dc_signed (DC_working->id); return 0; } @@ -2219,23 +2191,16 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { BIGNUM *r = BN_new (); BN_init (r); BN_mod_exp (r, g_a, b, p, ctx); - memset (E->key, 0, sizeof (E->key)); - BN_bn2bin (r, (void *)E->key); - for (i = 0; i < 64; i++) { - E->key[i] ^= *(((int *)E->nonce) + i); + static unsigned char kk[256]; + memset (kk, 0, sizeof (kk)); + BN_bn2bin (r, kk); + for (i = 0; i < 256; i++) { + kk[i] ^= E->nonce[i]; } static unsigned char sha_buffer[20]; - sha1 ((void *)E->key, 256, sha_buffer); - E->key_fingerprint = *(long long *)(sha_buffer + 12); + sha1 (kk, 256, sha_buffer); - if (binlog_enabled) { - int *ev = alloc_log_event (8 + 8 + 256); - ev[0] = LOG_ENCR_CHAT_KEY; - ev[1] = get_peer_id (E->id); - *(long long *)(ev + 2) = E->key_fingerprint; - memcpy (ev + 4, E->key, 256); - add_log_event (ev, 8 + 8 + 256); - } + bl_do_set_encr_chat_key (E, kk, *(long long *)(sha_buffer + 12)); clear_packet (); out_int (CODE_messages_accept_encryption); @@ -2256,16 +2221,6 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (p); BN_clear_free (r); - if (binlog_enabled) { - int *ev = alloc_log_event (16 + 512); - ev[0] = LOG_ENCR_CHAT_SEND_ACCEPT; - ev[1] = get_peer_id (E->id); - *(long long *)(ev + 2) = E->key_fingerprint; - memcpy (ev + 4, E->key, 256); - memcpy (ev + 68, buf, 256); - add_log_event (ev, 16 + 512); - } - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E); } @@ -2299,18 +2254,10 @@ void do_create_keys_end (struct secret_chat *U) { BN_clear_free (g_b); BN_clear_free (r); BN_clear_free (a); - - if (binlog_enabled) { - int *ev = alloc_log_event (8 + 8 + 256); - ev[0] = LOG_ENCR_CHAT_KEY; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = U->key_fingerprint; - memcpy (ev + 4, U->key, 256); - add_log_event (ev, 8 + 8 + 256); - } } -void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { +void do_send_create_encr_chat (void *x, unsigned char *random) { + int user_id = (long)x; int i; for (i = 0; i < 64; i++) { *(((int *)random) + i) ^= mrand48 (); @@ -2333,13 +2280,21 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { BN_mod_exp (r, g, a, p, ctx); - memcpy (E->key, random, 256); - static char g_a[256]; memset (g_a, 0, 256); BN_bn2bin (r, (void *)g_a); + int t = lrand48 (); + while (user_chat_get (MK_ENCR_CHAT (t))) { + t = lrand48 (); + } + + bl_do_encr_chat_init (t, user_id, (void *)random, (void *)g_a); + peer_t *_E = user_chat_get (MK_ENCR_CHAT (t)); + assert (_E); + struct secret_chat *E = &_E->encr_chat; + clear_packet (); out_int (CODE_messages_request_encryption); peer_t *U = user_chat_get (MK_USER (E->user_id)); @@ -2360,46 +2315,28 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (p); BN_clear_free (r); - if (binlog_enabled) { - int *ev = alloc_log_event (12 + 256); - ev[0] = LOG_ENCR_CHAT_SEND_CREATE; - ev[1] = get_peer_id (E->id); - ev[2] = E->user_id; - memcpy (ev + 3, E->key, 256); - add_log_event (ev, 12 + 256); - } - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E); } int get_dh_config_on_answer (struct query *q UU) { - int *start = in_ptr; unsigned x = fetch_int (); assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { - encr_root = fetch_int (); - if (encr_prime) { free (encr_prime); } + int a = fetch_int (); int l = prefetch_strlen (); assert (l == 256); - encr_prime = (void *)fetch_str_dup (); - encr_param_version = fetch_int (); - if (binlog_enabled) { - *start = LOG_DH_CONFIG; - add_log_event (start, 4 * (in_ptr - start)); - *start = CODE_messages_dh_config; - } + char *s = fetch_str (l); + int v = fetch_int (); + bl_do_set_dh_params (a, (void *)s, v); } if (x == LOG_DH_CONFIG) { return 0; } int l = prefetch_strlen (); assert (l == 256); unsigned char *random = (void *)fetch_str_dup (); if (q->extra) { - struct secret_chat *E = q->extra; - if (E->state == sc_request) { - do_send_accept_encr_chat (q->extra, random); - } else if (E->state == sc_none) { - do_send_create_encr_chat (q->extra, random); - } + void **x = q->extra; + ((void (*)(void *, void *))(*x))(x[1], random); + free (x); free (random); } else { free (random); @@ -2418,17 +2355,21 @@ void do_accept_encr_chat_request (struct secret_chat *E) { out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); + void **x = malloc (2 * sizeof (void *)); + x[0] = do_send_accept_encr_chat; + x[1] = E; + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); } -void do_create_encr_chat_request (struct secret_chat *E) { - assert (E->state == sc_none); - +void do_create_encr_chat_request (int user_id) { clear_packet (); out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); + void **x = malloc (2 * sizeof (void *)); + x[0] = do_send_create_encr_chat; + x[1] = (void *)(long)(user_id); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); } /* }}} */ @@ -2666,16 +2607,7 @@ void do_create_secret_chat (peer_id_t id) { return; } - peer_t *P = malloc (sizeof (*P)); - memset (P, 0, sizeof (*P)); - P->id = MK_ENCR_CHAT (lrand48 ()); - - P->encr_chat.user_id = get_peer_id (id); - - insert_encrypted_chat (P); - P->print_name = create_print_name (P->id, "!", U->user.first_name, U->user.last_name, 0); - - do_create_encr_chat_request (&P->encr_chat); + do_create_encr_chat_request (get_peer_id (id)); } /* }}} */ diff --git a/queries.h b/queries.h index 20015ca..e377a0a 100644 --- a/queries.h +++ b/queries.h @@ -81,7 +81,7 @@ void do_get_user_info (peer_id_t id); void do_forward_message (peer_id_t id, int n); void do_rename_chat (peer_id_t id, char *name); void do_load_encr_video (struct encr_video *V, int next); -void do_create_encr_chat_request (struct secret_chat *E); +void do_create_encr_chat_request (int user_id); void do_create_secret_chat (peer_id_t id); void do_get_suggested (void); diff --git a/structures.c b/structures.c index 9a48a42..4eab03f 100644 --- a/structures.c +++ b/structures.c @@ -42,39 +42,47 @@ int encr_chats_allocated; int geo_chats_allocated; extern int binlog_enabled; +void fetch_skip_photo (void); -void fetch_add_alloc_log_event (void *obj, int (*f)(void *)) { - int *start = in_ptr; - int r = f (obj); - if (binlog_enabled && r) { - add_log_event (start, 4 * (in_ptr - start)); - } -} +#define code_assert(x) if (!(x)) { logprintf ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } int fetch_file_location (struct file_location *loc) { int x = fetch_int (); - int new = 0; + code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); + if (x == CODE_file_location_unavailable) { - new |= set_update_int (&loc->dc, -1); - new |= fetch_update_long (&loc->volume); - new |= fetch_update_int (&loc->local_id); - new |= fetch_update_long (&loc->secret); + loc->dc = -1; + loc->volume = fetch_long (); + loc->local_id = fetch_int (); + loc->secret = fetch_long (); } else { - assert (x == CODE_file_location); - new |= fetch_update_int (&loc->dc); - new |= fetch_update_long (&loc->volume); - new |= fetch_update_int (&loc->local_id); - new |= fetch_update_long (&loc->secret); + loc->dc = fetch_int (); + loc->volume = fetch_long (); + loc->local_id = fetch_int (); + loc->secret = fetch_long (); } - return new; + return 0; +} + +int fetch_skip_file_location (void) { + int x = fetch_int (); + code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); + + if (x == CODE_file_location_unavailable) { + in_ptr += 5; + } else { + in_ptr += 6; + } + return 0; } int fetch_user_status (struct user_status *S) { - int x = fetch_int (); - int old = S->online; + unsigned x = fetch_int (); + code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); switch (x) { case CODE_user_status_empty: S->online = 0; + S->when = 0; break; case CODE_user_status_online: S->online = 1; @@ -87,7 +95,7 @@ int fetch_user_status (struct user_status *S) { default: assert (0); } - return (old == S->online); + return 0; } int our_id; @@ -149,223 +157,222 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha return strdup (s); } +long long fetch_user_photo (struct user *U) { + unsigned x = fetch_int (); + code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); + if (x == CODE_user_profile_photo_empty) { + bl_do_set_user_profile_photo (U, 0, 0, 0); + return 0; + } + long long photo_id = 1; + if (x == CODE_user_profile_photo) { + photo_id = fetch_long (); + } + struct file_location big; + struct file_location small; + if (fetch_file_location (&small) < 0) { return -1; } + if (fetch_file_location (&big) < 0) { return -1; } + + bl_do_set_user_profile_photo (U, photo_id, &big, &small); + return 0; +} + int fetch_user (struct user *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); + code_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 = MK_USER (fetch_int ()); if ((U->flags & FLAG_CREATED) && x == CODE_user_empty) { return 0; } - int old_flags = U->flags; - U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT | FLAG_CREATED); if (x == CODE_user_empty) { - U->flags |= FLAG_EMPTY; return 0; } - U->flags |= FLAG_CREATED; + if (x == CODE_user_self) { assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { - our_id = get_peer_id (U->id); + bl_do_set_our_id (get_peer_id (U->id)); write_auth_file (); - - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_OUR_ID; - ev[1] = our_id; - add_log_event (ev, 8); - } } } - int need_update = 0; - need_update |= fetch_update_str (&U->first_name); - need_update |= fetch_update_str (&U->last_name); - if (need_update) { - if (U->print_name) { free (U->print_name); } - U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); + + int new = 0; + if (!(U->flags & FLAG_CREATED)) { + new = 1; } - if (x == CODE_user_deleted) { - U->flags |= FLAG_DELETED; + if (new) { + int l1 = prefetch_strlen (); + char *s1 = fetch_str (l1); + int l2 = prefetch_strlen (); + char *s2 = fetch_str (l2); + + if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { + bl_do_new_user (get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); + bl_do_user_delete (U); + } + if (x != CODE_user_deleted) { + long long access_token = 0; + if (x != CODE_user_self) { + access_token = fetch_long (); + } + int phone_len = 0; + char *phone = 0; + if (x != CODE_user_foreign) { + phone_len = prefetch_strlen (); + phone = fetch_str (phone_len); + } + bl_do_new_user (get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); + if (fetch_user_photo (U) < 0) { return -1; } + + if (fetch_user_status (&U->status) < 0) { return -1; } + if (x == CODE_user_self) { + fetch_bool (); + } + } } else { - if (x == CODE_user_self) { - U->flags |= FLAG_USER_SELF; - } else { - need_update |= fetch_update_long (&U->access_hash); + int l1 = prefetch_strlen (); + char *s1 = fetch_str (l1); + int l2 = prefetch_strlen (); + char *s2 = fetch_str (l2); + + bl_do_set_user_name (U, s1, l1, s2, l2); + + if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { + bl_do_user_delete (U); } - if (x == CODE_user_foreign) { - U->flags |= FLAG_USER_FOREIGN; - } else { - need_update |= fetch_update_str (&U->phone); - } - unsigned y = fetch_int (); - if (y == CODE_user_profile_photo_empty) { - need_update |= set_update_int (&U->photo_small.dc, -2); - need_update |= set_update_int (&U->photo_big.dc, -2); - } else { - assert (y == CODE_user_profile_photo || y == CODE_user_profile_photo_old); - if (y == CODE_user_profile_photo) { - fetch_long (); + if (x != CODE_user_deleted) { + if (x != CODE_user_self) { + bl_do_set_user_access_token (U, fetch_long ()); + } + if (x != CODE_user_foreign) { + int l = prefetch_strlen (); + char *s = fetch_str (l); + bl_do_set_user_phone (U, s, l); + } + if (fetch_user_photo (U) < 0) { return -1; } + + fetch_user_status (&U->status); + if (x == CODE_user_self) { + fetch_bool (); + } + + if (x == CODE_user_contact) { + bl_do_set_user_friend (U, 1); + } else { + bl_do_set_user_friend (U, 0); } - need_update |= fetch_file_location (&U->photo_small); - need_update |= fetch_file_location (&U->photo_big); - } - fetch_user_status (&U->status); - if (x == CODE_user_self) { - fetch_bool (); - } - if (x == CODE_user_contact) { - U->flags |= FLAG_USER_CONTACT; } } - need_update |= (old_flags != U->flags); - return need_update; + return 0; } void fetch_encrypted_chat (struct secret_chat *U) { unsigned x = fetch_int (); assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); U->id = MK_ENCR_CHAT (fetch_int ()); - if ((U->flags & FLAG_CREATED) && x == CODE_encrypted_chat_empty) { - return; - } - U->flags &= ~(FLAG_EMPTY | FLAG_DELETED); - enum secret_chat_state old_state = U->state; if (x == CODE_encrypted_chat_empty) { - U->state = sc_none; - U->flags |= FLAG_EMPTY; - if (U->state != old_state) { - write_secret_chat_file (); - } return; } - U->flags |= FLAG_CREATED; + int new = !(U->flags & FLAG_CREATED); + if (x == CODE_encrypted_chat_discarded) { - U->state = sc_deleted; - U->flags |= FLAG_DELETED; - if (U->state != old_state) { - write_secret_chat_file (); - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_ENCR_CHAT_DELETED; - ev[1] = get_peer_id (U->id); - add_log_event (ev, 8); - } + if (new) { + logprintf ("Unknown chat in deleted state. May be we forgot something...\n"); + return; } + bl_do_encr_chat_delete (U); + write_secret_chat_file (); return; } - U->access_hash = fetch_long (); - U->date = fetch_int (); - U->admin_id = fetch_int (); - U->user_id = fetch_int () + U->admin_id - our_id; - if (!U->print_name) { - peer_t *P = user_chat_get (MK_USER (U->user_id)); - if (P) { - U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); - } else { - static char buf[100]; - sprintf (buf, "user#%d", U->user_id); - U->print_name = create_print_name (U->id, "!", buf, 0, 0); - } - } - if (x == CODE_encrypted_chat_waiting) { - U->state = sc_waiting; - if (old_state != sc_waiting) { - if (binlog_enabled) { - int *ev = alloc_log_event (28); - ev[0] = LOG_ENCR_CHAT_WAITING; - ev[1] = get_peer_id (U->id); - ev[2] = U->date; - ev[3] = U->admin_id; - ev[4] = U->user_id; - *(long long *)(ev + 5) = U->access_hash; - add_log_event (ev, 28); - } + static char g_key[256]; + static char nonce[256]; + if (new) { + long long access_hash = fetch_long (); + int date = fetch_int (); + int admin_id = fetch_int (); + int user_id = fetch_int () + admin_id - our_id; + + if (x == CODE_encrypted_chat_waiting) { + logprintf ("Unknown chat in waiting state. May be we forgot something...\n"); + return; } - } else if (x == CODE_encrypted_chat_requested) { - U->state = sc_request; - if (!U->g_key) { - U->g_key = malloc (256); + if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { + memset (g_key, 0, sizeof (g_key)); + memset (nonce, 0, sizeof (nonce)); } - memset (U->g_key, 0, 256); - if (!U->nonce) { - U->nonce = malloc (256); - } - memset (U->nonce, 0, 256); + int l = prefetch_strlen (); char *s = fetch_str (l); if (l < 256) { - memcpy (U->g_key + 256 - l, s, l); + memcpy (g_key + 256 - l, s, l); } else { - memcpy (U->g_key, s + (l - 256), 256); + memcpy (g_key, s + (l - 256), 256); } + l = prefetch_strlen (); s = fetch_str (l); if (l < 256) { - memcpy (U->nonce + 256 - l, s, l); + memcpy (nonce + 256 - l, s, l); } else { - memcpy (U->nonce, s + (l - 256), 256); + memcpy (nonce, s + (l - 256), 256); } - if (old_state != sc_request) { - if (binlog_enabled) { - int *ev = alloc_log_event (28); - ev[0] = LOG_ENCR_CHAT_REQUESTED; - ev[1] = get_peer_id (U->id); - ev[2] = U->date; - ev[3] = U->admin_id; - ev[4] = U->user_id; - *(long long *)(ev + 5) = U->access_hash; - add_log_event (ev, 28); - } + + if (x == CODE_encrypted_chat) { + fetch_long (); // fingerprint } - } else { - U->state = sc_ok; - if (!U->g_key) { - U->g_key = malloc (256); + + if (x == CODE_encrypted_chat) { + logprintf ("Unknown chat in ok state. May be we forgot something...\n"); + return; } - memset (U->g_key, 0, 256); - if (!U->nonce) { - U->nonce = malloc (256); - } - memset (U->nonce, 0, 256); - int l = prefetch_strlen (); - char *s = fetch_str (l); - if (l < 256) { - memcpy (U->g_key + 256 - l, s, l); - } else { - memcpy (U->g_key, s + (l - 256), 256); - } - l = prefetch_strlen (); - s = fetch_str (l); - if (l < 256) { - memcpy (U->nonce + 256 - l, s, l); - } else { - memcpy (U->nonce, s + (l - 256), 256); - } - if (!U->key_fingerprint) { - U->key_fingerprint = fetch_long (); - } else { - assert (U->key_fingerprint == fetch_long ()); - } - if (old_state == sc_waiting) { - do_create_keys_end (U); - } - free (U->g_key); - U->g_key = 0; - free (U->nonce); - U->nonce = 0; - if (old_state != sc_ok) { - if (binlog_enabled) { - int *ev = alloc_log_event (8); - ev[0] = LOG_ENCR_CHAT_OK; - ev[1] = get_peer_id (U->id); - add_log_event (ev, 8); - } - } - } - if (U->state != old_state) { + + bl_do_encr_chat_requested (U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); write_secret_chat_file (); + } else { + bl_do_set_encr_chat_access_hash (U, fetch_long ()); + bl_do_set_encr_chat_date (U, fetch_int ()); + if (fetch_int () != U->admin_id) { + logprintf ("Changed admin in secret chat. WTF?\n"); + return; + } + if (U->user_id != U->admin_id + fetch_int () - our_id) { + logprintf ("Changed partner in secret chat. WTF?\n"); + return; + } + if (x == CODE_encrypted_chat_waiting) { + bl_do_set_encr_chat_state (U, sc_waiting); + write_secret_chat_file (); + return; // We needed only access hash from here + } + + if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { + memset (g_key, 0, sizeof (g_key)); + memset (nonce, 0, sizeof (nonce)); + } + + int l = prefetch_strlen (); + char *s = fetch_str (l); + if (l < 256) { + memcpy (g_key + 256 - l, s, l); + } else { + memcpy (g_key, s + (l - 256), 256); + } + + l = prefetch_strlen (); + s = fetch_str (l); + if (l < 256) { + memcpy (nonce + 256 - l, s, l); + } else { + memcpy (nonce, s + (l - 256), 256); + } + + if (x == CODE_encrypted_chat_requested) { + return; // Duplicate? + } + bl_do_encr_chat_accepted (U, (void *)g_key, (void *)nonce, fetch_long ()); } + write_secret_chat_file (); } void fetch_notify_settings (void); @@ -376,46 +383,39 @@ void fetch_user_full (struct user *U) { assert (fetch_int () == (int)CODE_contacts_link); x = fetch_int (); assert (x == CODE_contacts_my_link_empty || x == CODE_contacts_my_link_requested || x == CODE_contacts_my_link_contact); - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (x == CODE_contacts_my_link_contact) { - U->flags |= FLAG_USER_IN_CONTACT; - } if (x == CODE_contacts_my_link_requested) { fetch_bool (); } x = fetch_int (); assert (x == CODE_contacts_foreign_link_unknown || x == CODE_contacts_foreign_link_requested || x == CODE_contacts_foreign_link_mutual); - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (x == CODE_contacts_foreign_link_mutual) { - U->flags |= FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT; - } if (x == CODE_contacts_foreign_link_requested) { - U->flags |= FLAG_USER_OUT_CONTACT; fetch_bool (); } fetch_alloc_user (); - if (U->flags & FLAG_HAS_PHOTO) { - free_photo (&U->photo); - } - fetch_photo (&U->photo); - U->flags |= FLAG_HAS_PHOTO; + + int *start = in_ptr; + fetch_skip_photo (); + bl_do_set_user_full_photo (U, start, 4 * (in_ptr - start)); + fetch_notify_settings (); - U->blocked = fetch_int (); - if (U->real_first_name) { free (U->real_first_name); } - if (U->real_last_name) { free (U->real_last_name); } - U->real_first_name = fetch_str_dup (); - U->real_last_name = fetch_str_dup (); + + bl_do_set_user_blocked (U, fetch_bool ()); + int l1 = prefetch_strlen (); + char *s1 = fetch_str (l1); + int l2 = prefetch_strlen (); + char *s2 = fetch_str (l2); + bl_do_set_user_real_name (U, s1, l1, s2, l2); } void fetch_chat (struct chat *C) { unsigned x = fetch_int (); assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); C->id = MK_CHAT (fetch_int ()); - C->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); if (x == CODE_chat_empty) { - C->flags |= FLAG_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; } @@ -472,7 +472,8 @@ 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_EMPTY | FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); + C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); + C->flags |= FLAG_CREATED; x = fetch_int (); if (x == CODE_chat_participants) { assert (fetch_int () == get_peer_id (C->id)); @@ -536,6 +537,23 @@ void fetch_photo_size (struct photo_size *S) { } } +void fetch_skip_photo_size (void) { + unsigned x = fetch_int (); + assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); + int l = prefetch_strlen (); + fetch_str (l); // type + if (x != CODE_photo_size_empty) { + fetch_skip_file_location (); + in_ptr += 2; // w, h + if (x == CODE_photo_size) { + in_ptr ++; + } else { + l = prefetch_strlen (); + fetch_str (l); + } + } +} + void fetch_geo (struct geo *G) { unsigned x = fetch_int (); if (x == CODE_geo_point) { @@ -548,6 +566,14 @@ void fetch_geo (struct geo *G) { } } +void fetch_skip_geo (void) { + unsigned x = fetch_int (); + assert (x == CODE_geo_point || x == CODE_geo_point_empty); + if (x == CODE_geo_point) { + in_ptr += 2; + } +} + void fetch_photo (struct photo *P) { memset (P, 0, sizeof (*P)); unsigned x = fetch_int (); @@ -568,6 +594,23 @@ void fetch_photo (struct photo *P) { } } +void fetch_skip_photo (void) { + unsigned x = fetch_int (); + assert (x == CODE_photo_empty || x == CODE_photo); + in_ptr += 2; // id + if (x == CODE_photo_empty) { return; } + in_ptr += 2 +1 + 1; // access_hash, user_id, date + int l = prefetch_strlen (); + fetch_str (l); // caption + fetch_skip_geo (); + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + int i; + for (i = 0; i < n; i++) { + fetch_skip_photo_size (); + } +} + void fetch_video (struct video *V) { memset (V, 0, sizeof (*V)); unsigned x = fetch_int (); @@ -902,11 +945,11 @@ void fetch_encrypted_message (struct message *M) { peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); M->to_id = chat; peer_t *P = user_chat_get (chat); - M->flags &= ~(FLAG_EMPTY | FLAG_DELETED); + M->flags &= ~(FLAG_MESSAGE_EMPTY | FLAG_DELETED); M->flags |= FLAG_ENCRYPTED; if (!P) { logprintf ("Encrypted message to unknown chat. Dropping\n"); - M->flags |= FLAG_EMPTY; + M->flags |= FLAG_MESSAGE_EMPTY; } M->date = fetch_int (); @@ -1012,36 +1055,32 @@ struct user *fetch_alloc_user (void) { int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); - if (U) { - fetch_add_alloc_log_event (&U->user, (void *)fetch_user); - return &U->user; - } else { + if (!U) { users_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - fetch_add_alloc_log_event (&U->user, (void *)fetch_user); + U->id = MK_USER (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[peer_num ++] = U; - return &U->user; } + fetch_user (&U->user); + return &U->user; } struct secret_chat *fetch_alloc_encrypted_chat (void) { int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); - if (U) { - fetch_encrypted_chat (&U->encr_chat); - return &U->encr_chat; - } else { - encr_chats_allocated ++; + if (!U) { U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - fetch_encrypted_chat (&U->encr_chat); + U->id = MK_ENCR_CHAT (data[1]); + encr_chats_allocated ++; peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[peer_num ++] = U; - return &U->encr_chat; } + fetch_encrypted_chat (&U->encr_chat); + return &U->encr_chat; } void insert_encrypted_chat (peer_t *P) { @@ -1050,6 +1089,12 @@ void insert_encrypted_chat (peer_t *P) { Peers[peer_num ++] = P; } +void insert_user (peer_t *P) { + users_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); @@ -1196,7 +1241,6 @@ void message_add_peer (struct message *M) { P = malloc (sizeof (*P)); memset (P, 0, sizeof (*P)); P->id = id; - P->flags = FLAG_EMPTY; switch (get_peer_type (id)) { case PEER_USER: users_allocated ++; diff --git a/structures.h b/structures.h index a06627a..3e3daf3 100644 --- a/structures.h +++ b/structures.h @@ -22,7 +22,8 @@ #include typedef struct { int type; int id; } peer_id_t; -#define FLAG_EMPTY 1 +//#define FLAG_EMPTY 1 +#define FLAG_MESSAGE_EMPTY 1 #define FLAG_DELETED 2 #define FLAG_FORBIDDEN 4 #define FLAG_HAS_PHOTO 8 @@ -117,6 +118,7 @@ struct user { int structure_version; struct file_location photo_big; struct file_location photo_small; + long long photo_id; struct photo photo; char *first_name; char *last_name; @@ -296,6 +298,9 @@ void message_insert (struct message *M); 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 fetch_photo (struct photo *P); +void free_photo (struct photo *P); #define PEER_USER 1 #define PEER_CHAT 2 From d8a10e52f31e056477bab7cc023ae4dd7c6b63e1 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 21 Nov 2013 23:54:06 +0400 Subject: [PATCH 115/465] Fixed bugs. Probably now something works --- binlog.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/binlog.c b/binlog.c index ef46b8b..ffe00bc 100644 --- a/binlog.c +++ b/binlog.c @@ -465,9 +465,9 @@ void replay_log_event (void) { if (!U->nonce) { U->nonce = malloc (256); } - memcpy (rptr, U->g_key, 256); + memcpy (U->g_key, rptr, 256); rptr += 64; - memcpy (rptr, U->nonce, 256); + memcpy (U->nonce, rptr, 256); rptr += 64; U->key_fingerprint = *(long long *)rptr; rptr += 2; @@ -835,7 +835,6 @@ void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, in ev[4] = date; ev[5] = admin_id; ev[6] = user_id; - logprintf ("user_id = %d, admin_id = %d, our_id = %d\n", user_id, admin_id, our_id); memcpy (ev + 7, g_key, 256); memcpy (ev + 7 + 64, nonce, 256); add_log_event (ev, 540); From 4c740e0bd4c40c5a2289e8eafb55271e3520a027 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 22 Nov 2013 01:40:31 +0400 Subject: [PATCH 116/465] Fixed binlog. Added state file to binlog --- binlog.c | 51 ++++++++++++++++++++++++++++++++++- binlog.h | 9 +++++++ loop.c | 2 ++ mtproto-client.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++-- mtproto-client.h | 1 + queries.c | 19 +++++++------ 6 files changed, 141 insertions(+), 11 deletions(-) diff --git a/binlog.c b/binlog.c index ffe00bc..30cc8a2 100644 --- a/binlog.c +++ b/binlog.c @@ -22,6 +22,11 @@ int *rptr; int *wptr; extern int test_dc; +extern int pts; +extern int qts; +extern int last_date; +extern int seq; + #define MAX_LOG_EVENT_SIZE (1 << 17) char *get_binlog_file_name (void); @@ -522,9 +527,25 @@ void replay_log_event (void) { P->flags |= FLAG_CREATED; } break; + case CODE_binlog_set_pts: + rptr ++; + pts = *(rptr ++); + break; + case CODE_binlog_set_qts: + rptr ++; + qts = *(rptr ++); + break; + case CODE_binlog_set_date: + rptr ++; + last_date = *(rptr ++); + break; + case CODE_binlog_set_seq: + rptr ++; + seq = *(rptr ++); + break; case CODE_update_user_photo: case CODE_update_user_name: - work_update (0, 0); + work_update_binlog (); rptr = in_ptr; break; default: @@ -905,3 +926,31 @@ void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned memcpy (ev + 67, g_a, 256); add_log_event (ev, 524); } + +void bl_do_set_pts (int pts) { + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_set_pts; + ev[1] = pts; + add_log_event (ev, 8); +} + +void bl_do_set_qts (int qts) { + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_set_qts; + ev[1] = qts; + add_log_event (ev, 8); +} + +void bl_do_set_date (int date) { + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_set_date; + ev[1] = date; + add_log_event (ev, 8); +} + +void bl_do_set_seq (int seq) { + int *ev = alloc_log_event (8); + ev[0] = CODE_binlog_set_seq; + ev[1] = seq; + add_log_event (ev, 8); +} diff --git a/binlog.h b/binlog.h index 1ce2a37..bf15775 100644 --- a/binlog.h +++ b/binlog.h @@ -36,6 +36,10 @@ #define CODE_binlog_set_encr_chat_key 0x179df2d4 #define CODE_binlog_set_dh_params 0x20ba46bc #define CODE_binlog_encr_chat_init 0x939cd1c7 +#define CODE_binlog_set_pts 0x844e4c1c +#define CODE_binlog_set_qts 0x3cf22b79 +#define CODE_binlog_set_date 0x33dfe392 +#define CODE_binlog_set_seq 0xb9294837 void *alloc_log_event (int l); void replay_log (void); @@ -69,4 +73,9 @@ void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned void bl_do_dc_signed (int id); void bl_do_set_working_dc (int num); void bl_do_set_dh_params (int root, unsigned char prime[], int version); + +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); #endif diff --git a/loop.c b/loop.c index 8680850..4ac7a54 100644 --- a/loop.c +++ b/loop.c @@ -260,6 +260,7 @@ void read_auth_file (void) { int pts, qts, seq, last_date; void read_state_file (void) { + if (binlog_enabled) { return; } int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600); if (state_file_fd < 0) { return; @@ -282,6 +283,7 @@ void read_state_file (void) { } void write_state_file (void) { + if (binlog_enabled) { return; } static int wseq; static int wpts; static int wqts; diff --git a/mtproto-client.c b/mtproto-client.c index da1ca8a..4b4399e 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -669,6 +669,7 @@ void fetch_pts (void) { } else { pts ++; } + bl_do_set_pts (pts); } void fetch_qts (void) { @@ -685,12 +686,14 @@ void fetch_qts (void) { } else { qts ++; } + bl_do_set_qts (qts); } void fetch_date (void) { int p = fetch_int (); if (p > last_date) { last_date = p; + bl_do_set_date (last_date); } } @@ -699,9 +702,72 @@ void fetch_seq (void) { if (x > seq + 1) { logprintf ("Hole in seq: seq = %d, x = %d\n", seq, x); //do_get_difference (); + //seq = x; + } else if (x == seq + 1) { seq = x; - } else if (x >= seq + 1) { - seq = x; + bl_do_set_seq (seq); + } +} + +void work_update_binlog (void) { + unsigned op = fetch_int (); + switch (op) { + case CODE_update_user_name: + { + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *UC = user_chat_get (user_id); + if (UC) { + struct user *U = &UC->user; + 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); + } else { + int l; + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + } + } + break; + case CODE_update_user_photo: + { + peer_id_t user_id = MK_USER (fetch_int ()); + peer_t *UC = user_chat_get (user_id); + fetch_date (); + if (UC) { + struct user *U = &UC->user; + + 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 (); + if (y == CODE_user_profile_photo_empty) { + } else { + assert (y == CODE_user_profile_photo); + fetch_long (); // photo_id + fetch_file_location (&t); + fetch_file_location (&t); + } + } + fetch_bool (); + } + break; + default: + assert (0); } } diff --git a/mtproto-client.h b/mtproto-client.h index 9e44df2..2a7d7e8 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -24,4 +24,5 @@ void on_start (void); long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); void dc_authorize (struct dc *DC); void work_update (struct connection *c, long long msg_id); +void work_update_binlog (void); #endif diff --git a/queries.c b/queries.c index 1539791..5c72769 100644 --- a/queries.c +++ b/queries.c @@ -2409,17 +2409,19 @@ int difference_got; int seq, pts, qts, last_date; int get_state_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_updates_state); - pts = fetch_int (); - qts = fetch_int (); - last_date = fetch_int (); - seq = fetch_int (); + bl_do_set_pts (fetch_int ()); + bl_do_set_qts (fetch_int ()); + bl_do_set_date (fetch_int ()); + bl_do_set_seq (fetch_int ()); unread_messages = fetch_int (); write_state_file (); difference_got = 1; return 0; } +int get_difference_active; 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 (); @@ -2463,10 +2465,10 @@ int get_difference_on_answer (struct query *q UU) { fetch_alloc_user (); } assert (fetch_int () == (int)CODE_updates_state); - pts = fetch_int (); - qts = fetch_int (); - last_date = fetch_int (); - seq = fetch_int (); + bl_do_set_pts (fetch_int ()); + bl_do_set_qts (fetch_int ()); + bl_do_set_date (fetch_int ()); + bl_do_set_seq (fetch_int ()); unread_messages = fetch_int (); write_state_file (); for (i = 0; i < ml_pos; i++) { @@ -2492,6 +2494,7 @@ struct query_methods get_difference_methods = { }; void do_get_difference (void) { + get_difference_active = 1; difference_got = 0; clear_packet (); do_insert_header (); From 9022881234eeb2550253388ec4326fbeee58ec99 Mon Sep 17 00:00:00 2001 From: tazhate Date: Fri, 22 Nov 2013 12:34:29 +0400 Subject: [PATCH 117/465] added chat options to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d4301e0..4322cea 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ By default public key is stored in the same folder named tg.pub: * **chat_info** \ - prints info about chat * **user_info** \ - prints info about user * **fwd** \ \ - forward message to user. You can see message numbers starting client with -N +* **chat_add_user** \ \ - add user to chat +* **chat_del_user** \ \ - remove user from chat * **rename_chat** \ \ * **load_photo**/load_video/load_video_thumb \ - loads photo/video to download dir * **view_photo**/view_video/view_video_thumb \ - loads photo/video to download dir and starts system default viewer From 6246e670281e53fd1b7139759255085427a2e7e2 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 22 Nov 2013 21:48:23 +0400 Subject: [PATCH 118/465] Fixed (probable) bug with updateChatParticipants --- mtproto-client.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 4b4399e..fb7a40f 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -977,20 +977,28 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_chat_participants: { - assert (fetch_int () == CODE_chat_participants); + unsigned x = fetch_int (); + assert (x == CODE_chat_participants || x == CODE_chat_participants_forbidden); peer_id_t chat_id = MK_CHAT (fetch_int ()); - fetch_int (); // admin_id - assert (fetch_int () == CODE_vector); - int n = fetch_int (); - fetch_skip (n * 4); - fetch_int (); // version + 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); print_start (); push_color (COLOR_YELLOW); print_date (time (0)); printf (" Chat "); print_chat_name (chat_id, C); - printf (" changed list: now %d members\n", n); + if (x == CODE_chat_participants) { + printf (" changed list: now %d members\n", n); + } else { + printf (" changed list, but we are forbidden to know about it (Why this update even was sent to us?\n"); + } pop_color (); print_end (); } From a8fe99a10c924ba82e97cbdf93096f25db7fa808 Mon Sep 17 00:00:00 2001 From: tazhate Date: Fri, 22 Nov 2013 23:36:37 +0400 Subject: [PATCH 119/465] added info about completion --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4322cea..f84e18b 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ If you manage to launch it on other UNIX, please let me know. By default public key is stored in the same folder named tg.pub: ./telegram -k tg.pub + +Client support TAB completion and command history. #### Supported commands: From 9ea07afc8cee5ad86ab52776e7f83fc22c05765a Mon Sep 17 00:00:00 2001 From: tazhate Date: Fri, 22 Nov 2013 23:49:59 +0400 Subject: [PATCH 120/465] new format of readme --- README.md | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f84e18b..ffc66e2 100644 --- a/README.md +++ b/README.md @@ -45,31 +45,50 @@ By default public key is stored in the same folder named tg.pub: Client support TAB completion and command history. -#### Supported commands: +#### Supported commands + +## Messaging + * **msg** \ Text - sends message to this peer -* **contact_list** - prints info about users in your contact list -* **stats** - just for debugging -* **history** \ [limit] - prints history (and marks it as read). Default limit = 40 -* **dialog_list** - prints info about your dialogs +* **fwd** \ \ - forward message to user. You can see message numbers starting client with -N +* **add_contact** \ \ \ - tries to add contact to contact-list by phone +* **rename_contact** \ \ \ - tries to rename contact. If you have another device it will be a fight +* **mark_read** \ - mark read all received messages with peer + +## Multimedia + * **send_photo** \ \ - sends photo to peer * **send_video** \ \ - sends video to peer * **send_text** \ \ - sends text file as plain messages +* **load_photo**/load_video/load_video_thumb \ - loads photo/video to download dir +* **view_photo**/view_video/view_video_thumb \ - loads photo/video to download dir and starts system default viewer + + +## Group chat options + * **chat_info** \ - prints info about chat -* **user_info** \ - prints info about user -* **fwd** \ \ - forward message to user. You can see message numbers starting client with -N * **chat_add_user** \ \ - add user to chat * **chat_del_user** \ \ - remove user from chat * **rename_chat** \ \ -* **load_photo**/load_video/load_video_thumb \ - loads photo/video to download dir -* **view_photo**/view_video/view_video_thumb \ - loads photo/video to download dir and starts system default viewer + +## Search + * **search** \ pattern - searches pattern in messages with peer * **global_search** pattern - searches pattern in all messages -* **mark_read** \ - mark read all received messages with peer -* **add_contact** \ \ \ - tries to add contact to contact-list by phone + +## Secret chat + * **create_secret_chat** \ - creates secret chat with this user -* **rename_contact** \ \ \ - tries to rename contact. If you have another device it will be a fight -* **suggested_contacts** - print info about contacts, you have max common friends * **visualize_key** \ - prints visualization of encryption key. You should compare it to your partner's one + +## Stats and various info + +* **user_info** \ - prints info about user +* **history** \ [limit] - prints history (and marks it as read). Default limit = 40 +* **dialog_list** - prints info about your dialogs +* **contact_list** - prints info about users in your contact list +* **suggested_contacts** - print info about contacts, you have max common friends +* **stats** - just for debugging * **show_license** - prints contents of GPLv2 * **help** - prints this help From ce931f6eebd1130c5684b57086a7aa08ba7c1147 Mon Sep 17 00:00:00 2001 From: tazhate Date: Fri, 22 Nov 2013 23:51:58 +0400 Subject: [PATCH 121/465] fixed h1 --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ffc66e2..6263538 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,9 @@ By default public key is stored in the same folder named tg.pub: Client support TAB completion and command history. -#### Supported commands +### Supported commands -## Messaging +#### Messaging * **msg** \ Text - sends message to this peer @@ -56,7 +56,7 @@ Client support TAB completion and command history. * **rename_contact** \ \ \ - tries to rename contact. If you have another device it will be a fight * **mark_read** \ - mark read all received messages with peer -## Multimedia +#### Multimedia * **send_photo** \ \ - sends photo to peer * **send_video** \ \ - sends video to peer @@ -65,24 +65,24 @@ Client support TAB completion and command history. * **view_photo**/view_video/view_video_thumb \ - loads photo/video to download dir and starts system default viewer -## Group chat options +#### Group chat options * **chat_info** \ - prints info about chat * **chat_add_user** \ \ - add user to chat * **chat_del_user** \ \ - remove user from chat * **rename_chat** \ \ -## Search +#### Search * **search** \ pattern - searches pattern in messages with peer * **global_search** pattern - searches pattern in all messages -## Secret chat +#### Secret chat * **create_secret_chat** \ - creates secret chat with this user * **visualize_key** \ - prints visualization of encryption key. You should compare it to your partner's one -## Stats and various info +#### Stats and various info * **user_info** \ - prints info about user * **history** \ [limit] - prints history (and marks it as read). Default limit = 40 From 852c7687360d27b4ec9d7830083cc304fcaa65ca Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 23 Nov 2013 03:26:35 +0400 Subject: [PATCH 122/465] Chats added to binlog --- binlog.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++ binlog.h | 15 +++++ interface.c | 6 ++ mtproto-common.c | 2 +- mtproto-common.h | 8 ++- structures.c | 127 ++++++++++++++++++++++++++---------- structures.h | 1 + 7 files changed, 289 insertions(+), 36 deletions(-) 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); From 2362d8826640dfa519049bd3277e013c1f6fa7f2 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 25 Nov 2013 20:13:36 +0400 Subject: [PATCH 123/465] added chat info to binlog --- binlog.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++ binlog.h | 11 +++- mtproto-client.c | 91 +++++++++++++++++++++---------- queries.c | 14 ++--- structures.c | 90 ++++++++++++++++--------------- structures.h | 4 +- 6 files changed, 268 insertions(+), 80 deletions(-) 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; From 698004d92d0d9800ba0f96b12dfe9914d61cabfd Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 25 Nov 2013 21:16:34 +0400 Subject: [PATCH 124/465] Added [offline] modifier --- interface.c | 26 ++++++++++++++++++++++++-- queries.c | 38 +++++++++++++++++++++++++++++++++----- structures.c | 13 ++++++------- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/interface.c b/interface.c index db43a1b..d952a11 100644 --- a/interface.c +++ b/interface.c @@ -42,6 +42,8 @@ #include "structures.h" #include "mtproto-common.h" + +#define ALLOW_MULT 1 char *default_prompt = "> "; int unread_messages; @@ -493,13 +495,24 @@ char **complete_text (char *text, int start UU, int end UU) { return (char **) rl_completion_matches (text, command_generator); } -void work_modifier (const char *s UU) { +int offline_mode; +int count = 1; +void work_modifier (const char *s, int l) { + if (is_same_word (s, l, "[offline]")) { + offline_mode = 1; + } +#ifdef ALLOW_MULT + if (sscanf (s, "[x%d]", &count) >= 1) { + } +#endif } void interpreter (char *line UU) { line_ptr = line; assert (!in_readline); in_readline = 1; + offline_mode = 0; + count = 1; if (!line) { in_readline = 0; return; @@ -514,12 +527,20 @@ void interpreter (char *line UU) { command = next_token (&l); if (!command) { in_readline = 0; return; } if (*command == '[' && command[l - 1] == ']') { - work_modifier (command); + work_modifier (command, l); } else { break; } } + int _; + char *save = line_ptr; + int ll = l; + char *cs = command; + for (_ = 0; _ < count; _ ++) { + line_ptr = save; + l = ll; + command = cs; #define IS_WORD(s) is_same_word (command, l, (s)) #define RET in_readline = 0; return; @@ -970,6 +991,7 @@ void interpreter (char *line UU) { } else if (IS_WORD ("quit")) { exit (0); } + } #undef IS_WORD #undef RET update_prompt (); diff --git a/queries.c b/queries.c index 695cb25..85cec4a 100644 --- a/queries.c +++ b/queries.c @@ -50,6 +50,7 @@ char *get_downloads_directory (void); int verbosity; +extern int offline_mode; long long cur_uploading_bytes; long long cur_uploaded_bytes; @@ -1080,7 +1081,7 @@ void do_get_local_history (peer_id_t id, int limit) { } void do_get_history (peer_id_t id, int limit) { - if (get_peer_type (id) == PEER_ENCR_CHAT) { + if (get_peer_type (id) == PEER_ENCR_CHAT || offline_mode) { do_get_local_history (id, limit); do_mark_read (id); return; @@ -1609,8 +1610,7 @@ void do_rename_chat (peer_id_t id, char *name) { /* }}} */ /* {{{ Chat info */ -int chat_info_on_answer (struct query *q UU) { - struct chat *C = fetch_alloc_chat_full (); +void print_chat_info (struct chat *C) { peer_t *U = (void *)C; print_start (); push_color (COLOR_YELLOW); @@ -1632,6 +1632,11 @@ int chat_info_on_answer (struct query *q UU) { } pop_color (); print_end (); +} + +int chat_info_on_answer (struct query *q UU) { + struct chat *C = fetch_alloc_chat_full (); + print_chat_info (C); return 0; } @@ -1640,6 +1645,15 @@ struct query_methods chat_info_methods = { }; void do_get_chat_info (peer_id_t id) { + if (offline_mode) { + peer_t *C = user_chat_get (id); + if (!C) { + rprintf ("No such chat\n"); + } else { + print_chat_info (&C->chat); + } + return; + } clear_packet (); out_int (CODE_messages_get_full_chat); assert (get_peer_type (id) == PEER_CHAT); @@ -1649,8 +1663,8 @@ void do_get_chat_info (peer_id_t id) { /* }}} */ /* {{{ User info */ -int user_info_on_answer (struct query *q UU) { - struct user *U = fetch_alloc_user_full (); + +void print_user_info (struct user *U) { peer_t *C = (void *)U; print_start (); push_color (COLOR_YELLOW); @@ -1668,6 +1682,11 @@ int user_info_on_answer (struct query *q UU) { } pop_color (); print_end (); +} + +int user_info_on_answer (struct query *q UU) { + struct user *U = fetch_alloc_user_full (); + print_user_info (U); return 0; } @@ -1676,6 +1695,15 @@ struct query_methods user_info_methods = { }; void do_get_user_info (peer_id_t id) { + if (offline_mode) { + peer_t *C = user_chat_get (id); + if (!C) { + rprintf ("No such user\n"); + } else { + print_user_info (&C->user); + } + return; + } clear_packet (); out_int (CODE_users_get_full_user); assert (get_peer_type (id) == PEER_USER); diff --git a/structures.c b/structures.c index a3cba31..56ff4ba 100644 --- a/structures.c +++ b/structures.c @@ -135,6 +135,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha s++; } s = buf; + int fl = strlen (s); int cc = 0; while (1) { int ok = 1; @@ -149,17 +150,15 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha break; } cc ++; - assert (cc <= 99); + assert (cc <= 9999); if (cc == 1) { int l = strlen (s); s[l + 2] = 0; s[l] = '#'; s[l + 1] = '1'; - } else if (cc == 10) { - int l = strlen (s); - s[l + 1] = 0; - s[l] = '0'; - s[l - 1] = '1'; + } else if (cc == 10 || cc == 100 || cc == 1000) { +// int l = strlen (s); + sprintf (s + fl, "#%d", cc); } else { int l = strlen (s); s[l - 1] ++; @@ -548,7 +547,7 @@ void fetch_chat_full (struct chat *C) { users_num = fetch_int (); users = malloc (sizeof (struct chat_user) * users_num); int i; - for (i = 0; i < C->users_num; i++) { + for (i = 0; i < users_num; i++) { assert (fetch_int () == (int)CODE_chat_participant); users[i].user_id = fetch_int (); users[i].inviter_id = fetch_int (); From 7c1825d1b2c23abe1081bab16c82c9a6e99deb7e Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 25 Nov 2013 21:21:08 +0400 Subject: [PATCH 125/465] fixed detailed info --- interface.c | 2 +- mtproto-client.c | 18 ++++++++++++++---- mtproto-common.h | 4 +++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/interface.c b/interface.c index d952a11..2001df1 100644 --- a/interface.c +++ b/interface.c @@ -43,7 +43,7 @@ #include "mtproto-common.h" -#define ALLOW_MULT 1 +//#define ALLOW_MULT 1 char *default_prompt = "> "; int unread_messages; diff --git a/mtproto-client.c b/mtproto-client.c index 8e29dbb..7b8836a 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1431,14 +1431,21 @@ void work_pong (struct connection *c UU, long long msg_id UU) { fetch_long (); // ping_id } -void work_detained_info (struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == CODE_msg_detained_info); +void work_detailed_info (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == CODE_msg_detailed_info); fetch_long (); // msg_id fetch_long (); // answer_msg_id fetch_int (); // bytes fetch_int (); // status } +void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == CODE_msg_detailed_info); + fetch_long (); // answer_msg_id + fetch_int (); // bytes + fetch_int (); // status +} + void work_updates_to_long (struct connection *c UU, long long msg_id UU) { assert (fetch_int () == (int)CODE_updates_too_long); logprintf ("updates to long... Getting difference\n"); @@ -1484,8 +1491,11 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_pong: work_pong (c, msg_id); return; - case CODE_msg_detained_info: - work_detained_info (c, msg_id); + case CODE_msg_detailed_info: + work_detailed_info (c, msg_id); + return; + case CODE_msg_new_detailed_info: + work_new_detailed_info (c, msg_id); return; case CODE_updates_too_long: work_updates_to_long (c, msg_id); diff --git a/mtproto-common.h b/mtproto-common.h index d119cec..79d4f3b 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -78,7 +78,9 @@ #define CODE_peer_notify_settings_old 0xddbcd4a5 #define CODE_user_profile_photo_old 0x990d1493 -#define CODE_msg_detained_info 0x276d3ec6 +#define CODE_msg_new_detailed_info 0x809db6df + +#define CODE_msg_detailed_info 0x276d3ec6 /* not really a limit, for struct encrypted_message only */ // #define MAX_MESSAGE_INTS 16384 #define MAX_MESSAGE_INTS 1048576 From 400e3bde76f64cde3c48ef5fdf9e0d17862f894f Mon Sep 17 00:00:00 2001 From: Dann Luciano Date: Thu, 28 Nov 2013 17:49:20 -0200 Subject: [PATCH 126/465] Update README.md Added info for download source code. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 6263538..c82dee5 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,15 @@ Documentation for MTproto protocol is available here: http://core.telegram.org/m ### Installation +Clone GitHub Repository + + $ git clone https://github.com/vysheng/tg.git && cd tg + +or download and extrac zip + + $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip + $ tar xzf tg-master.zip && cd tg-master + #### Linux Just run From 639160bc75d30e04f3824caebc0f0e7c2aa9080e Mon Sep 17 00:00:00 2001 From: Dann Luciano Date: Fri, 29 Nov 2013 19:33:05 -0200 Subject: [PATCH 127/465] Added open support in OS X. --- queries.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/queries.c b/queries.c index 85cec4a..f57666b 100644 --- a/queries.c +++ b/queries.c @@ -48,6 +48,12 @@ #define sha1 SHA1 +#ifdef __APPLE__ +#define OPEN_BIN "open %s" +#else +#define OPEN_BIN "xdg-open %s" +#endif + char *get_downloads_directory (void); int verbosity; extern int offline_mode; @@ -1777,7 +1783,7 @@ void end_load (struct download *D) { logprintf ("Done: %s\n", D->name); } else if (D->next == 2) { static char buf[1000]; - sprintf (buf, "xdg-open %s", D->name); + sprintf (buf, OPEN_BIN, D->name); int x = system (buf); if (x < 0) { logprintf ("Can not open image viewer: %m\n"); From 544b0698a74dd931a698eceecbe274b9d6cc394b Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 30 Nov 2013 00:43:36 +0300 Subject: [PATCH 128/465] fixed CE on 32-bit systems --- binlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binlog.c b/binlog.c index 2860157..ada9333 100644 --- a/binlog.c +++ b/binlog.c @@ -803,7 +803,7 @@ void add_log_event (const int *data, int len) { int *end = in_end; replay_log_event (); if (rptr != wptr) { - logprintf ("Unread %ld ints. Len = %d\n", wptr - rptr, len); + logprintf ("Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len); assert (rptr == wptr); } if (binlog_enabled) { From ee1f45ec3d80ebc8a888a969de6bea527a6f8924 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 30 Nov 2013 01:43:56 +0400 Subject: [PATCH 129/465] Manty fixes. Mostly binlog for messages --- binlog.c | 466 +++++++++++++++++++++++++++++++++- binlog.h | 25 ++ interface.c | 3 +- loop.c | 5 + mtproto-client.c | 6 +- mtproto-common.h | 2 +- queries.c | 119 ++++----- queries.h | 1 + structures.c | 631 +++++++++++++++++++++++++++++++++++------------ structures.h | 15 ++ telegram.h | 4 +- 11 files changed, 1040 insertions(+), 237 deletions(-) diff --git a/binlog.c b/binlog.c index 2860157..3e69207 100644 --- a/binlog.c +++ b/binlog.c @@ -38,6 +38,7 @@ extern int binlog_enabled; extern int encr_root; extern unsigned char *encr_prime; extern int encr_param_version; +extern int messages_allocated; int in_replay_log; @@ -53,11 +54,12 @@ void replay_log_event (void) { assert (rptr < wptr); int op = *rptr; + if (verbosity >= 2) { + logprintf ("log_pos %lld, op 0x%08x\n", binlog_pos, op); + } + in_ptr = rptr; in_end = wptr; - if (verbosity >= 2) { - logprintf ("event = 0x%08x. pos = %lld\n", op, binlog_pos); - } switch (op) { case LOG_START: rptr ++; @@ -703,6 +705,319 @@ void replay_log_event (void) { C->user_list_version = version; } break; + case CODE_binlog_create_message_text: + case CODE_binlog_send_message_text: + in_ptr ++; + { + long long id; + if (op == CODE_binlog_create_message_text) { + id = fetch_int (); + } else { + id = fetch_long (); + } + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + if (t == PEER_ENCR_CHAT) { + M->flags |= FLAG_ENCRYPTED; + } + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + + int l = prefetch_strlen (); + M->message = malloc (l + 1); + memcpy (M->message, fetch_str (l), l); + M->message[l] = 0; + M->message_len = l; + + if (t == PEER_ENCR_CHAT) { + M->media.type = CODE_decrypted_message_media_empty; + } else { + M->media.type = CODE_message_media_empty; + } + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + + message_insert (M); + if (op == CODE_binlog_send_message_text) { + message_insert_unsent (M); + M->flags |= FLAG_PENDING; + } + } + rptr = in_ptr; + break; + case CODE_binlog_create_message_text_fwd: + in_ptr ++; + { + int id = fetch_int (); + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + M->fwd_from_id = MK_USER (fetch_int ()); + M->fwd_date = fetch_int (); + + int l = prefetch_strlen (); + M->message = malloc (l + 1); + memcpy (M->message, fetch_str (l), l); + M->message[l] = 0; + M->message_len = l; + + M->media.type = CODE_message_media_empty; + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + + message_insert (M); + } + rptr = in_ptr; + break; + case CODE_binlog_create_message_media: + in_ptr ++; + { + int id = fetch_int (); + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + + int l = prefetch_strlen (); + M->message = malloc (l + 1); + memcpy (M->message, fetch_str (l), l); + M->message[l] = 0; + M->message_len = l; + + fetch_message_media (&M->media); + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + + message_insert (M); + } + rptr = in_ptr; + break; + case CODE_binlog_create_message_media_encr: + in_ptr ++; + { + long long id = fetch_long (); + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + + int l = prefetch_strlen (); + M->message = malloc (l + 1); + memcpy (M->message, fetch_str (l), l); + M->message[l] = 0; + M->message_len = l; + + fetch_message_media_encrypted (&M->media); + fetch_encrypted_message_file (&M->media); + + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + + message_insert (M); + } + rptr = in_ptr; + break; + case CODE_binlog_create_message_media_fwd: + in_ptr ++; + { + int id = fetch_int (); + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + M->fwd_from_id = MK_USER (fetch_int ()); + M->fwd_date = fetch_int (); + + int l = prefetch_strlen (); + M->message = malloc (l + 1); + memcpy (M->message, fetch_str (l), l); + M->message[l] = 0; + M->message_len = l; + + fetch_message_media (&M->media); + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + + message_insert (M); + } + rptr = in_ptr; + break; + case CODE_binlog_create_message_service: + in_ptr ++; + { + int id = fetch_int (); + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + + fetch_message_action (&M->action); + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + M->service = 1; + + message_insert (M); + } + rptr = in_ptr; + break; + case CODE_binlog_create_message_service_encr: + in_ptr ++; + { + long long id = fetch_long (); + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + + fetch_message_action_encrypted (&M->action); + + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + M->service = 1; + + message_insert (M); + } + rptr = in_ptr; + break; + case CODE_binlog_create_message_service_fwd: + in_ptr ++; + { + int id = fetch_int (); + struct message *M = message_get (id); + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = id; + message_insert_tree (M); + messages_allocated ++; + } else { + assert (!(M->flags & FLAG_CREATED)); + } + M->flags |= FLAG_CREATED; + M->from_id = MK_USER (fetch_int ()); + int t = fetch_int (); + M->to_id = set_peer_id (t, fetch_int ()); + M->date = fetch_int (); + M->fwd_from_id = MK_USER (fetch_int ()); + M->fwd_date = fetch_int (); + fetch_message_action (&M->action); + M->unread = 1; + M->out = get_peer_id (M->from_id) == our_id; + M->service = 1; + + message_insert (M); + } + rptr = in_ptr; + break; + case CODE_binlog_set_unread: + rptr ++; + { + struct message *M = message_get (*(rptr ++)); + assert (M); + M->unread = 0; + } + break; + case CODE_binlog_set_message_sent: + rptr ++; + { + struct message *M = message_get (*(long long *)rptr); + rptr += 2; + assert (M); + message_remove_unsent (M); + M->flags &= ~FLAG_PENDING; + } + break; + case CODE_binlog_set_msg_id: + rptr ++; + { + struct message *M = message_get (*(long long *)rptr); + rptr += 2; + assert (M); + message_remove_tree (M); + message_del_peer (M); + M->id = *(rptr ++); + message_insert_tree (M); + message_add_peer (M); + } + break; case CODE_update_user_photo: case CODE_update_user_name: work_update_binlog (); @@ -807,6 +1122,7 @@ void add_log_event (const int *data, int len) { assert (rptr == wptr); } if (binlog_enabled) { + assert (binlog_fd > 0); assert (write (binlog_fd, data, len) == len); } in_ptr = in; @@ -1009,6 +1325,7 @@ void bl_do_encr_chat_delete (struct secret_chat *U) { } void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]) { + if (U->state != sc_none) { return; } int *ev = alloc_log_event (540); ev[0] = CODE_binlog_encr_chat_requested; ev[1] = get_peer_id (U->id); @@ -1258,3 +1575,146 @@ void bl_do_chat_del_user (struct chat *C, int version, int user) { ev[3] = user; add_log_event (ev, 16); } + +void bl_do_create_message_text (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { + clear_packet (); + out_int (CODE_binlog_create_message_text); + out_int (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_cstring (s, l); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_send_message_text (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { + clear_packet (); + out_int (CODE_binlog_send_message_text); + out_long (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_cstring (s, l); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_create_message_text_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s) { + clear_packet (); + out_int (CODE_binlog_create_message_text_fwd); + out_int (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_int (fwd); + out_int (fwd_date); + out_cstring (s, l); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_create_message_media (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len) { + clear_packet (); + out_int (CODE_binlog_create_message_media); + out_int (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_cstring (s, l); + out_ints (data, len); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_create_message_media_encr (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2) { + clear_packet (); + out_int (CODE_binlog_create_message_media_encr); + out_long (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_cstring (s, l); + out_ints (data, len); + out_ints (data2, len2); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_create_message_media_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len) { + clear_packet (); + out_int (CODE_binlog_create_message_media_fwd); + out_int (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_int (fwd); + out_int (fwd_date); + out_cstring (s, l); + out_ints (data, len); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_create_message_service (int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { + clear_packet (); + out_int (CODE_binlog_create_message_service); + out_int (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_ints (data, len); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_create_message_service_encr (long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { + clear_packet (); + out_int (CODE_binlog_create_message_service_encr); + out_long (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_ints (data, len); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_create_message_service_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len) { + clear_packet (); + out_int (CODE_binlog_create_message_service_fwd); + out_int (msg_id); + out_int (from_id); + out_int (to_type); + out_int (to_id); + out_int (date); + out_int (fwd); + out_int (fwd_date); + out_ints (data, len); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_unread (struct message *M, int unread) { + if (unread || !M->unread) { return; } + clear_packet (); + out_int (CODE_binlog_set_unread); + out_int (M->id); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_message_sent (struct message *M) { + if (!(M->flags & FLAG_PENDING)) { return; } + clear_packet (); + out_int (CODE_binlog_set_message_sent); + out_long (M->id); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} + +void bl_do_set_msg_id (struct message *M, int id) { + if (M->id == id) { return; } + clear_packet (); + out_int (CODE_binlog_set_msg_id); + out_long (M->id); + out_int (id); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} diff --git a/binlog.h b/binlog.h index 02c7af5..a3e231a 100644 --- a/binlog.h +++ b/binlog.h @@ -51,6 +51,18 @@ #define CODE_binlog_chat_full_photo 0x6cca6629 #define CODE_binlog_add_chat_participant 0x63345108 #define CODE_binlog_del_chat_participant 0x82d1f0ee +#define CODE_binlog_create_message_text 0x269acd5b +#define CODE_binlog_create_message_text_fwd 0xa3d864cd +#define CODE_binlog_create_message_service 0xbbe5e94b +#define CODE_binlog_create_message_service_fwd 0xea9c57ae +#define CODE_binlog_create_message_media 0x62a92d19 +#define CODE_binlog_create_message_media_fwd 0xbefdc462 +#define CODE_binlog_send_message_text 0x31cfd652 +#define CODE_binlog_set_unread 0x21d4c909 +#define CODE_binlog_set_message_sent 0xc335282b +#define CODE_binlog_set_msg_id 0xf3285b6a +#define CODE_binlog_create_message_media_encr 0x19cd7c9d +#define CODE_binlog_create_message_service_encr 0x8b4b9395 void *alloc_log_event (int l); void replay_log (void); @@ -102,4 +114,17 @@ void bl_do_set_chat_participants (struct chat *C, int version, int user_num, str 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); + +void bl_do_create_message_text (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); +void bl_do_create_message_text_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s); +void bl_do_create_message_service (int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); +void bl_do_create_message_service_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len); +void bl_do_create_message_media (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len); +void bl_do_create_message_media_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len); +void bl_do_create_message_media_encr (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2); +void bl_do_create_message_service_encr (long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); +void bl_do_send_message_text (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); +void bl_do_set_unread (struct message *M, int unread); +void bl_do_set_message_sent (struct message *M); +void bl_do_set_msg_id (struct message *M, int id); #endif diff --git a/interface.c b/interface.c index 2001df1..6460ba0 100644 --- a/interface.c +++ b/interface.c @@ -43,7 +43,7 @@ #include "mtproto-common.h" -//#define ALLOW_MULT 1 +#define ALLOW_MULT 1 char *default_prompt = "> "; int unread_messages; @@ -1096,6 +1096,7 @@ void pop_color (void) { void print_media (struct message_media *M) { switch (M->type) { case CODE_message_media_empty: + case CODE_decrypted_message_media_empty: return; case CODE_message_media_photo: if (M->photo.caption && strlen (M->photo.caption)) { diff --git a/loop.c b/loop.c index 4ac7a54..d9f3bf3 100644 --- a/loop.c +++ b/loop.c @@ -436,7 +436,10 @@ int new_dc_num; int loop (void) { on_start (); if (binlog_enabled) { + double t = get_double_time (); + logprintf ("replay log start\n"); replay_log (); + logprintf ("replay log end in %lf seconds\n", get_double_time () - t); write_binlog (); } else { read_auth_file (); @@ -571,6 +574,8 @@ int loop (void) { do_get_difference (); net_loop (0, dgot); + send_all_unsent (); + do_get_dialog_list (); return main_loop (); diff --git a/mtproto-client.c b/mtproto-client.c index 7b8836a..83e43f6 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -789,7 +789,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { int new = fetch_long (); // random_id struct message *M = message_get (new); if (M) { - update_message_id (M, id); + bl_do_set_msg_id (M, id); } } break; @@ -802,7 +802,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { int id = fetch_int (); struct message *M = message_get (id); if (M) { - M->unread = 0; + bl_do_set_unread (M, 0); } } fetch_pts (); @@ -885,7 +885,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { int l2 = prefetch_strlen (); char *l = fetch_str (l2); struct user *U = &UC->user; - bl_do_set_user_name (U, f, l1, l, l2); + bl_do_set_user_real_name (U, f, l1, l, l2); print_start (); push_color (COLOR_YELLOW); print_date (time (0)); diff --git a/mtproto-common.h b/mtproto-common.h index 79d4f3b..43efac1 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -226,7 +226,7 @@ long long compute_rsa_key_fingerprint (RSA *key); extern int *packet_buffer; extern int *packet_ptr; -static inline void out_ints (int *what, int len) { +static inline void out_ints (const int *what, int len) { assert (packet_ptr + len <= packet_buffer + PACKET_BUFFER_SIZE); memcpy (packet_ptr, what, len * 4); packet_ptr += len; diff --git a/queries.c b/queries.c index 85cec4a..e841793 100644 --- a/queries.c +++ b/queries.c @@ -779,8 +779,9 @@ int msg_send_encr_on_answer (struct query *q UU) { assert (fetch_int () == CODE_messages_sent_encrypted_message); rprintf ("Sent\n"); struct message *M = q->extra; - M->date = fetch_int (); - message_insert (M); + //M->date = fetch_int (); + fetch_int (); + bl_do_set_message_sent (M); return 0; } @@ -788,12 +789,11 @@ int msg_send_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_sent_message || x == CODE_messages_sent_message_link); int id = fetch_int (); // id + struct message *M = q->extra; + bl_do_set_msg_id (M, id); fetch_date (); fetch_pts (); fetch_seq (); - struct message *M = q->extra; - M->id = id; - message_insert (M); if (x == CODE_messages_sent_message_link) { assert (fetch_int () == CODE_vector); int n = fetch_int (); @@ -834,6 +834,7 @@ int msg_send_on_answer (struct query *q UU) { } } rprintf ("Sent: id = %d\n", id); + bl_do_set_message_sent (M); return 0; } @@ -848,86 +849,62 @@ struct query_methods msg_send_encr_methods = { int out_message_num; int our_id; -void do_send_encr_message (peer_id_t id, const char *msg, int len) { - peer_t *P = user_chat_get (id); - if (!P) { - logprintf ("Can not send to unknown encrypted chat\n"); - return; - } - if (P->encr_chat.state != sc_ok) { - logprintf ("Chat is not yet initialized\n"); - return; - } +void do_send_encr_msg (struct message *M) { + peer_t *P = user_chat_get (M->to_id); + if (!P || P->encr_chat.state != sc_ok) { return; } + clear_packet (); out_int (CODE_messages_send_encrypted); out_int (CODE_input_encrypted_chat); - out_int (get_peer_id (id)); + out_int (get_peer_id (M->to_id)); out_long (P->encr_chat.access_hash); - if (!out_message_num) { - out_message_num = -lrand48 (); - } - out_long ((--out_message_num) - (4ll << 32)); + out_long (M->id); encr_start (); - //out_int (CODE_decrypted_message_layer); - //out_int (8); out_int (CODE_decrypted_message); - out_long ((out_message_num) - (4ll << 32)); + out_long (M->id); static int buf[4]; int i; for (i = 0; i < 3; i++) { buf[i] = mrand48 (); } out_cstring ((void *)buf, 16); - out_cstring ((void *)msg, len); + out_cstring ((void *)M->message, M->message_len); out_int (CODE_decrypted_message_media_empty); encr_finish (&P->encr_chat); - struct message *M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); - M->flags = FLAG_ENCRYPTED; - M->from_id = MK_USER (our_id); - M->to_id = id; - M->unread = 1; - M->message = malloc (len + 1); - memcpy (M->message, msg, len); - M->message[len] = 0; - M->message_len = len; - M->out = 1; - M->media.type = CODE_message_media_empty; - M->id = (out_message_num) - (4ll << 32); - M->date = time (0); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M); - print_message (M); +} + +void do_send_msg (struct message *M) { + if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { + do_send_encr_msg (M); + return; + } + clear_packet (); + out_int (CODE_messages_send_message); + out_peer_id (M->to_id); + out_cstring (M->message, M->message_len); + out_long (M->id); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M); } void do_send_message (peer_id_t id, const char *msg, int len) { if (get_peer_type (id) == PEER_ENCR_CHAT) { - do_send_encr_message (id, msg, len); - return; + peer_t *P = user_chat_get (id); + if (!P) { + logprintf ("Can not send to unknown encrypted chat\n"); + return; + } + if (P->encr_chat.state != sc_ok) { + logprintf ("Chat is not yet initialized\n"); + return; + } } - if (!out_message_num) { - out_message_num = -lrand48 (); - } - clear_packet (); - out_int (CODE_messages_send_message); - struct message *M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); - M->from_id = MK_USER (our_id); - M->to_id = id; - M->unread = 1; - out_peer_id (id); - M->message = malloc (len + 1); - memcpy (M->message, msg, len); - M->message[len] = 0; - M->message_len = len; - M->out = 1; - M->media.type = CODE_message_media_empty; - M->id = out_message_num; - M->date = time (0); - out_cstring (msg, len); - out_long ((--out_message_num) - (1ll << 32)); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M); + long long t = -lrand48 () * (1ll << 32) - lrand48 (); + bl_do_send_message_text (t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); + struct message *M = message_get (t); + assert (M); + do_send_msg (M); print_message (M); } /* }}} */ @@ -1070,6 +1047,7 @@ void do_get_local_history (peer_id_t id, int limit) { if (!P || !P->last) { return; } struct message *M = P->last; int count = 1; + assert (!M->prev); while (count < limit && M->next) { M = M->next; count ++; @@ -2295,6 +2273,9 @@ void do_create_keys_end (struct secret_chat *U) { BIGNUM *a = BN_bin2bn ((void *)U->key, 256, 0); BN_init (r); BN_mod_exp (r, g_b, a, p, ctx); + + void *t = malloc (256); + memcpy (t, U->key, 256); memset (U->key, 0, sizeof (U->key)); BN_bn2bin (r, (void *)U->key); @@ -2306,7 +2287,15 @@ void do_create_keys_end (struct secret_chat *U) { static unsigned char sha_buffer[20]; sha1 ((void *)U->key, 256, sha_buffer); long long k = *(long long *)(sha_buffer + 12); - assert (k == U->key_fingerprint); + if (k != U->key_fingerprint) { + logprintf ("version = %d\n", encr_param_version); + hexdump ((void *)U->nonce, (void *)(U->nonce + 256)); + hexdump ((void *)U->g_key, (void *)(U->g_key + 256)); + hexdump ((void *)U->key, (void *)(U->key + 64)); + hexdump ((void *)t, (void *)(t + 256)); + logprintf ("!!Key fingerprint mismatch\n"); + U->state = sc_deleted; + } BN_clear_free (p); BN_clear_free (g_b); diff --git a/queries.h b/queries.h index e377a0a..3259b33 100644 --- a/queries.h +++ b/queries.h @@ -107,6 +107,7 @@ void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit); void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); void do_update_status (int online); void do_contacts_search (int limit, const char *s); +void do_send_msg (struct message *M); // For binlog diff --git a/structures.c b/structures.c index 56ff4ba..6356ed6 100644 --- a/structures.c +++ b/structures.c @@ -47,6 +47,7 @@ struct message message_list = { struct tree_peer *peer_tree; struct tree_message *message_tree; +struct tree_message *message_unsent_tree; int users_allocated; int chats_allocated; @@ -121,6 +122,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha const char *d[4]; d[0] = a1; d[1] = a2; d[2] = a3; d[3] = a4; static char buf[10000]; + buf[0] = 0; int i; int p = 0; for (i = 0; i < 4; i++) { @@ -141,6 +143,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha int ok = 1; int i; for (i = 0; i < peer_num; i++) { + assert (Peers[i]); if (cmp_peer_id (Peers[i]->id, id) && Peers[i]->print_name && !strcmp (Peers[i]->print_name, s)) { ok = 0; break; @@ -151,24 +154,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha } cc ++; assert (cc <= 9999); - if (cc == 1) { - int l = strlen (s); - s[l + 2] = 0; - s[l] = '#'; - s[l + 1] = '1'; - } else if (cc == 10 || cc == 100 || cc == 1000) { -// int l = strlen (s); - sprintf (s + fl, "#%d", cc); - } else { - int l = strlen (s); - s[l - 1] ++; - int cc = l - 1; - while (s[cc] > '9') { - s[cc] = '0'; - s[cc - 1] ++; - cc --; - } - } + sprintf (s + fl, "#%d", cc); } return strdup (s); } @@ -320,6 +306,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { int l = prefetch_strlen (); char *s = fetch_str (l); + if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (g_key + 256 - l, s, l); } else { @@ -328,6 +315,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { l = prefetch_strlen (); s = fetch_str (l); + if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); } else { @@ -369,6 +357,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { int l = prefetch_strlen (); char *s = fetch_str (l); + if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (g_key + 256 - l, s, l); } else { @@ -377,6 +366,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { l = prefetch_strlen (); s = fetch_str (l); + if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); } else { @@ -635,7 +625,7 @@ void fetch_skip_geo (void) { unsigned x = fetch_int (); assert (x == CODE_geo_point || x == CODE_geo_point_empty); if (x == CODE_geo_point) { - in_ptr += 2; + in_ptr += 4; } } @@ -693,6 +683,18 @@ void fetch_video (struct video *V) { V->h = fetch_int (); } +void fetch_skip_video (void) { + unsigned x = fetch_int (); + fetch_long (); + if (x == CODE_video_empty) { return; } + fetch_skip (4); + int l = prefetch_strlen (); + fetch_str (l); + fetch_skip (2); + fetch_skip_photo_size (); + fetch_skip (3); +} + void fetch_audio (struct audio *V) { memset (V, 0, sizeof (*V)); unsigned x = fetch_int (); @@ -706,6 +708,13 @@ void fetch_audio (struct audio *V) { V->dc_id = fetch_int (); } +void fetch_skip_audio (void) { + unsigned x = fetch_int (); + fetch_skip (2); + if (x == CODE_audio_empty) { return; } + fetch_skip (7); +} + void fetch_document (struct document *V) { memset (V, 0, sizeof (*V)); unsigned x = fetch_int (); @@ -721,6 +730,20 @@ void fetch_document (struct document *V) { V->dc_id = fetch_int (); } +void fetch_skip_document (void) { + unsigned x = fetch_int (); + fetch_skip (2); + if (x == CODE_document_empty) { return; } + fetch_skip (4); + int l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + fetch_skip (1); + fetch_skip_photo_size (); + fetch_skip (1); +} + void fetch_message_action (struct message_action *M) { memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); @@ -765,30 +788,104 @@ void fetch_message_action (struct message_action *M) { } } +void fetch_skip_message_action (void) { + unsigned x = fetch_int (); + int l; + switch (x) { + case CODE_message_action_empty: + break; + case CODE_message_action_geo_chat_create: + { + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + } + break; + case CODE_message_action_geo_chat_checkin: + break; + case CODE_message_action_chat_create: + l = prefetch_strlen (); + fetch_str (l); + assert (fetch_int () == (int)CODE_vector); + l = fetch_int (); + fetch_skip (l); + break; + case CODE_message_action_chat_edit_title: + l = prefetch_strlen (); + fetch_str (l); + break; + case CODE_message_action_chat_edit_photo: + fetch_skip_photo (); + break; + case CODE_message_action_chat_delete_photo: + break; + case CODE_message_action_chat_add_user: + fetch_int (); + break; + case CODE_message_action_chat_delete_user: + fetch_int (); + break; + default: + assert (0); + } +} + void fetch_message_short (struct message *M) { - memset (M, 0, sizeof (*M)); - M->id = fetch_int (); - M->to_id = MK_USER (our_id); - M->from_id = MK_USER (fetch_int ()); - M->message = fetch_str_dup (); - fetch_pts (); - M->date = fetch_int (); - fetch_seq (); - M->media.type = CODE_message_media_empty; - M->unread = 1; + int new = !(M->flags & FLAG_CREATED); + + if (new) { + int id = fetch_int (); + int from_id = fetch_int (); + int to_id = our_id; + int l = prefetch_strlen (); + char *s = fetch_str (l); + + fetch_pts (); + + int date = fetch_int (); + fetch_seq (); + + bl_do_create_message_text (id, from_id, PEER_USER, to_id, date, l, s); + } else { + fetch_int (); // id + fetch_int (); // from_id + int l = prefetch_strlen (); + fetch_str (l); // text + + fetch_pts (); + fetch_int (); + fetch_seq (); + } } void fetch_message_short_chat (struct message *M) { - memset (M, 0, sizeof (*M)); - M->id = fetch_int (); - M->from_id = MK_USER (fetch_int ()); - M->to_id = MK_CHAT (fetch_int ()); - M->message = fetch_str_dup (); - fetch_pts (); - M->date = fetch_int (); - fetch_seq (); - M->media.type = CODE_message_media_empty; - M->unread = 1; + int new = !(M->flags & FLAG_CREATED); + + if (new) { + int id = fetch_int (); + int from_id = fetch_int (); + int to_id = fetch_int (); + int l = prefetch_strlen (); + char *s = fetch_str (l); + + fetch_pts (); + + int date = fetch_int (); + fetch_seq (); + + bl_do_create_message_text (id, from_id, PEER_CHAT, to_id, date, l, s); + } else { + fetch_int (); // id + fetch_int (); // from_id + fetch_int (); // to_id + int l = prefetch_strlen (); + fetch_str (l); // text + + fetch_pts (); + fetch_int (); + fetch_seq (); + } } @@ -828,6 +925,124 @@ void fetch_message_media (struct message_media *M) { } } +void fetch_skip_message_media (void) { + unsigned x = fetch_int (); + switch (x) { + case CODE_message_media_empty: + break; + case CODE_message_media_photo: + fetch_skip_photo (); + break; + case CODE_message_media_video: + fetch_skip_video (); + break; + case CODE_message_media_audio: + fetch_skip_audio (); + break; + case CODE_message_media_document: + fetch_skip_document (); + break; + case CODE_message_media_geo: + fetch_skip_geo (); + break; + case CODE_message_media_contact: + { + int l; + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + l = prefetch_strlen (); + fetch_str (l); + fetch_int (); + } + break; + case CODE_message_media_unsupported: + { + int l = prefetch_strlen (); + fetch_str (l); + } + break; + default: + logprintf ("type = 0x%08x\n", x); + assert (0); + } +} + +void fetch_skip_message_media_encrypted (void) { + unsigned x = fetch_int (); + int l; + switch (x) { + case CODE_decrypted_message_media_empty: + break; + case CODE_decrypted_message_media_photo: + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_skip (5); + + l = prefetch_strlen (); + fetch_str (l); + + l = prefetch_strlen (); + fetch_str (l); + break; + case CODE_decrypted_message_media_video: + l = prefetch_strlen (); + fetch_str (l); // thumb + + fetch_skip (6); + + l = prefetch_strlen (); + fetch_str (l); + + l = prefetch_strlen (); + fetch_str (l); + break; + case CODE_decrypted_message_media_audio: + fetch_skip (2); + + l = prefetch_strlen (); + fetch_str (l); + + l = prefetch_strlen (); + fetch_str (l); + break; + case CODE_decrypted_message_media_document: + l = prefetch_strlen (); + fetch_str (l); // thumb + + fetch_skip (2); + + l = prefetch_strlen (); + fetch_str (l); // thumb + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_skip (1); + + l = prefetch_strlen (); + fetch_str (l); + + l = prefetch_strlen (); + fetch_str (l); + break; + case CODE_decrypted_message_media_geo_point: + fetch_skip (4); + break; + case CODE_decrypted_message_media_contact: + l = prefetch_strlen (); + fetch_str (l); // thumb + l = prefetch_strlen (); + fetch_str (l); // thumb + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_skip (1); + break; + default: + logprintf ("type = 0x%08x\n", x); + assert (0); + } +} + void fetch_message_media_encrypted (struct message_media *M) { memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); @@ -977,7 +1192,32 @@ void fetch_message_media_encrypted (struct message_media *M) { M->user_id = fetch_int (); break; default: - logprintf ("type = 0x%08x\n", M->type); + logprintf ("type = 0x%08x\n", x); + assert (0); + } +} + +void fetch_skip_message_action_encrypted (void) { + unsigned x = fetch_int (); + switch (x) { + case CODE_decrypted_message_action_set_message_t_t_l: + fetch_skip (1); + break; + default: + logprintf ("x = 0x%08x\n", x); + assert (0); + } +} + +void fetch_message_action_encrypted (struct message_action *M) { + unsigned x = fetch_int (); + switch (x) { + case CODE_decrypted_message_action_set_message_t_t_l: + M->type = x; + M->ttl = fetch_int (); + break; + default: + logprintf ("x = 0x%08x\n", x); assert (0); } } @@ -993,30 +1233,54 @@ peer_id_t fetch_peer_id (void) { } 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 (); + int id = fetch_int (); + assert (M->id == id); if (x == CODE_message_empty) { - M->flags |= 1; return; } + int fwd_from_id = 0; + int fwd_date = 0; + if (x == CODE_message_forwarded) { - M->fwd_from_id = MK_USER (fetch_int ()); - M->fwd_date = fetch_int (); + fwd_from_id = fetch_int (); + fwd_date = fetch_int (); } - M->from_id = MK_USER (fetch_int ()); - M->to_id = fetch_peer_id (); - M->out = fetch_bool (); - M->unread = fetch_bool (); - M->date = fetch_int (); + int from_id = fetch_int (); + peer_id_t to_id = fetch_peer_id (); + + fetch_bool (); // out. + + int unread = fetch_bool (); + int date = fetch_int (); + + int new = !(M->flags & FLAG_CREATED); + if (x == CODE_message_service) { - M->service = 1; - fetch_message_action (&M->action); + int *start = in_ptr; + fetch_skip_message_action (); + if (new) { + if (fwd_from_id) { + bl_do_create_message_service_fwd (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, fwd_from_id, fwd_date, start, (in_ptr - start)); + } else { + bl_do_create_message_service (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, start, (in_ptr - start)); + } + } } else { - M->message = fetch_str_dup (); - fetch_message_media (&M->media); + int l = prefetch_strlen (); + char *s = fetch_str (l); + int *start = in_ptr; + fetch_skip_message_media (); + if (new) { + if (fwd_from_id) { + bl_do_create_message_media_fwd (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, fwd_from_id, fwd_date, l, s, start, in_ptr - start); + } else { + bl_do_create_message_media (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, l, s, start, in_ptr - start); + } + } } + bl_do_set_unread (M, unread); } void fetch_geo_message (struct message *M) { @@ -1100,29 +1364,26 @@ int decrypt_encrypted_message (struct secret_chat *E) { } void fetch_encrypted_message (struct message *M) { - memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service); unsigned sx = x; - M->id = fetch_long (); - peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); - M->from_id = MK_USER (our_id); - M->to_id = chat; + int new = !(M->flags & FLAG_CREATED); + long long id = fetch_long (); + int to_id = fetch_int (); + peer_id_t chat = MK_ENCR_CHAT (to_id); + int date = fetch_int (); + peer_t *P = user_chat_get (chat); - M->flags &= ~(FLAG_MESSAGE_EMPTY | FLAG_DELETED); - M->flags |= FLAG_ENCRYPTED; if (!P) { logprintf ("Encrypted message to unknown chat. Dropping\n"); M->flags |= FLAG_MESSAGE_EMPTY; } - M->date = fetch_int (); int len = prefetch_strlen (); assert ((len & 15) == 8); decr_ptr = (void *)fetch_str (len); decr_end = decr_ptr + (len / 4); - M->flags |= FLAG_ENCRYPTED; int ok = 0; if (P) { if (*(long long *)decr_ptr != P->encr_chat.key_fingerprint) { @@ -1131,32 +1392,39 @@ void fetch_encrypted_message (struct message *M) { } decr_ptr += 2; } - if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) { + int l = 0; + char *s = 0; + int *start = 0; + int *end = 0; + x = 0; + if (P && decrypt_encrypted_message (&P->encr_chat) >= 0 && new) { ok = 1; int *save_in_ptr = in_ptr; int *save_in_end = in_end; in_ptr = decr_ptr; - int l = fetch_int (); - in_end = in_ptr + l; - unsigned x = fetch_int (); + int ll = fetch_int (); + in_end = in_ptr + ll; + x = fetch_int (); if (x == CODE_decrypted_message_layer) { int layer = fetch_int (); assert (layer >= 0); x = fetch_int (); } assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service); - assert (M->id = fetch_long ()); - l = prefetch_strlen (); - fetch_str (l); // random_bytes + //assert (id == fetch_long ()); + fetch_long (); + ll = prefetch_strlen (); + fetch_str (ll); // random_bytes if (x == CODE_decrypted_message) { - M->message = fetch_str_dup (); - fetch_message_media_encrypted (&M->media); + l = prefetch_strlen (); + s = fetch_str (l); + start = in_ptr; + fetch_skip_message_media_encrypted (); + end = in_ptr; } else { - assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l); - M->action.type = CODE_decrypted_message_action_set_message_t_t_l; - P->encr_chat.ttl = fetch_int (); - M->action.ttl = P->encr_chat.ttl; - M->service = 1; + start = in_ptr; + fetch_skip_message_action_encrypted (); + end = in_ptr; } in_ptr = save_in_ptr; in_end = save_in_end; @@ -1164,7 +1432,11 @@ void fetch_encrypted_message (struct message *M) { if (sx == CODE_encrypted_message) { if (ok) { - fetch_encrypted_message_file (&M->media); + int *start_file = in_ptr; + fetch_skip_encrypted_message_file (); + if (x == CODE_decrypted_message) { + bl_do_create_message_media_encr (id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, in_ptr - start_file); + } } else { x = fetch_int (); if (x == CODE_encrypted_file) { @@ -1174,6 +1446,10 @@ void fetch_encrypted_message (struct message *M) { } M->media.type = CODE_message_media_empty; } + } else { + if (ok && x == CODE_decrypted_message_service) { + bl_do_create_message_service_encr (id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, start, end - start); + } } } @@ -1195,6 +1471,15 @@ void fetch_encrypted_message_file (struct message_media *M) { } } +void fetch_skip_encrypted_message_file (void) { + unsigned x = fetch_int (); + assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); + if (x == CODE_encrypted_file_empty) { + } else { + fetch_skip (7); + } +} + static int id_cmp (struct message *M1, struct message *M2) { if (M1->id < M2->id) { return -1; } else if (M1->id > M2->id) { return 1; } @@ -1424,10 +1709,33 @@ void message_add_peer (struct message *M) { peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); Peers[peer_num ++] = P; } - M->next = P->last; - if (M->next) { M->next->prev = M; } - M->prev = 0; - P->last = M; + if (!P->last) { + P->last = M; + M->prev = M->next = 0; + } else { + if (get_peer_type (P->id) != PEER_ENCR_CHAT) { + struct message *N = P->last; + struct message *NP = 0; + while (N && N->id > M->id) { + NP = N; + N = N->next; + } + if (N) { assert (N->id < M->id); } + M->next = N; + M->prev = NP; + if (N) { N->prev = M; } + if (NP) { NP->next = M; } + else { P->last = M; } + } else { + struct message *N = P->last; + struct message *NP = 0; + M->next = N; + M->prev = NP; + if (N) { N->prev = M; } + if (NP) { NP->next = M; } + else { P->last = M; } + } + } } void message_del_peer (struct message *M) { @@ -1450,26 +1758,19 @@ void message_del_peer (struct message *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); - message_del_peer (M1); - free_message (M1); - memcpy (M1, M, sizeof (*M)); - free (M); - message_add_use (M1); - message_add_peer (M1); - messages_allocated --; - return M1; - } else { - message_add_use (M); - message_add_peer (M); - message_tree = tree_insert_message (message_tree, M, lrand48 ()); - return M; + int data[2]; + prefetch_data (data, 8); + struct message *M = message_get (data[1]); + + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = data[1]; + message_insert_tree (M); + messages_allocated ++; } + fetch_message (M); + return M; } struct message *fetch_alloc_geo_message (void) { @@ -1496,75 +1797,53 @@ struct message *fetch_alloc_geo_message (void) { } struct message *fetch_alloc_encrypted_message (void) { - struct message *M = malloc (sizeof (*M)); - fetch_encrypted_message (M); - struct message *M1 = tree_lookup_message (message_tree, M); - messages_allocated ++; - if (M1) { - message_del_use (M1); - message_del_peer (M1); - free_message (M1); - memcpy (M1, M, sizeof (*M)); - free (M); - message_add_use (M1); - message_add_peer (M1); - messages_allocated --; - return M1; - } else { - message_add_use (M); - message_add_peer (M); - message_tree = tree_insert_message (message_tree, M, lrand48 ()); - return M; + int data[3]; + prefetch_data (data, 12); + struct message *M = message_get (*(long long *)(data + 1)); + + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = *(long long *)(data + 1); + message_insert_tree (M); + messages_allocated ++; + assert (message_get (M->id) == M); + logprintf ("id = %lld\n", M->id); } + fetch_encrypted_message (M); + return M; } struct message *fetch_alloc_message_short (void) { - struct message *M = malloc (sizeof (*M)); - fetch_message_short (M); - struct message *M1 = tree_lookup_message (message_tree, M); - messages_allocated ++; - if (M1) { - message_del_use (M1); - message_del_peer (M1); - free_message (M1); - memcpy (M1, M, sizeof (*M)); - free (M); - message_add_use (M1); - message_add_peer (M1); - messages_allocated --; - return M1; - } else { - message_add_use (M); - message_add_peer (M); - message_tree = tree_insert_message (message_tree, M, lrand48 ()); - return M; + int data[1]; + prefetch_data (data, 4); + struct message *M = message_get (data[0]); + + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = data[0]; + message_insert_tree (M); + messages_allocated ++; } + fetch_message_short (M); + return M; } struct message *fetch_alloc_message_short_chat (void) { - struct message *M = malloc (sizeof (*M)); + int data[1]; + prefetch_data (data, 4); + struct message *M = message_get (data[0]); + + if (!M) { + M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + M->id = data[0]; + message_insert_tree (M); + messages_allocated ++; + } fetch_message_short_chat (M); - if (verbosity >= 2) { - logprintf ("Read message with id %lld\n", M->id); - } - struct message *M1 = tree_lookup_message (message_tree, M); - messages_allocated ++; - if (M1) { - message_del_use (M1); - message_del_peer (M1); - free_message (M1); - memcpy (M1, M, sizeof (*M)); - free (M); - message_add_use (M1); - message_add_peer (M1); - messages_allocated --; - return M1; - } else { - message_add_use (M); - message_add_peer (M); - message_tree = tree_insert_message (message_tree, M, lrand48 ()); - return M; - } + return M; } struct chat *fetch_alloc_chat (void) { @@ -1640,8 +1919,36 @@ void update_message_id (struct message *M, long long id) { message_tree = tree_insert_message (message_tree, M, lrand48 ()); } +void message_insert_tree (struct message *M) { + assert (M->id); + message_tree = tree_insert_message (message_tree, M, lrand48 ()); +} + +void message_remove_tree (struct message *M) { + assert (M->id); + message_tree = tree_delete_message (message_tree, M); +} + void message_insert (struct message *M) { message_add_use (M); message_add_peer (M); - message_tree = tree_insert_message (message_tree, M, lrand48 ()); +} + +void message_insert_unsent (struct message *M) { + message_unsent_tree = tree_insert_message (message_unsent_tree, M, lrand48 ()); +} + +void message_remove_unsent (struct message *M) { + message_unsent_tree = tree_delete_message (message_unsent_tree, M); +} + +void __send_msg (struct message *M) { + logprintf ("Resending message...\n"); + print_message (M); + + do_send_msg (M); +} + +void send_all_unsent (void ) { + tree_act_message (message_unsent_tree, __send_msg); } diff --git a/structures.h b/structures.h index dc33ee2..202e522 100644 --- a/structures.h +++ b/structures.h @@ -38,6 +38,7 @@ typedef struct { int type; int id; } peer_id_t; #define FLAG_CHAT_IN_CHAT 128 #define FLAG_ENCRYPTED 4096 +#define FLAG_PENDING 8192 struct file_location { int dc; @@ -337,8 +338,16 @@ struct message *fetch_alloc_message_short (void); struct message *fetch_alloc_message_short_chat (void); struct message *fetch_alloc_encrypted_message (void); void fetch_encrypted_message_file (struct message_media *M); +void fetch_skip_encrypted_message_file (void); +void fetch_encrypted_message_file (struct message_media *M); +void fetch_message_action_encrypted (struct message_action *M); peer_id_t fetch_peer_id (void); +void fetch_message_media (struct message_media *M); +void fetch_message_media_encrypted (struct message_media *M); +void fetch_message_action (struct message_action *M); +void message_insert_tree (struct message *M); + void free_user (struct user *U); void free_chat (struct chat *U); @@ -356,6 +365,12 @@ void insert_user (peer_t *P); void insert_chat (peer_t *P); void fetch_photo (struct photo *P); void free_photo (struct photo *P); +void message_insert_unsent (struct message *M); +void message_remove_unsent (struct message *M); +void send_all_unsent (void); +void message_remove_tree (struct message *M); +void message_add_peer (struct message *M); +void message_del_peer (struct message *M); #define PEER_USER 1 #define PEER_CHAT 2 diff --git a/telegram.h b/telegram.h index b5ea029..0ec1fd5 100644 --- a/telegram.h +++ b/telegram.h @@ -17,5 +17,5 @@ Copyright Vitaly Valtman 2013 */ #define MAX_DC_NUM 9 -#define MAX_USER_NUM 1000 -#define MAX_CHAT_NUM 1000 +#define MAX_USER_NUM 100000 +#define MAX_CHAT_NUM 100000 From 6d56e0e6442413b59e901c15d54364d741f86828 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 30 Nov 2013 03:15:10 +0400 Subject: [PATCH 130/465] fixed binlog problems. Set lock on binlog --- binlog.c | 14 ++++++++---- config.sample | 60 ++++++++++++++++++++++++++++++++++++++++++++------- main.c | 6 +++++- queries.c | 14 +++++++++++- 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/binlog.c b/binlog.c index 62382db..df30269 100644 --- a/binlog.c +++ b/binlog.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -1024,7 +1025,7 @@ void replay_log_event (void) { rptr = in_ptr; break; default: - logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x]\n", *(rptr - 1), op, *(rptr + 1)); + logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(rptr - 1), op, *(rptr + 1), binlog_pos); assert (0); } @@ -1075,8 +1076,8 @@ void replay_log (void) { } else { int x = wptr - rptr; memcpy (binlog_buffer, rptr, 4 * x); - wptr -= x; - rptr -= x; + wptr -= (rptr - binlog_buffer); + rptr = binlog_buffer; } int l = (binlog_buffer + BINLOG_BUFFER_SIZE - wptr) * 4; int k = read (fd, wptr, l); @@ -1103,7 +1104,12 @@ void write_binlog (void) { perror ("binlog open"); exit (2); } - lseek (binlog_fd, 0, SEEK_END); + + assert (lseek (binlog_fd, binlog_pos, SEEK_SET) == binlog_pos); + if (flock (binlog_fd, LOCK_EX | LOCK_NB) < 0) { + perror ("get lock"); + exit (2); + } } void add_log_event (const int *data, int len) { diff --git a/config.sample b/config.sample index 588090f..dffcc44 100644 --- a/config.sample +++ b/config.sample @@ -1,22 +1,66 @@ -# This is my real config -# Feel free to edit it +# This is an empty config file +# Feel free to put something here -default_profile = "tele2"; +default_profile = "binlog"; -mts = { +test_dc1 = { + config_directory = ".telegram/test_dc1"; + test = true; + msg_num = true; + binlog_enabled = true; +}; + +binlog = { + config_directory = ".telegram/binlog"; + test = false; + msg_num = true; + binlog_enabled = true; + log_level = 2; +}; + +binlog_mts = { + config_directory = ".telegram/binlog_mts"; + test = false; + msg_num = true; + binlog_enabled = true; + log_level = 2; +}; + +mega = { + config_directory = ".telegram/mega"; + test = false; + msg_num = true; + binlog_enabled = true; + log_level = 2; +}; + +new = { + config_directory = ".telegram/new"; test = false; - config_directory = ".telegram/mts"; msg_num = true; }; -tele2 = { +production = { + config_directory = ".telegram/production"; test = false; - config_directory = ".telegram/tele2"; msg_num = true; }; test = { - test = true; config_directory = ".telegram/test"; + test = true; msg_num = true; }; + +test1 = { + config_directory = ".telegram/test1"; + msg_num = true; + binlog_enabled = true; +}; + +test2 = { + config_directory = ".telegram/test2"; + msg_num = true; + binlog_enabled = true; +}; + diff --git a/main.c b/main.c index 3d9c4a1..10fc3be 100644 --- a/main.c +++ b/main.c @@ -77,6 +77,7 @@ char *config_directory; char *binlog_file_name; int binlog_enabled; extern int log_level; +int sync_from_start; void set_default_username (const char *s) { if (default_username) { @@ -315,7 +316,7 @@ extern int default_dc_num; int register_mode; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:R")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:Rf")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -342,6 +343,9 @@ void args_parse (int argc, char **argv) { case 'R': register_mode = 1; break; + case 'f': + sync_from_start = 1; + break; case 'h': default: usage (); diff --git a/queries.c b/queries.c index bd4aaf8..64351d9 100644 --- a/queries.c +++ b/queries.c @@ -64,6 +64,7 @@ long long cur_downloading_bytes; long long cur_downloaded_bytes; extern int binlog_enabled; +extern int sync_from_start; void out_peer_id (peer_id_t id); #define QUERY_TIMEOUT 6.0 @@ -2218,6 +2219,14 @@ BN_CTX *ctx; void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { int i; + int ok = 0; + for (i = 0; i < 64; i++) { + if (E->key[i]) { + ok = 1; + break; + } + } + if (ok) { return; } // Already generated key for this chat for (i = 0; i < 64; i++) { *(((int *)random) + i) ^= mrand48 (); } @@ -2521,7 +2530,10 @@ void do_get_difference (void) { difference_got = 0; clear_packet (); do_insert_header (); - if (seq > 0) { + if (seq > 0 || sync_from_start) { + if (pts == 0) { pts = 1; } + if (qts == 0) { qts = 1; } + if (last_date == 0) { last_date = 1; } out_int (CODE_updates_get_difference); out_int (pts); out_int (last_date); From b9e75c348948d40a305b13780472f8232013322c Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 30 Nov 2013 14:12:51 +0400 Subject: [PATCH 131/465] binlog.c/binlog.h: added GPL headers --- binlog.c | 18 ++++++++++++++++++ binlog.h | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/binlog.c b/binlog.c index df30269..8f5379e 100644 --- a/binlog.c +++ b/binlog.c @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #include #include #include diff --git a/binlog.h b/binlog.h index a3e231a..ba6061f 100644 --- a/binlog.h +++ b/binlog.h @@ -1,3 +1,21 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ #ifndef __BINLOG_H__ #define __BINLOG_H__ From 5c976ea1c4cc346240a446f1242d91f58ac46ad8 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 30 Nov 2013 22:52:13 +0400 Subject: [PATCH 132/465] interface: added auto-completion for modifiers (only [offline] for now) --- interface.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 6460ba0..c8a1519 100644 --- a/interface.c +++ b/interface.c @@ -43,7 +43,7 @@ #include "mtproto-common.h" -#define ALLOW_MULT 1 +//#define ALLOW_MULT 1 char *default_prompt = "> "; int unread_messages; @@ -247,6 +247,11 @@ void update_prompt (void) { print_end (); } +char *modifiers[] = { + "[offline]", + 0 +}; + char *commands[] = { "help", "msg", @@ -339,6 +344,8 @@ int commands_flags[] = { 07, }; + + int get_complete_mode (void) { line_ptr = rl_line_buffer; int l = 0; @@ -348,6 +355,9 @@ int get_complete_mode (void) { r = next_token (&l); if (!r) { return 0; } } + if (*r == '[' && !r[l]) { + return 6; + } if (!*line_ptr) { return 0; } char **command = commands; @@ -485,6 +495,10 @@ char *command_generator (const char *text, int state) { index = complete_encr_chat_list (index, text, len, &R); if (c) { rl_line_buffer[rl_point] = c; } return R; + case 6: + index = complete_string_list (modifiers, index, text, len, &R); + if (c) { rl_line_buffer[rl_point] = c; } + return R; default: if (c) { rl_line_buffer[rl_point] = c; } return 0; From 18df862737df9b2dad17c06354aafaffd2b1b80f Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 2 Dec 2013 19:11:05 +0400 Subject: [PATCH 133/465] main.c: fixed CE on 32-bit systems --- main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 10fc3be..4fd18bf 100644 --- a/main.c +++ b/main.c @@ -263,7 +263,9 @@ void parse_config (void) { config_lookup_bool (&conf, buf, &test_dc); strcpy (buf + l, "log_level"); - config_lookup_int (&conf, buf, &log_level); + long long t = log_level; + config_lookup_int (&conf, buf, (void *)&t); + log_level = t; if (!msg_num_mode) { strcpy (buf + l, "msg_num"); From ae29e1d93337822dd7a9dc72d108d0ea630edeb8 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 2 Dec 2013 21:19:08 +0400 Subject: [PATCH 134/465] Many fixes. --- binlog.c | 9 ++++-- main.c | 31 ++++++++++++------- mtproto-client.c | 4 +-- net.c | 2 +- structures.c | 80 +++++++++++++++++++++++++++++++++++------------- structures.h | 1 + telegram.h | 3 +- tree.h | 2 ++ 8 files changed, 93 insertions(+), 39 deletions(-) diff --git a/binlog.c b/binlog.c index 8f5379e..24624b5 100644 --- a/binlog.c +++ b/binlog.c @@ -1033,8 +1033,13 @@ void replay_log_event (void) { message_remove_tree (M); message_del_peer (M); M->id = *(rptr ++); - message_insert_tree (M); - message_add_peer (M); + if (message_get (M->id)) { + free_message (M); + free (M); + } else { + message_insert_tree (M); + message_add_peer (M); + } } break; case CODE_update_user_photo: diff --git a/main.c b/main.c index 10fc3be..4cdaf9a 100644 --- a/main.c +++ b/main.c @@ -86,24 +86,33 @@ void set_default_username (const char *s) { default_username = strdup (s); } + /* {{{ TERMINAL */ -tcflag_t old_lflag; -cc_t old_vtime; -struct termios term; +static struct termios term_in, term_out; +static int term_set_in; +static int term_set_out; void get_terminal_attributes (void) { - if (tcgetattr (STDIN_FILENO, &term) < 0) { - perror ("tcgetattr()"); - exit (EXIT_FAILURE); + if (tcgetattr (STDIN_FILENO, &term_in) < 0) { + } else { + term_set_in = 1; + } + if (tcgetattr (STDOUT_FILENO, &term_out) < 0) { + } else { + term_set_out = 1; } - old_lflag = term.c_lflag; - old_vtime = term.c_cc[VTIME]; } void set_terminal_attributes (void) { - if (tcsetattr (STDIN_FILENO, 0, &term) < 0) { - perror ("tcsetattr()"); - exit (EXIT_FAILURE); + if (term_set_in) { + if (tcsetattr (STDIN_FILENO, 0, &term_in) < 0) { + perror ("tcsetattr()"); + } + } + if (term_set_out) { + if (tcsetattr (STDOUT_FILENO, 0, &term_out) < 0) { + perror ("tcsetattr()"); + } } } /* }}} */ diff --git a/mtproto-client.c b/mtproto-client.c index 83e43f6..27034ef 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1284,8 +1284,8 @@ void work_updates (struct connection *c, long long msg_id) { for (i = 0; i < n; i++) { fetch_alloc_chat (); } - fetch_date (); // date - fetch_seq (); // seq + bl_do_set_date (fetch_int ()); + bl_do_set_seq (fetch_int ()); } void work_update_short_message (struct connection *c UU, long long msg_id UU) { diff --git a/net.c b/net.c index 546f48d..7d5db84 100644 --- a/net.c +++ b/net.c @@ -411,7 +411,7 @@ void hexdump_buf (struct connection_buffer *b) { void try_rpc_read (struct connection *c) { assert (c->in_head); - if (verbosity >= 1) { + if (verbosity >= 3) { hexdump_buf (c->in_head); } diff --git a/structures.c b/structures.c index 6356ed6..3c88a24 100644 --- a/structures.c +++ b/structures.c @@ -52,19 +52,27 @@ struct tree_message *message_unsent_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; + +int our_id; +int verbosity; + +peer_t *Peers[MAX_PEER_NUM]; 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; } +#define code_try(x) if ((x) == -1) { return -1; } + +/* + * + * Fetch simple structures (immediate fetch into buffer) + * + */ int fetch_file_location (struct file_location *loc) { int x = fetch_int (); @@ -84,18 +92,6 @@ int fetch_file_location (struct file_location *loc) { return 0; } -int fetch_skip_file_location (void) { - int x = fetch_int (); - code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); - - if (x == CODE_file_location_unavailable) { - in_ptr += 5; - } else { - in_ptr += 6; - } - return 0; -} - int fetch_user_status (struct user_status *S) { unsigned x = fetch_int (); code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); @@ -118,6 +114,33 @@ int fetch_user_status (struct user_status *S) { return 0; } +/* + * + * Skip simple structures + * + */ + +int fetch_skip_file_location (void) { + int x = fetch_int (); + code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); + + if (x == CODE_file_location_unavailable) { + in_ptr += 5; + } else { + in_ptr += 6; + } + return 0; +} + +int fetch_skip_user_status (void) { + unsigned x = fetch_int (); + code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); + if (x != CODE_user_status_empty) { + fetch_int (); + } + return 0; +} + 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; @@ -159,6 +182,12 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha return strdup (s); } +/* + * + * Fetch with log event + * + */ + long long fetch_user_photo (struct user *U) { unsigned x = fetch_int (); code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); @@ -172,8 +201,8 @@ long long fetch_user_photo (struct user *U) { } struct file_location big; struct file_location small; - if (fetch_file_location (&small) < 0) { return -1; } - if (fetch_file_location (&big) < 0) { return -1; } + code_try (fetch_file_location (&small)); + code_try (fetch_file_location (&big)); bl_do_set_user_profile_photo (U, photo_id, &big, &small); return 0; @@ -183,9 +212,6 @@ int fetch_user (struct user *U) { unsigned x = fetch_int (); code_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 = MK_USER (fetch_int ()); - if ((U->flags & FLAG_CREATED) && x == CODE_user_empty) { - return 0; - } if (x == CODE_user_empty) { return 0; } @@ -204,8 +230,10 @@ int fetch_user (struct user *U) { } if (new) { int l1 = prefetch_strlen (); + code_assert (l1 >= 0); char *s1 = fetch_str (l1); int l2 = prefetch_strlen (); + code_assert (l2 >= 0); char *s2 = fetch_str (l2); if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { @@ -221,6 +249,7 @@ int fetch_user (struct user *U) { char *phone = 0; if (x != CODE_user_foreign) { phone_len = prefetch_strlen (); + code_assert (phone_len >= 0); phone = fetch_str (phone_len); } bl_do_new_user (get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); @@ -1496,6 +1525,7 @@ struct user *fetch_alloc_user (void) { memset (U, 0, sizeof (*U)); U->id = MK_USER (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; } fetch_user (&U->user); @@ -1512,6 +1542,7 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) { U->id = MK_ENCR_CHAT (data[1]); encr_chats_allocated ++; peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; } fetch_encrypted_chat (&U->encr_chat); @@ -1521,18 +1552,21 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) { void insert_encrypted_chat (peer_t *P) { encr_chats_allocated ++; peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = P; } void insert_user (peer_t *P) { users_allocated ++; peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = P; } void insert_chat (peer_t *P) { chats_allocated ++; peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = P; } @@ -1550,6 +1584,7 @@ struct user *fetch_alloc_user_full (void) { U->id = MK_USER (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_user_full (&U->user); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; return &U->user; } @@ -1707,6 +1742,7 @@ void message_add_peer (struct message *M) { break; } peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = P; } if (!P->last) { @@ -1856,6 +1892,7 @@ struct chat *fetch_alloc_chat (void) { memset (U, 0, sizeof (*U)); U->id = MK_CHAT (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; } fetch_chat (&U->chat); @@ -1876,6 +1913,7 @@ struct chat *fetch_alloc_chat_full (void) { U->id = MK_CHAT (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_chat_full (&U->chat); + assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; return &U->chat; } diff --git a/structures.h b/structures.h index 202e522..7e316fe 100644 --- a/structures.h +++ b/structures.h @@ -371,6 +371,7 @@ void send_all_unsent (void); void message_remove_tree (struct message *M); void message_add_peer (struct message *M); void message_del_peer (struct message *M); +void free_message (struct message *M); #define PEER_USER 1 #define PEER_CHAT 2 diff --git a/telegram.h b/telegram.h index 0ec1fd5..41315ce 100644 --- a/telegram.h +++ b/telegram.h @@ -17,5 +17,4 @@ Copyright Vitaly Valtman 2013 */ #define MAX_DC_NUM 9 -#define MAX_USER_NUM 100000 -#define MAX_CHAT_NUM 100000 +#define MAX_PEER_NUM 100000 diff --git a/tree.h b/tree.h index d5cdb73..2c86e1c 100644 --- a/tree.h +++ b/tree.h @@ -147,6 +147,8 @@ void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ assert (T->right->y <= T->y);\ assert (X_CMP (T->right->x, T->x) > 0); \ }\ + tree_check_ ## X_NAME (T->left); \ + tree_check_ ## X_NAME (T->right); \ }\ #define int_cmp(a,b) ((a) - (b)) From bc7887b5df8b545397fdb7782f218238a85856a0 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Tue, 3 Dec 2013 15:44:14 +0400 Subject: [PATCH 135/465] main: added [-B] key --- main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.c b/main.c index 075bea3..c0a8951 100644 --- a/main.c +++ b/main.c @@ -357,6 +357,9 @@ void args_parse (int argc, char **argv) { case 'f': sync_from_start = 1; break; + case 'B': + binlog_enabled = 1; + break; case 'h': default: usage (); From 1198159162a939d88a190e7ae6b197bd0d88ac9a Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 6 Dec 2013 20:40:52 +0400 Subject: [PATCH 136/465] Fixed bug --- binlog.c | 4 ++++ interface.c | 2 +- mtproto-client.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/binlog.c b/binlog.c index 24624b5..c006e65 100644 --- a/binlog.c +++ b/binlog.c @@ -1030,6 +1030,10 @@ void replay_log_event (void) { struct message *M = message_get (*(long long *)rptr); rptr += 2; assert (M); + if (M->flags & FLAG_PENDING) { + message_remove_unsent (M); + M->flags &= ~FLAG_PENDING; + } message_remove_tree (M); message_del_peer (M); M->id = *(rptr ++); diff --git a/interface.c b/interface.c index c8a1519..3f86c8e 100644 --- a/interface.c +++ b/interface.c @@ -562,7 +562,7 @@ void interpreter (char *line UU) { #define GET_PEER \ id = next_token_peer (); \ if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ - printf ("Bad user/char id\n"); \ + printf ("Bad user/chat id\n"); \ RET; \ } #define GET_PEER_USER \ diff --git a/mtproto-client.c b/mtproto-client.c index 27034ef..944d05a 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; From 4e2e651e2aa6d2ecd65279d0f2b1171e92a3aede Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 6 Dec 2013 21:14:41 +0400 Subject: [PATCH 137/465] Added chat_with_peer command --- binlog.c | 23 +++++++++++++++++++++ binlog.h | 2 ++ interface.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++------- queries.c | 10 ++++++++- 4 files changed, 85 insertions(+), 8 deletions(-) diff --git a/binlog.c b/binlog.c index c006e65..beb7aa3 100644 --- a/binlog.c +++ b/binlog.c @@ -1046,6 +1046,22 @@ void replay_log_event (void) { } } break; + case CODE_binlog_delete_msg: + rptr ++; + { + struct message *M = message_get (*(long long *)rptr); + rptr += 2; + assert (M); + if (M->flags & FLAG_PENDING) { + message_remove_unsent (M); + M->flags &= ~FLAG_PENDING; + } + message_remove_tree (M); + message_del_peer (M); + free_message (M); + free (M); + } + break; case CODE_update_user_photo: case CODE_update_user_name: work_update_binlog (); @@ -1751,3 +1767,10 @@ void bl_do_set_msg_id (struct message *M, int id) { out_int (id); add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); } + +void bl_do_delete_msg (struct message *M) { + clear_packet (); + out_int (CODE_binlog_delete_msg); + out_long (M->id); + add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +} diff --git a/binlog.h b/binlog.h index ba6061f..d0d2d9b 100644 --- a/binlog.h +++ b/binlog.h @@ -81,6 +81,7 @@ #define CODE_binlog_set_msg_id 0xf3285b6a #define CODE_binlog_create_message_media_encr 0x19cd7c9d #define CODE_binlog_create_message_service_encr 0x8b4b9395 +#define CODE_binlog_delete_msg 0xa1d6ab6d void *alloc_log_event (int l); void replay_log (void); @@ -145,4 +146,5 @@ void bl_do_send_message_text (long long msg_id, int from_id, int to_type, int to void bl_do_set_unread (struct message *M, int unread); void bl_do_set_message_sent (struct message *M); void bl_do_set_msg_id (struct message *M, int id); +void bl_do_delete_msg (struct message *M); #endif diff --git a/interface.c b/interface.c index 3f86c8e..fc0ea75 100644 --- a/interface.c +++ b/interface.c @@ -63,6 +63,9 @@ char *line_ptr; extern peer_t *Peers[]; extern int peer_num; +int in_chat_mode; +peer_id_t chat_mode_id; + int is_same_word (const char *s, size_t l, const char *word) { return s && word && strlen (word) == l && !memcmp (s, word, l); @@ -204,9 +207,15 @@ peer_id_t next_token_peer (void) { } char *get_default_prompt (void) { - static char buf[100]; + static char buf[1000]; + int l = 0; + if (in_chat_mode) { + peer_t *U = user_chat_get (chat_mode_id); + assert (U && U->print_name); + l += sprintf (buf + l, COLOR_RED "%.*s " COLOR_NORMAL, 100, U->print_name); + } if (unread_messages || cur_uploading_bytes || cur_downloading_bytes) { - int l = sprintf (buf, COLOR_RED "["); + l += sprintf (buf + l, COLOR_RED "["); int ok = 0; if (unread_messages) { l += sprintf (buf + l, "%d unread", unread_messages); @@ -222,11 +231,11 @@ char *get_default_prompt (void) { ok = 1; l += sprintf (buf + l, "%lld%%Down", 100 * cur_downloaded_bytes / cur_downloading_bytes); } - sprintf (buf + l, "]" COLOR_NORMAL "%s", default_prompt); + l += sprintf (buf + l, "]" COLOR_NORMAL); return buf; - } else { - return default_prompt; - } + } + l += sprintf (buf + l, "%s", default_prompt); + return buf; } char *complete_none (const char *text UU, int state UU) { @@ -252,6 +261,12 @@ char *modifiers[] = { 0 }; +char *in_chat_commands[] = { + "/exit", + "/quit", + 0 +}; + char *commands[] = { "help", "msg", @@ -296,6 +311,7 @@ char *commands[] = { "load_document", "view_document", "set", + "chat_with_peer", 0 }; int commands_flags[] = { @@ -342,6 +358,7 @@ int commands_flags[] = { 07, 07, 07, + 072, }; @@ -451,6 +468,12 @@ int complete_string_list (char **list, int index, const char *text, int len, cha } char *command_generator (const char *text, int state) { static int len, index, mode; + + if (in_chat_mode) { + char *R = 0; + index = complete_string_list (in_chat_commands, index, text, rl_point, &R); + return R; + } char c = 0; if (!state) { @@ -521,10 +544,27 @@ void work_modifier (const char *s, int l) { #endif } + + +void interpreter_chat_mode (char *line) { + if (!strncmp (line, "/exit", 5) || !strncmp (line, "/quit", 5)) { + in_chat_mode = 0; + update_prompt (); + return; + } + do_send_message (chat_mode_id, line, strlen (line)); +} + void interpreter (char *line UU) { - line_ptr = line; assert (!in_readline); in_readline = 1; + if (in_chat_mode) { + interpreter_chat_mode (line); + in_readline = 0; + return; + } + + line_ptr = line; offline_mode = 0; count = 1; if (!line) { @@ -1002,6 +1042,10 @@ void interpreter (char *line UU) { } else if (IS_WORD ("msg_num")) { msg_num_mode = num; } + } else if (IS_WORD ("chat_with_peer")) { + GET_PEER; + in_chat_mode = 1; + chat_mode_id = id; } else if (IS_WORD ("quit")) { exit (0); } diff --git a/queries.c b/queries.c index 64351d9..27aef3a 100644 --- a/queries.c +++ b/queries.c @@ -845,8 +845,16 @@ int msg_send_on_answer (struct query *q UU) { return 0; } +int msg_send_on_error (struct query *q, int error_code, int error_len, char *error) { + logprintf ( "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error); + struct message *M = q->extra; + bl_do_delete_msg (M); + return 0; +} + struct query_methods msg_send_methods = { - .on_answer = msg_send_on_answer + .on_answer = msg_send_on_answer, + .on_error = msg_send_on_error }; struct query_methods msg_send_encr_methods = { From 7a3ef6d6244270b1e673d48e9a6176c2e2a35b5f Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 6 Dec 2013 21:16:17 +0400 Subject: [PATCH 138/465] Updated help --- interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/interface.c b/interface.c index fc0ea75..b006aa7 100644 --- a/interface.c +++ b/interface.c @@ -871,6 +871,7 @@ void interpreter (char *line UU) { "\t\tLevel 2: prints line, when somebody is typing in chat\n" "\t\tLevel 3: prints line, when somebody changes online status\n" "\tmsg_num - enables/disables numeration of messages\n" + "chat_with_peer - starts chat with this peer. Every command after is message to this peer. Type /exit or /quit to end this mode\n" ); pop_color (); } else if (IS_WORD ("show_license")) { From bb53f75e2bb565054b5cf30f3af96fd4cae546bb Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Tue, 17 Dec 2013 02:30:36 +0800 Subject: [PATCH 139/465] Make it compile on FreeBSD. --- Makefile | 10 +++++----- Makefile.in | 4 ++-- config.h | 2 +- loop.c | 1 + mtproto-client.c | 18 ++++++++++++------ net.c | 5 ++++- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index c7e68f3..23f76ac 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ srcdir=. -CFLAGS=-g -O2 -LDFLAGS= +CFLAGS=-I/usr/local/include +LDFLAGS=-L/usr/local/lib CPPFLAGS= DEFS=-DHAVE_CONFIG_H -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -EXTRA_LIBS= -lreadline -lrt -lconfig -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} +EXTRA_LIBS= +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb -lconfig -lreadline -lexecinfo ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h diff --git a/Makefile.in b/Makefile.in index 1bf9014..68e199c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,10 +4,10 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@EXTRA_LIBS@ -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb -lconfig -lreadline -lexecinfo ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h diff --git a/config.h b/config.h index 73aaaf3..538a278 100644 --- a/config.h +++ b/config.h @@ -24,7 +24,7 @@ #define HAVE_MALLOC 1 /* Define to 1 if you have the header file. */ -#define HAVE_MALLOC_H 1 +/* #undef HAVE_MALLOC_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 diff --git a/loop.c b/loop.c index d9f3bf3..3a0dcbf 100644 --- a/loop.c +++ b/loop.c @@ -20,6 +20,7 @@ #include "config.h" #include +#define _WITH_GETLINE #include #include diff --git a/mtproto-client.c b/mtproto-client.c index 944d05a..d8a2e48 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +48,10 @@ #include "structures.h" #include "binlog.h" +#if defined(__FreeBSD__) +#define __builtin_bswap32(x) bswap32(x) +#endif + #define sha1 SHA1 #include "mtproto-common.h" @@ -1589,7 +1595,7 @@ int rpc_execute (struct connection *c, int op, int len) { logprintf ( "have %d Response bytes\n", Response_len); } -#ifndef __MACH__ +#if !defined(__MACH__) && !defined(__FreeBSD__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif int o = c_state; @@ -1597,19 +1603,19 @@ int rpc_execute (struct connection *c, int op, int len) { switch (o) { case st_reqpq_sent: process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#ifndef __MACH__ +#if !defined(__MACH__) && !defined(__FreeBSD__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; case st_reqdh_sent: process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#ifndef __MACH__ +#if !defined(__MACH__) && !defined(__FreeBSD__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; case st_client_dh_sent: process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); -#ifndef __MACH__ +#if !defined(__MACH__) && !defined(__FreeBSD__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; @@ -1619,7 +1625,7 @@ int rpc_execute (struct connection *c, int op, int len) { } else { process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); } -#ifndef __MACH__ +#if !defined(__MACH__) && !defined(__FreeBSD__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; @@ -1647,7 +1653,7 @@ int tc_becomes_ready (struct connection *c) { assert (write_out (c, &byte, 1) == 1); flush_out (c); -#ifndef __MACH__ +#if !defined(__MACH__) && !defined(__FreeBSD__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif int o = c_state; diff --git a/net.c b/net.c index 7d5db84..22eec8c 100644 --- a/net.c +++ b/net.c @@ -21,8 +21,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -37,7 +40,7 @@ #include "tree.h" #include "interface.h" -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #define POLLRDHUP 0 #endif From 3b033ea3ff62110324fcd201968e80a2d6f4f341 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 18 Dec 2013 19:21:49 +0400 Subject: [PATCH 140/465] Added dump packets to file --- interface.c | 4 ++++ loop.c | 1 + main.c | 17 ++++++++++++++++- mtproto-client.c | 3 ++- net.c | 20 ++++++++++++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/interface.c b/interface.c index b006aa7..bd7c041 100644 --- a/interface.c +++ b/interface.c @@ -1369,6 +1369,10 @@ void print_message (struct message *M) { print_service_message (M); return; } + if (!get_peer_type (M->to_id)) { + logprintf ("Bad msg\n"); + return; + } last_from_id = M->from_id; last_to_id = M->to_id; diff --git a/loop.c b/loop.c index d9f3bf3..970c1a7 100644 --- a/loop.c +++ b/loop.c @@ -104,6 +104,7 @@ size_t *_l; int got_it_ok; void got_it (char *line, int len) { + assert (len > 0); line[-- len] = 0; // delete end of line *_s = line; *_l = len; diff --git a/main.c b/main.c index c0a8951..1de65d8 100644 --- a/main.c +++ b/main.c @@ -324,10 +324,14 @@ extern char *rsa_public_key_name; extern int verbosity; extern int default_dc_num; +char *log_net_file; +FILE *log_net_f; + int register_mode; +int disable_auto_accept; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:Rf")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:RfBL:E")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -360,6 +364,17 @@ void args_parse (int argc, char **argv) { case 'B': binlog_enabled = 1; break; + case 'L': + if (log_net_file) { + usage (); + } + log_net_file = strdup (optarg); + log_net_f = fopen (log_net_file, "a"); + assert (log_net_f); + break; + case 'E': + disable_auto_accept = 1; + break; case 'h': default: usage (); diff --git a/mtproto-client.c b/mtproto-client.c index 944d05a..f6696d6 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -60,6 +60,7 @@ char nonce[256]; char new_nonce[256]; char server_nonce[256]; extern int binlog_enabled; +extern int disable_auto_accept; int total_packets_sent; @@ -1148,7 +1149,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { } pop_color (); print_end (); - if (E->state == sc_request) { + if (E->state == sc_request && !disable_auto_accept) { do_accept_encr_chat_request (E); } fetch_int (); // date diff --git a/net.c b/net.c index 7d5db84..2b283d8 100644 --- a/net.c +++ b/net.c @@ -45,6 +45,7 @@ DEFINE_TREE(int,int,int_cmp,0) int verbosity; extern struct connection_methods auth_methods; +extern FILE *log_net_f; void fail_connection (struct connection *c); @@ -348,6 +349,7 @@ void fail_connection (struct connection *c) { restart_connection (c); } +extern FILE *log_net_f; void try_write (struct connection *c) { if (verbosity) { logprintf ( "try write: fd = %d\n", c->fd); @@ -355,6 +357,15 @@ void try_write (struct connection *c) { int x = 0; while (c->out_head) { int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + if (r > 0 && log_net_f) { + fprintf (log_net_f, "OUT %s:%d", c->ip, c->port); + int i; + for (i = 0; i < r; i++) { + fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); + } + fprintf (log_net_f, "\n"); + fflush (log_net_f); + } if (r >= 0) { x += r; c->out_head->rptr += r; @@ -457,6 +468,15 @@ void try_read (struct connection *c) { int x = 0; while (1) { int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); + if (r > 0 && log_net_f) { + fprintf (log_net_f, "IN %s:%d", c->ip, c->port); + int i; + for (i = 0; i < r; i++) { + fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i)); + } + fprintf (log_net_f, "\n"); + fflush (log_net_f); + } if (r > 0) { c->last_receive_time = get_double_time (); stop_ping_timer (c); From cd3c22fa6692cf1b3d615b9ee5003e652d3c0bb3 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 18 Dec 2013 19:42:53 +0400 Subject: [PATCH 141/465] Fixed log --- net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net.c b/net.c index 2b283d8..db88fd4 100644 --- a/net.c +++ b/net.c @@ -358,7 +358,7 @@ void try_write (struct connection *c) { while (c->out_head) { int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); if (r > 0 && log_net_f) { - fprintf (log_net_f, "OUT %s:%d", c->ip, c->port); + fprintf (log_net_f, "%d %d OUT %s:%d", (int)time (0), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); @@ -469,7 +469,7 @@ void try_read (struct connection *c) { while (1) { int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); if (r > 0 && log_net_f) { - fprintf (log_net_f, "IN %s:%d", c->ip, c->port); + fprintf (log_net_f, "%d %d IN %s:%d", (int)time (0), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i)); From 658c45c94cfc6e0cf9e3f2fbbbe2502eac5aee05 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 18 Dec 2013 21:57:51 +0400 Subject: [PATCH 142/465] Fixed time format in logs --- net.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net.c b/net.c index db88fd4..92372dc 100644 --- a/net.c +++ b/net.c @@ -42,6 +42,7 @@ #endif DEFINE_TREE(int,int,int_cmp,0) +double get_utime (int clock_id); int verbosity; extern struct connection_methods auth_methods; @@ -358,7 +359,7 @@ void try_write (struct connection *c) { while (c->out_head) { int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); if (r > 0 && log_net_f) { - fprintf (log_net_f, "%d %d OUT %s:%d", (int)time (0), r, c->ip, c->port); + fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); @@ -469,7 +470,7 @@ void try_read (struct connection *c) { while (1) { int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); if (r > 0 && log_net_f) { - fprintf (log_net_f, "%d %d IN %s:%d", (int)time (0), r, c->ip, c->port); + fprintf (log_net_f, "%.02lf %d IN %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i)); From cacf0582bcbb9663c262afc87531ae069f5562c4 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Thu, 19 Dec 2013 01:58:51 +0800 Subject: [PATCH 143/465] Define _GNU_SOURCE for getline(3) --- loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loop.c b/loop.c index 3a0dcbf..ed6bf91 100644 --- a/loop.c +++ b/loop.c @@ -18,9 +18,9 @@ */ #define READLINE_CALLBACKS #include "config.h" +#define _GNU_SOURCE #include -#define _WITH_GETLINE #include #include From 0d80f5e298604cb6c098ddff24162c33e190a1a2 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Thu, 19 Dec 2013 02:17:21 +0800 Subject: [PATCH 144/465] Restore flags not supported by gcc 4.2 --- Makefile | 2 +- Makefile.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 23f76ac..c28f79e 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib CPPFLAGS= DEFS=-DHAVE_CONFIG_H -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS= LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb -lconfig -lreadline -lexecinfo ${EXTRA_LIBS} diff --git a/Makefile.in b/Makefile.in index 68e199c..eef20d9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@EXTRA_LIBS@ LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb -lconfig -lreadline -lexecinfo ${EXTRA_LIBS} From 715378408b4b92163273513b8ab67696b1298fcc Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Thu, 19 Dec 2013 02:19:37 +0800 Subject: [PATCH 145/465] Remove generated files and add .gitignore --- .gitignore | 2 + Makefile | 35 ------------------ config.h | 106 ----------------------------------------------------- 3 files changed, 2 insertions(+), 141 deletions(-) create mode 100644 .gitignore delete mode 100644 Makefile delete mode 100644 config.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..547646a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Makefile +config.h diff --git a/Makefile b/Makefile deleted file mode 100644 index c28f79e..0000000 --- a/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -srcdir=. - -CFLAGS=-I/usr/local/include -LDFLAGS=-L/usr/local/lib -CPPFLAGS= -DEFS=-DHAVE_CONFIG_H -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb - -EXTRA_LIBS= -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb -lconfig -lreadline -lexecinfo ${EXTRA_LIBS} -LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} - -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h -INCLUDE=-I. -I${srcdir} -CC=gcc -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o - -.SUFFIXES: - -.SUFFIXES: .c .h .o - -all: telegram - -${OBJECTS}: ${HEADERS} - -telegram: ${OBJECTS} - ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ - -.c.o : - ${CC} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ - - -clean: - rm -rf *.o telegram > /dev/null || echo "all clean" - diff --git a/config.h b/config.h deleted file mode 100644 index 538a278..0000000 --- a/config.h +++ /dev/null @@ -1,106 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* enable libconfig */ -#define ENABLE_LIBCONFIG 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -#define HAVE_LIBCRYPTO 1 - -/* Define to 1 if you have the `edit' library (-ledit). */ -/* #undef HAVE_LIBEDIT */ - -/* Define to 1 if you have the `m' library (-lm). */ -#define HAVE_LIBM 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MALLOC_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#define HAVE_REALLOC 1 - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strndup' function. */ -#define HAVE_STRNDUP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "telegram" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "telegram 0.1" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "telegram" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.1" - -/* Use libedit */ -/* #undef READLINE_EDIT */ - -/* Use gnu libreadline */ -#define READLINE_GNU 1 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to rpl_malloc if the replacement function should be used. */ -/* #undef malloc */ - -/* Define to rpl_realloc if the replacement function should be used. */ -/* #undef realloc */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ From 7c42025800978e9ebc8719faac733a69ec24ae13 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Thu, 19 Dec 2013 02:25:34 +0800 Subject: [PATCH 146/465] Clean up more generated files --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index eef20d9..6600ce9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,5 +31,5 @@ telegram: ${OBJECTS} clean: - rm -rf *.o telegram > /dev/null || echo "all clean" + rm -rf *.o telegram config.log config.status > /dev/null || echo "all clean" From c05bb7599b1059f13ecfb55dc7f651a3c1bf8a44 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Thu, 19 Dec 2013 02:26:29 +0800 Subject: [PATCH 147/465] Add instructions to build on FreeBSD --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index c82dee5..9620f2b 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,15 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea $ ./configure && make Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. + +#### FreeBSD + +Install these ports: +* devel/libconfig +* devel/libexecinfo + + $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure + $ make #### Other UNIX From edc4d2eba148638a98144719e92095b573a82dc4 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Thu, 19 Dec 2013 02:37:46 +0800 Subject: [PATCH 148/465] Insert newlines and some words for markdown formating --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9620f2b..e82c523 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,12 @@ Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-2829373 #### FreeBSD Install these ports: + * devel/libconfig * devel/libexecinfo +Then build: + $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure $ make From e439bef899ee77dee9d25d9c50d54643669315f6 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 20 Dec 2013 02:50:31 +0400 Subject: [PATCH 149/465] added /read and /history in chat_with_peer mode --- interface.c | 21 +++++++++++++++++++++ mtproto-client.c | 17 ++++++----------- mtproto-common.h | 7 +++++++ queries.c | 5 +++-- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/interface.c b/interface.c index bd7c041..ad77bfc 100644 --- a/interface.c +++ b/interface.c @@ -264,6 +264,8 @@ char *modifiers[] = { char *in_chat_commands[] = { "/exit", "/quit", + "/history", + "/read", 0 }; @@ -552,6 +554,17 @@ void interpreter_chat_mode (char *line) { update_prompt (); return; } + if (!strncmp (line, "/history", 8)) { + int limit = 40; + sscanf (line, "/history %d", &limit); + if (limit < 0 || limit > 1000) { limit = 40; } + do_get_history (chat_mode_id, limit); + return; + } + if (!strncmp (line, "/read", 5)) { + do_mark_read (chat_mode_id); + return; + } do_send_message (chat_mode_id, line, strlen (line)); } @@ -1153,6 +1166,7 @@ void pop_color (void) { } void print_media (struct message_media *M) { + assert (M); switch (M->type) { case CODE_message_media_empty: case CODE_decrypted_message_media_empty: @@ -1250,6 +1264,7 @@ void print_user_name (peer_id_t id, peer_t *U) { } void print_chat_name (peer_id_t id, peer_t *C) { + assert (get_peer_type (id) == PEER_CHAT); push_color (COLOR_MAGENTA); if (!C) { printf ("chat#%d", get_peer_id (id)); @@ -1260,6 +1275,7 @@ void print_chat_name (peer_id_t id, peer_t *C) { } void print_encr_chat_name (peer_id_t id, peer_t *C) { + assert (get_peer_type (id) == PEER_ENCR_CHAT); push_color (COLOR_MAGENTA); if (!C) { printf ("encr_chat#%d", get_peer_id (id)); @@ -1270,6 +1286,7 @@ void print_encr_chat_name (peer_id_t id, peer_t *C) { } void print_encr_chat_name_full (peer_id_t id, peer_t *C) { + assert (get_peer_type (id) == PEER_ENCR_CHAT); push_color (COLOR_MAGENTA); if (!C) { printf ("encr_chat#%d", get_peer_id (id)); @@ -1297,6 +1314,7 @@ void print_date_full (long t) { int our_id; void print_service_message (struct message *M) { + assert (M); print_start (); push_color (COLOR_GREY); @@ -1310,6 +1328,7 @@ void print_service_message (struct message *M) { if (get_peer_type (M->to_id) == PEER_CHAT) { print_chat_name (M->to_id, user_chat_get (M->to_id)); } else { + assert (get_peer_type (M->to_id) == PEER_ENCR_CHAT); print_encr_chat_name (M->to_id, user_chat_get (M->to_id)); } printf (" "); @@ -1362,9 +1381,11 @@ peer_id_t last_from_id; peer_id_t last_to_id; void print_message (struct message *M) { + assert (M); if (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED)) { return; } + if (!(M->flags & FLAG_CREATED)) { return; } if (M->service) { print_service_message (M); return; diff --git a/mtproto-client.c b/mtproto-client.c index f6696d6..4c86857 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -205,7 +205,7 @@ int rpc_send_message (struct connection *c, void *data, int len) { assert (write_out (c, &total_len, 4) == 4); } c->out_packet_num ++; - write_out (c, data, len); + assert (write_out (c, data, len) == len); flush_out (c); total_packets_sent ++; @@ -726,11 +726,8 @@ void work_update_binlog (void) { U->last_name = fetch_str_dup (); U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); } else { - int l; - l = prefetch_strlen (); - fetch_str (l); - l = prefetch_strlen (); - fetch_str (l); + fetch_skip_str (); + fetch_skip_str (); } } break; @@ -778,6 +775,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { case CODE_update_new_message: { struct message *M = fetch_alloc_message (); + assert (M); fetch_pts (); unread_messages ++; print_message (M); @@ -898,11 +896,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { pop_color (); print_end (); } else { - int l; - l = prefetch_strlen (); - fetch_str (l); - l = prefetch_strlen (); - fetch_str (l); + fetch_skip_str (); + fetch_skip_str (); } } break; diff --git a/mtproto-common.h b/mtproto-common.h index 43efac1..b811ecc 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -304,6 +304,7 @@ static inline char *fetch_str (int len) { static inline char *fetch_str_dup (void) { int l = prefetch_strlen (); + assert (l >= 0); char *s = malloc (l + 1); memcpy (s, fetch_str (l), l); s[l] = 0; @@ -361,6 +362,12 @@ static inline void fetch_skip (int n) { in_ptr += n; } +static inline void fetch_skip_str (void) { + int l = prefetch_strlen (); + assert (l >= 0); + fetch_str (l); +} + static __inline__ unsigned long long rdtsc(void) { unsigned hi, lo; __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); diff --git a/queries.c b/queries.c index 27aef3a..629b5f0 100644 --- a/queries.c +++ b/queries.c @@ -1592,7 +1592,7 @@ struct query_methods rename_chat_methods = { .on_answer = rename_chat_on_answer }; -void do_rename_chat (peer_id_t id, char *name) { +void do_rename_chat (peer_id_t id, char *name UU) { clear_packet (); out_int (CODE_messages_edit_chat_title); assert (get_peer_type (id) == PEER_CHAT); @@ -2316,7 +2316,8 @@ void do_create_keys_end (struct secret_chat *U) { hexdump ((void *)U->g_key, (void *)(U->g_key + 256)); hexdump ((void *)U->key, (void *)(U->key + 64)); hexdump ((void *)t, (void *)(t + 256)); - logprintf ("!!Key fingerprint mismatch\n"); + hexdump ((void *)sha_buffer, (void *)(sha_buffer + 20)); + logprintf ("!!Key fingerprint mismatch (my 0x%llx 0x%llx)\n", (unsigned long long)k, (unsigned long long)U->key_fingerprint); U->state = sc_deleted; } From 20f1c7629b0b061c3135851b98ab6990ee448fc7 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 20 Dec 2013 17:57:00 +0400 Subject: [PATCH 150/465] Merge BSD-fixed from lwhsu --- .gitignore | 2 - Makefile | 35 ++++++++++++++++ Makefile.in | 2 +- config.h | 106 +++++++++++++++++++++++++++++++++++++++++++++++ mtproto-client.c | 2 + 5 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 Makefile create mode 100644 config.h diff --git a/.gitignore b/.gitignore index 547646a..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +0,0 @@ -Makefile -config.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ba848c9 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +srcdir=. + +CFLAGS=-g -O2 +LDFLAGS= +CPPFLAGS= +DEFS=-DHAVE_CONFIG_H +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb + +EXTRA_LIBS= -lreadline -lrt -lconfig +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} +LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} + +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h +INCLUDE=-I. -I${srcdir} +CC=gcc +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o + +.SUFFIXES: + +.SUFFIXES: .c .h .o + +all: telegram + +${OBJECTS}: ${HEADERS} + +telegram: ${OBJECTS} + ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ + +.c.o : + ${CC} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ + + +clean: + rm -rf *.o telegram config.log config.status > /dev/null || echo "all clean" + diff --git a/Makefile.in b/Makefile.in index 6600ce9..7c6589d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,7 +7,7 @@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@EXTRA_LIBS@ -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb -lconfig -lreadline -lexecinfo ${EXTRA_LIBS} +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h diff --git a/config.h b/config.h new file mode 100644 index 0000000..73aaaf3 --- /dev/null +++ b/config.h @@ -0,0 +1,106 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* enable libconfig */ +#define ENABLE_LIBCONFIG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define to 1 if you have the `edit' library (-ledit). */ +/* #undef HAVE_LIBEDIT */ + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "telegram" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "telegram 0.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "telegram" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.1" + +/* Use libedit */ +/* #undef READLINE_EDIT */ + +/* Use gnu libreadline */ +#define READLINE_GNU 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/mtproto-client.c b/mtproto-client.c index b766c40..811ba56 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -26,7 +26,9 @@ #include #include #include +#ifdef __FreeBSD__ #include +#endif #include #include #include From 0275f7e9702c956e1dd62ed3123b643c00554e60 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 20 Dec 2013 18:25:22 +0400 Subject: [PATCH 151/465] Add -lexecinfo if no bt found --- config.h | 3 + config.h.in | 3 + configure | 194 +++++++++++++++++++++++++++++++++------------------ configure.ac | 15 ++++ 4 files changed, 148 insertions(+), 67 deletions(-) diff --git a/config.h b/config.h index 73aaaf3..babca79 100644 --- a/config.h +++ b/config.h @@ -16,6 +16,9 @@ /* Define to 1 if you have the `edit' library (-ledit). */ /* #undef HAVE_LIBEDIT */ +/* Define to 1 if you have the `execinfo' library (-lexecinfo). */ +/* #undef HAVE_LIBEXECINFO */ + /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 diff --git a/config.h.in b/config.h.in index ce8b6b2..d8fc8ae 100644 --- a/config.h.in +++ b/config.h.in @@ -15,6 +15,9 @@ /* Define to 1 if you have the `edit' library (-ledit). */ #undef HAVE_LIBEDIT +/* Define to 1 if you have the `execinfo' library (-lexecinfo). */ +#undef HAVE_LIBEXECINFO + /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM diff --git a/configure b/configure index 49c45d3..f601cc7 100755 --- a/configure +++ b/configure @@ -1469,6 +1469,73 @@ fi } # ac_fn_c_try_link +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. @@ -1719,73 +1786,6 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -3028,6 +3028,66 @@ fi EXTRA_LIBS="" +BT= +ac_fn_c_check_func "$LINENO" "backtrace" "ac_cv_func_backtrace" +if test "x$ac_cv_func_backtrace" = xyes; then : + + BT=1 + +fi + + +if test "x$BT" = "x" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace in -lexecinfo" >&5 +$as_echo_n "checking for backtrace in -lexecinfo... " >&6; } +if ${ac_cv_lib_execinfo_backtrace+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lexecinfo $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char backtrace (); +int +main () +{ +return backtrace (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_execinfo_backtrace=yes +else + ac_cv_lib_execinfo_backtrace=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_execinfo_backtrace" >&5 +$as_echo "$ac_cv_lib_execinfo_backtrace" >&6; } +if test "x$ac_cv_lib_execinfo_backtrace" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBEXECINFO 1 +_ACEOF + + LIBS="-lexecinfo $LIBS" + +fi + + EXTRA_LIBS+=" -lexecinfo" ; +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_save_prompt in -lreadline" >&5 $as_echo_n "checking for rl_save_prompt in -lreadline... " >&6; } if ${ac_cv_lib_readline_rl_save_prompt+:} false; then : diff --git a/configure.ac b/configure.ac index a1d2d47..24f2153 100644 --- a/configure.ac +++ b/configure.ac @@ -12,6 +12,21 @@ AC_CHECK_LIB([crypto], [AES_set_encrypt_key]) EXTRA_LIBS="" +BT= +AC_CHECK_FUNC([backtrace], + [ + BT=1 + ], + [ + ] +) + +if test "x$BT" = "x" ; then + AC_MSG_RESULT([no]) + AC_CHECK_LIB([execinfo], [backtrace]) + [ EXTRA_LIBS+=" -lexecinfo" ; ] +fi + AC_CHECK_LIB([readline], [rl_save_prompt], [ AC_DEFINE([READLINE_GNU], [1], [Use gnu libreadline]) From 03bd7f55a92afef2a6f8bd91cccc5e280ee24c06 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 20 Dec 2013 19:45:59 +0400 Subject: [PATCH 152/465] Fixed bug in document loading --- interface.c | 10 +++++----- queries.c | 25 ++++++++++++++++++++++++- queries.h | 2 ++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/interface.c b/interface.c index ad77bfc..664b976 100644 --- a/interface.c +++ b/interface.c @@ -43,7 +43,7 @@ #include "mtproto-common.h" -//#define ALLOW_MULT 1 +#define ALLOW_MULT 1 char *default_prompt = "> "; int unread_messages; @@ -994,7 +994,7 @@ void interpreter (char *line UU) { } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_document) { - do_load_video_thumb (&M->media.video, 1); + do_load_document_thumb (&M->media.document, 1); } else { printf ("Bad msg id\n"); RET; @@ -1007,7 +1007,7 @@ void interpreter (char *line UU) { } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_document) { - do_load_video_thumb (&M->media.video, 2); + do_load_document_thumb (&M->media.document, 2); } else { printf ("Bad msg id\n"); RET; @@ -1020,7 +1020,7 @@ void interpreter (char *line UU) { } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_document) { - do_load_video (&M->media.video, 1); + do_load_document (&M->media.document, 1); } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { do_load_encr_video (&M->media.encr_video, 1); } else { @@ -1035,7 +1035,7 @@ void interpreter (char *line UU) { } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_document) { - do_load_video (&M->media.video, 2); + do_load_document (&M->media.document, 2); } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { do_load_encr_video (&M->media.encr_video, 2); } else { diff --git a/queries.c b/queries.c index 629b5f0..8ec160d 100644 --- a/queries.c +++ b/queries.c @@ -1758,6 +1758,7 @@ struct download { long long id; unsigned char *iv; unsigned char *key; + int type; }; @@ -1861,7 +1862,7 @@ void load_next_part (struct download *D) { if (D->iv) { out_int (CODE_input_encrypted_file_location); } else { - out_int (CODE_input_video_file_location); + out_int (D->type); } out_long (D->id); out_long (D->access_hash); @@ -1913,6 +1914,10 @@ void do_load_video_thumb (struct video *video, int next) { do_load_photo_size (&video->thumb, next); } +void do_load_document_thumb (struct document *video, int next) { + do_load_photo_size (&video->thumb, next); +} + void do_load_video (struct video *V, int next) { assert (V); assert (next); @@ -1926,6 +1931,24 @@ void do_load_video (struct video *V, int next) { D->next = next; D->name = 0; D->fd = -1; + D->type = CODE_input_video_file_location; + load_next_part (D); +} + +void do_load_document (struct document *V, int next) { + assert (V); + assert (next); + struct download *D = malloc (sizeof (*D)); + memset (D, 0, sizeof (*D)); + D->offset = 0; + D->size = V->size; + D->id = V->id; + D->access_hash = V->access_hash; + D->dc = V->dc_id; + D->next = next; + D->name = 0; + D->fd = -1; + D->type = CODE_input_document_file_location; load_next_part (D); } diff --git a/queries.h b/queries.h index 3259b33..bb8f9d6 100644 --- a/queries.h +++ b/queries.h @@ -90,6 +90,8 @@ 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_load_document (struct document *V, int next); +void do_load_document_thumb (struct document *video, int next); void do_help_get_config (void); int do_auth_check_phone (const char *user); int do_get_nearest_dc (void); From 9f758a772f4140f3ed9901f35d327324e8b61179 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sat, 21 Dec 2013 02:43:21 +0800 Subject: [PATCH 153/465] Use Travis CI --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3e53cc1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: c +compiler: + - gcc + - clang +script: ./configure && make From c798191b744958d7c3699314ca32a9867fcd9ffd Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sat, 21 Dec 2013 03:30:48 +0800 Subject: [PATCH 154/465] Install prerequisites --- .travis.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e53cc1..04d6c1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,14 @@ language: c + compiler: - gcc - clang -script: ./configure && make + +install: + - apt-get install libconfig8-dev + - apt-get install libreadline6-dev + - apt-get install libssl-dev + +script: + - ./configure + - make From d980e1630d8aca5fe03b210e5bbace910ac3f24c Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sat, 21 Dec 2013 03:33:04 +0800 Subject: [PATCH 155/465] Use sudo --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 04d6c1d..f453581 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,9 @@ compiler: - clang install: - - apt-get install libconfig8-dev - - apt-get install libreadline6-dev - - apt-get install libssl-dev + - sudo apt-get install libconfig8-dev + - sudo apt-get install libreadline6-dev + - sudo apt-get install libssl-dev script: - ./configure From 9f8679b1a36693e8b6501d3562f29622f5ad0943 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sat, 21 Dec 2013 03:42:24 +0800 Subject: [PATCH 156/465] Add build status icon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e82c523..64b442c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Telegram messenger CLI +## Telegram messenger CLI [![Build Status](https://travis-ci.org/lwhsu/tg.png)](https://travis-ci.org/lwhsu/tg) Command-line interface for [Telegram](http://telegram.org). Uses readline interface. From a0a628963e51492cd97d00725b3c5b1d6b56453a Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sat, 21 Dec 2013 04:13:53 +0800 Subject: [PATCH 157/465] Use syntax that Bourne shell also supports --- configure | 12 ++++++------ configure.ac | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/configure b/configure index f601cc7..a71c4b7 100755 --- a/configure +++ b/configure @@ -3085,7 +3085,7 @@ _ACEOF fi - EXTRA_LIBS+=" -lexecinfo" ; + EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_save_prompt in -lreadline" >&5 @@ -3129,7 +3129,7 @@ if test "x$ac_cv_lib_readline_rl_save_prompt" = xyes; then : $as_echo "#define READLINE_GNU 1" >>confdefs.h - EXTRA_LIBS+=" -lreadline" ; + EXTRA_LIBS="${EXTRA_LIBS} -lreadline" ; else @@ -3181,7 +3181,7 @@ fi $as_echo "#define READLINE_EDIT 1" >>confdefs.h - EXTRA_LIBS+=" -ledit" ; + EXTRA_LIBS="${EXTRA_LIBS} -ledit" ; fi @@ -3225,7 +3225,7 @@ fi $as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : - EXTRA_LIBS+=" -lrt" ; + EXTRA_LIBS="${EXTRA_LIBS} -lrt" ; fi @@ -3285,7 +3285,7 @@ else as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 fi - EXTRA_LIBS+=" -lconfig" ; + EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; fi else @@ -3336,7 +3336,7 @@ else as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 fi - EXTRA_LIBS+=" -lconfig" ; + EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; fi diff --git a/configure.ac b/configure.ac index 24f2153..8825ff3 100644 --- a/configure.ac +++ b/configure.ac @@ -24,24 +24,24 @@ AC_CHECK_FUNC([backtrace], if test "x$BT" = "x" ; then AC_MSG_RESULT([no]) AC_CHECK_LIB([execinfo], [backtrace]) - [ EXTRA_LIBS+=" -lexecinfo" ; ] + [ EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; ] fi AC_CHECK_LIB([readline], [rl_save_prompt], [ AC_DEFINE([READLINE_GNU], [1], [Use gnu libreadline]) - [ EXTRA_LIBS+=" -lreadline" ; ] + [ EXTRA_LIBS="${EXTRA_LIBS} -lreadline" ; ] ], [ AC_CHECK_LIB([edit], [rl_set_prompt]) AC_DEFINE([READLINE_EDIT], [1], [Use libedit]) - [ EXTRA_LIBS+=" -ledit" ; ] + [ EXTRA_LIBS="${EXTRA_LIBS} -ledit" ; ] ] ) AC_CHECK_LIB([rt], [clock_gettime], [ - [ EXTRA_LIBS+=" -lrt" ; ] + [ EXTRA_LIBS="${EXTRA_LIBS} -lrt" ; ] ], [ ] @@ -55,12 +55,12 @@ AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], else AC_MSG_RESULT([enabled]) AC_CHECK_LIB([config],[config_init],AC_DEFINE(ENABLE_LIBCONFIG,1,[enable libconfig]),AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) - [EXTRA_LIBS+=" -lconfig" ; ] + [EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; ] fi ],[ AC_MSG_RESULT([enabled]) AC_CHECK_LIB([config],[config_init],AC_DEFINE(ENABLE_LIBCONFIG,1,[enable libconfig]),AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) - [EXTRA_LIBS+=" -lconfig" ; ] + [EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; ] ]) # Checks for header files. From 3ff3550a588b9fda3636029cfea3100f0548fc6a Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 21 Dec 2013 03:00:35 +0300 Subject: [PATCH 158/465] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64b442c..9a28410 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Telegram messenger CLI [![Build Status](https://travis-ci.org/lwhsu/tg.png)](https://travis-ci.org/lwhsu/tg) +## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) Command-line interface for [Telegram](http://telegram.org). Uses readline interface. From 93fec1d7a707fca931e1d73182d5927908f14088 Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 21 Dec 2013 15:46:25 +0400 Subject: [PATCH 159/465] configure.ac: fixed duplicate "no" answer --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8825ff3..f1480ed 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,6 @@ AC_CHECK_FUNC([backtrace], ) if test "x$BT" = "x" ; then - AC_MSG_RESULT([no]) AC_CHECK_LIB([execinfo], [backtrace]) [ EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; ] fi From 9b67354294cea7c6eb24c3b7e544b3faf82d0fb6 Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 21 Dec 2013 15:53:32 +0400 Subject: [PATCH 160/465] Added safe_quit query. Useful in pipe mode --- interface.c | 5 +++++ loop.c | 9 ++++++++- queries.c | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 664b976..86ad62b 100644 --- a/interface.c +++ b/interface.c @@ -49,6 +49,8 @@ char *default_prompt = "> "; int unread_messages; int msg_num_mode; +int safe_quit; + int in_readline; int readline_active; @@ -304,6 +306,7 @@ char *commands[] = { "status_offline", "contacts_search", "quit", + "safe_quit", "send_audio", "load_audio", "view_audio", @@ -1062,6 +1065,8 @@ void interpreter (char *line UU) { chat_mode_id = id; } else if (IS_WORD ("quit")) { exit (0); + } else if (IS_WORD ("safe_quit")) { + safe_quit = 1; } } #undef IS_WORD diff --git a/loop.c b/loop.c index 1dd73f8..f4b5fef 100644 --- a/loop.c +++ b/loop.c @@ -59,6 +59,8 @@ extern int binlog_enabled; extern int unknown_user_list_pos; extern int unknown_user_list[]; int register_mode; +extern int safe_quit; +extern int queries_num; int unread_messages; void got_it (char *line, int len); @@ -93,10 +95,15 @@ void net_loop (int flags, int (*is_end)(void)) { } } connections_poll_result (fds + cc, x - cc); + if (safe_quit && !queries_num) { + printf ("All done. Exit\n"); + rl_callback_handler_remove (); + exit (0); + } if (unknown_user_list_pos) { do_get_user_list_info_silent (unknown_user_list_pos, unknown_user_list); unknown_user_list_pos = 0; - } + } } } diff --git a/queries.c b/queries.c index 8ec160d..9067d1e 100644 --- a/queries.c +++ b/queries.c @@ -66,6 +66,8 @@ long long cur_downloaded_bytes; extern int binlog_enabled; extern int sync_from_start; +int queries_num; + void out_peer_id (peer_id_t id); #define QUERY_TIMEOUT 6.0 @@ -150,6 +152,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth insert_event_timer (&q->ev); q->extra = extra; + queries_num ++; return q; } @@ -188,6 +191,7 @@ void query_error (long long id) { free (q->data); free (q); } + queries_num --; } #define MAX_PACKED_SIZE (1 << 24) @@ -255,6 +259,7 @@ void query_result (long long id UU) { in_ptr = end; in_end = eend; } + queries_num --; } #define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) From 89ee6e100257bfca14e70c1db1ff7e2270867788 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 23 Dec 2013 14:09:57 +0400 Subject: [PATCH 161/465] Support for g!=2 in DH --- mtproto-client.c | 4 ++-- queries.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 811ba56..d4521e5 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -441,7 +441,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { assert (decrypt_buffer[5] == (int)CODE_server_DH_inner_data); assert (!memcmp (decrypt_buffer + 6, nonce, 16)); assert (!memcmp (decrypt_buffer + 10, server_nonce, 16)); - assert (decrypt_buffer[14] == 2); + int g = decrypt_buffer[14]; in_ptr = decrypt_buffer + 15; in_end = decrypt_buffer + (l >> 2); BN_init (&dh_prime); @@ -469,7 +469,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { out_long (0LL); BN_init (&dh_g); - BN_set_word (&dh_g, 2); + BN_set_word (&dh_g, g); assert (RAND_pseudo_bytes ((unsigned char *)s_power, 256) >= 0); BIGNUM *dh_power = BN_new (); diff --git a/queries.c b/queries.c index 8ec160d..747c07b 100644 --- a/queries.c +++ b/queries.c @@ -302,8 +302,8 @@ extern struct dc *DC_list[]; extern struct dc *DC_working; void out_random (int n) { - assert (n <= 16); - static char buf[16]; + assert (n <= 32); + static char buf[32]; int i; for (i = 0; i < n; i++) { buf[i] = lrand48 () & 255; @@ -1375,7 +1375,7 @@ void send_part (struct send_file *f) { encr_start (); out_int (CODE_decrypted_message); out_long (r); - out_random (16); + out_random (15 + 4 * (lrand48 () % 3)); out_string (""); if (f->media_type == CODE_input_media_uploaded_photo) { out_int (CODE_decrypted_message_media_photo); From 59a82bbfe94b5a0c57fc74810aefd75f4c6791a3 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 23 Dec 2013 14:45:40 +0400 Subject: [PATCH 162/465] Additional checks in DH --- mtproto-client.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/mtproto-client.c b/mtproto-client.c index d4521e5..3932233 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -416,6 +416,77 @@ int process_respq_answer (struct connection *c, char *packet, int len) { return rpc_send_packet (c); } +int check_DH_params (BIGNUM *p, int g) { + if (g < 2 || g > 7) { return -1; } + BIGNUM t; + BN_init (&t); + + BN_init (&dh_g); + BN_set_word (&dh_g, 4 * g); + + BN_mod (&t, p, &dh_g, BN_ctx); + int x = BN_get_word (&t); + assert (x >= 0 && x < 4 * g); + + BN_clear (&dh_g); + + switch (g) { + case 2: + if (x != 7) { return -1; } + break; + case 3: + if (x % 3 != 2 ) { return -1; } + break; + case 4: + break; + case 5: + if (x % 5 != 1 && x % 5 != 4) { return -1; } + break; + case 6: + if (x != 19 && x != 23) { return -1; } + break; + case 7: + if (x % 7 != 3 && x % 7 != 5 && x % 7 != 6) { return -1; } + break; + } + + if (!BN_is_prime (p, BN_prime_checks, 0, BN_ctx, 0)) { return -1; } + + BIGNUM b; + BN_init (&b); + BN_set_word (&b, 2); + BN_div (&t, 0, p, &b, BN_ctx); + if (!BN_is_prime (&t, BN_prime_checks, 0, BN_ctx, 0)) { return -1; } + BN_clear (&b); + BN_clear (&t); + return 0; +} + +int check_g (BIGNUM *g) { + static unsigned char s[256]; + memset (s, 0, 256); + assert (BN_num_bytes (g) <= 256); + BN_bn2bin (g, s); + int ok = 0; + int i; + for (i = 0; i < 64; i++) { + if (s[i]) { + ok = 1; + break; + } + } + if (!ok) { return -1; } + ok = 0; + for (i = 0; i < 64; i++) { + if (s[255 - i]) { + ok = 1; + break; + } + } + if (!ok) { return -1; } + return 0; +} + int process_dh_answer (struct connection *c, char *packet, int len) { if (verbosity) { logprintf ( "process_dh_answer(), len=%d\n", len); @@ -448,9 +519,12 @@ int process_dh_answer (struct connection *c, char *packet, int len) { BN_init (&g_a); assert (fetch_bignum (&dh_prime) > 0); assert (fetch_bignum (&g_a) > 0); + assert (check_g (&g_a) >= 0); int server_time = *in_ptr++; assert (in_ptr <= in_end); + assert (check_DH_params (&dh_prime, g) >= 0); + static char sha1_buffer[20]; sha1 ((unsigned char *) decrypt_buffer + 20, (in_ptr - decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); assert (!memcmp (decrypt_buffer, sha1_buffer, 20)); From b13434e37873863b960976945b2647b68ad191fe Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 23 Dec 2013 15:10:53 +0400 Subject: [PATCH 163/465] Fixed check g_a in encr chats --- binlog.c | 2 ++ mtproto-client.h | 3 +++ queries.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/binlog.c b/binlog.c index beb7aa3..a71b4a7 100644 --- a/binlog.c +++ b/binlog.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "binlog.h" #include "mtproto-common.h" @@ -525,6 +526,7 @@ void replay_log_event (void) { memcpy (encr_prime, rptr, 256); rptr += 64; encr_param_version = *(rptr ++); + } break; case CODE_binlog_encr_chat_init: diff --git a/mtproto-client.h b/mtproto-client.h index 2a7d7e8..2b603d5 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -20,9 +20,12 @@ #ifndef __MTPROTO_CLIENT_H__ #define __MTPROTO_CLIENT_H__ #include "net.h" +#include void on_start (void); long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); void dc_authorize (struct dc *DC); void work_update (struct connection *c, long long msg_id); void work_update_binlog (void); +int check_g (BIGNUM *g); +int check_DH_params (BIGNUM *p, int g); #endif diff --git a/queries.c b/queries.c index d42c448..41c5025 100644 --- a/queries.c +++ b/queries.c @@ -2270,6 +2270,7 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { assert (b); BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0); assert (g_a); + assert (check_g (g_a) >= 0); if (!ctx) { ctx = BN_CTX_new (); BN_CTX_init (ctx); @@ -2315,6 +2316,7 @@ void do_create_keys_end (struct secret_chat *U) { assert (encr_prime); BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); assert (g_b); + assert (check_g (g_b) >= 0); if (!ctx) { ctx = BN_CTX_new (); BN_CTX_init (ctx); From 039657187799f9b5efa67a8acfa3511c8901e436 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 23 Dec 2013 15:13:43 +0400 Subject: [PATCH 164/465] DH: added check for bad prime in encr chats --- queries.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/queries.c b/queries.c index 41c5025..edbae9c 100644 --- a/queries.c +++ b/queries.c @@ -2429,6 +2429,10 @@ int get_dh_config_on_answer (struct query *q UU) { char *s = fetch_str (l); int v = fetch_int (); bl_do_set_dh_params (a, (void *)s, v); + + BIGNUM *p = BN_bin2bn ((void *)s, 256, 0); + assert (check_DH_params (p, a) >= 0); + BN_free (p); } if (x == LOG_DH_CONFIG) { return 0; } int l = prefetch_strlen (); From 98a6fcb82190f1052cac749196720bfd84b32403 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 24 Dec 2013 00:22:44 +0300 Subject: [PATCH 165/465] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a28410..53c48f0 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,14 @@ or download and extrac zip #### Linux -Just run +Install libs: readline openssl and (if you want to use config) libconfig. +On ubuntu use: + + $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev +On gentoo: + + $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl +Then $ ./configure $ make From 3421589432d1eb0de199ed41d8f2bf7878625b0a Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 24 Dec 2013 04:57:01 +0400 Subject: [PATCH 166/465] Support for layer 11 --- constants.h | 6 ++++-- queries.c | 5 +++-- structures.c | 8 ++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/constants.h b/constants.h index fbd674f..54d7372 100644 --- a/constants.h +++ b/constants.h @@ -229,8 +229,8 @@ #define CODE_update_encrypted_messages_read 0x38fe25b7 #define CODE_encrypted_chat_empty 0xab7ec0a0 #define CODE_encrypted_chat_waiting 0x3bf703dc -#define CODE_encrypted_chat_requested 0xfda9a7b7 -#define CODE_encrypted_chat 0x6601d14f +#define CODE_encrypted_chat_requested 0xc878527e +#define CODE_encrypted_chat 0xfa56ce36 #define CODE_encrypted_chat_discarded 0x13d6dd27 #define CODE_input_encrypted_chat 0xf141b5e1 #define CODE_encrypted_file_empty 0xc21f497e @@ -258,6 +258,7 @@ #define CODE_input_encrypted_file_big_uploaded 0x2dc173c8 #define CODE_update_chat_participant_add 0x3a0eeb22 #define CODE_update_chat_participant_delete 0x6e5f8c22 +#define CODE_update_dc_options 0x8e5e9873 #define CODE_input_media_uploaded_audio 0x61a6d436 #define CODE_input_media_audio 0x89938781 #define CODE_input_media_uploaded_document 0x34e794bd @@ -377,4 +378,5 @@ #define CODE_init_connection 0x69796de9 #define CODE_invoke_with_layer9 0x76715a63 #define CODE_invoke_with_layer10 0x39620c41 +#define CODE_invoke_with_layer11 0xa6b88fdf #endif diff --git a/queries.c b/queries.c index edbae9c..537c324 100644 --- a/queries.c +++ b/queries.c @@ -318,7 +318,7 @@ void out_random (int n) { int allow_send_linux_version; void do_insert_header (void) { - out_int (CODE_invoke_with_layer10); + out_int (CODE_invoke_with_layer11); out_int (CODE_init_connection); out_int (TG_APP_ID); if (allow_send_linux_version) { @@ -2422,6 +2422,7 @@ void do_send_create_encr_chat (void *x, unsigned char *random) { int get_dh_config_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); + logprintf ("old = %d\n", encr_param_version); if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { int a = fetch_int (); int l = prefetch_strlen (); @@ -2432,7 +2433,7 @@ int get_dh_config_on_answer (struct query *q UU) { BIGNUM *p = BN_bin2bn ((void *)s, 256, 0); assert (check_DH_params (p, a) >= 0); - BN_free (p); + BN_free (p); } if (x == LOG_DH_CONFIG) { return 0; } int l = prefetch_strlen (); diff --git a/structures.c b/structures.c index 3c88a24..014a8e9 100644 --- a/structures.c +++ b/structures.c @@ -342,14 +342,14 @@ void fetch_encrypted_chat (struct secret_chat *U) { memcpy (g_key, s + (l - 256), 256); } - l = prefetch_strlen (); + /*l = prefetch_strlen (); s = fetch_str (l); if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); } else { memcpy (nonce, s + (l - 256), 256); - } + }*/ if (x == CODE_encrypted_chat) { fetch_long (); // fingerprint @@ -393,14 +393,14 @@ void fetch_encrypted_chat (struct secret_chat *U) { memcpy (g_key, s + (l - 256), 256); } - l = prefetch_strlen (); + /*l = prefetch_strlen (); s = fetch_str (l); if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); } else { memcpy (nonce, s + (l - 256), 256); - } + }*/ if (x == CODE_encrypted_chat_requested) { return; // Duplicate? From 73b17ee19de89ba4c9f4a1200cd9540a6c933185 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 24 Dec 2013 15:29:18 +0400 Subject: [PATCH 167/465] Added more checks on g_a and g --- interface.c | 2 +- mtproto-client.c | 23 +++++++++++++++++++++-- mtproto-client.h | 3 ++- net.c | 2 +- queries.c | 4 ++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/interface.c b/interface.c index 86ad62b..4141c4f 100644 --- a/interface.c +++ b/interface.c @@ -43,7 +43,7 @@ #include "mtproto-common.h" -#define ALLOW_MULT 1 +//#define ALLOW_MULT 1 char *default_prompt = "> "; int unread_messages; diff --git a/mtproto-client.c b/mtproto-client.c index 3932233..c22bb5a 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -462,7 +462,7 @@ int check_DH_params (BIGNUM *p, int g) { return 0; } -int check_g (BIGNUM *g) { +int check_g (unsigned char p[256], BIGNUM *g) { static unsigned char s[256]; memset (s, 0, 256); assert (BN_num_bytes (g) <= 256); @@ -484,9 +484,28 @@ int check_g (BIGNUM *g) { } } if (!ok) { return -1; } + ok = 0; + for (i = 0; i < 64; i++) { + if (s[i] < p[i]) { + ok = 1; + break; + } else if (s[i] > p[i]) { + logprintf ("i = %d (%d %d)\n", i, (int)s[i], (int)p[i]); + return -1; + } + } + if (!ok) { return -1; } return 0; } +int check_g_bn (BIGNUM *p, BIGNUM *g) { + static unsigned char s[256]; + memset (s, 0, 256); + assert (BN_num_bytes (p) <= 256); + BN_bn2bin (p, s); + return check_g (s, g); +} + int process_dh_answer (struct connection *c, char *packet, int len) { if (verbosity) { logprintf ( "process_dh_answer(), len=%d\n", len); @@ -519,7 +538,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { BN_init (&g_a); assert (fetch_bignum (&dh_prime) > 0); assert (fetch_bignum (&g_a) > 0); - assert (check_g (&g_a) >= 0); + assert (check_g_bn (&dh_prime, &g_a) >= 0); int server_time = *in_ptr++; assert (in_ptr <= in_end); diff --git a/mtproto-client.h b/mtproto-client.h index 2b603d5..458d6c5 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -26,6 +26,7 @@ long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, in void dc_authorize (struct dc *DC); void work_update (struct connection *c, long long msg_id); void work_update_binlog (void); -int check_g (BIGNUM *g); +int check_g (unsigned char p[256], BIGNUM *g); +int check_g_bn (BIGNUM *p, BIGNUM *g); int check_DH_params (BIGNUM *p, int g); #endif diff --git a/net.c b/net.c index e31fda8..4f429f9 100644 --- a/net.c +++ b/net.c @@ -596,7 +596,7 @@ void insert_seqno (struct session *S, int seqno) { extern struct dc *DC_list[]; -struct dc *alloc_dc (int id, char *ip, int port) { +struct dc *alloc_dc (int id, char *ip, int port UU) { assert (!DC_list[id]); struct dc *DC = malloc (sizeof (*DC)); memset (DC, 0, sizeof (*DC)); diff --git a/queries.c b/queries.c index 537c324..ec35d15 100644 --- a/queries.c +++ b/queries.c @@ -2270,7 +2270,7 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { assert (b); BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0); assert (g_a); - assert (check_g (g_a) >= 0); + assert (check_g (encr_prime, g_a) >= 0); if (!ctx) { ctx = BN_CTX_new (); BN_CTX_init (ctx); @@ -2316,7 +2316,7 @@ void do_create_keys_end (struct secret_chat *U) { assert (encr_prime); BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); assert (g_b); - assert (check_g (g_b) >= 0); + assert (check_g (encr_prime, g_b) >= 0); if (!ctx) { ctx = BN_CTX_new (); BN_CTX_init (ctx); From 820ccce22061f7541d8423328d628aa1a70f4366 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 24 Dec 2013 15:58:31 +0400 Subject: [PATCH 168/465] Fixed autocompete in send_document --- interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/interface.c b/interface.c index 4141c4f..a535e82 100644 --- a/interface.c +++ b/interface.c @@ -354,6 +354,7 @@ int commands_flags[] = { 07, 07, 07, + 07, 0732, 07, 07, From f8793376a5a4956c9203bfe89e4d1c0a6121afd2 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 25 Dec 2013 03:42:05 +0400 Subject: [PATCH 169/465] Fixed random on sensible parts (generation auth_key, session_id and keys for secret chats) --- main.c | 4 ++++ mtproto-client.c | 19 ++++++++++++++----- mtproto-client.h | 1 + queries.c | 6 ++++-- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/main.c b/main.c index 1de65d8..f0cd56d 100644 --- a/main.c +++ b/main.c @@ -78,6 +78,7 @@ char *binlog_file_name; int binlog_enabled; extern int log_level; int sync_from_start; +int allow_weak_random; void set_default_username (const char *s) { if (default_username) { @@ -375,6 +376,9 @@ void args_parse (int argc, char **argv) { case 'E': disable_auto_accept = 1; break; + case 'w': + allow_weak_random = 1; + break; case 'h': default: usage (); diff --git a/mtproto-client.c b/mtproto-client.c index c22bb5a..a010d85 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -69,7 +69,7 @@ char new_nonce[256]; char server_nonce[256]; extern int binlog_enabled; extern int disable_auto_accept; - +extern int allow_weak_random; int total_packets_sent; long long total_data_sent; @@ -98,6 +98,15 @@ double get_utime (int clock_id) { return res; } +void do_rand (void *s, int l) { + if (RAND_bytes (s, l) < 0) { + if (allow_weak_random) { + RAND_pseudo_bytes (s, l); + } else { + assert (0 && "End of random. If you want, you can start with -w"); + } + } +} #define STATS_BUFF_SIZE (64 << 10) @@ -223,7 +232,7 @@ int rpc_send_message (struct connection *c, void *data, int len) { int send_req_pq_packet (struct connection *c) { assert (c_state == st_init); - assert (RAND_pseudo_bytes ((unsigned char *) nonce, 16) >= 0); + do_rand (nonce, 16); unenc_msg_header.out_msg_id = 0; clear_packet (); out_int (CODE_req_pq); @@ -371,7 +380,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { //out_int (0x0501); // q=5 out_ints ((int *) nonce, 4); out_ints ((int *) server_nonce, 4); - assert (RAND_pseudo_bytes ((unsigned char *) new_nonce, 32) >= 0); + do_rand (new_nonce, 32); out_ints ((int *) new_nonce, 8); sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); @@ -564,7 +573,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { BN_init (&dh_g); BN_set_word (&dh_g, g); - assert (RAND_pseudo_bytes ((unsigned char *)s_power, 256) >= 0); + do_rand (s_power, 256); BIGNUM *dh_power = BN_new (); assert (BN_bin2bn ((unsigned char *)s_power, 256, dh_power) == dh_power); @@ -683,7 +692,7 @@ void init_enc_msg (struct session *S, int useful) { // assert (DC->server_salt); enc_msg.server_salt = DC->server_salt; if (!S->session_id) { - assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); + do_rand (&S->session_id, 8); } enc_msg.session_id = S->session_id; //enc_msg.auth_key_id2 = auth_key_id; diff --git a/mtproto-client.h b/mtproto-client.h index 458d6c5..5f04dea 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -29,4 +29,5 @@ void work_update_binlog (void); int check_g (unsigned char p[256], BIGNUM *g); int check_g_bn (BIGNUM *p, BIGNUM *g); int check_DH_params (BIGNUM *p, int g); +void do_rand (void *s, int l); #endif diff --git a/queries.c b/queries.c index ec35d15..3719de7 100644 --- a/queries.c +++ b/queries.c @@ -2263,8 +2263,10 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { } } if (ok) { return; } // Already generated key for this chat - for (i = 0; i < 64; i++) { - *(((int *)random) + i) ^= mrand48 (); + unsigned char random_here[256]; + do_rand (random_here, 256); + for (i = 0; i < 256; i++) { + random[i] ^= random_here[i]; } BIGNUM *b = BN_bin2bn (random, 256, 0); assert (b); From 5cde89b5c881ce92d4cba052c178769c9b1cabac Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 25 Dec 2013 04:44:36 +0400 Subject: [PATCH 170/465] do_rand () renamed to secure_random () --- mtproto-client.c | 10 +++++----- mtproto-client.h | 2 +- queries.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index a010d85..906efbe 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -98,7 +98,7 @@ double get_utime (int clock_id) { return res; } -void do_rand (void *s, int l) { +void secure_random (void *s, int l) { if (RAND_bytes (s, l) < 0) { if (allow_weak_random) { RAND_pseudo_bytes (s, l); @@ -232,7 +232,7 @@ int rpc_send_message (struct connection *c, void *data, int len) { int send_req_pq_packet (struct connection *c) { assert (c_state == st_init); - do_rand (nonce, 16); + secure_random (nonce, 16); unenc_msg_header.out_msg_id = 0; clear_packet (); out_int (CODE_req_pq); @@ -380,7 +380,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { //out_int (0x0501); // q=5 out_ints ((int *) nonce, 4); out_ints ((int *) server_nonce, 4); - do_rand (new_nonce, 32); + secure_random (new_nonce, 32); out_ints ((int *) new_nonce, 8); sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); @@ -573,7 +573,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { BN_init (&dh_g); BN_set_word (&dh_g, g); - do_rand (s_power, 256); + secure_random (s_power, 256); BIGNUM *dh_power = BN_new (); assert (BN_bin2bn ((unsigned char *)s_power, 256, dh_power) == dh_power); @@ -692,7 +692,7 @@ void init_enc_msg (struct session *S, int useful) { // assert (DC->server_salt); enc_msg.server_salt = DC->server_salt; if (!S->session_id) { - do_rand (&S->session_id, 8); + secure_random (&S->session_id, 8); } enc_msg.session_id = S->session_id; //enc_msg.auth_key_id2 = auth_key_id; diff --git a/mtproto-client.h b/mtproto-client.h index 5f04dea..0782b7b 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -29,5 +29,5 @@ void work_update_binlog (void); int check_g (unsigned char p[256], BIGNUM *g); int check_g_bn (BIGNUM *p, BIGNUM *g); int check_DH_params (BIGNUM *p, int g); -void do_rand (void *s, int l); +void secure_random (void *s, int l); #endif diff --git a/queries.c b/queries.c index 3719de7..51ab012 100644 --- a/queries.c +++ b/queries.c @@ -2264,7 +2264,7 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { } if (ok) { return; } // Already generated key for this chat unsigned char random_here[256]; - do_rand (random_here, 256); + secure_random (random_here, 256); for (i = 0; i < 256; i++) { random[i] ^= random_here[i]; } From 5ea4683d16d666e0f575d310638b3e42f8449825 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 25 Dec 2013 12:35:13 +0400 Subject: [PATCH 171/465] Fixed secure random. --- queries.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/queries.c b/queries.c index 51ab012..962ccd5 100644 --- a/queries.c +++ b/queries.c @@ -1505,16 +1505,11 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { if (get_peer_type (f->to_id) == PEER_ENCR_CHAT) { f->encr = 1; f->iv = malloc (32); - int i; - for (i = 0; i < 8; i++) { - ((int *)f->iv)[i] = mrand48 (); - } + secure_random (f->iv, 32); f->init_iv = malloc (32); memcpy (f->init_iv, f->iv, 32); f->key = malloc (32); - for (i = 0; i < 8; i++) { - ((int *)f->key)[i] = mrand48 (); - } + secure_random (f->key, 32); } if (f->part_size > (512 << 10)) { close (fd); @@ -2362,8 +2357,10 @@ void do_create_keys_end (struct secret_chat *U) { void do_send_create_encr_chat (void *x, unsigned char *random) { int user_id = (long)x; int i; - for (i = 0; i < 64; i++) { - *(((int *)random) + i) ^= mrand48 (); + unsigned char random_here[256]; + secure_random (random_here, 256); + for (i = 0; i < 256; i++) { + random[i] ^= random_here[i]; } if (!ctx) { ctx = BN_CTX_new (); From cb29ce45235bc2acd672e166b85cf8752fcc3843 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 25 Dec 2013 12:56:46 +0400 Subject: [PATCH 172/465] Some other things changed to secure_random --- queries.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/queries.c b/queries.c index 962ccd5..af48ff3 100644 --- a/queries.c +++ b/queries.c @@ -310,9 +310,7 @@ void out_random (int n) { assert (n <= 32); static char buf[32]; int i; - for (i = 0; i < n; i++) { - buf[i] = lrand48 () & 255; - } + secure_random (buf, n); out_cstring (buf, n); } @@ -771,8 +769,8 @@ void encr_start (void) { void encr_finish (struct secret_chat *E) { int l = packet_ptr - (encr_extra + 8); - while (((packet_ptr - encr_extra) - 3) & 3) { - out_int (mrand48 ()); + while (((packet_ptr - encr_extra) - 3) & 3) { + out_rand (4); } *encr_extra = ((packet_ptr - encr_extra) - 1) * 4 * 256 + 0xfe; @@ -883,10 +881,7 @@ void do_send_encr_msg (struct message *M) { out_int (CODE_decrypted_message); out_long (M->id); static int buf[4]; - int i; - for (i = 0; i < 3; i++) { - buf[i] = mrand48 (); - } + secure_random (buf, 16); out_cstring ((void *)buf, 16); out_cstring ((void *)M->message, M->message_len); out_int (CODE_decrypted_message_media_empty); @@ -1299,8 +1294,9 @@ void send_part (struct send_file *f) { if (f->encr) { if (x & 15) { assert (f->offset == f->size); - while (x & 15) { - buf[x ++] = lrand48 () & 255; + if (x & 15) { + secure_random (buf + x, (-x) & 15); + x = (x + 15) & ~15; } } @@ -1375,7 +1371,7 @@ void send_part (struct send_file *f) { peer_t *P = user_chat_get (f->to_id); assert (P); out_long (P->encr_chat.access_hash); - long long r = -lrand48 () * (1ll << 32) - lrand48 (); + long long r = -lrand48 () * (1ll << 32) - lrand48 (); out_long (r); encr_start (); out_int (CODE_decrypted_message); From df3dc013061f5fdce9498319b1f0cd610a9e5a79 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 25 Dec 2013 13:07:10 +0400 Subject: [PATCH 173/465] Fixed CE --- queries.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/queries.c b/queries.c index af48ff3..bd5a86d 100644 --- a/queries.c +++ b/queries.c @@ -309,7 +309,6 @@ extern struct dc *DC_working; void out_random (int n) { assert (n <= 32); static char buf[32]; - int i; secure_random (buf, n); out_cstring (buf, n); } @@ -770,7 +769,9 @@ void encr_start (void) { void encr_finish (struct secret_chat *E) { int l = packet_ptr - (encr_extra + 8); while (((packet_ptr - encr_extra) - 3) & 3) { - out_rand (4); + int t; + secure_random (&t, 4); + out_int (t); } *encr_extra = ((packet_ptr - encr_extra) - 1) * 4 * 256 + 0xfe; From 567afd1aa578b4750ac2d4febf43f8d73fef426a Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 26 Dec 2013 19:08:35 +0300 Subject: [PATCH 174/465] fixed Typo in Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53c48f0..0be4923 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Clone GitHub Repository $ git clone https://github.com/vysheng/tg.git && cd tg -or download and extrac zip +or download and extract zip $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip $ tar xzf tg-master.zip && cd tg-master From 2cfe58c1a97e9d743a40c34125fc4d77b3a38aea Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 2 Jan 2014 22:52:41 +0400 Subject: [PATCH 175/465] fixed acks --- mtproto-client.c | 34 +++++++++++++++++++++++++++------- net.c | 35 ++++++++++++++++++++++++++--------- net.h | 6 +++--- 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index c22bb5a..67174d5 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1416,9 +1416,10 @@ void work_container (struct connection *c, long long msg_id UU) { int i; for (i = 0; i < n; i++) { long long id = fetch_long (); - int seqno = fetch_int (); - if (seqno & 1) { - insert_seqno (c->session, seqno); + //int seqno = fetch_int (); + fetch_int (); // seq_no + if (id & 1) { + insert_msg_id (c->session, id); } int bytes = fetch_int (); int *t = in_end; @@ -1537,7 +1538,7 @@ void work_detailed_info (struct connection *c UU, long long msg_id UU) { } void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == CODE_msg_detailed_info); + assert (fetch_int () == (int)CODE_msg_new_detailed_info); fetch_long (); // answer_msg_id fetch_int (); // bytes fetch_int (); // status @@ -1548,6 +1549,15 @@ void work_updates_to_long (struct connection *c UU, long long msg_id UU) { logprintf ("updates to long... Getting difference\n"); do_get_difference (); } + +void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { + assert (fetch_int () == (int)CODE_bad_msg_notification); + long long m1 = fetch_long (); + int s = fetch_int (); + int e = fetch_int (); + logprintf ("bad_msg_notification: msg_id = %lld, seq = %d, error = %d\n", m1, s, e); +} + void rpc_execute_answer (struct connection *c, long long msg_id UU) { if (verbosity >= 5) { logprintf ("rpc_execute_answer: fd=%d\n", c->fd); @@ -1597,6 +1607,9 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { case CODE_updates_too_long: work_updates_to_long (c, msg_id); return; + case CODE_bad_msg_notification: + work_bad_msg_notification (c, msg_id); + return; } logprintf ( "Unknown message: \n"); hexdump_in (); @@ -1629,10 +1642,17 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int this_server_time = enc->msg_id >> 32LL; if (!DC->server_time_delta) { - DC->server_time_delta = this_server_time - time (0); + DC->server_time_delta = this_server_time - get_utime (CLOCK_REALTIME); DC->server_time_udelta = this_server_time - get_utime (CLOCK_MONOTONIC); } double st = get_server_time (DC); + if (this_server_time < st - 300 || this_server_time > st + 30) { + logprintf ("salt = %lld, session_id = %lld, msg_id = %lld, seq_no = %d, st = %lf, now = %lf\n", enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); + in_ptr = enc->message; + in_end = in_ptr + (enc->msg_len / 4); + hexdump_in (); + } + assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); if (verbosity >= 1) { @@ -1651,8 +1671,8 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, in_ptr = enc->message; in_end = in_ptr + (enc->msg_len / 4); - if (enc->seq_no & 1) { - insert_seqno (c->session, enc->seq_no); + if (enc->msg_id & 1) { + insert_msg_id (c->session, enc->msg_id); } assert (c->session->session_id == enc->session_id); rpc_execute_answer (c, enc->msg_id); diff --git a/net.c b/net.c index 4f429f9..c6643f6 100644 --- a/net.c +++ b/net.c @@ -44,7 +44,8 @@ #define POLLRDHUP 0 #endif -DEFINE_TREE(int,int,int_cmp,0) +#define long_cmp(a,b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1) +DEFINE_TREE(long,long long,long_cmp,0) double get_utime (int clock_id); int verbosity; @@ -208,6 +209,20 @@ void flush_out (struct connection *c UU) { struct connection *Connections[MAX_CONNECTIONS]; int max_connection_fd; +void rotate_port (struct connection *c) { + switch (c->port) { + case 443: + c->port = 80; + break; + case 80: + c->port = 25; + break; + case 25: + c->port = 443; + break; + } +} + struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods) { struct connection *c = malloc (sizeof (*c)); memset (c, 0, sizeof (*c)); @@ -332,6 +347,7 @@ void fail_connection (struct connection *c) { if (c->state == conn_ready || c->state == conn_connecting) { stop_ping_timer (c); } + rotate_port (c); struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; @@ -349,7 +365,7 @@ void fail_connection (struct connection *c) { c->out_bytes = c->in_bytes = 0; close (c->fd); Connections[c->fd] = 0; - logprintf ("Lost connection to server... \n"); + logprintf ("Lost connection to server... %s:%d\n", c->ip, c->port); restart_connection (c); } @@ -572,25 +588,26 @@ void connections_poll_result (struct pollfd *fds, int max) { int send_all_acks (struct session *S) { clear_packet (); out_int (CODE_msgs_ack); - out_int (tree_count_int (S->ack_tree)); + out_int (CODE_vector); + out_int (tree_count_long (S->ack_tree)); while (S->ack_tree) { - int x = tree_get_min_int (S->ack_tree); - out_int (x); - S->ack_tree = tree_delete_int (S->ack_tree, x); + long long x = tree_get_min_long (S->ack_tree); + out_long (x); + S->ack_tree = tree_delete_long (S->ack_tree, x); } encrypt_send_message (S->c, packet_buffer, packet_ptr - packet_buffer, 0); return 0; } -void insert_seqno (struct session *S, int seqno) { +void insert_msg_id (struct session *S, long long id) { if (!S->ack_tree) { S->ev.alarm = (void *)send_all_acks; S->ev.self = (void *)S; S->ev.timeout = get_double_time () + ACK_TIMEOUT; insert_event_timer (&S->ev); } - if (!tree_lookup_int (S->ack_tree, seqno)) { - S->ack_tree = tree_insert_int (S->ack_tree, seqno, lrand48 ()); + if (!tree_lookup_long (S->ack_tree, id)) { + S->ack_tree = tree_insert_long (S->ack_tree, id, lrand48 ()); } } diff --git a/net.h b/net.h index 1fda52a..69a473b 100644 --- a/net.h +++ b/net.h @@ -30,7 +30,7 @@ struct dc; #define TG_VERSION "0.01-beta" -#define ACK_TIMEOUT 60 +#define ACK_TIMEOUT 1 #define MAX_DC_ID 10 enum dc_state { @@ -57,7 +57,7 @@ struct session { long long session_id; int seq_no; struct connection *c; - struct tree_int *ack_tree; + struct tree_long *ack_tree; struct event_timer ev; }; @@ -143,7 +143,7 @@ struct connection *create_connection (const char *host, int port, struct session int connections_make_poll_array (struct pollfd *fds, int max); void connections_poll_result (struct pollfd *fds, int max); void dc_create_session (struct dc *DC); -void insert_seqno (struct session *S, int seqno); +void insert_msg_id (struct session *S, long long id); struct dc *alloc_dc (int id, char *ip, int port); #define GET_DC(c) (c->session->dc) From bb24fba98f88f28adecf97587f39267bc703d477 Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 15:32:57 +0400 Subject: [PATCH 176/465] check return values of strdup and malloc add talloc0 function (malloc and zero fill) check return values of arithmetic openssl BN_* functions check return values of BN_bin2bn function remove useless BN_init calls right after BN_new fix 2 small memory leaks --- Makefile | 2 +- Makefile.in | 2 +- binlog.c | 71 +++++++++++++++---------------------- interface.c | 12 +++---- loop.c | 16 ++++----- main.c | 15 ++++---- mtproto-client.c | 21 +++++------ mtproto-common.c | 3 +- mtproto-common.h | 5 +-- net.c | 16 ++++----- queries.c | 91 +++++++++++++++++++++++++----------------------- structures.c | 68 ++++++++++++++---------------------- tools.c | 66 +++++++++++++++++++++++++++++++++++ tools.h | 29 +++++++++++++++ 14 files changed, 240 insertions(+), 177 deletions(-) create mode 100644 tools.c create mode 100644 tools.h diff --git a/Makefile b/Makefile index ba848c9..47ce820 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h INCLUDE=-I. -I${srcdir} CC=gcc -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o .SUFFIXES: diff --git a/Makefile.in b/Makefile.in index 7c6589d..7898905 100644 --- a/Makefile.in +++ b/Makefile.in @@ -13,7 +13,7 @@ LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o .SUFFIXES: diff --git a/binlog.c b/binlog.c index a71b4a7..0414fa1 100644 --- a/binlog.c +++ b/binlog.c @@ -183,7 +183,7 @@ void replay_log_event (void) { memcpy (U->key, rptr, 256); rptr += 64; if (!U->g_key) { - U->g_key = malloc (256); + U->g_key = talloc (256); } memcpy (U->g_key, rptr, 256); rptr += 64; @@ -196,8 +196,7 @@ void replay_log_event (void) { struct secret_chat *U = (void *)user_chat_get (id); assert (!U || !(U->flags & FLAG_CREATED)); if (!U) { - U = malloc (sizeof (peer_t)); - memset (U, 0, sizeof (peer_t)); + U = talloc0 (sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); } @@ -223,8 +222,7 @@ void replay_log_event (void) { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); if (!U) { - U = malloc (sizeof (peer_t)); - memset (U, 0, sizeof (peer_t)); + U = talloc0 (sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); } @@ -252,8 +250,7 @@ void replay_log_event (void) { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); if (!U) { - U = malloc (sizeof (peer_t)); - memset (U, 0, sizeof (peer_t)); + U = talloc0 (sizeof (peer_t)); U->id = id; insert_encrypted_chat ((void *)U); } @@ -291,8 +288,7 @@ void replay_log_event (void) { peer_id_t id = MK_USER (fetch_int ()); peer_t *_U = user_chat_get (id); if (!_U) { - _U = malloc (sizeof (*_U)); - memset (_U, 0, sizeof (*_U)); + _U = talloc0 (sizeof (*_U)); _U->id = id; insert_user (_U); } else { @@ -418,8 +414,7 @@ void replay_log_event (void) { peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); peer_t *_U = user_chat_get (id); if (!_U) { - _U = malloc (sizeof (*_U)); - memset (_U, 0, sizeof (*_U)); + _U = talloc0 (sizeof (*_U)); _U->id = id; insert_encrypted_chat (_U); } else { @@ -440,8 +435,8 @@ void replay_log_event (void) { sprintf (buf, "user#%d", U->user_id); U->print_name = create_print_name (id, "!", buf, 0, 0); } - U->g_key = malloc (256); - U->nonce = malloc (256); + U->g_key = talloc (256); + U->nonce = talloc (256); memcpy (U->g_key, rptr, 256); rptr += 64; memcpy (U->nonce, rptr, 256); @@ -487,10 +482,10 @@ void replay_log_event (void) { assert (_U); struct secret_chat *U = &_U->encr_chat; if (!U->g_key) { - U->g_key = malloc (256); + U->g_key = talloc (256); } if (!U->nonce) { - U->nonce = malloc (256); + U->nonce = talloc (256); } memcpy (U->g_key, rptr, 256); rptr += 64; @@ -522,7 +517,7 @@ void replay_log_event (void) { { if (encr_prime) { free (encr_prime); } encr_root = *(rptr ++); - encr_prime = malloc (256); + encr_prime = talloc (256); memcpy (encr_prime, rptr, 256); rptr += 64; encr_param_version = *(rptr ++); @@ -532,8 +527,7 @@ void replay_log_event (void) { case CODE_binlog_encr_chat_init: rptr ++; { - peer_t *P = malloc (sizeof (*P)); - memset (P, 0, sizeof (*P)); + peer_t *P = talloc0 (sizeof (*P)); P->id = MK_ENCR_CHAT (*(rptr ++)); assert (!user_chat_get (P->id)); P->encr_chat.user_id = *(rptr ++); @@ -544,7 +538,7 @@ void replay_log_event (void) { P->print_name = create_print_name (P->id, "!", Us->user.first_name, Us->user.last_name, 0); memcpy (P->encr_chat.key, rptr, 256); rptr += 64; - P->encr_chat.g_key = malloc (256); + P->encr_chat.g_key = talloc (256); memcpy (P->encr_chat.g_key, rptr, 256); rptr += 64; P->flags |= FLAG_CREATED; @@ -572,8 +566,7 @@ void replay_log_event (void) { 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 = talloc0 (sizeof (*_C)); _C->id = id; insert_chat (_C); } else { @@ -655,7 +648,7 @@ void replay_log_event (void) { 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); + C->chat.user_list = talloc (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; }; @@ -738,8 +731,7 @@ void replay_log_event (void) { } struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; @@ -756,7 +748,7 @@ void replay_log_event (void) { M->date = fetch_int (); int l = prefetch_strlen (); - M->message = malloc (l + 1); + M->message = talloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; @@ -783,8 +775,7 @@ void replay_log_event (void) { int id = fetch_int (); struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; @@ -800,7 +791,7 @@ void replay_log_event (void) { M->fwd_date = fetch_int (); int l = prefetch_strlen (); - M->message = malloc (l + 1); + M->message = talloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; @@ -819,8 +810,7 @@ void replay_log_event (void) { int id = fetch_int (); struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; @@ -834,7 +824,7 @@ void replay_log_event (void) { M->date = fetch_int (); int l = prefetch_strlen (); - M->message = malloc (l + 1); + M->message = talloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; @@ -853,8 +843,7 @@ void replay_log_event (void) { long long id = fetch_long (); struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; @@ -868,7 +857,7 @@ void replay_log_event (void) { M->date = fetch_int (); int l = prefetch_strlen (); - M->message = malloc (l + 1); + M->message = talloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; @@ -889,8 +878,7 @@ void replay_log_event (void) { int id = fetch_int (); struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; @@ -906,7 +894,7 @@ void replay_log_event (void) { M->fwd_date = fetch_int (); int l = prefetch_strlen (); - M->message = malloc (l + 1); + M->message = talloc (l + 1); memcpy (M->message, fetch_str (l), l); M->message[l] = 0; M->message_len = l; @@ -925,8 +913,7 @@ void replay_log_event (void) { int id = fetch_int (); struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; @@ -954,8 +941,7 @@ void replay_log_event (void) { long long id = fetch_long (); struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; @@ -984,8 +970,7 @@ void replay_log_event (void) { int id = fetch_int (); struct message *M = message_get (id); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); messages_allocated ++; diff --git a/interface.c b/interface.c index a535e82..65a5f56 100644 --- a/interface.c +++ b/interface.c @@ -413,7 +413,7 @@ int complete_user_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = strdup (Peers[index]->print_name); + *R = tstrdup (Peers[index]->print_name); return index; } else { return -1; @@ -426,7 +426,7 @@ int complete_chat_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = strdup (Peers[index]->print_name); + *R = tstrdup (Peers[index]->print_name); return index; } else { return -1; @@ -439,7 +439,7 @@ int complete_encr_chat_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = strdup (Peers[index]->print_name); + *R = tstrdup (Peers[index]->print_name); return index; } else { return -1; @@ -452,7 +452,7 @@ int complete_user_chat_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = strdup (Peers[index]->print_name); + *R = tstrdup (Peers[index]->print_name); return index; } else { return -1; @@ -465,7 +465,7 @@ int complete_string_list (char **list, int index, const char *text, int len, cha index ++; } if (list[index]) { - *R = strdup (list[index]); + *R = tstrdup (list[index]); return index; } else { *R = 0; @@ -1100,7 +1100,7 @@ void print_start (void) { rl_replace_line("", 0); #else assert (rl_end >= 0); - saved_line = malloc (rl_end + 1); + saved_line = talloc (rl_end + 1); memcpy (saved_line, rl_line_buffer, rl_end + 1); rl_line_buffer[0] = 0; set_prompt (""); diff --git a/loop.c b/loop.c index f4b5fef..71c4746 100644 --- a/loop.c +++ b/loop.c @@ -200,7 +200,7 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { int l = 0; assert (read (auth_file_fd, &l, 4) == 4); assert (l >= 0); - char *ip = malloc (l + 1); + char *ip = talloc (l + 1); assert (read (auth_file_fd, ip, l) == l); ip[l] = 0; struct dc *DC = alloc_dc (id, ip, port); @@ -218,8 +218,7 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { } void empty_auth_file (void) { - struct dc *DC = alloc_dc (1, strdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); - assert (DC); + alloc_dc (1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); dc_working_num = 1; auth_state = 0; write_auth_file (); @@ -338,8 +337,7 @@ void read_secret_chat_file (void) { assert (read (fd, &cc, 4) == 4); int i; for (i = 0; i < cc; i++) { - peer_t *P = malloc (sizeof (*P)); - memset (P, 0, sizeof (*P)); + peer_t *P = talloc0 (sizeof (*P)); struct secret_chat *E = &P->encr_chat; int t; assert (read (fd, &t, 4) == 4); @@ -347,7 +345,7 @@ void read_secret_chat_file (void) { assert (read (fd, &P->flags, 4) == 4); assert (read (fd, &t, 4) == 4); assert (t > 0); - P->print_name = malloc (t + 1); + P->print_name = talloc (t + 1); assert (read (fd, P->print_name, t) == t); P->print_name[t] = 0; @@ -358,9 +356,9 @@ void read_secret_chat_file (void) { assert (read (fd, &E->access_hash, 8) == 8); if (E->state != sc_waiting) { - E->g_key = malloc (256); + E->g_key = talloc (256); assert (read (fd, E->g_key, 256) == 256); - E->nonce = malloc (256); + E->nonce = talloc (256); assert (read (fd, E->nonce, 256) == 256); } assert (read (fd, E->key, 256) == 256); @@ -371,7 +369,7 @@ void read_secret_chat_file (void) { assert (read (fd, &encr_root, 4) == 4); if (encr_root) { assert (read (fd, &encr_param_version, 4) == 4); - encr_prime = malloc (256); + encr_prime = talloc (256); assert (read (fd, encr_prime, 256) == 256); } } diff --git a/main.c b/main.c index f0cd56d..4c6841f 100644 --- a/main.c +++ b/main.c @@ -45,6 +45,7 @@ #include "loop.h" #include "mtproto-client.h" #include "interface.h" +#include "tools.h" #define PROGNAME "telegram-client" #define VERSION "0.01" @@ -84,7 +85,7 @@ void set_default_username (const char *s) { if (default_username) { free (default_username); } - default_username = strdup (s); + default_username = tstrdup (s); } @@ -236,13 +237,13 @@ void parse_config_val (config_t *conf, char **s, char *param_name, const char *d if (path) { assert (asprintf (s, "%s/%s", path, r) >= 0); } else { - *s = strdup (r); + *s = tstrdup (r); } } else { if (path) { assert (asprintf (s, "%s/%s", path, default_name) >= 0); } else { - *s = strdup (default_name); + *s = tstrdup (default_name); } } } @@ -338,7 +339,7 @@ void args_parse (int argc, char **argv) { set_default_username (optarg); break; case 'k': - rsa_public_key_name = strdup (optarg); + rsa_public_key_name = tstrdup (optarg); break; case 'v': verbosity ++; @@ -347,10 +348,10 @@ void args_parse (int argc, char **argv) { msg_num_mode ++; break; case 'c': - config_filename = strdup (optarg); + config_filename = tstrdup (optarg); break; case 'p': - prefix = strdup (optarg); + prefix = tstrdup (optarg); assert (strlen (prefix) <= 100); break; case 'l': @@ -369,7 +370,7 @@ void args_parse (int argc, char **argv) { if (log_net_file) { usage (); } - log_net_file = strdup (optarg); + log_net_file = tstrdup (optarg); log_net_f = fopen (log_net_file, "a"); assert (log_net_f); break; diff --git a/mtproto-client.c b/mtproto-client.c index 54fde7a..3fc865c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -431,9 +431,9 @@ int check_DH_params (BIGNUM *p, int g) { BN_init (&t); BN_init (&dh_g); - BN_set_word (&dh_g, 4 * g); + ensure (BN_set_word (&dh_g, 4 * g)); - BN_mod (&t, p, &dh_g, BN_ctx); + ensure (BN_mod (&t, p, &dh_g, BN_ctx)); int x = BN_get_word (&t); assert (x >= 0 && x < 4 * g); @@ -463,8 +463,8 @@ int check_DH_params (BIGNUM *p, int g) { BIGNUM b; BN_init (&b); - BN_set_word (&b, 2); - BN_div (&t, 0, p, &b, BN_ctx); + ensure (BN_set_word (&b, 2)); + ensure (BN_div (&t, 0, p, &b, BN_ctx)); if (!BN_is_prime (&t, BN_prime_checks, 0, BN_ctx, 0)) { return -1; } BN_clear (&b); BN_clear (&t); @@ -571,19 +571,20 @@ int process_dh_answer (struct connection *c, char *packet, int len) { out_long (0LL); BN_init (&dh_g); - BN_set_word (&dh_g, g); + ensure (BN_set_word (&dh_g, g)); secure_random (s_power, 256); - BIGNUM *dh_power = BN_new (); - assert (BN_bin2bn ((unsigned char *)s_power, 256, dh_power) == dh_power); + BIGNUM *dh_power = BN_bin2bn ((unsigned char *)s_power, 256, 0); + ensure_ptr (dh_power); BIGNUM *y = BN_new (); - assert (BN_mod_exp (y, &dh_g, dh_power, &dh_prime, BN_ctx) == 1); + ensure_ptr (y); + ensure (BN_mod_exp (y, &dh_g, dh_power, &dh_prime, BN_ctx)); out_bignum (y); BN_free (y); BN_init (&auth_key_num); - assert (BN_mod_exp (&auth_key_num, &g_a, dh_power, &dh_prime, BN_ctx) == 1); + ensure (BN_mod_exp (&auth_key_num, &g_a, dh_power, &dh_prime, BN_ctx)); l = BN_num_bytes (&auth_key_num); assert (l >= 250 && l <= 256); assert (BN_bn2bin (&auth_key_num, (unsigned char *)GET_DC(c)->auth_key)); @@ -1098,7 +1099,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { bl_do_set_chat_admin (&C->chat, fetch_int ()); assert (fetch_int () == CODE_vector); n = fetch_int (); - struct chat_user *users = malloc (12 * n); + struct chat_user *users = talloc (12 * n); int i; for (i = 0; i < n; i++) { assert (fetch_int () == (int)CODE_chat_participant); diff --git a/mtproto-common.c b/mtproto-common.c index 07d073c..2d87f83 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -102,8 +102,7 @@ void my_clock_gettime (int clock_id UU, struct timespec *T) { void prng_seed (const char *password_filename, int password_length) { - unsigned char *a = calloc (64 + password_length, 1); - assert (a != NULL); + unsigned char *a = talloc0 (64 + password_length); long long r = rdtsc (); struct timespec T; my_clock_gettime (CLOCK_REALTIME, &T); diff --git a/mtproto-common.h b/mtproto-common.h index b811ecc..0b8bffd 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -27,6 +27,7 @@ #include #include "interface.h" +#include "tools.h" #include "constants.h" /* DH key exchange protocol data structures */ #define CODE_req_pq 0x60469778 @@ -305,7 +306,7 @@ static inline char *fetch_str (int len) { static inline char *fetch_str_dup (void) { int l = prefetch_strlen (); assert (l >= 0); - char *s = malloc (l + 1); + char *s = talloc (l + 1); memcpy (s, fetch_str (l), l); s[l] = 0; return s; @@ -320,7 +321,7 @@ static inline int fetch_update_str (char **s) { char *r = fetch_str (l); if (memcmp (*s, r, l) || (*s)[l]) { free (*s); - *s = malloc (l + 1); + *s = talloc (l + 1); memcpy (*s, r, l); (*s)[l] = 0; return 1; diff --git a/net.c b/net.c index c6643f6..3ecfa51 100644 --- a/net.c +++ b/net.c @@ -103,9 +103,8 @@ void start_fail_timer (struct connection *c) { } struct connection_buffer *new_connection_buffer (int size) { - struct connection_buffer *b = malloc (sizeof (*b)); - memset (b, 0, sizeof (*b)); - b->start = malloc (size); + struct connection_buffer *b = talloc0 (sizeof (*b)); + b->start = talloc (size); b->end = b->start + size; b->rptr = b->wptr = b->start; return b; @@ -224,8 +223,7 @@ void rotate_port (struct connection *c) { } struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods) { - struct connection *c = malloc (sizeof (*c)); - memset (c, 0, sizeof (*c)); + struct connection *c = talloc0 (sizeof (*c)); int fd = socket (AF_INET, SOCK_STREAM, 0); if (fd == -1) { logprintf ("Can not create socket: %m\n"); @@ -276,7 +274,7 @@ struct connection *create_connection (const char *host, int port, struct session c->session = session; c->fd = fd; - c->ip = strdup (host); + c->ip = tstrdup (host); c->flags = 0; c->state = conn_ready; c->methods = methods; @@ -615,8 +613,7 @@ extern struct dc *DC_list[]; struct dc *alloc_dc (int id, char *ip, int port UU) { assert (!DC_list[id]); - struct dc *DC = malloc (sizeof (*DC)); - memset (DC, 0, sizeof (*DC)); + struct dc *DC = talloc0 (sizeof (*DC)); DC->id = id; DC->ip = ip; DC->port = port; @@ -625,8 +622,7 @@ struct dc *alloc_dc (int id, char *ip, int port UU) { } void dc_create_session (struct dc *DC) { - struct session *S = malloc (sizeof (*S)); - memset (S, 0, sizeof (*S)); + struct session *S = talloc0 (sizeof (*S)); assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); S->dc = DC; S->c = create_connection (DC->ip, DC->port, S, &auth_methods); diff --git a/queries.c b/queries.c index bd5a86d..72d6962 100644 --- a/queries.c +++ b/queries.c @@ -126,10 +126,9 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth if (verbosity) { logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } - struct query *q = malloc (sizeof (*q)); - memset (q, 0, sizeof (*q)); + struct query *q = talloc0 (sizeof (*q)); q->data_len = ints; - q->data = malloc (4 * ints); + q->data = talloc (4 * ints); memcpy (q->data, data, 4 * ints); q->msg_id = encrypt_send_message (DC->sessions[0]->c, data, ints, 1); q->session = DC->sessions[0]; @@ -436,7 +435,7 @@ char *suser; extern int dc_working_num; void do_send_code (const char *user) { logprintf ("sending code\n"); - suser = strdup (user); + suser = tstrdup (user); want_dc_num = 0; clear_packet (); do_insert_header (); @@ -527,7 +526,7 @@ struct query_methods check_phone_methods = { }; int do_auth_check_phone (const char *user) { - suser = strdup (user); + suser = tstrdup (user); clear_packet (); out_int (CODE_auth_check_phone); out_string (user); @@ -1363,8 +1362,7 @@ void send_part (struct send_file *f) { out_long (-lrand48 () * (1ll << 32) - lrand48 ()); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); } else { - struct message *M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + struct message *M = talloc0 (sizeof (*M)); out_int (CODE_messages_send_encrypted_file); out_int (CODE_input_encrypted_chat); @@ -1446,7 +1444,7 @@ void send_part (struct send_file *f) { M->from_id = MK_USER (our_id); M->to_id = f->to_id; M->unread = 1; - M->message = strdup (""); + M->message = tstrdup (""); M->out = 1; M->id = r; M->date = time (0); @@ -1483,8 +1481,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { close (fd); return; } - struct send_file *f = malloc (sizeof (*f)); - memset (f, 0, sizeof (*f)); + struct send_file *f = talloc0 (sizeof (*f)); f->fd = fd; f->size = size; f->offset = 0; @@ -1501,11 +1498,11 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { f->file_name = file_name; if (get_peer_type (f->to_id) == PEER_ENCR_CHAT) { f->encr = 1; - f->iv = malloc (32); + f->iv = talloc (32); secure_random (f->iv, 32); - f->init_iv = malloc (32); + f->init_iv = talloc (32); memcpy (f->init_iv, f->iv, 32); - f->key = malloc (32); + f->key = talloc (32); secure_random (f->key, 32); } if (f->part_size > (512 << 10)) { @@ -1831,7 +1828,7 @@ void load_next_part (struct download *D) { } else { sprintf (buf, "%s/download_%lld", get_downloads_directory (), D->id); } - D->name = strdup (buf); + D->name = tstrdup (buf); struct stat st; if (stat (buf, &st) >= 0) { D->offset = st.st_size; @@ -1878,8 +1875,7 @@ void do_load_photo_size (struct photo_size *P, int next) { assert (P); assert (next); - struct download *D = malloc (sizeof (*D)); - memset (D, 0, sizeof (*D)); + struct download *D = talloc0 (sizeof (*D)); D->id = 0; D->offset = 0; D->size = P->size; @@ -1918,8 +1914,7 @@ void do_load_document_thumb (struct document *video, int next) { void do_load_video (struct video *V, int next) { assert (V); assert (next); - struct download *D = malloc (sizeof (*D)); - memset (D, 0, sizeof (*D)); + struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; @@ -1935,8 +1930,7 @@ void do_load_video (struct video *V, int next) { void do_load_document (struct document *V, int next) { assert (V); assert (next); - struct download *D = malloc (sizeof (*D)); - memset (D, 0, sizeof (*D)); + struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; @@ -1952,8 +1946,7 @@ void do_load_document (struct document *V, int next) { void do_load_encr_video (struct encr_video *V, int next) { assert (V); assert (next); - struct download *D = malloc (sizeof (*D)); - memset (D, 0, sizeof (*D)); + struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; @@ -1963,7 +1956,7 @@ void do_load_encr_video (struct encr_video *V, int next) { D->name = 0; D->fd = -1; D->key = V->key; - D->iv = malloc (32); + D->iv = talloc (32); memcpy (D->iv, V->iv, 32); load_next_part (D); @@ -1995,7 +1988,7 @@ int export_auth_on_answer (struct query *q UU) { assert (our_id == l); } l = prefetch_strlen (); - char *s = malloc (l); + char *s = talloc (l); memcpy (s, fetch_str (l), l); export_auth_str_len = l; export_auth_str = s; @@ -2261,18 +2254,19 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { random[i] ^= random_here[i]; } BIGNUM *b = BN_bin2bn (random, 256, 0); - assert (b); + ensure_ptr (b); BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0); - assert (g_a); + ensure_ptr (g_a); assert (check_g (encr_prime, g_a) >= 0); if (!ctx) { ctx = BN_CTX_new (); - BN_CTX_init (ctx); + ensure_ptr (ctx); } BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + ensure_ptr (p); BIGNUM *r = BN_new (); - BN_init (r); - BN_mod_exp (r, g_a, b, p, ctx); + ensure_ptr (r); + ensure (BN_mod_exp (r, g_a, b, p, ctx)); static unsigned char kk[256]; memset (kk, 0, sizeof (kk)); BN_bn2bin (r, kk); @@ -2290,8 +2284,8 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { out_int (get_peer_id (E->id)); out_long (E->access_hash); - BN_set_word (g_a, encr_root); - BN_mod_exp (r, g_a, b, p, ctx); + ensure (BN_set_word (g_a, encr_root)); + ensure (BN_mod_exp (r, g_a, b, p, ctx)); static unsigned char buf[256]; memset (buf, 0, sizeof (buf)); BN_bn2bin (r, buf); @@ -2309,19 +2303,21 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { void do_create_keys_end (struct secret_chat *U) { assert (encr_prime); BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); - assert (g_b); + ensure_ptr (g_b); assert (check_g (encr_prime, g_b) >= 0); if (!ctx) { ctx = BN_CTX_new (); - BN_CTX_init (ctx); + ensure_ptr (ctx); } BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + ensure_ptr (p); BIGNUM *r = BN_new (); + ensure_ptr (r); BIGNUM *a = BN_bin2bn ((void *)U->key, 256, 0); - BN_init (r); - BN_mod_exp (r, g_b, a, p, ctx); + ensure_ptr (a); + ensure (BN_mod_exp (r, g_b, a, p, ctx)); - void *t = malloc (256); + void *t = talloc (256); memcpy (t, U->key, 256); memset (U->key, 0, sizeof (U->key)); @@ -2344,6 +2340,9 @@ void do_create_keys_end (struct secret_chat *U) { logprintf ("!!Key fingerprint mismatch (my 0x%llx 0x%llx)\n", (unsigned long long)k, (unsigned long long)U->key_fingerprint); U->state = sc_deleted; } + + memset (t, 0, 256); + free (t); BN_clear_free (p); BN_clear_free (g_b); @@ -2361,21 +2360,24 @@ void do_send_create_encr_chat (void *x, unsigned char *random) { } if (!ctx) { ctx = BN_CTX_new (); - BN_CTX_init (ctx); + ensure_ptr (ctx); } BIGNUM *a = BN_bin2bn (random, 256, 0); - assert (a); + ensure_ptr (a); BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + ensure_ptr (p); BIGNUM *g = BN_new (); - BN_init (g); + ensure_ptr (g); - BN_set_word (g, encr_root); + ensure (BN_set_word (g, encr_root)); BIGNUM *r = BN_new (); - BN_init (r); + ensure_ptr (r); - BN_mod_exp (r, g, a, p, ctx); + ensure (BN_mod_exp (r, g, a, p, ctx)); + + BN_clear_free (a); static char g_a[256]; memset (g_a, 0, 256); @@ -2428,6 +2430,7 @@ int get_dh_config_on_answer (struct query *q UU) { bl_do_set_dh_params (a, (void *)s, v); BIGNUM *p = BN_bin2bn ((void *)s, 256, 0); + ensure_ptr (p); assert (check_DH_params (p, a) >= 0); BN_free (p); } @@ -2457,7 +2460,7 @@ void do_accept_encr_chat_request (struct secret_chat *E) { out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - void **x = malloc (2 * sizeof (void *)); + void **x = talloc (2 * sizeof (void *)); x[0] = do_send_accept_encr_chat; x[1] = E; send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); @@ -2468,7 +2471,7 @@ void do_create_encr_chat_request (int user_id) { out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - void **x = malloc (2 * sizeof (void *)); + void **x = talloc (2 * sizeof (void *)); x[0] = do_send_create_encr_chat; x[1] = (void *)(long)(user_id); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); diff --git a/structures.c b/structures.c index 014a8e9..2992fe7 100644 --- a/structures.c +++ b/structures.c @@ -179,7 +179,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha assert (cc <= 9999); sprintf (s + fl, "#%d", cc); } - return strdup (s); + return tstrdup (s); } /* @@ -564,7 +564,7 @@ void fetch_chat_full (struct chat *C) { admin_id = fetch_int (); assert (fetch_int () == CODE_vector); users_num = fetch_int (); - users = malloc (sizeof (struct chat_user) * users_num); + users = talloc (sizeof (struct chat_user) * users_num); int i; for (i = 0; i < users_num; i++) { assert (fetch_int () == (int)CODE_chat_participant); @@ -613,8 +613,7 @@ void fetch_photo_size (struct photo_size *S) { S->size = fetch_int (); } else { S->size = prefetch_strlen (); -// S->data = malloc (S->size); -// assert (S->data); +// S->data = talloc (S->size); fetch_str (S->size); // memcpy (S->data, fetch_str (S->size), S->size); } @@ -671,7 +670,7 @@ void fetch_photo (struct photo *P) { fetch_geo (&P->geo); assert (fetch_int () == CODE_vector); P->sizes_num = fetch_int (); - P->sizes = malloc (sizeof (struct photo_size) * P->sizes_num); + P->sizes = talloc (sizeof (struct photo_size) * P->sizes_num); int i; for (i = 0; i < P->sizes_num; i++) { fetch_photo_size (&P->sizes[i]); @@ -795,7 +794,7 @@ void fetch_message_action (struct message_action *M) { M->title = fetch_str_dup (); assert (fetch_int () == (int)CODE_vector); M->user_num = fetch_int (); - M->users = malloc (M->user_num * 4); + M->users = talloc (M->user_num * 4); fetch_ints (M->users, M->user_num); break; case CODE_message_action_chat_edit_title: @@ -1092,14 +1091,14 @@ void fetch_message_media_encrypted (struct message_media *M) { l = prefetch_strlen (); assert (l > 0); - M->encr_photo.key = malloc (32); + M->encr_photo.key = talloc (32); memset (M->encr_photo.key, 0, 32); if (l <= 32) { memcpy (M->encr_photo.key + (32 - l), fetch_str (l), l); } else { memcpy (M->encr_photo.key, fetch_str (l) + (l - 32), 32); } - M->encr_photo.iv = malloc (32); + M->encr_photo.iv = talloc (32); l = prefetch_strlen (); assert (l > 0); memset (M->encr_photo.iv, 0, 32); @@ -1122,14 +1121,13 @@ void fetch_message_media_encrypted (struct message_media *M) { l = prefetch_strlen (); assert (l > 0); - M->encr_video.key = malloc (32); - memset (M->encr_photo.key, 0, 32); + M->encr_video.key = talloc0 (32); if (l <= 32) { memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); } else { memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); } - M->encr_video.iv = malloc (32); + M->encr_video.iv = talloc (32); l = prefetch_strlen (); assert (l > 0); memset (M->encr_video.iv, 0, 32); @@ -1146,17 +1144,15 @@ void fetch_message_media_encrypted (struct message_media *M) { l = prefetch_strlen (); assert (l > 0); - M->encr_video.key = malloc (32); - memset (M->encr_photo.key, 0, 32); + M->encr_video.key = talloc0 (32); if (l <= 32) { memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); } else { memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); } - M->encr_video.iv = malloc (32); + M->encr_video.iv = talloc0 (32); l = prefetch_strlen (); assert (l > 0); - memset (M->encr_video.iv, 0, 32); if (l <= 32) { memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); } else { @@ -1175,17 +1171,15 @@ void fetch_message_media_encrypted (struct message_media *M) { l = prefetch_strlen (); assert (l > 0); - M->encr_video.key = malloc (32); - memset (M->encr_photo.key, 0, 32); + M->encr_video.key = talloc0 (32); if (l <= 32) { memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); } else { memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); } - M->encr_video.iv = malloc (32); + M->encr_video.iv = talloc0 (32); l = prefetch_strlen (); assert (l > 0); - memset (M->encr_video.iv, 0, 32); if (l <= 32) { memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); } else { @@ -1199,12 +1193,12 @@ void fetch_message_media_encrypted (struct message_media *M) { fetch_str (l); // thumb l = fetch_int (); assert (l > 0); - M->encr_file.key = malloc (l); + M->encr_file.key = talloc (l); memcpy (M->encr_file.key, fetch_str (l), l); l = fetch_int (); assert (l > 0); - M->encr_file.iv = malloc (l); + M->encr_file.iv = talloc (l); memcpy (M->encr_file.iv, fetch_str (l), l); break; */ @@ -1521,8 +1515,7 @@ struct user *fetch_alloc_user (void) { peer_t *U = user_chat_get (MK_USER (data[1])); if (!U) { users_allocated ++; - U = malloc (sizeof (*U)); - memset (U, 0, sizeof (*U)); + U = talloc0 (sizeof (*U)); U->id = MK_USER (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); assert (peer_num < MAX_PEER_NUM); @@ -1537,8 +1530,7 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) { prefetch_data (data, 8); peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); if (!U) { - U = malloc (sizeof (*U)); - memset (U, 0, sizeof (*U)); + U = talloc0 (sizeof (*U)); U->id = MK_ENCR_CHAT (data[1]); encr_chats_allocated ++; peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); @@ -1579,8 +1571,7 @@ struct user *fetch_alloc_user_full (void) { return &U->user; } else { users_allocated ++; - U = malloc (sizeof (*U)); - memset (U, 0, sizeof (*U)); + U = talloc0 (sizeof (*U)); U->id = MK_USER (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_user_full (&U->user); @@ -1724,8 +1715,7 @@ void message_add_peer (struct message *M) { } peer_t *P = user_chat_get (id); if (!P) { - P = malloc (sizeof (*P)); - memset (P, 0, sizeof (*P)); + P = talloc0 (sizeof (*P)); P->id = id; switch (get_peer_type (id)) { case PEER_USER: @@ -1799,8 +1789,7 @@ struct message *fetch_alloc_message (void) { struct message *M = message_get (data[1]); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = data[1]; message_insert_tree (M); messages_allocated ++; @@ -1810,7 +1799,7 @@ struct message *fetch_alloc_message (void) { } struct message *fetch_alloc_geo_message (void) { - struct message *M = malloc (sizeof (*M)); + struct message *M = talloc (sizeof (*M)); fetch_geo_message (M); struct message *M1 = tree_lookup_message (message_tree, M); messages_allocated ++; @@ -1838,8 +1827,7 @@ struct message *fetch_alloc_encrypted_message (void) { struct message *M = message_get (*(long long *)(data + 1)); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = *(long long *)(data + 1); message_insert_tree (M); messages_allocated ++; @@ -1856,8 +1844,7 @@ struct message *fetch_alloc_message_short (void) { struct message *M = message_get (data[0]); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = data[0]; message_insert_tree (M); messages_allocated ++; @@ -1872,8 +1859,7 @@ struct message *fetch_alloc_message_short_chat (void) { struct message *M = message_get (data[0]); if (!M) { - M = malloc (sizeof (*M)); - memset (M, 0, sizeof (*M)); + M = talloc0 (sizeof (*M)); M->id = data[0]; message_insert_tree (M); messages_allocated ++; @@ -1888,8 +1874,7 @@ struct chat *fetch_alloc_chat (void) { peer_t *U = user_chat_get (MK_CHAT (data[1])); if (!U) { chats_allocated ++; - U = malloc (sizeof (*U)); - memset (U, 0, sizeof (*U)); + U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); assert (peer_num < MAX_PEER_NUM); @@ -1908,8 +1893,7 @@ struct chat *fetch_alloc_chat_full (void) { return &U->chat; } else { chats_allocated ++; - U = malloc (sizeof (*U)); - memset (U, 0, sizeof (*U)); + U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); fetch_chat_full (&U->chat); diff --git a/tools.c b/tools.c new file mode 100644 index 0000000..bcaa527 --- /dev/null +++ b/tools.c @@ -0,0 +1,66 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ + +#include +#include +#include +#include +#include + +#include "interface.h" +#include "tools.h" + +static void out_of_memory (void) { + logprintf ("Out of memory\n"); + assert (0 && "Out of memory"); +} + +void *talloc (size_t size) { + void *p = malloc (size); + ensure_ptr (p); + return p; +} + +void *talloc0 (size_t size) { + void *p = talloc (size); + memset (p, 0, size); + return p; +} + +char *tstrdup (const char *s) { + char *p = strdup (s); + if (p == NULL) { + out_of_memory (); + } + return p; +} + +void ensure (int r) { + if (!r) { + logprintf ("Open SSL error\n"); + ERR_print_errors_fp (stderr); + assert (0); + } +} + +void ensure_ptr (void *p) { + if (p == NULL) { + out_of_memory (); + } +} diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..f3f7f88 --- /dev/null +++ b/tools.h @@ -0,0 +1,29 @@ +/* + This file is part of telegram-client. + + Telegram-client is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Telegram-client is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this telegram-client. If not, see . + + Copyright Vitaly Valtman 2013 +*/ + +#ifndef __TOOLS_H__ +#define __TOOLS_H__ + +void *talloc (size_t size); +void *talloc0 (size_t size); +char *tstrdup (const char *s); +void ensure (int r); +void ensure_ptr (void *p); + +#endif From 35923482bc696825f8b8673e045e0e887dbf7781 Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 15:40:28 +0400 Subject: [PATCH 177/465] close /etc/passwd file handle right after evaluating home directory --- main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 4c6841f..e57da3b 100644 --- a/main.c +++ b/main.c @@ -120,16 +120,25 @@ void set_terminal_attributes (void) { /* }}} */ char *get_home_directory (void) { + static char *home_directory = NULL; + if (home_directory != NULL) { + return home_directory; + } struct passwd *current_passwd; uid_t user_id; setpwent (); user_id = getuid (); while ((current_passwd = getpwent ())) { if (current_passwd->pw_uid == user_id) { - return current_passwd->pw_dir; + home_directory = tstrdup (current_passwd->pw_dir); + break; } } - return ""; + endpwent (); + if (home_directory == NULL) { + home_directory = tstrdup ("."); + } + return home_directory; } char *get_config_directory (void) { From 933a65c335c787b9f2dc80cca88bc0785390ecbe Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 15:46:46 +0400 Subject: [PATCH 178/465] fix small memory leak in running_for_first_time (local variable config_directory) --- main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index e57da3b..4d74782 100644 --- a/main.c +++ b/main.c @@ -143,12 +143,7 @@ char *get_home_directory (void) { char *get_config_directory (void) { char *config_directory; - int length = strlen (get_home_directory ()) + strlen (CONFIG_DIRECTORY) + 2; - - config_directory = (char *) calloc (length, sizeof (char)); - sprintf (config_directory, "%s/" CONFIG_DIRECTORY, - get_home_directory ()); - + assert (asprintf (&config_directory, "%s/" CONFIG_DIRECTORY, get_home_directory ()) >= 0); return config_directory; } @@ -201,6 +196,8 @@ void running_for_first_time (void) { printf ("[%s] created\n", config_directory); } + free (config_directory); + config_directory = NULL; // see if config file is there if (stat (config_filename, &config_file_stat) != 0) { // config file missing, so touch it From e1c750ad7ff554091af0addb8e21c7be3a0e48bb Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 15:59:48 +0400 Subject: [PATCH 179/465] add length modifier to the format for strings in sprintf call --- queries.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries.c b/queries.c index 72d6962..5856f36 100644 --- a/queries.c +++ b/queries.c @@ -321,8 +321,8 @@ void do_insert_header (void) { struct utsname st; uname (&st); out_string (st.machine); - static char buf[1000000]; - sprintf (buf, "%s %s %s", st.sysname, st.release, st.version); + static char buf[65536]; + sprintf (buf, "%999s %999s %999s", st.sysname, st.release, st.version); out_string (buf); out_string (TG_VERSION " (build " TG_BUILD ")"); out_string ("En"); From 206fa4323222f86097890a117ee41e51f291e49f Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 16:05:39 +0400 Subject: [PATCH 180/465] replace sprintf call with snprintf for downloaded part name --- queries.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/queries.c b/queries.c index 5856f36..bf1af61 100644 --- a/queries.c +++ b/queries.c @@ -1822,11 +1822,16 @@ struct query_methods download_methods = { void load_next_part (struct download *D) { if (!D->offset) { - static char buf[1000]; + static char buf[PATH_MAX]; + int l; if (!D->id) { - sprintf (buf, "%s/download_%lld_%d", get_downloads_directory (), D->volume, D->local_id); + l = snprintf (buf, sizeof (buf), "%s/download_%lld_%d", get_downloads_directory (), D->volume, D->local_id); } else { - sprintf (buf, "%s/download_%lld", get_downloads_directory (), D->id); + l = snprintf (buf, sizeof (buf), "%s/download_%lld", get_downloads_directory (), D->id); + } + if (l >= (int) sizeof (buf)) { + logprintf ("Download filename is too long"); + exit (1); } D->name = tstrdup (buf); struct stat st; From 70441cfcdf82891f782014b540d4714cd6c980d2 Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 16:15:59 +0400 Subject: [PATCH 181/465] replace sprintf call with snprintf for open image command --- queries.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/queries.c b/queries.c index bf1af61..e602f55 100644 --- a/queries.c +++ b/queries.c @@ -1764,12 +1764,15 @@ void end_load (struct download *D) { if (D->next == 1) { logprintf ("Done: %s\n", D->name); } else if (D->next == 2) { - static char buf[1000]; - sprintf (buf, OPEN_BIN, D->name); - int x = system (buf); - if (x < 0) { - logprintf ("Can not open image viewer: %m\n"); - logprintf ("Image is at %s\n", D->name); + static char buf[PATH_MAX]; + if (snprintf (buf, sizeof (buf), OPEN_BIN, D->name) >= (int) sizeof (buf)) { + logprintf ("Open image command buffer overflow\n"); + } else { + int x = system (buf); + if (x < 0) { + logprintf ("Can not open image viewer: %m\n"); + logprintf ("Image is at %s\n", D->name); + } } } if (D->iv) { From e8943b5aa1a7010fb02e42f24cd161025f51bfa2 Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 16:21:34 +0400 Subject: [PATCH 182/465] remove undefined behavior flush (stdin) call http://stackoverflow.com/questions/2979209/using-fflushstdin --- loop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/loop.c b/loop.c index 71c4746..6742763 100644 --- a/loop.c +++ b/loop.c @@ -570,7 +570,6 @@ int loop (void) { } write_auth_file (); - fflush (stdin); fflush (stdout); fflush (stderr); From c9c8daac458a7eaa6cc986b5083fbb17ffc2454c Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 16:30:56 +0400 Subject: [PATCH 183/465] checking sizeof (void) at the runtime --- main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.c b/main.c index 4d74782..56094cc 100644 --- a/main.c +++ b/main.c @@ -181,6 +181,11 @@ char *make_full_path (char *s) { } void running_for_first_time (void) { + if (sizeof (void) != 1) { + logprintf ("sizeof (void) isn't equal 1\n"); + logprintf ("GNU C compiler extension isn't available?\n"); + exit (1); + } if (config_filename) { return; // Do not create custom config file } From f2f4153d007142a8c53da6b11a588683e264a782 Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 16:37:07 +0400 Subject: [PATCH 184/465] add field limit for sscanf call (fix libc versions older than 2.13-25) --- interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 65a5f56..c3b7cc6 100644 --- a/interface.c +++ b/interface.c @@ -560,7 +560,7 @@ void interpreter_chat_mode (char *line) { } if (!strncmp (line, "/history", 8)) { int limit = 40; - sscanf (line, "/history %d", &limit); + sscanf (line, "/history %99d", &limit); if (limit < 0 || limit > 1000) { limit = 40; } do_get_history (chat_mode_id, limit); return; From fad27bbd39cd949ccec697ae6f09c9cd6b6d06bf Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 10 Jan 2014 17:03:47 +0400 Subject: [PATCH 185/465] Fixed CE. Fixed tree.h to use talloc --- queries.c | 4 ++++ tree.h | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/queries.c b/queries.c index e602f55..7eaff00 100644 --- a/queries.c +++ b/queries.c @@ -27,6 +27,10 @@ #include #include +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + #include "include.h" #include "mtproto-client.h" #include "queries.h" diff --git a/tree.h b/tree.h index 2c86e1c..f75449b 100644 --- a/tree.h +++ b/tree.h @@ -21,9 +21,7 @@ #include #include -#ifdef HAVE_MALLOC_H -#include -#endif +#include #include #define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ @@ -34,7 +32,7 @@ struct tree_ ## X_NAME { \ };\ \ struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ - struct tree_ ## X_NAME *T = malloc (sizeof (*T));\ + struct tree_ ## X_NAME *T = talloc (sizeof (*T));\ T->x = x;\ T->y = y;\ T->left = T->right = 0;\ From 692c9274ce85815171796f0584684487439ac82e Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 10 Jan 2014 17:08:12 +0400 Subject: [PATCH 186/465] realloc->trealloc --- binlog.c | 4 ++-- tools.c | 6 ++++++ tools.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/binlog.c b/binlog.c index 0414fa1..49dfee0 100644 --- a/binlog.c +++ b/binlog.c @@ -685,7 +685,7 @@ void replay_log_event (void) { 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 = trealloc (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; @@ -715,7 +715,7 @@ void replay_log_event (void) { } 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 = trealloc (C->user_list, 12 * C->user_list_size); C->user_list_version = version; } break; diff --git a/tools.c b/tools.c index bcaa527..748edd5 100644 --- a/tools.c +++ b/tools.c @@ -31,6 +31,12 @@ static void out_of_memory (void) { assert (0 && "Out of memory"); } +void *trealloc (void *ptr, size_t size) { + void *p = realloc (ptr, size); + ensure_ptr (p); + return p; +} + void *talloc (size_t size) { void *p = malloc (size); ensure_ptr (p); diff --git a/tools.h b/tools.h index f3f7f88..9753b86 100644 --- a/tools.h +++ b/tools.h @@ -21,6 +21,7 @@ #define __TOOLS_H__ void *talloc (size_t size); +void *trealloc (void *ptr, size_t size); void *talloc0 (size_t size); char *tstrdup (const char *s); void ensure (int r); From feed5229b5843c1a48857b46fc1d20df0d491167 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 10 Jan 2014 18:37:56 +0400 Subject: [PATCH 187/465] free->tfree. Memory checks, if compiled with -DDEBUG --- binlog.c | 34 +++++++++++------------- interface.c | 33 ++++++++++++----------- loop.c | 4 +-- main.c | 26 +++++++++--------- mtproto-client.c | 10 +++---- mtproto-common.c | 3 +-- mtproto-common.h | 2 +- net.c | 8 +++--- queries.c | 51 ++++++++++++++++++----------------- structures.c | 60 +++++++++++++++++++++-------------------- structures.h | 1 + tools.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++- tools.h | 10 ++++++- tree.h | 2 +- 14 files changed, 195 insertions(+), 118 deletions(-) diff --git a/binlog.c b/binlog.c index 49dfee0..883f5d5 100644 --- a/binlog.c +++ b/binlog.c @@ -210,7 +210,7 @@ void replay_log_event (void) { U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); } else { static char buf[100]; - sprintf (buf, "user#%d", U->user_id); + tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = create_print_name (U->id, "!", buf, 0, 0); } } @@ -266,7 +266,7 @@ void replay_log_event (void) { U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); } else { static char buf[100]; - sprintf (buf, "user#%d", U->user_id); + tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = create_print_name (U->id, "!", buf, 0, 0); } } @@ -335,7 +335,7 @@ void replay_log_event (void) { peer_id_t id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (id); assert (U); - if (U->user.phone) { free (U->user.phone); } + if (U->user.phone) { tfree_str (U->user.phone); } U->user.phone = fetch_str_dup (); } rptr = in_ptr; @@ -379,8 +379,8 @@ void replay_log_event (void) { peer_id_t id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (id); assert (U); - if (U->user.real_first_name) { free (U->user.real_first_name); } - if (U->user.real_last_name) { free (U->user.real_last_name); } + if (U->user.real_first_name) { tfree_str (U->user.real_first_name); } + if (U->user.real_last_name) { tfree_str (U->user.real_last_name); } U->user.real_first_name = fetch_str_dup (); U->user.real_last_name = fetch_str_dup (); } @@ -397,13 +397,11 @@ void replay_log_event (void) { U->flags |= FLAG_DELETED; U->state = sc_deleted; if (U->nonce) { - memset (U->nonce, 0, 256); - free (U->nonce); + tfree_secure (U->nonce, 256); U->nonce = 0; } if (U->g_key) { - memset (U->g_key, 0, 256); - free (U->g_key); + tfree_secure (U->g_key, 256); U->g_key = 0; } } @@ -431,8 +429,8 @@ void replay_log_event (void) { if (Us) { U->print_name = create_print_name (id, "!", Us->user.first_name, Us->user.last_name, 0); } else { - static char buf[20]; - sprintf (buf, "user#%d", U->user_id); + static char buf[100]; + tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = create_print_name (id, "!", buf, 0, 0); } U->g_key = talloc (256); @@ -515,7 +513,7 @@ void replay_log_event (void) { case CODE_binlog_set_dh_params: rptr ++; { - if (encr_prime) { free (encr_prime); } + if (encr_prime) { tfree_str (encr_prime); } encr_root = *(rptr ++); encr_prime = talloc (256); memcpy (encr_prime, rptr, 256); @@ -599,7 +597,7 @@ void replay_log_event (void) { 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); } + if (C->title) { tfree_str (C->title); } C->title = fetch_str_dup (); C->print_title = create_print_name (C->id, C->title, 0, 0, 0); }; @@ -646,8 +644,8 @@ void replay_log_event (void) { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.user_list_version = *(rptr ++); + if (C->chat.user_list) { tfree (C->chat.user_list, 12 * C->chat.user_list_size); } C->chat.user_list_size = *(rptr ++); - if (C->chat.user_list) { free (C->chat.user_list); } C->chat.user_list = talloc (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; @@ -685,7 +683,7 @@ void replay_log_event (void) { assert (C->user_list[i].user_id != user); } C->user_list_size ++; - C->user_list = trealloc (C->user_list, 12 * C->user_list_size); + C->user_list = trealloc (C->user_list, 12 * C->user_list_size - 12, 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; @@ -715,7 +713,7 @@ void replay_log_event (void) { } assert (C->user_list[C->user_list_size - 1].user_id == user); C->user_list_size --; - C->user_list = trealloc (C->user_list, 12 * C->user_list_size); + C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); C->user_list_version = version; } break; @@ -1026,7 +1024,7 @@ void replay_log_event (void) { M->id = *(rptr ++); if (message_get (M->id)) { free_message (M); - free (M); + tfree (M, sizeof (*M)); } else { message_insert_tree (M); message_add_peer (M); @@ -1046,7 +1044,7 @@ void replay_log_event (void) { message_remove_tree (M); message_del_peer (M); free_message (M); - free (M); + tfree (M, sizeof (*M)); } break; case CODE_update_user_photo: diff --git a/interface.c b/interface.c index c3b7cc6..53a245c 100644 --- a/interface.c +++ b/interface.c @@ -214,29 +214,29 @@ char *get_default_prompt (void) { if (in_chat_mode) { peer_t *U = user_chat_get (chat_mode_id); assert (U && U->print_name); - l += sprintf (buf + l, COLOR_RED "%.*s " COLOR_NORMAL, 100, U->print_name); + l += tsnprintf (buf + l, 999 - l, COLOR_RED "%.*s " COLOR_NORMAL, 100, U->print_name); } if (unread_messages || cur_uploading_bytes || cur_downloading_bytes) { - l += sprintf (buf + l, COLOR_RED "["); + l += tsnprintf (buf + l, 999 - l, COLOR_RED "["); int ok = 0; if (unread_messages) { - l += sprintf (buf + l, "%d unread", unread_messages); + l += tsnprintf (buf + l, 999 - l, "%d unread", unread_messages); ok = 1; } if (cur_uploading_bytes) { if (ok) { *(buf + l) = ' '; l ++; } ok = 1; - l += sprintf (buf + l, "%lld%%Up", 100 * cur_uploaded_bytes / cur_uploading_bytes); + l += tsnprintf (buf + l, 999 - l, "%lld%%Up", 100 * cur_uploaded_bytes / cur_uploading_bytes); } if (cur_downloading_bytes) { if (ok) { *(buf + l) = ' '; l ++; } ok = 1; - l += sprintf (buf + l, "%lld%%Down", 100 * cur_downloaded_bytes / cur_downloading_bytes); + l += tsnprintf (buf + l, 999 - l, "%lld%%Down", 100 * cur_downloaded_bytes / cur_downloading_bytes); } - l += sprintf (buf + l, "]" COLOR_NORMAL); + l += tsnprintf (buf + l, 999 - l, "]" COLOR_NORMAL); return buf; } - l += sprintf (buf + l, "%s", default_prompt); + l += tsnprintf (buf + l, 999 - l, "%s", default_prompt); return buf; } @@ -413,7 +413,7 @@ int complete_user_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = tstrdup (Peers[index]->print_name); + *R = strdup (Peers[index]->print_name); return index; } else { return -1; @@ -426,7 +426,7 @@ int complete_chat_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = tstrdup (Peers[index]->print_name); + *R = strdup (Peers[index]->print_name); return index; } else { return -1; @@ -439,7 +439,7 @@ int complete_encr_chat_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = tstrdup (Peers[index]->print_name); + *R = strdup (Peers[index]->print_name); return index; } else { return -1; @@ -452,7 +452,7 @@ int complete_user_chat_list (int index, const char *text, int len, char **R) { index ++; } if (index < peer_num) { - *R = tstrdup (Peers[index]->print_name); + *R = strdup (Peers[index]->print_name); return index; } else { return -1; @@ -465,7 +465,7 @@ int complete_string_list (char **list, int index, const char *text, int len, cha index ++; } if (list[index]) { - *R = tstrdup (list[index]); + *R = strdup (list[index]); return index; } else { *R = 0; @@ -505,7 +505,7 @@ char *command_generator (const char *text, int state) { if (c) { rl_line_buffer[rl_point] = c; } return R; case 1: - index = complete_user_list (index, text, len, &R); + index = complete_user_list (index, text, len, &R); if (c) { rl_line_buffer[rl_point] = c; } return R; case 2: @@ -1095,7 +1095,10 @@ void print_start (void) { if (readline_active) { saved_point = rl_point; #ifdef READLINE_GNU - saved_line = rl_copy_text(0, rl_end); + saved_line = talloc (rl_end + 1); + saved_line[rl_end] = 0; + memcpy (saved_line, rl_line_buffer, rl_end); + rl_save_prompt(); rl_replace_line("", 0); #else @@ -1122,7 +1125,7 @@ void print_end (void) { #endif rl_point = saved_point; rl_redisplay(); - free(saved_line); + tfree_str (saved_line); } prompt_was = 0; } diff --git a/loop.c b/loop.c index 6742763..104c30a 100644 --- a/loop.c +++ b/loop.c @@ -510,7 +510,7 @@ int loop (void) { break; } printf ("Invalid code. Try again: "); - free (code); + tfree_str (code); } auth_state = 300; } else { @@ -556,7 +556,7 @@ int loop (void) { break; } printf ("Invalid code. Try again: "); - free (code); + tfree_str (code); } auth_state = 300; } diff --git a/main.c b/main.c index 56094cc..fa5178b 100644 --- a/main.c +++ b/main.c @@ -83,7 +83,7 @@ int allow_weak_random; void set_default_username (const char *s) { if (default_username) { - free (default_username); + tfree_str (default_username); } default_username = tstrdup (s); } @@ -143,7 +143,7 @@ char *get_home_directory (void) { char *get_config_directory (void) { char *config_directory; - assert (asprintf (&config_directory, "%s/" CONFIG_DIRECTORY, get_home_directory ()) >= 0); + tasprintf (&config_directory, "%s/" CONFIG_DIRECTORY, get_home_directory ()); return config_directory; } @@ -174,8 +174,8 @@ char *get_binlog_file_name (void) { char *make_full_path (char *s) { if (*s != '/') { char *t = s; - assert (asprintf (&s, "%s/%s", get_home_directory (), s) >= 0); - free (t); + tasprintf (&s, "%s/%s", get_home_directory (), s); + tfree_str (t); } return s; } @@ -189,7 +189,7 @@ void running_for_first_time (void) { if (config_filename) { return; // Do not create custom config file } - assert (asprintf (&config_filename, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, CONFIG_FILE) >= 0); + tasprintf (&config_filename, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, CONFIG_FILE); config_filename = make_full_path (config_filename); static struct stat config_file_stat; @@ -201,7 +201,7 @@ void running_for_first_time (void) { printf ("[%s] created\n", config_directory); } - free (config_directory); + tfree_str (config_directory); config_directory = NULL; // see if config file is there if (stat (config_filename, &config_file_stat) != 0) { @@ -246,13 +246,13 @@ void parse_config_val (config_t *conf, char **s, char *param_name, const char *d config_lookup_string (conf, buf, &r); if (r) { if (path) { - assert (asprintf (s, "%s/%s", path, r) >= 0); + tasprintf (s, "%s/%s", path, r); } else { *s = tstrdup (r); } } else { if (path) { - assert (asprintf (s, "%s/%s", path, default_name) >= 0); + tasprintf (s, "%s/%s", path, default_name); } else { *s = tstrdup (default_name); } @@ -316,11 +316,11 @@ void parse_config (void) { #else void parse_config (void) { printf ("libconfig not enabled\n"); - assert (asprintf (&auth_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, AUTH_KEY_FILE) >= 0); - assert (asprintf (&state_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, STATE_FILE) >= 0); - assert (asprintf (&secret_chat_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, SECRET_CHAT_FILE) >= 0); - assert (asprintf (&downloads_directory, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, DOWNLOADS_DIRECTORY) >= 0); - assert (asprintf (&binlog_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, BINLOG_FILE) >= 0); + tasprintf (&auth_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, AUTH_KEY_FILE); + tasprintf (&state_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, STATE_FILE); + tasprintf (&secret_chat_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, SECRET_CHAT_FILE); + tasprintf (&downloads_directory, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, DOWNLOADS_DIRECTORY); + tasprintf (&binlog_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, BINLOG_FILE); } #endif diff --git a/mtproto-client.c b/mtproto-client.c index 3fc865c..fb4103f 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -830,9 +830,9 @@ void work_update_binlog (void) { peer_t *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; - if (U->first_name) { free (U->first_name); } - if (U->last_name) { free (U->last_name); } - if (U->print_name) { free (U->print_name); } + if (U->first_name) { tfree_str (U->first_name); } + if (U->last_name) { tfree_str (U->last_name); } + if (U->print_name) { tfree_str (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); @@ -1199,8 +1199,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { s, location); pop_color (); print_end (); - free (s); - free (location); + tfree_str (s); + tfree_str (location); } break; case CODE_update_new_geo_chat_message: diff --git a/mtproto-common.c b/mtproto-common.c index 2d87f83..8175864 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -131,8 +131,7 @@ void prng_seed (const char *password_filename, int password_length) { } RAND_seed (a, s); BN_ctx = BN_CTX_new (); - memset (a, 0, s); - free (a); + tfree_secure (a, 64 + password_length); } int serialize_bignum (BIGNUM *b, char *buffer, int maxlen) { diff --git a/mtproto-common.h b/mtproto-common.h index 0b8bffd..0fda8c8 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -320,7 +320,7 @@ static inline int fetch_update_str (char **s) { int l = prefetch_strlen (); char *r = fetch_str (l); if (memcmp (*s, r, l) || (*s)[l]) { - free (*s); + tfree_str (*s); *s = talloc (l + 1); memcpy (*s, r, l); (*s)[l] = 0; diff --git a/net.c b/net.c index 3ecfa51..5d62e87 100644 --- a/net.c +++ b/net.c @@ -111,8 +111,8 @@ struct connection_buffer *new_connection_buffer (int size) { } void delete_connection_buffer (struct connection_buffer *b) { - free (b->start); - free (b); + tfree (b->start, b->end - b->start); + tfree (b, sizeof (*b)); } int write_out (struct connection *c, const void *data, int len) { @@ -250,7 +250,7 @@ struct connection *create_connection (const char *host, int port, struct session if (errno != EINPROGRESS) { logprintf ( "Can not connect to %s:%d %m\n", host, port); close (fd); - free (c); + tfree (c, sizeof (*c)); return 0; } } @@ -268,7 +268,7 @@ struct connection *create_connection (const char *host, int port, struct session } logprintf ("Connect with %s:%d timeout\n", host, port); close (fd); - free (c); + tfree (c, sizeof (*c)); return 0; } diff --git a/queries.c b/queries.c index 7eaff00..3fbfb24 100644 --- a/queries.c +++ b/queries.c @@ -191,8 +191,8 @@ void query_error (long long id) { } else { logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); } - free (q->data); - free (q); + tfree (q->data, q->data_len * 4); + tfree (q, sizeof (*q)); } queries_num --; } @@ -255,8 +255,8 @@ void query_result (long long id UU) { q->methods->on_answer (q); assert (in_ptr == in_end); } - free (q->data); - free (q); + tfree (q->data, 4 * q->data_len); + tfree (q, sizeof (*q)); } if (end) { in_ptr = end; @@ -326,7 +326,7 @@ void do_insert_header (void) { uname (&st); out_string (st.machine); static char buf[65536]; - sprintf (buf, "%999s %999s %999s", st.sysname, st.release, st.version); + tsnprintf (buf, 65535, "%999s %999s %999s", st.sysname, st.release, st.version); out_string (buf); out_string (TG_VERSION " (build " TG_BUILD ")"); out_string ("En"); @@ -399,7 +399,7 @@ int send_code_on_answer (struct query *q UU) { int l = prefetch_strlen (); char *s = fetch_str (l); if (phone_code_hash) { - free (phone_code_hash); + tfree_str (phone_code_hash); } phone_code_hash = strndup (s, l); want_dc_num = -1; @@ -933,7 +933,7 @@ void do_send_text (peer_id_t id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { rprintf ("No such file '%s'\n", file_name); - free (file_name); + tfree_str (file_name); return; } static char buf[(1 << 20) + 1]; @@ -941,12 +941,12 @@ void do_send_text (peer_id_t id, char *file_name) { assert (x >= 0); if (x == (1 << 20) + 1) { rprintf ("Too big file '%s'\n", file_name); - free (file_name); + tfree_str (file_name); close (fd); } else { buf[x] = 0; do_send_message (id, buf, x); - free (file_name); + tfree_str (file_name); close (fd); } } @@ -1437,7 +1437,7 @@ void send_part (struct send_file *f) { MD5 (str, 64, md5); out_int ((*(int *)md5) ^ (*(int *)(md5 + 4))); - free (f->iv); + tfree_secure (f->iv, 32); M->media.encr_photo.key = f->key; M->media.encr_photo.iv = f->init_iv; @@ -1456,8 +1456,8 @@ void send_part (struct send_file *f) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M); } - free (f->file_name); - free (f); + tfree_str (f->file_name); + tfree (f, sizeof (*f)); } } @@ -1769,7 +1769,7 @@ void end_load (struct download *D) { logprintf ("Done: %s\n", D->name); } else if (D->next == 2) { static char buf[PATH_MAX]; - if (snprintf (buf, sizeof (buf), OPEN_BIN, D->name) >= (int) sizeof (buf)) { + if (tsnprintf (buf, sizeof (buf), OPEN_BIN, D->name) >= (int) sizeof (buf)) { logprintf ("Open image command buffer overflow\n"); } else { int x = system (buf); @@ -1780,10 +1780,10 @@ void end_load (struct download *D) { } } if (D->iv) { - free (D->iv); + tfree_secure (D->iv, 32); } - free (D->name); - free (D); + tfree_str (D->name); + tfree (D, sizeof (*D)); } void load_next_part (struct download *D); @@ -1832,9 +1832,9 @@ void load_next_part (struct download *D) { static char buf[PATH_MAX]; int l; if (!D->id) { - l = snprintf (buf, sizeof (buf), "%s/download_%lld_%d", get_downloads_directory (), D->volume, D->local_id); + l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", get_downloads_directory (), D->volume, D->local_id); } else { - l = snprintf (buf, sizeof (buf), "%s/download_%lld", get_downloads_directory (), D->id); + l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", get_downloads_directory (), D->id); } if (l >= (int) sizeof (buf)) { logprintf ("Download filename is too long"); @@ -2027,7 +2027,7 @@ 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); + tfree_str (export_auth_str); export_auth_str = 0; return 0; } @@ -2353,8 +2353,7 @@ void do_create_keys_end (struct secret_chat *U) { U->state = sc_deleted; } - memset (t, 0, 256); - free (t); + tfree_secure (t, 256); BN_clear_free (p); BN_clear_free (g_b); @@ -2432,7 +2431,6 @@ void do_send_create_encr_chat (void *x, unsigned char *random) { int get_dh_config_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); - logprintf ("old = %d\n", encr_param_version); if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { int a = fetch_int (); int l = prefetch_strlen (); @@ -2449,14 +2447,15 @@ int get_dh_config_on_answer (struct query *q UU) { if (x == LOG_DH_CONFIG) { return 0; } int l = prefetch_strlen (); assert (l == 256); - unsigned char *random = (void *)fetch_str_dup (); + unsigned char *random = talloc (256); + memcpy (random, fetch_str (256), 256); if (q->extra) { void **x = q->extra; ((void (*)(void *, void *))(*x))(x[1], random); - free (x); - free (random); + tfree (x, 2 * sizeof (void *)); + tfree_secure (random, 256); } else { - free (random); + tfree_secure (random, 256); } return 0; } diff --git a/structures.c b/structures.c index 2992fe7..0bde616 100644 --- a/structures.c +++ b/structures.c @@ -150,7 +150,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha int p = 0; for (i = 0; i < 4; i++) { if (d[i] && strlen (d[i])) { - p += snprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]); + p += tsnprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]); assert (p < 9990); } } @@ -177,7 +177,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha } cc ++; assert (cc <= 9999); - sprintf (s + fl, "#%d", cc); + tsnprintf (s + fl, 9999 - fl, "#%d", cc); } return tstrdup (s); } @@ -595,7 +595,7 @@ void fetch_chat_full (struct chat *C) { } if (version > 0) { bl_do_set_chat_participants (C, version, users_num, users); - free (users); + tfree (users, sizeof (struct chat_user) * users_num); } bl_do_set_chat_full_photo (C, start, 4 * (end - start)); } @@ -945,7 +945,9 @@ void fetch_message_media (struct message_media *M) { M->user_id = fetch_int (); break; case CODE_message_media_unsupported: - M->data = fetch_str_dup (); + M->data_size = prefetch_strlen (); + M->data = talloc (M->data_size); + memcpy (M->data, fetch_str (M->data_size), M->data_size); break; default: logprintf ("type = 0x%08x\n", M->type); @@ -1582,41 +1584,41 @@ struct user *fetch_alloc_user_full (void) { } void free_user (struct user *U) { - if (U->first_name) { free (U->first_name); } - if (U->last_name) { free (U->last_name); } - if (U->print_name) { free (U->print_name); } - if (U->phone) { free (U->phone); } + if (U->first_name) { tfree_str (U->first_name); } + if (U->last_name) { tfree_str (U->last_name); } + if (U->print_name) { tfree_str (U->print_name); } + if (U->phone) { tfree_str (U->phone); } } void free_photo_size (struct photo_size *S) { - free (S->type); + tfree_str (S->type); if (S->data) { - free (S->data); + tfree (S->data, S->size); } } void free_photo (struct photo *P) { if (!P->access_hash) { return; } - if (P->caption) { free (P->caption); } + if (P->caption) { tfree_str (P->caption); } if (P->sizes) { int i; for (i = 0; i < P->sizes_num; i++) { free_photo_size (&P->sizes[i]); } - free (P->sizes); + tfree (P->sizes, sizeof (struct photo_size) * P->sizes_num); } } void free_video (struct video *V) { if (!V->access_hash) { return; } - free (V->caption); + tfree_str (V->caption); free_photo_size (&V->thumb); } void free_document (struct document *D) { if (!D->access_hash) { return; } - free (D->caption); - free (D->mime_type); + tfree_str (D->caption); + tfree_str (D->mime_type); free_photo_size (&D->thumb); } @@ -1633,22 +1635,22 @@ void free_message_media (struct message_media *M) { free_video (&M->video); return; case CODE_message_media_contact: - free (M->phone); - free (M->first_name); - free (M->last_name); + tfree_str (M->phone); + tfree_str (M->first_name); + tfree_str (M->last_name); return; case CODE_message_media_document: free_document (&M->document); return; case CODE_message_media_unsupported: - free (M->data); + tfree (M->data, M->data_size); return; case CODE_decrypted_message_media_photo: case CODE_decrypted_message_media_video: case CODE_decrypted_message_media_audio: case CODE_decrypted_message_media_document: - free (M->encr_photo.key); - free (M->encr_photo.iv); + tfree_secure (M->encr_photo.key, 32); + tfree_secure (M->encr_photo.iv, 32); return; case 0: break; @@ -1663,11 +1665,11 @@ void free_message_action (struct message_action *M) { case CODE_message_action_empty: break; case CODE_message_action_chat_create: - free (M->title); - free (M->users); + tfree_str (M->title); + tfree (M->users, M->user_num * 4); break; case CODE_message_action_chat_edit_title: - free (M->new_title); + tfree_str (M->new_title); break; case CODE_message_action_chat_edit_photo: free_photo (&M->photo); @@ -1687,7 +1689,7 @@ void free_message_action (struct message_action *M) { void free_message (struct message *M) { if (!M->service) { - if (M->message) { free (M->message); } + if (M->message) { tfree_str (M->message); } free_message_media (&M->media); } else { free_message_action (&M->action); @@ -1808,7 +1810,7 @@ struct message *fetch_alloc_geo_message (void) { message_del_peer (M1); free_message (M1); memcpy (M1, M, sizeof (*M)); - free (M); + tfree (M, sizeof (*M)); message_add_use (M1); message_add_peer (M1); messages_allocated --; @@ -1904,12 +1906,12 @@ struct chat *fetch_alloc_chat_full (void) { } void free_chat (struct chat *U) { - if (U->title) { free (U->title); } - if (U->print_title) { free (U->print_title); } + if (U->title) { tfree_str (U->title); } + if (U->print_title) { tfree_str (U->print_title); } } int print_stat (char *s, int len) { - return snprintf (s, len, + return tsnprintf (s, len, "users_allocated\t%d\n" "chats_allocated\t%d\n" "secret_chats_allocated\t%d\n" diff --git a/structures.h b/structures.h index 7e316fe..264317f 100644 --- a/structures.h +++ b/structures.h @@ -298,6 +298,7 @@ struct message_media { struct encr_document encr_document; struct encr_file encr_file; void *data; + int data_size; }; }; diff --git a/tools.c b/tools.c index 748edd5..bc8597f 100644 --- a/tools.c +++ b/tools.c @@ -17,6 +17,8 @@ Copyright Vitaly Valtman 2013 */ +#define _GNU_SOURCE + #include #include #include @@ -26,21 +28,79 @@ #include "interface.h" #include "tools.h" + static void out_of_memory (void) { logprintf ("Out of memory\n"); assert (0 && "Out of memory"); } -void *trealloc (void *ptr, size_t size) { +int tsnprintf (char *buf, int len, const char *format, ...) { + va_list ap; + va_start (ap, format); + int r = vsnprintf (buf, len, format, ap); + va_end (ap); + assert (r <= len && "tsnprintf buffer overflow"); + return r; +} + +int tasprintf (char **res, const char *format, ...) { + va_list ap; + va_start (ap, format); + int r = vasprintf (res, format, ap); + assert (r >= 0); + va_end (ap); + void *rs = talloc (strlen (*res) + 1); + memcpy (rs, *res, strlen (*res) + 1); + free (*res); + *res = rs; + return r; +} + +void tfree (void *ptr, int size) { +#ifdef DEBUG + ptr -= 4; + assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); + assert (*(int *)(ptr + 4 + size) == (int)((size) ^ 0x0bed0bed)); + memset (ptr, 0, size + 8); +#endif + free (ptr); +} + +void tfree_str (void *ptr) { + if (!ptr) { return; } + tfree (ptr, strlen (ptr) + 1); +} + +void tfree_secure (void *ptr, int size) { + memset (ptr, 0, size); + tfree (ptr, size); +} + +void *trealloc (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) { +#ifdef DEBUG + void *p = talloc (size); + memcpy (p, ptr, size >= old_size ? old_size : size); + tfree (ptr, old_size); + return p; +#else void *p = realloc (ptr, size); ensure_ptr (p); return p; +#endif } void *talloc (size_t size) { +#ifdef DEBUG + void *p = malloc (size + 8); + ensure_ptr (p); + *(int *)p = size ^ 0xbedabeda; + *(int *)(p + 4 + size) = size ^ 0x0bed0bed; + return p + 4; +#else void *p = malloc (size); ensure_ptr (p); return p; +#endif } void *talloc0 (size_t size) { @@ -50,11 +110,18 @@ void *talloc0 (size_t size) { } char *tstrdup (const char *s) { +#ifdef DEBUG + int l = strlen (s); + char *p = talloc (l + 1); + memcpy (p, s, l + 1); + return p; +#else char *p = strdup (s); if (p == NULL) { out_of_memory (); } return p; +#endif } void ensure (int r) { diff --git a/tools.h b/tools.h index 9753b86..66c6d96 100644 --- a/tools.h +++ b/tools.h @@ -21,10 +21,18 @@ #define __TOOLS_H__ void *talloc (size_t size); -void *trealloc (void *ptr, size_t size); +void *trealloc (void *ptr, size_t old_size, size_t size); void *talloc0 (size_t size); char *tstrdup (const char *s); void ensure (int r); void ensure_ptr (void *p); +void tfree (void *ptr, int size); +void tfree_str (void *ptr); +void tfree_secure (void *ptr, int size); + + +int tsnprintf (char *buf, int len, const char *format, ...) __attribute__ ((format (printf, 3, 4))); +int tasprintf (char **res, const char *format, ...) __attribute__ ((format (printf, 2, 3))); + #endif diff --git a/tree.h b/tree.h index f75449b..3de93aa 100644 --- a/tree.h +++ b/tree.h @@ -40,7 +40,7 @@ struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ }\ \ void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ - free (T);\ + tfree (T, sizeof (*T));\ }\ \ void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ From 3ec80b7ac746a8230955f051a2819af97e4e022a Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 19:04:27 +0400 Subject: [PATCH 188/465] enhance portability (replace void* by char*) When using void pointers in calculations, the behaviour is undefined. Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1. --- main.c | 15 +++++++++++---- mtproto-common.c | 2 +- mtproto-common.h | 2 +- net.c | 9 ++++++--- net.h | 8 ++++---- queries.c | 2 +- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/main.c b/main.c index 56094cc..77a98ba 100644 --- a/main.c +++ b/main.c @@ -180,12 +180,19 @@ char *make_full_path (char *s) { return s; } -void running_for_first_time (void) { - if (sizeof (void) != 1) { - logprintf ("sizeof (void) isn't equal 1\n"); - logprintf ("GNU C compiler extension isn't available?\n"); +void check_type_sizes (void) { + if (sizeof (int) != 4u) { + logprintf ("sizeof (int) isn't equal 4.\n"); exit (1); } + if (sizeof (char) != 1u) { + logprintf ("sizeof (char) isn't equal 1.\n"); + exit (1); + } +} + +void running_for_first_time (void) { + check_type_sizes (); if (config_filename) { return; // Do not create custom config file } diff --git a/mtproto-common.c b/mtproto-common.c index 2d87f83..4ef429f 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -52,7 +52,7 @@ long long rsa_encrypted_chunks, rsa_decrypted_chunks; BN_CTX *BN_ctx; int verbosity; -int get_random_bytes (void *buf, int n) { +int get_random_bytes (unsigned char *buf, int n) { int r = 0, h = open ("/dev/random", O_RDONLY | O_NONBLOCK); if (h >= 0) { r = read (h, buf, n); diff --git a/mtproto-common.h b/mtproto-common.h index 0b8bffd..7cd6691 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -427,7 +427,7 @@ static inline void fetch_ints (void *data, int count) { in_ptr += count; } -int get_random_bytes (void *buf, int n); +int get_random_bytes (unsigned char *buf, int n); int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E); int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D); diff --git a/net.c b/net.c index 3ecfa51..ccd5db9 100644 --- a/net.c +++ b/net.c @@ -115,7 +115,8 @@ void delete_connection_buffer (struct connection_buffer *b) { free (b); } -int write_out (struct connection *c, const void *data, int len) { +int write_out (struct connection *c, const void *_data, int len) { + const unsigned char *data = _data; if (!len) { return 0; } assert (len > 0); int x = 0; @@ -146,7 +147,8 @@ int write_out (struct connection *c, const void *data, int len) { return x; } -int read_in (struct connection *c, void *data, int len) { +int read_in (struct connection *c, void *_data, int len) { + unsigned char *data = _data; if (!len) { return 0; } assert (len > 0); if (len > c->in_bytes) { @@ -177,7 +179,8 @@ int read_in (struct connection *c, void *data, int len) { return x; } -int read_in_lookup (struct connection *c, void *data, int len) { +int read_in_lookup (struct connection *c, void *_data, int len) { + unsigned char *data = _data; if (!len || !c->in_bytes) { return 0; } assert (len > 0); if (len > c->in_bytes) { diff --git a/net.h b/net.h index 69a473b..181c46c 100644 --- a/net.h +++ b/net.h @@ -93,10 +93,10 @@ struct dc_serialized { }; struct connection_buffer { - void *start; - void *end; - void *rptr; - void *wptr; + unsigned char *start; + unsigned char *end; + unsigned char *rptr; + unsigned char *wptr; struct connection_buffer *next; }; diff --git a/queries.c b/queries.c index 7eaff00..aa3321b 100644 --- a/queries.c +++ b/queries.c @@ -2329,7 +2329,7 @@ void do_create_keys_end (struct secret_chat *U) { ensure_ptr (a); ensure (BN_mod_exp (r, g_b, a, p, ctx)); - void *t = talloc (256); + unsigned char *t = talloc (256); memcpy (t, U->key, 256); memset (U->key, 0, sizeof (U->key)); From afdcd9b7df49b724af2f0d6189a4e18e55e9b736 Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 10 Jan 2014 20:54:47 +0400 Subject: [PATCH 189/465] fix missed inflateEnd call and enhance handling inflate return value --- mtproto-client.c | 20 +++----------------- queries.c | 21 +++------------------ tools.c | 26 ++++++++++++++++++++++++++ tools.h | 1 + 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 3fc865c..f86fa18 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -40,7 +40,6 @@ #include #include #include -#include #include "net.h" #include "include.h" @@ -1493,26 +1492,13 @@ void work_packed (struct connection *c, long long msg_id) { int l = prefetch_strlen (); char *s = fetch_str (l); - size_t dl = MAX_PACKED_SIZE; - z_stream strm; - memset (&strm, 0, sizeof (strm)); - assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); - strm.avail_in = l; - strm.next_in = (void *)s; - strm.avail_out = MAX_PACKED_SIZE; - strm.next_out = (void *)buf; - - int err = inflate (&strm, Z_FINISH); - if (verbosity) { - logprintf ( "inflate error = %d\n", err); - logprintf ( "inflated %d bytes\n", (int)strm.total_out); - } + int total_out = tinflate (s, l, buf, MAX_PACKED_SIZE); int *end = in_ptr; int *eend = in_end; - assert (dl % 4 == 0); + //assert (total_out % 4 == 0); in_ptr = buf; - in_end = in_ptr + strm.total_out / 4; + in_end = in_ptr + total_out / 4; if (verbosity >= 4) { logprintf ( "Unzipped data: "); hexdump_in (); diff --git a/queries.c b/queries.c index aa3321b..8cf357a 100644 --- a/queries.c +++ b/queries.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -215,26 +214,12 @@ void query_result (long long id UU) { fetch_int (); int l = prefetch_strlen (); char *s = fetch_str (l); - size_t dl = MAX_PACKED_SIZE; - - z_stream strm; - memset (&strm, 0, sizeof (strm)); - assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); - strm.avail_in = l; - strm.next_in = (void *)s; - strm.avail_out = MAX_PACKED_SIZE; - strm.next_out = (void *)packed_buffer; - - int err = inflate (&strm, Z_FINISH); - if (verbosity) { - logprintf ( "inflate error = %d\n", err); - logprintf ( "inflated %d bytes\n", (int)strm.total_out); - } + int total_out = tinflate (s, l, packed_buffer, MAX_PACKED_SIZE); end = in_ptr; eend = in_end; - assert (dl % 4 == 0); + //assert (total_out % 4 == 0); in_ptr = packed_buffer; - in_end = in_ptr + strm.total_out / 4; + in_end = in_ptr + total_out / 4; if (verbosity >= 4) { logprintf ( "Unzipped data: "); hexdump_in (); diff --git a/tools.c b/tools.c index 748edd5..1970ba9 100644 --- a/tools.c +++ b/tools.c @@ -22,10 +22,13 @@ #include #include #include +#include #include "interface.h" #include "tools.h" +extern int verbosity; + static void out_of_memory (void) { logprintf ("Out of memory\n"); assert (0 && "Out of memory"); @@ -70,3 +73,26 @@ void ensure_ptr (void *p) { out_of_memory (); } } + +int tinflate (void *input, int ilen, void *output, int olen) { + z_stream strm; + memset (&strm, 0, sizeof (strm)); + assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); + strm.avail_in = ilen; + strm.next_in = input; + strm.avail_out = olen ; + strm.next_out = output; + int err = inflate (&strm, Z_FINISH), total_out = 0; + if (err == Z_OK || err == Z_STREAM_END) { + total_out = (int) strm.total_out; + if (err == Z_STREAM_END && verbosity >= 2) { + logprintf ( "inflated %d bytes\n", (int) strm.total_out); + } + } + if (verbosity && err != Z_STREAM_END) { + logprintf ( "inflate error = %d\n", err); + logprintf ( "inflated %d bytes\n", (int) strm.total_out); + } + inflateEnd (&strm); + return total_out; +} diff --git a/tools.h b/tools.h index 9753b86..4b3d7dd 100644 --- a/tools.h +++ b/tools.h @@ -24,6 +24,7 @@ void *talloc (size_t size); void *trealloc (void *ptr, size_t size); void *talloc0 (size_t size); char *tstrdup (const char *s); +int tinflate (void *input, int ilen, void *output, int olen); void ensure (int r); void ensure_ptr (void *p); From 4a9eedba81496517bbbaabc6a98650de20bc070d Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 10 Jan 2014 21:13:27 +0400 Subject: [PATCH 190/465] Fixed warning --- tools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools.c b/tools.c index bc8597f..1fccb5e 100644 --- a/tools.c +++ b/tools.c @@ -56,7 +56,7 @@ int tasprintf (char **res, const char *format, ...) { return r; } -void tfree (void *ptr, int size) { +void tfree (void *ptr, int size __attribute__ ((unused))) { #ifdef DEBUG ptr -= 4; assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); From e22eff09ddf27517352ee06d3f4a5b7e6492ad30 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 11 Jan 2014 03:26:53 +0400 Subject: [PATCH 191/465] binlog.c: fixed tfree len --- binlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binlog.c b/binlog.c index 883f5d5..947670b 100644 --- a/binlog.c +++ b/binlog.c @@ -513,7 +513,7 @@ void replay_log_event (void) { case CODE_binlog_set_dh_params: rptr ++; { - if (encr_prime) { tfree_str (encr_prime); } + if (encr_prime) { tfree (encr_prime, 256); } encr_root = *(rptr ++); encr_prime = talloc (256); memcpy (encr_prime, rptr, 256); From 8c3953f84fdd73bbd4dbe927ad10e593a408a381 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 11 Jan 2014 20:00:31 +0400 Subject: [PATCH 192/465] tools: added more debug --- tools.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- tools.h | 3 +++ 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/tools.c b/tools.c index 8bed89b..2c50c42 100644 --- a/tools.c +++ b/tools.c @@ -29,8 +29,26 @@ #include "interface.h" #include "tools.h" +#ifdef DEBUG +#define MAX_BLOCKS 1000000 +void *blocks[MAX_BLOCKS]; +void *free_blocks[MAX_BLOCKS]; +int used_blocks; +int free_blocks_cnt; + +char data[1 << 20]; +void *data_ptr = data; +#endif + +#ifdef DEBUG +#define RES_PRE 8 +#define RES_AFTER 8 +#endif + extern int verbosity; +long long total_allocated_bytes; + static void out_of_memory (void) { logprintf ("Out of memory\n"); assert (0 && "Out of memory"); @@ -58,14 +76,32 @@ int tasprintf (char **res, const char *format, ...) { return r; } +void print_backtrace (void); void tfree (void *ptr, int size __attribute__ ((unused))) { #ifdef DEBUG - ptr -= 4; + total_allocated_bytes -= size; + ptr -= RES_PRE; assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); - assert (*(int *)(ptr + 4 + size) == (int)((size) ^ 0x0bed0bed)); - memset (ptr, 0, size + 8); -#endif + assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); + assert (*(int *)(ptr + 4) == size); + int block_num = *(int *)(ptr + 4 + RES_PRE + size); + if (block_num >= used_blocks) { + logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); + } + assert (block_num < used_blocks); + if (block_num < used_blocks - 1) { + void *p = blocks[used_blocks - 1]; + int s = (*(int *)p) ^ 0xbedabeda; + *(int *)(p + 4 + RES_PRE + s) = block_num; + blocks[block_num] = p; + } + blocks[--used_blocks] = 0; + memset (ptr, 0, size + RES_PRE + RES_AFTER); + *(int *)ptr = size + 12; + free_blocks[free_blocks_cnt ++] = ptr; +#else free (ptr); +#endif } void tfree_str (void *ptr) { @@ -93,11 +129,15 @@ void *trealloc (void *ptr, size_t old_size __attribute__ ((unused)), size_t size void *talloc (size_t size) { #ifdef DEBUG - void *p = malloc (size + 8); + total_allocated_bytes += size; + void *p = malloc (size + RES_PRE + RES_AFTER); ensure_ptr (p); *(int *)p = size ^ 0xbedabeda; - *(int *)(p + 4 + size) = size ^ 0x0bed0bed; - return p + 4; + *(int *)(p + 4) = size; + *(int *)(p + RES_PRE + size) = size ^ 0x7bed7bed; + *(int *)(p + RES_AFTER + 4 + size) = used_blocks; + blocks[used_blocks ++] = p; + return p + 8; #else void *p = malloc (size); ensure_ptr (p); @@ -162,3 +202,29 @@ int tinflate (void *input, int ilen, void *output, int olen) { inflateEnd (&strm); return total_out; } + +#ifdef DEBUG +void tcheck (void) { + int i; + for (i = 0; i < used_blocks; i++) { + void *ptr = blocks[i]; + int size = (*(int *)ptr) ^ 0xbedabeda; + assert (*(int *)(ptr + 4) == size); + assert (*(int *)(ptr + RES_PRE + size) == (size ^ 0x7bed7bed)); + assert (*(int *)(ptr + RES_PRE + 4 + size) == i); + } + for (i = 0; i < free_blocks_cnt; i++) { + void *ptr = free_blocks[i]; + int l = *(int *)ptr; + int j = 0; + for (j = 0; j < l; j++) { + if (*(char *)(ptr + 4 + j)) { + hexdump (ptr + 8, ptr + 8 + l + ((-l) & 3)); + logprintf ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr); + assert (0); + } + } + } + logprintf ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt); +} +#endif diff --git a/tools.h b/tools.h index d6cbeca..8105c27 100644 --- a/tools.h +++ b/tools.h @@ -36,4 +36,7 @@ void tfree_secure (void *ptr, int size); int tsnprintf (char *buf, int len, const char *format, ...) __attribute__ ((format (printf, 3, 4))); int tasprintf (char **res, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +#ifdef DEBUG +void tcheck (void); +#endif #endif From 4d8dc59e8726a929a8bd23b2658949ae784df998 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 11 Jan 2014 20:01:01 +0400 Subject: [PATCH 193/465] structures.h: added del_use --- structures.h | 1 + 1 file changed, 1 insertion(+) diff --git a/structures.h b/structures.h index 264317f..3b529ff 100644 --- a/structures.h +++ b/structures.h @@ -373,6 +373,7 @@ void message_remove_tree (struct message *M); void message_add_peer (struct message *M); void message_del_peer (struct message *M); void free_message (struct message *M); +void message_del_use (struct message *M); #define PEER_USER 1 #define PEER_CHAT 2 From 3714035357824aa86d3367b4bde260e8b393c72b Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 11 Jan 2014 20:03:02 +0400 Subject: [PATCH 194/465] tools.c: deleted unneeded arrays --- tools.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools.c b/tools.c index 2c50c42..74c5e2c 100644 --- a/tools.c +++ b/tools.c @@ -35,9 +35,6 @@ void *blocks[MAX_BLOCKS]; void *free_blocks[MAX_BLOCKS]; int used_blocks; int free_blocks_cnt; - -char data[1 << 20]; -void *data_ptr = data; #endif #ifdef DEBUG From 90dd95392ffd1205ef5c3c75e4f9c414b1ba9226 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sun, 12 Jan 2014 04:43:29 +0400 Subject: [PATCH 195/465] Added partial lua support --- Makefile | 8 +- Makefile.in | 4 +- ax_lua.m4 | 607 ++++++++++++++++++ binlog.c | 74 ++- config.h | 15 + config.h.in | 15 + configure | 1578 +++++++++++++++++++++++++++++++++++++++++++++- configure.ac | 38 +- loop.c | 11 + lua-tg.c | 445 +++++++++++++ lua-tg.h | 16 + main.c | 19 +- mtproto-common.h | 22 +- queries.c | 4 +- tools.c | 3 + tree.h | 4 + 16 files changed, 2842 insertions(+), 21 deletions(-) create mode 100644 ax_lua.m4 create mode 100644 lua-tg.c create mode 100644 lua-tg.h diff --git a/Makefile b/Makefile index 47ce820..1c4c05c 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,19 @@ srcdir=. -CFLAGS=-g -O2 +CFLAGS=-g -O2 -I/usr/include/lua5.2 LDFLAGS= CPPFLAGS= DEFS=-DHAVE_CONFIG_H COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -EXTRA_LIBS= -lreadline -lrt -lconfig +EXTRA_LIBS= -lreadline -lrt -lconfig -llua5.2 -ldl LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h INCLUDE=-I. -I${srcdir} CC=gcc -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o .SUFFIXES: diff --git a/Makefile.in b/Makefile.in index 7898905..9f8947d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -10,10 +10,10 @@ EXTRA_LIBS=@EXTRA_LIBS@ LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o .SUFFIXES: diff --git a/ax_lua.m4 b/ax_lua.m4 new file mode 100644 index 0000000..c6f5974 --- /dev/null +++ b/ax_lua.m4 @@ -0,0 +1,607 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_lua.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# +# DESCRIPTION +# +# Detect a Lua interpreter, optionally specifying a minimum and maximum +# version number. Set up important Lua paths, such as the directories in +# which to install scripts and modules (shared libraries). +# +# Also detect Lua headers and libraries. The Lua version contained in the +# header is checked to match the Lua interpreter version exactly. When +# searching for Lua libraries, the version number is used as a suffix. +# This is done with the goal of supporting multiple Lua installs (5.1 and +# 5.2 side-by-side). +# +# A note on compatibility with previous versions: This file has been +# mostly rewritten for serial 18. Most developers should be able to use +# these macros without needing to modify configure.ac. Care has been taken +# to preserve each macro's behavior, but there are some differences: +# +# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as +# AX_PROG_LUA with no arguments. +# +# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h +# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore +# unnecessary, so it is deprecated and does not expand to anything. +# +# 3) The configure flag --with-lua-suffix no longer exists; the user +# should instead specify the LUA precious variable on the command line. +# See the AX_PROG_LUA description for details. +# +# Please read the macro descriptions below for more information. +# +# This file was inspired by Andrew Dalke's and James Henstridge's +# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 +# (serial 17). Basically, this file is a mash-up of those two files. I +# like to think it combines the best of the two! +# +# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua +# paths. Adds precious variable LUA, which may contain the path of the Lua +# interpreter. If LUA is blank, the user's path is searched for an +# suitable interpreter. +# +# If MINIMUM-VERSION is supplied, then only Lua interpreters with a +# version number greater or equal to MINIMUM-VERSION will be accepted. If +# TOO-BIG- VERSION is also supplied, then only Lua interpreters with a +# version number greater or equal to MINIMUM-VERSION and less than +# TOO-BIG-VERSION will be accepted. +# +# Version comparisons require the AX_COMPARE_VERSION macro, which is +# provided by ax_compare_version.m4 from the Autoconf Archive. +# +# The Lua version number, LUA_VERSION, is found from the interpreter, and +# substituted. LUA_PLATFORM is also found, but not currently supported (no +# standard representation). +# +# Finally, the macro finds four paths: +# +# luadir Directory to install Lua scripts. +# pkgluadir $luadir/$PACKAGE +# luaexecdir Directory to install Lua modules. +# pkgluaexecdir $luaexecdir/$PACKAGE +# +# These paths a found based on $prefix, $exec_prefix, Lua's package.path, +# and package.cpath. The first path of package.path beginning with $prefix +# is selected as luadir. The first path of package.cpath beginning with +# $exec_prefix is used as luaexecdir. This should work on all reasonable +# Lua installations. If a path cannot be determined, a default path is +# used. Of course, the user can override these later when invoking make. +# +# luadir Default: $prefix/share/lua/$LUA_VERSION +# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION +# +# These directories can be used by Automake as install destinations. The +# variable name minus 'dir' needs to be used as a prefix to the +# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. +# +# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is +# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- +# FOUND is blank, then it will default to printing an error. To prevent +# the default behavior, give ':' as an action. +# +# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be +# expanded before this macro. Adds precious variable LUA_INCLUDE, which +# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If +# LUA_INCLUDE is blank, then this macro will attempt to find suitable +# flags. +# +# LUA_INCLUDE can be used by Automake to compile Lua modules or +# executables with embedded interpreters. The *_CPPFLAGS variables should +# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). +# +# This macro searches for the header lua.h (and others). The search is +# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. +# If the search is unsuccessful, then some common directories are tried. +# If the headers are then found, then LUA_INCLUDE is set accordingly. +# +# The paths automatically searched are: +# +# * /usr/include/luaX.Y +# * /usr/include/lua/X.Y +# * /usr/include/luaXY +# * /usr/local/include/luaX.Y +# * /usr/local/include/lua/X.Y +# * /usr/local/include/luaXY +# +# (Where X.Y is the Lua version number, e.g. 5.1.) +# +# The Lua version number found in the headers is always checked to match +# the Lua interpreter's version number. Lua headers with mismatched +# version numbers are not accepted. +# +# If headers are found, then ACTION-IF-FOUND is performed, otherwise +# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then +# it will default to printing an error. To prevent the default behavior, +# set the action to ':'. +# +# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be +# expanded before this macro. Adds precious variable LUA_LIB, which may +# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, +# then this macro will attempt to find suitable flags. +# +# LUA_LIB can be used by Automake to link Lua modules or executables with +# embedded interpreters. The *_LIBADD and *_LDADD variables should be used +# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). +# +# This macro searches for the Lua library. More technically, it searches +# for a library containing the function lua_load. The search is performed +# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. +# +# If the search determines that some linker flags are missing, then those +# flags will be added to LUA_LIB. +# +# If libraries are found, then ACTION-IF-FOUND is performed, otherwise +# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then +# it will default to printing an error. To prevent the default behavior, +# set the action to ':'. +# +# AX_LUA_READLINE: Search for readline headers and libraries. Requires the +# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the +# Autoconf Archive. +# +# If a readline compatible library is found, then ACTION-IF-FOUND is +# performed, otherwise ACTION-IF-NOT-FOUND is performed. +# +# LICENSE +# +# Copyright (c) 2013 Tim Perkins +# Copyright (c) 2013 Reuben Thomas +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 20 + +dnl ========================================================================= +dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION], +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_PROG_LUA], +[ + dnl Make LUA a precious variable. + AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1]) + + dnl Find a Lua interpreter. + m4_define_default([_AX_LUA_INTERPRETER_LIST], + [lua lua5.2 lua5.1 lua50]) + + m4_if([$1], [], + [ dnl No version check is needed. Find any Lua interpreter. + AS_IF([test "x$LUA" = 'x'], + [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])]) + ax_display_LUA='lua' + + dnl At least check if this is a Lua interpreter. + AC_MSG_CHECKING([if $LUA is a Lua interpreter]) + _AX_LUA_CHK_IS_INTRP([$LUA], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([not a Lua interpreter]) + ]) + ], + [ dnl A version check is needed. + AS_IF([test "x$LUA" != 'x'], + [ dnl Check if this is a Lua interpreter. + AC_MSG_CHECKING([if $LUA is a Lua interpreter]) + _AX_LUA_CHK_IS_INTRP([$LUA], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([not a Lua interpreter]) + ]) + dnl Check the version. + m4_if([$2], [], + [_ax_check_text="whether $LUA version >= $1"], + [_ax_check_text="whether $LUA version >= $1, < $2"]) + AC_MSG_CHECKING([$_ax_check_text]) + _AX_LUA_CHK_VER([$LUA], [$1], [$2], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([version is out of range for specified LUA])]) + ax_display_LUA=$LUA + ], + [ dnl Try each interpreter until we find one that satisfies VERSION. + m4_if([$2], [], + [_ax_check_text="for a Lua interpreter with version >= $1"], + [_ax_check_text="for a Lua interpreter with version >= $1, < $2"]) + AC_CACHE_CHECK([$_ax_check_text], + [ax_cv_pathless_LUA], + [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do + test "x$ax_cv_pathless_LUA" = 'xnone' && break + _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue]) + _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break]) + done + ]) + dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA. + AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'], + [LUA=':'], + [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])]) + ax_display_LUA=$ax_cv_pathless_LUA + ]) + ]) + + AS_IF([test "x$LUA" = 'x:'], + [ dnl Run any user-specified action, or abort. + m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])]) + ], + [ dnl Query Lua for its version number. + AC_CACHE_CHECK([for $ax_display_LUA version], [ax_cv_lua_version], + [ ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ + sed "s|^Lua \(.*\)|\1|" | \ + grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"` + ]) + AS_IF([test "x$ax_cv_lua_version" = 'x'], + [AC_MSG_ERROR([invalid Lua version number])]) + AC_SUBST([LUA_VERSION], [$ax_cv_lua_version]) + AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | sed 's|\.||'`]) + + dnl The following check is not supported: + dnl At times (like when building shared libraries) you may want to know + dnl which OS platform Lua thinks this is. + AC_CACHE_CHECK([for $ax_display_LUA platform], [ax_cv_lua_platform], + [ax_cv_lua_platform=`$LUA -e "print('unknown')"`]) + AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform]) + + dnl Use the values of $prefix and $exec_prefix for the corresponding + dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct + dnl variables so they can be overridden if need be. However, the general + dnl consensus is that you shouldn't need this ability. + AC_SUBST([LUA_PREFIX], ['${prefix}']) + AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}']) + + dnl Lua provides no way to query the script directory, and instead + dnl provides LUA_PATH. However, we should be able to make a safe educated + dnl guess. If the built-in search path contains a directory which is + dnl prefixed by $prefix, then we can store scripts there. The first + dnl matching path will be used. + AC_CACHE_CHECK([for $ax_display_LUA script directory], + [ax_cv_lua_luadir], + [ AS_IF([test "x$prefix" = 'xNONE'], + [ax_lua_prefix=$ac_default_prefix], + [ax_lua_prefix=$prefix]) + + dnl Initialize to the default path. + ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" + + dnl Try to find a path with the prefix. + _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [package.path]) + AS_IF([test "x$ax_lua_prefixed_path" != 'x'], + [ dnl Fix the prefix. + _ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'` + ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ + sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"` + ]) + ]) + AC_SUBST([luadir], [$ax_cv_lua_luadir]) + AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE]) + + dnl Lua provides no way to query the module directory, and instead + dnl provides LUA_PATH. However, we should be able to make a safe educated + dnl guess. If the built-in search path contains a directory which is + dnl prefixed by $exec_prefix, then we can store modules there. The first + dnl matching path will be used. + AC_CACHE_CHECK([for $ax_display_LUA module directory], + [ax_cv_lua_luaexecdir], + [ AS_IF([test "x$exec_prefix" = 'xNONE'], + [ax_lua_exec_prefix=$ax_lua_prefix], + [ax_lua_exec_prefix=$exec_prefix]) + + dnl Initialize to the default path. + ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" + + dnl Try to find a path with the prefix. + _AX_LUA_FND_PRFX_PTH([$LUA], + [$ax_lua_exec_prefix], [package.cpathd]) + AS_IF([test "x$ax_lua_prefixed_path" != 'x'], + [ dnl Fix the prefix. + _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'` + ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ + sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"` + ]) + ]) + AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir]) + AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE]) + + dnl Run any user specified action. + $3 + ]) +]) + +dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA. +AC_DEFUN([AX_WITH_LUA], +[ + AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA]]) + AX_PROG_LUA +]) + + +dnl ========================================================================= +dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +dnl ========================================================================= +AC_DEFUN([_AX_LUA_CHK_IS_INTRP], +[ + dnl Just print _VERSION because all Lua interpreters have this global. + AS_IF([$1 -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null], + [$2], [$3]) +]) + + +dnl ========================================================================= +dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION], +dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +dnl ========================================================================= +AC_DEFUN([_AX_LUA_CHK_VER], +[ + _ax_test_ver=`$1 -e "print(_VERSION)" 2>/dev/null | \ + sed "s|^Lua \(.*\)|\1|" | grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"` + AS_IF([test "x$_ax_test_ver" = 'x'], + [_ax_test_ver='0']) + AX_COMPARE_VERSION([$_ax_test_ver], [ge], [$2]) + m4_if([$3], [], [], + [ AS_IF([$ax_compare_version], + [AX_COMPARE_VERSION([$_ax_test_ver], [lt], [$3])]) + ]) + AS_IF([$ax_compare_version], [$4], [$5]) +]) + + +dnl ========================================================================= +dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, LUA-PATH-VARIABLE) +dnl ========================================================================= +AC_DEFUN([_AX_LUA_FND_PRFX_PTH], +[ + dnl Invokes the Lua interpreter PROG to print the path variable + dnl LUA-PATH-VARIABLE, usually package.path or package.cpath. Paths are + dnl then matched against PREFIX. The first path to begin with PREFIX is set + dnl to ax_lua_prefixed_path. + + ax_lua_prefixed_path='' + _ax_package_paths=`$1 -e 'print($3)' 2>/dev/null | sed 's|;|\n|g'` + dnl Try the paths in order, looking for the prefix. + for _ax_package_path in $_ax_package_paths; do + dnl Copy the path, up to the use of a Lua wildcard. + _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` + _ax_reassembled='' + for _ax_path_part in $_ax_path_parts; do + echo "$_ax_path_part" | grep '\?' >/dev/null && break + _ax_reassembled="$_ax_reassembled/$_ax_path_part" + done + dnl Check the path against the prefix. + _ax_package_path=$_ax_reassembled + if echo "$_ax_package_path" | grep "^$2" >/dev/null; then + dnl Found it. + ax_lua_prefixed_path=$_ax_package_path + break + fi + done +]) + + +dnl ========================================================================= +dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_LUA_HEADERS], +[ + dnl Check for LUA_VERSION. + AC_MSG_CHECKING([if LUA_VERSION is defined]) + AS_IF([test "x$LUA_VERSION" != 'x'], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION]) + ]) + + dnl Make LUA_INCLUDE a precious variable. + AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1]) + + dnl Some default directories to search. + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` + m4_define_default([_AX_LUA_INCLUDE_LIST], + [ /usr/include/lua$LUA_VERSION \ + /usr/include/lua/$LUA_VERSION \ + /usr/include/lua$LUA_SHORT_VERSION \ + /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua/$LUA_VERSION \ + /usr/local/include/lua$LUA_SHORT_VERSION \ + ]) + + dnl Try to find the headers. + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) + CPPFLAGS=$_ax_lua_saved_cppflags + + dnl Try some other directories if LUA_INCLUDE was not set. + AS_IF([test "x$LUA_INCLUDE" = 'x' && + test "x$ac_cv_header_lua_h" != 'xyes'], + [ dnl Try some common include paths. + for _ax_include_path in _AX_LUA_INCLUDE_LIST; do + test ! -d "$_ax_include_path" && continue + + AC_MSG_CHECKING([for Lua headers in]) + AC_MSG_RESULT([$_ax_include_path]) + + AS_UNSET([ac_cv_header_lua_h]) + AS_UNSET([ac_cv_header_lualib_h]) + AS_UNSET([ac_cv_header_lauxlib_h]) + AS_UNSET([ac_cv_header_luaconf_h]) + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -I$_ax_include_path" + AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) + CPPFLAGS=$_ax_lua_saved_cppflags + + AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], + [ LUA_INCLUDE="-I$_ax_include_path" + break + ]) + done + ]) + + AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], + [ dnl Make a program to print LUA_VERSION defined in the header. + dnl TODO This probably shouldn't be a runtime test. + + AC_CACHE_CHECK([for Lua header version], + [ax_cv_lua_header_version], + [ _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + AC_RUN_IFELSE( + [ AC_LANG_SOURCE([[ +#include +#include +#include +int main(int argc, char ** argv) +{ + if(argc > 1) printf("%s", LUA_VERSION); + exit(EXIT_SUCCESS); +} +]]) + ], + [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ + sed "s|^Lua \(.*\)|\1|" | \ + grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"` + ], + [ax_cv_lua_header_version='unknown']) + CPPFLAGS=$_ax_lua_saved_cppflags + ]) + + dnl Compare this to the previously found LUA_VERSION. + AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) + AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], + [ AC_MSG_RESULT([yes]) + ax_header_version_match='yes' + ], + [ AC_MSG_RESULT([no]) + ax_header_version_match='no' + ]) + ]) + + dnl Was LUA_INCLUDE specified? + AS_IF([test "x$ax_header_version_match" != 'xyes' && + test "x$LUA_INCLUDE" != 'x'], + [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])]) + + dnl Test the final result and run user code. + AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1], + [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])]) +]) + +dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS. +AC_DEFUN([AX_LUA_HEADERS_VERSION], +[ + AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS]]) +]) + + +dnl ========================================================================= +dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_LUA_LIBS], +[ + dnl TODO Should this macro also check various -L flags? + + dnl Check for LUA_VERSION. + AC_MSG_CHECKING([if LUA_VERSION is defined]) + AS_IF([test "x$LUA_VERSION" != 'x'], + [AC_MSG_RESULT([yes])], + [ AC_MSG_RESULT([no]) + AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION]) + ]) + + dnl Make LUA_LIB a precious variable. + AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1]) + + AS_IF([test "x$LUA_LIB" != 'x'], + [ dnl Check that LUA_LIBS works. + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + AC_SEARCH_LIBS([lua_load], [], + [_ax_found_lua_libs='yes'], + [_ax_found_lua_libs='no']) + LIBS=$_ax_lua_saved_libs + + dnl Check the result. + AS_IF([test "x$_ax_found_lua_libs" != 'xyes'], + [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])]) + ], + [ dnl First search for extra libs. + _ax_lua_extra_libs='' + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + AC_SEARCH_LIBS([exp], [m]) + AC_SEARCH_LIBS([dlopen], [dl]) + LIBS=$_ax_lua_saved_libs + + AS_IF([test "x$ac_cv_search_exp" != 'xno' && + test "x$ac_cv_search_exp" != 'xnone required'], + [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"]) + + AS_IF([test "x$ac_cv_search_dlopen" != 'xno' && + test "x$ac_cv_search_dlopen" != 'xnone required'], + [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"]) + + dnl Try to find the Lua libs. + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + AC_SEARCH_LIBS([lua_load], [lua$LUA_VERSION lua$LUA_SHORT_VERSION lua], + [_ax_found_lua_libs='yes'], + [_ax_found_lua_libs='no'], + [$_ax_lua_extra_libs]) + LIBS=$_ax_lua_saved_libs + + AS_IF([test "x$ac_cv_search_lua_load" != 'xno' && + test "x$ac_cv_search_lua_load" != 'xnone required'], + [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"]) + ]) + + dnl Test the result and run user code. + AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1], + [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])]) +]) + + +dnl ========================================================================= +dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ========================================================================= +AC_DEFUN([AX_LUA_READLINE], +[ + AX_LIB_READLINE + AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' && + test "x$ac_cv_header_readline_history_h" != 'x'], + [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS" + $1 + ], + [$2]) +]) diff --git a/binlog.c b/binlog.c index 947670b..00dc12b 100644 --- a/binlog.c +++ b/binlog.c @@ -16,6 +16,10 @@ Copyright Vitaly Valtman 2013 */ +#include "config.h" +#ifdef USE_LUA +# include "lua-tg.h" +#endif #include #include #include @@ -126,6 +130,9 @@ void replay_log_event (void) { rptr ++; { our_id = *(rptr ++); + #ifdef USE_LUA + lua_our_id (our_id); + #endif } break; case LOG_DC_SIGNED: @@ -280,6 +287,9 @@ void replay_log_event (void) { struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->state = sc_ok; + #ifdef USE_LUA + lua_secret_chat_created (U); + #endif } break; case CODE_binlog_new_user: @@ -307,6 +317,10 @@ void replay_log_event (void) { if (fetch_int ()) { U->flags |= FLAG_USER_CONTACT; } + + #ifdef USE_LUA + lua_user_update (U); + #endif } rptr = in_ptr; break; @@ -337,6 +351,10 @@ void replay_log_event (void) { assert (U); if (U->user.phone) { tfree_str (U->user.phone); } U->user.phone = fetch_str_dup (); + + #ifdef USE_LUA + lua_user_update (&U->user); + #endif } rptr = in_ptr; break; @@ -383,6 +401,10 @@ void replay_log_event (void) { if (U->user.real_last_name) { tfree_str (U->user.real_last_name); } U->user.real_first_name = fetch_str_dup (); U->user.real_last_name = fetch_str_dup (); + + #ifdef USE_LUA + lua_user_update (&U->user); + #endif } rptr = in_ptr; break; @@ -519,7 +541,6 @@ void replay_log_event (void) { memcpy (encr_prime, rptr, 256); rptr += 64; encr_param_version = *(rptr ++); - } break; case CODE_binlog_encr_chat_init: @@ -579,6 +600,10 @@ void replay_log_event (void) { C->version = fetch_int (); fetch_data (&C->photo_big, sizeof (struct file_location)); fetch_data (&C->photo_small, sizeof (struct file_location)); + + #ifdef USE_LUA + lua_chat_update (C); + #endif }; rptr = in_ptr; break; @@ -600,6 +625,9 @@ void replay_log_event (void) { if (C->title) { tfree_str (C->title); } C->title = fetch_str_dup (); C->print_title = create_print_name (C->id, C->title, 0, 0, 0); + #ifdef USE_LUA + lua_chat_update (C); + #endif }; rptr = in_ptr; break; @@ -619,6 +647,9 @@ void replay_log_event (void) { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.date = *(rptr ++); + #ifdef USE_LUA + lua_chat_update (&C->chat); + #endif }; break; case CODE_binlog_set_chat_version: @@ -628,6 +659,9 @@ void replay_log_event (void) { assert (C && (C->flags & FLAG_CREATED)); C->chat.version = *(rptr ++); C->chat.users_num = *(rptr ++); + #ifdef USE_LUA + lua_chat_update (&C->chat); + #endif }; break; case CODE_binlog_set_chat_admin: @@ -636,6 +670,9 @@ void replay_log_event (void) { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.admin_id = *(rptr ++); + #ifdef USE_LUA + lua_chat_update (&C->chat); + #endif }; break; case CODE_binlog_set_chat_participants: @@ -649,6 +686,9 @@ void replay_log_event (void) { C->chat.user_list = talloc (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; + #ifdef USE_LUA + lua_chat_update (&C->chat); + #endif }; break; case CODE_binlog_chat_full_photo: @@ -688,6 +728,9 @@ void replay_log_event (void) { 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; + #ifdef USE_LUA + lua_chat_update (C); + #endif } break; case CODE_binlog_del_chat_participant: @@ -715,6 +758,9 @@ void replay_log_event (void) { C->user_list_size --; C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); C->user_list_version = version; + #ifdef USE_LUA + lua_chat_update (C); + #endif } break; case CODE_binlog_create_message_text: @@ -764,6 +810,10 @@ void replay_log_event (void) { message_insert_unsent (M); M->flags |= FLAG_PENDING; } + + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -799,6 +849,9 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -832,6 +885,9 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -867,6 +923,9 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -902,6 +961,9 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -930,6 +992,9 @@ void replay_log_event (void) { M->service = 1; message_insert (M); + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -959,6 +1024,9 @@ void replay_log_event (void) { M->service = 1; message_insert (M); + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -988,6 +1056,9 @@ void replay_log_event (void) { M->service = 1; message_insert (M); + #ifdef USE_LUA + lua_new_msg (M); + #endif } rptr = in_ptr; break; @@ -1043,6 +1114,7 @@ void replay_log_event (void) { } message_remove_tree (M); message_del_peer (M); + message_del_use (M); free_message (M); tfree (M, sizeof (*M)); } diff --git a/config.h b/config.h index babca79..3ee4d79 100644 --- a/config.h +++ b/config.h @@ -10,6 +10,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_LAUXLIB_H 1 + /* Define to 1 if you have the `crypto' library (-lcrypto). */ #define HAVE_LIBCRYPTO 1 @@ -22,6 +25,15 @@ /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 +/* Define to 1 if you have the header file. */ +#define HAVE_LUACONF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LUALIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LUA_H 1 + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 @@ -99,6 +111,9 @@ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 +/* use lua */ +#define USE_LUA 1 + /* Define to rpl_malloc if the replacement function should be used. */ /* #undef malloc */ diff --git a/config.h.in b/config.h.in index d8fc8ae..26115be 100644 --- a/config.h.in +++ b/config.h.in @@ -9,6 +9,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LAUXLIB_H + /* Define to 1 if you have the `crypto' library (-lcrypto). */ #undef HAVE_LIBCRYPTO @@ -21,6 +24,15 @@ /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM +/* Define to 1 if you have the header file. */ +#undef HAVE_LUACONF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUALIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LUA_H + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC @@ -98,6 +110,9 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* use lua */ +#undef USE_LUA + /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc diff --git a/configure b/configure index a71c4b7..cc99b1e 100755 --- a/configure +++ b/configure @@ -622,9 +622,21 @@ ac_includes_default="\ ac_subst_vars='LTLIBOBJS EXTRA_LIBS LIBOBJS +LUA_LIB EGREP GREP CPP +LUA_INCLUDE +pkgluaexecdir +luaexecdir +pkgluadir +luadir +LUA_EXEC_PREFIX +LUA_PREFIX +LUA_PLATFORM +LUA_SHORT_VERSION +LUA_VERSION +LUA OBJEXT EXEEXT ac_ct_CC @@ -674,6 +686,7 @@ ac_subst_files='' ac_user_opts=' enable_option_checking enable_libconfig +enable_liblua ' ac_precious_vars='build_alias host_alias @@ -683,7 +696,10 @@ CFLAGS LDFLAGS LIBS CPPFLAGS -CPP' +LUA +LUA_INCLUDE +CPP +LUA_LIB' # Initialize some variables set by options. @@ -1294,6 +1310,7 @@ Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-libconfig/--disable-libconfig +--enable-liblua/--disable-liblua Some influential environment variables: CC C compiler command @@ -1303,7 +1320,10 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory + LUA The Lua interpreter, e.g. /usr/bin/lua5.1 + LUA_INCLUDE The Lua includes, e.g. -I/usr/include/lua5.1 CPP C preprocessor + LUA_LIB The Lua library, e.g. -llua5.1 Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -2140,6 +2160,217 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" + + +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_lua.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] +# +# DESCRIPTION +# +# Detect a Lua interpreter, optionally specifying a minimum and maximum +# version number. Set up important Lua paths, such as the directories in +# which to install scripts and modules (shared libraries). +# +# Also detect Lua headers and libraries. The Lua version contained in the +# header is checked to match the Lua interpreter version exactly. When +# searching for Lua libraries, the version number is used as a suffix. +# This is done with the goal of supporting multiple Lua installs (5.1 and +# 5.2 side-by-side). +# +# A note on compatibility with previous versions: This file has been +# mostly rewritten for serial 18. Most developers should be able to use +# these macros without needing to modify configure.ac. Care has been taken +# to preserve each macro's behavior, but there are some differences: +# +# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as +# AX_PROG_LUA with no arguments. +# +# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h +# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore +# unnecessary, so it is deprecated and does not expand to anything. +# +# 3) The configure flag --with-lua-suffix no longer exists; the user +# should instead specify the LUA precious variable on the command line. +# See the AX_PROG_LUA description for details. +# +# Please read the macro descriptions below for more information. +# +# This file was inspired by Andrew Dalke's and James Henstridge's +# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 +# (serial 17). Basically, this file is a mash-up of those two files. I +# like to think it combines the best of the two! +# +# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua +# paths. Adds precious variable LUA, which may contain the path of the Lua +# interpreter. If LUA is blank, the user's path is searched for an +# suitable interpreter. +# +# If MINIMUM-VERSION is supplied, then only Lua interpreters with a +# version number greater or equal to MINIMUM-VERSION will be accepted. If +# TOO-BIG- VERSION is also supplied, then only Lua interpreters with a +# version number greater or equal to MINIMUM-VERSION and less than +# TOO-BIG-VERSION will be accepted. +# +# Version comparisons require the AX_COMPARE_VERSION macro, which is +# provided by ax_compare_version.m4 from the Autoconf Archive. +# +# The Lua version number, LUA_VERSION, is found from the interpreter, and +# substituted. LUA_PLATFORM is also found, but not currently supported (no +# standard representation). +# +# Finally, the macro finds four paths: +# +# luadir Directory to install Lua scripts. +# pkgluadir $luadir/$PACKAGE +# luaexecdir Directory to install Lua modules. +# pkgluaexecdir $luaexecdir/$PACKAGE +# +# These paths a found based on $prefix, $exec_prefix, Lua's package.path, +# and package.cpath. The first path of package.path beginning with $prefix +# is selected as luadir. The first path of package.cpath beginning with +# $exec_prefix is used as luaexecdir. This should work on all reasonable +# Lua installations. If a path cannot be determined, a default path is +# used. Of course, the user can override these later when invoking make. +# +# luadir Default: $prefix/share/lua/$LUA_VERSION +# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION +# +# These directories can be used by Automake as install destinations. The +# variable name minus 'dir' needs to be used as a prefix to the +# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. +# +# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is +# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- +# FOUND is blank, then it will default to printing an error. To prevent +# the default behavior, give ':' as an action. +# +# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be +# expanded before this macro. Adds precious variable LUA_INCLUDE, which +# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If +# LUA_INCLUDE is blank, then this macro will attempt to find suitable +# flags. +# +# LUA_INCLUDE can be used by Automake to compile Lua modules or +# executables with embedded interpreters. The *_CPPFLAGS variables should +# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). +# +# This macro searches for the header lua.h (and others). The search is +# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. +# If the search is unsuccessful, then some common directories are tried. +# If the headers are then found, then LUA_INCLUDE is set accordingly. +# +# The paths automatically searched are: +# +# * /usr/include/luaX.Y +# * /usr/include/lua/X.Y +# * /usr/include/luaXY +# * /usr/local/include/luaX.Y +# * /usr/local/include/lua/X.Y +# * /usr/local/include/luaXY +# +# (Where X.Y is the Lua version number, e.g. 5.1.) +# +# The Lua version number found in the headers is always checked to match +# the Lua interpreter's version number. Lua headers with mismatched +# version numbers are not accepted. +# +# If headers are found, then ACTION-IF-FOUND is performed, otherwise +# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then +# it will default to printing an error. To prevent the default behavior, +# set the action to ':'. +# +# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be +# expanded before this macro. Adds precious variable LUA_LIB, which may +# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, +# then this macro will attempt to find suitable flags. +# +# LUA_LIB can be used by Automake to link Lua modules or executables with +# embedded interpreters. The *_LIBADD and *_LDADD variables should be used +# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). +# +# This macro searches for the Lua library. More technically, it searches +# for a library containing the function lua_load. The search is performed +# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. +# +# If the search determines that some linker flags are missing, then those +# flags will be added to LUA_LIB. +# +# If libraries are found, then ACTION-IF-FOUND is performed, otherwise +# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then +# it will default to printing an error. To prevent the default behavior, +# set the action to ':'. +# +# AX_LUA_READLINE: Search for readline headers and libraries. Requires the +# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the +# Autoconf Archive. +# +# If a readline compatible library is found, then ACTION-IF-FOUND is +# performed, otherwise ACTION-IF-NOT-FOUND is performed. +# +# LICENSE +# +# Copyright (c) 2013 Tim Perkins +# Copyright (c) 2013 Reuben Thomas +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 20 + + + + + + + + + + + + + + + + + + + + + + + + # Checks for programs. @@ -3038,8 +3269,6 @@ fi if test "x$BT" = "x" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace in -lexecinfo" >&5 $as_echo_n "checking for backtrace in -lexecinfo... " >&6; } if ${ac_cv_lib_execinfo_backtrace+:} false; then : @@ -3230,8 +3459,8 @@ if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Checking for libconfig" >&5 -$as_echo_n "checking Checking for libconfig... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libconfig" >&5 +$as_echo_n "checking for libconfig... " >&6; } # Check whether --enable-libconfig was given. if test "${enable_libconfig+set}" = set; then : enableval=$enable_libconfig; @@ -3341,7 +3570,8 @@ fi fi -# Checks for header files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for liblua" >&5 +$as_echo_n "checking for liblua... " >&6; } ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3739,6 +3969,1342 @@ fi done +# Check whether --enable-liblua was given. +if test "${enable_liblua+set}" = set; then : + enableval=$enable_liblua; + if test "x$enableval" = "xno" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 +$as_echo "disabled" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 +$as_echo "enabled" >&6; } + + + + + + if test "x$LUA" = 'x'; then : + for ac_prog in lua lua5.2 lua5.1 lua50 +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_LUA+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $LUA in + [\\/]* | ?:[\\/]*) + ac_cv_path_LUA="$LUA" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_LUA="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +LUA=$ac_cv_path_LUA +if test -n "$LUA"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LUA" >&5 +$as_echo "$LUA" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$LUA" && break +done +test -n "$LUA" || LUA=":" + +fi + ax_display_LUA='lua' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LUA is a Lua interpreter" >&5 +$as_echo_n "checking if $LUA is a Lua interpreter... " >&6; } + + if $LUA -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "not a Lua interpreter" "$LINENO" 5 + +fi + + + + if test "x$LUA" = 'x:'; then : + + as_fn_error $? "No lua found. Try --disable-liblua" "$LINENO" 5 + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA version" >&5 +$as_echo_n "checking for $ax_display_LUA version... " >&6; } +if ${ax_cv_lua_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ + sed "s|^Lua \(.*\)|\1|" | \ + grep -o "^[0-9]\+\\.[0-9]\+"` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_version" >&5 +$as_echo "$ax_cv_lua_version" >&6; } + if test "x$ax_cv_lua_version" = 'x'; then : + as_fn_error $? "invalid Lua version number" "$LINENO" 5 +fi + LUA_VERSION=$ax_cv_lua_version + + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA platform" >&5 +$as_echo_n "checking for $ax_display_LUA platform... " >&6; } +if ${ax_cv_lua_platform+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_lua_platform=`$LUA -e "print('unknown')"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_platform" >&5 +$as_echo "$ax_cv_lua_platform" >&6; } + LUA_PLATFORM=$ax_cv_lua_platform + + + LUA_PREFIX='${prefix}' + + LUA_EXEC_PREFIX='${exec_prefix}' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA script directory" >&5 +$as_echo_n "checking for $ax_display_LUA script directory... " >&6; } +if ${ax_cv_lua_luadir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$prefix" = 'xNONE'; then : + ax_lua_prefix=$ac_default_prefix +else + ax_lua_prefix=$prefix +fi + + ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" + + + + ax_lua_prefixed_path='' + _ax_package_paths=`$LUA -e 'print(package.path)' 2>/dev/null | sed 's|;|\n|g'` + for _ax_package_path in $_ax_package_paths; do + _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` + _ax_reassembled='' + for _ax_path_part in $_ax_path_parts; do + echo "$_ax_path_part" | grep '\?' >/dev/null && break + _ax_reassembled="$_ax_reassembled/$_ax_path_part" + done + _ax_package_path=$_ax_reassembled + if echo "$_ax_package_path" | grep "^$ax_lua_prefix" >/dev/null; then + ax_lua_prefixed_path=$_ax_package_path + break + fi + done + + if test "x$ax_lua_prefixed_path" != 'x'; then : + _ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'` + ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ + sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"` + +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luadir" >&5 +$as_echo "$ax_cv_lua_luadir" >&6; } + luadir=$ax_cv_lua_luadir + + pkgluadir=\${luadir}/$PACKAGE + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA module directory" >&5 +$as_echo_n "checking for $ax_display_LUA module directory... " >&6; } +if ${ax_cv_lua_luaexecdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$exec_prefix" = 'xNONE'; then : + ax_lua_exec_prefix=$ax_lua_prefix +else + ax_lua_exec_prefix=$exec_prefix +fi + + ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" + + + + ax_lua_prefixed_path='' + _ax_package_paths=`$LUA -e 'print(package.cpathd)' 2>/dev/null | sed 's|;|\n|g'` + for _ax_package_path in $_ax_package_paths; do + _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` + _ax_reassembled='' + for _ax_path_part in $_ax_path_parts; do + echo "$_ax_path_part" | grep '\?' >/dev/null && break + _ax_reassembled="$_ax_reassembled/$_ax_path_part" + done + _ax_package_path=$_ax_reassembled + if echo "$_ax_package_path" | grep "^$ax_lua_exec_prefix" >/dev/null; then + ax_lua_prefixed_path=$_ax_package_path + break + fi + done + + if test "x$ax_lua_prefixed_path" != 'x'; then : + _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'` + ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ + sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"` + +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luaexecdir" >&5 +$as_echo "$ax_cv_lua_luaexecdir" >&6; } + luaexecdir=$ax_cv_lua_luaexecdir + + pkgluaexecdir=\${luaexecdir}/$PACKAGE + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 +$as_echo_n "checking if LUA_VERSION is defined... " >&6; } + if test "x$LUA_VERSION" != 'x'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "cannot check Lua headers without knowing LUA_VERSION" "$LINENO" 5 + +fi + + + + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` + + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + for ac_header in lua.h lualib.h lauxlib.h luaconf.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + CPPFLAGS=$_ax_lua_saved_cppflags + + if test "x$LUA_INCLUDE" = 'x' && + test "x$ac_cv_header_lua_h" != 'xyes'; then : + for _ax_include_path in /usr/include/lua$LUA_VERSION \ + /usr/include/lua/$LUA_VERSION \ + /usr/include/lua$LUA_SHORT_VERSION \ + /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua/$LUA_VERSION \ + /usr/local/include/lua$LUA_SHORT_VERSION \ + ; do + test ! -d "$_ax_include_path" && continue + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua headers in" >&5 +$as_echo_n "checking for Lua headers in... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_ax_include_path" >&5 +$as_echo "$_ax_include_path" >&6; } + + { ac_cv_header_lua_h=; unset ac_cv_header_lua_h;} + { ac_cv_header_lualib_h=; unset ac_cv_header_lualib_h;} + { ac_cv_header_lauxlib_h=; unset ac_cv_header_lauxlib_h;} + { ac_cv_header_luaconf_h=; unset ac_cv_header_luaconf_h;} + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -I$_ax_include_path" + for ac_header in lua.h lualib.h lauxlib.h luaconf.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + CPPFLAGS=$_ax_lua_saved_cppflags + + if test "x$ac_cv_header_lua_h" = 'xyes'; then : + LUA_INCLUDE="-I$_ax_include_path" + break + +fi + done + +fi + + if test "x$ac_cv_header_lua_h" = 'xyes'; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua header version" >&5 +$as_echo_n "checking for Lua header version... " >&6; } +if ${ax_cv_lua_header_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +int main(int argc, char ** argv) +{ + if(argc > 1) printf("%s", LUA_VERSION); + exit(EXIT_SUCCESS); +} + + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ax_cv_lua_header_version=`./conftest$EXEEXT p | \ + sed "s|^Lua \(.*\)|\1|" | \ + grep -o "^[0-9]\+\\.[0-9]\+"` + +else + ax_cv_lua_header_version='unknown' +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CPPFLAGS=$_ax_lua_saved_cppflags + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_header_version" >&5 +$as_echo "$ax_cv_lua_header_version" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Lua header version matches $LUA_VERSION" >&5 +$as_echo_n "checking if Lua header version matches $LUA_VERSION... " >&6; } + if test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ax_header_version_match='yes' + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ax_header_version_match='no' + +fi + +fi + + if test "x$ax_header_version_match" != 'xyes' && + test "x$LUA_INCLUDE" != 'x'; then : + as_fn_error $? "cannot find headers for specified LUA_INCLUDE" "$LINENO" 5 +fi + + if test "x$ax_header_version_match" = 'xyes'; then : + +else + as_fn_error $? "No lua headers found. Try --disable-liblua" "$LINENO" 5 +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 +$as_echo_n "checking if LUA_VERSION is defined... " >&6; } + if test "x$LUA_VERSION" != 'x'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "cannot check Lua libs without knowing LUA_VERSION" "$LINENO" 5 + +fi + + + + if test "x$LUA_LIB" != 'x'; then : + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 +$as_echo_n "checking for library containing lua_load... " >&6; } +if ${ac_cv_search_lua_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lua_load (); +int +main () +{ +return lua_load (); + ; + return 0; +} +_ACEOF +for ac_lib in '' ; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_lua_load=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_lua_load+:} false; then : + break +fi +done +if ${ac_cv_search_lua_load+:} false; then : + +else + ac_cv_search_lua_load=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 +$as_echo "$ac_cv_search_lua_load" >&6; } +ac_res=$ac_cv_search_lua_load +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + _ax_found_lua_libs='yes' +else + _ax_found_lua_libs='no' +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$_ax_found_lua_libs" != 'xyes'; then : + as_fn_error $? "cannot find libs for specified LUA_LIB" "$LINENO" 5 +fi + +else + _ax_lua_extra_libs='' + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing exp" >&5 +$as_echo_n "checking for library containing exp... " >&6; } +if ${ac_cv_search_exp+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char exp (); +int +main () +{ +return exp (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_exp=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_exp+:} false; then : + break +fi +done +if ${ac_cv_search_exp+:} false; then : + +else + ac_cv_search_exp=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_exp" >&5 +$as_echo "$ac_cv_search_exp" >&6; } +ac_res=$ac_cv_search_exp +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if ${ac_cv_search_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dlopen=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_dlopen+:} false; then : + break +fi +done +if ${ac_cv_search_dlopen+:} false; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$ac_cv_search_exp" != 'xno' && + test "x$ac_cv_search_exp" != 'xnone required'; then : + _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp" +fi + + if test "x$ac_cv_search_dlopen" != 'xno' && + test "x$ac_cv_search_dlopen" != 'xnone required'; then : + _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen" +fi + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 +$as_echo_n "checking for library containing lua_load... " >&6; } +if ${ac_cv_search_lua_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lua_load (); +int +main () +{ +return lua_load (); + ; + return 0; +} +_ACEOF +for ac_lib in '' lua$LUA_VERSION lua$LUA_SHORT_VERSION lua; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $_ax_lua_extra_libs $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_lua_load=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_lua_load+:} false; then : + break +fi +done +if ${ac_cv_search_lua_load+:} false; then : + +else + ac_cv_search_lua_load=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 +$as_echo "$ac_cv_search_lua_load" >&6; } +ac_res=$ac_cv_search_lua_load +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + _ax_found_lua_libs='yes' +else + _ax_found_lua_libs='no' +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$ac_cv_search_lua_load" != 'xno' && + test "x$ac_cv_search_lua_load" != 'xnone required'; then : + LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs" +fi + +fi + + if test "x$_ax_found_lua_libs" = 'xyes'; then : + +else + as_fn_error $? "No lua libs found. Try --disable-liblua" "$LINENO" 5 +fi + + EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; + CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; + +$as_echo "#define USE_LUA 1" >>confdefs.h + + + +fi + + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 +$as_echo "enabled" >&6; } + + + + + + if test "x$LUA" = 'x'; then : + for ac_prog in lua lua5.2 lua5.1 lua50 +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_LUA+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $LUA in + [\\/]* | ?:[\\/]*) + ac_cv_path_LUA="$LUA" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_LUA="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +LUA=$ac_cv_path_LUA +if test -n "$LUA"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LUA" >&5 +$as_echo "$LUA" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$LUA" && break +done +test -n "$LUA" || LUA=":" + +fi + ax_display_LUA='lua' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LUA is a Lua interpreter" >&5 +$as_echo_n "checking if $LUA is a Lua interpreter... " >&6; } + + if $LUA -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "not a Lua interpreter" "$LINENO" 5 + +fi + + + + if test "x$LUA" = 'x:'; then : + + as_fn_error $? "No lua found. Try --disable-liblua" "$LINENO" 5 + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA version" >&5 +$as_echo_n "checking for $ax_display_LUA version... " >&6; } +if ${ax_cv_lua_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ + sed "s|^Lua \(.*\)|\1|" | \ + grep -o "^[0-9]\+\\.[0-9]\+"` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_version" >&5 +$as_echo "$ax_cv_lua_version" >&6; } + if test "x$ax_cv_lua_version" = 'x'; then : + as_fn_error $? "invalid Lua version number" "$LINENO" 5 +fi + LUA_VERSION=$ax_cv_lua_version + + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA platform" >&5 +$as_echo_n "checking for $ax_display_LUA platform... " >&6; } +if ${ax_cv_lua_platform+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_lua_platform=`$LUA -e "print('unknown')"` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_platform" >&5 +$as_echo "$ax_cv_lua_platform" >&6; } + LUA_PLATFORM=$ax_cv_lua_platform + + + LUA_PREFIX='${prefix}' + + LUA_EXEC_PREFIX='${exec_prefix}' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA script directory" >&5 +$as_echo_n "checking for $ax_display_LUA script directory... " >&6; } +if ${ax_cv_lua_luadir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$prefix" = 'xNONE'; then : + ax_lua_prefix=$ac_default_prefix +else + ax_lua_prefix=$prefix +fi + + ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" + + + + ax_lua_prefixed_path='' + _ax_package_paths=`$LUA -e 'print(package.path)' 2>/dev/null | sed 's|;|\n|g'` + for _ax_package_path in $_ax_package_paths; do + _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` + _ax_reassembled='' + for _ax_path_part in $_ax_path_parts; do + echo "$_ax_path_part" | grep '\?' >/dev/null && break + _ax_reassembled="$_ax_reassembled/$_ax_path_part" + done + _ax_package_path=$_ax_reassembled + if echo "$_ax_package_path" | grep "^$ax_lua_prefix" >/dev/null; then + ax_lua_prefixed_path=$_ax_package_path + break + fi + done + + if test "x$ax_lua_prefixed_path" != 'x'; then : + _ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'` + ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ + sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"` + +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luadir" >&5 +$as_echo "$ax_cv_lua_luadir" >&6; } + luadir=$ax_cv_lua_luadir + + pkgluadir=\${luadir}/$PACKAGE + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA module directory" >&5 +$as_echo_n "checking for $ax_display_LUA module directory... " >&6; } +if ${ax_cv_lua_luaexecdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$exec_prefix" = 'xNONE'; then : + ax_lua_exec_prefix=$ax_lua_prefix +else + ax_lua_exec_prefix=$exec_prefix +fi + + ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" + + + + ax_lua_prefixed_path='' + _ax_package_paths=`$LUA -e 'print(package.cpathd)' 2>/dev/null | sed 's|;|\n|g'` + for _ax_package_path in $_ax_package_paths; do + _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` + _ax_reassembled='' + for _ax_path_part in $_ax_path_parts; do + echo "$_ax_path_part" | grep '\?' >/dev/null && break + _ax_reassembled="$_ax_reassembled/$_ax_path_part" + done + _ax_package_path=$_ax_reassembled + if echo "$_ax_package_path" | grep "^$ax_lua_exec_prefix" >/dev/null; then + ax_lua_prefixed_path=$_ax_package_path + break + fi + done + + if test "x$ax_lua_prefixed_path" != 'x'; then : + _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'` + ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ + sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"` + +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luaexecdir" >&5 +$as_echo "$ax_cv_lua_luaexecdir" >&6; } + luaexecdir=$ax_cv_lua_luaexecdir + + pkgluaexecdir=\${luaexecdir}/$PACKAGE + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 +$as_echo_n "checking if LUA_VERSION is defined... " >&6; } + if test "x$LUA_VERSION" != 'x'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "cannot check Lua headers without knowing LUA_VERSION" "$LINENO" 5 + +fi + + + + LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` + + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + for ac_header in lua.h lualib.h lauxlib.h luaconf.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + CPPFLAGS=$_ax_lua_saved_cppflags + + if test "x$LUA_INCLUDE" = 'x' && + test "x$ac_cv_header_lua_h" != 'xyes'; then : + for _ax_include_path in /usr/include/lua$LUA_VERSION \ + /usr/include/lua/$LUA_VERSION \ + /usr/include/lua$LUA_SHORT_VERSION \ + /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua/$LUA_VERSION \ + /usr/local/include/lua$LUA_SHORT_VERSION \ + ; do + test ! -d "$_ax_include_path" && continue + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua headers in" >&5 +$as_echo_n "checking for Lua headers in... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_ax_include_path" >&5 +$as_echo "$_ax_include_path" >&6; } + + { ac_cv_header_lua_h=; unset ac_cv_header_lua_h;} + { ac_cv_header_lualib_h=; unset ac_cv_header_lualib_h;} + { ac_cv_header_lauxlib_h=; unset ac_cv_header_lauxlib_h;} + { ac_cv_header_luaconf_h=; unset ac_cv_header_luaconf_h;} + + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -I$_ax_include_path" + for ac_header in lua.h lualib.h lauxlib.h luaconf.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + CPPFLAGS=$_ax_lua_saved_cppflags + + if test "x$ac_cv_header_lua_h" = 'xyes'; then : + LUA_INCLUDE="-I$_ax_include_path" + break + +fi + done + +fi + + if test "x$ac_cv_header_lua_h" = 'xyes'; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua header version" >&5 +$as_echo_n "checking for Lua header version... " >&6; } +if ${ax_cv_lua_header_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + _ax_lua_saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" + if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run test program while cross compiling +See \`config.log' for more details" "$LINENO" 5; } +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +int main(int argc, char ** argv) +{ + if(argc > 1) printf("%s", LUA_VERSION); + exit(EXIT_SUCCESS); +} + + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ax_cv_lua_header_version=`./conftest$EXEEXT p | \ + sed "s|^Lua \(.*\)|\1|" | \ + grep -o "^[0-9]\+\\.[0-9]\+"` + +else + ax_cv_lua_header_version='unknown' +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CPPFLAGS=$_ax_lua_saved_cppflags + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_header_version" >&5 +$as_echo "$ax_cv_lua_header_version" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Lua header version matches $LUA_VERSION" >&5 +$as_echo_n "checking if Lua header version matches $LUA_VERSION... " >&6; } + if test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ax_header_version_match='yes' + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ax_header_version_match='no' + +fi + +fi + + if test "x$ax_header_version_match" != 'xyes' && + test "x$LUA_INCLUDE" != 'x'; then : + as_fn_error $? "cannot find headers for specified LUA_INCLUDE" "$LINENO" 5 +fi + + if test "x$ax_header_version_match" = 'xyes'; then : + +else + as_fn_error $? "No lua headers found. Try --disable-liblua" "$LINENO" 5 +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 +$as_echo_n "checking if LUA_VERSION is defined... " >&6; } + if test "x$LUA_VERSION" != 'x'; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "cannot check Lua libs without knowing LUA_VERSION" "$LINENO" 5 + +fi + + + + if test "x$LUA_LIB" != 'x'; then : + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 +$as_echo_n "checking for library containing lua_load... " >&6; } +if ${ac_cv_search_lua_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lua_load (); +int +main () +{ +return lua_load (); + ; + return 0; +} +_ACEOF +for ac_lib in '' ; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_lua_load=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_lua_load+:} false; then : + break +fi +done +if ${ac_cv_search_lua_load+:} false; then : + +else + ac_cv_search_lua_load=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 +$as_echo "$ac_cv_search_lua_load" >&6; } +ac_res=$ac_cv_search_lua_load +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + _ax_found_lua_libs='yes' +else + _ax_found_lua_libs='no' +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$_ax_found_lua_libs" != 'xyes'; then : + as_fn_error $? "cannot find libs for specified LUA_LIB" "$LINENO" 5 +fi + +else + _ax_lua_extra_libs='' + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing exp" >&5 +$as_echo_n "checking for library containing exp... " >&6; } +if ${ac_cv_search_exp+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char exp (); +int +main () +{ +return exp (); + ; + return 0; +} +_ACEOF +for ac_lib in '' m; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_exp=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_exp+:} false; then : + break +fi +done +if ${ac_cv_search_exp+:} false; then : + +else + ac_cv_search_exp=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_exp" >&5 +$as_echo "$ac_cv_search_exp" >&6; } +ac_res=$ac_cv_search_exp +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if ${ac_cv_search_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dlopen=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_dlopen+:} false; then : + break +fi +done +if ${ac_cv_search_dlopen+:} false; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$ac_cv_search_exp" != 'xno' && + test "x$ac_cv_search_exp" != 'xnone required'; then : + _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp" +fi + + if test "x$ac_cv_search_dlopen" != 'xno' && + test "x$ac_cv_search_dlopen" != 'xnone required'; then : + _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen" +fi + + _ax_lua_saved_libs=$LIBS + LIBS="$LIBS $LUA_LIB" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 +$as_echo_n "checking for library containing lua_load... " >&6; } +if ${ac_cv_search_lua_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lua_load (); +int +main () +{ +return lua_load (); + ; + return 0; +} +_ACEOF +for ac_lib in '' lua$LUA_VERSION lua$LUA_SHORT_VERSION lua; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $_ax_lua_extra_libs $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_lua_load=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_lua_load+:} false; then : + break +fi +done +if ${ac_cv_search_lua_load+:} false; then : + +else + ac_cv_search_lua_load=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 +$as_echo "$ac_cv_search_lua_load" >&6; } +ac_res=$ac_cv_search_lua_load +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + _ax_found_lua_libs='yes' +else + _ax_found_lua_libs='no' +fi + + LIBS=$_ax_lua_saved_libs + + if test "x$ac_cv_search_lua_load" != 'xno' && + test "x$ac_cv_search_lua_load" != 'xnone required'; then : + LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs" +fi + +fi + + if test "x$_ax_found_lua_libs" = 'xyes'; then : + +else + as_fn_error $? "No lua libs found. Try --disable-liblua" "$LINENO" 5 +fi + + EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; + CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; + +$as_echo "#define USE_LUA 1" >>confdefs.h + + + +fi + + +fi + + +# Checks for header files. for ac_header in fcntl.h malloc.h stdlib.h string.h sys/socket.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` diff --git a/configure.ac b/configure.ac index f1480ed..b4a9ca7 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,8 @@ AC_INIT([telegram], [0.1]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) +m4_include([ax_lua.m4]) + # Checks for programs. AC_PROG_CC @@ -46,7 +48,7 @@ AC_CHECK_LIB([rt], [clock_gettime], ] ) -AC_MSG_CHECKING([Checking for libconfig]) +AC_MSG_CHECKING([for libconfig]) AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], [ if test "x$enableval" = "xno" ; then @@ -61,6 +63,40 @@ AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], AC_CHECK_LIB([config],[config_init],AC_DEFINE(ENABLE_LIBCONFIG,1,[enable libconfig]),AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) [EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; ] ]) + +AC_MSG_CHECKING([for liblua]) +AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], + [ + if test "x$enableval" = "xno" ; then + AC_MSG_RESULT([disabled]) + else + AC_MSG_RESULT([enabled]) + AX_PROG_LUA([],[], + [ + AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) + AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) + [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] + [CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; ] + AC_DEFINE(USE_LUA,1,[use lua]) + ], + [ + AC_MSG_ERROR([No lua found. Try --disable-liblua]) + ]) + fi + ],[ + AC_MSG_RESULT([enabled]) + AX_PROG_LUA([],[], + [ + AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) + AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) + [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] + [CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; ] + AC_DEFINE(USE_LUA,1,[use lua]) + ], + [ + AC_MSG_ERROR([No lua found. Try --disable-liblua]) + ]) + ]) # Checks for header files. AC_CHECK_HEADERS([fcntl.h malloc.h stdlib.h string.h sys/socket.h unistd.h]) diff --git a/loop.c b/loop.c index 104c30a..fa06a2c 100644 --- a/loop.c +++ b/loop.c @@ -48,6 +48,7 @@ #include "telegram.h" #include "loop.h" #include "binlog.h" +#include "lua-tg.h" extern char *default_username; extern char *auth_token; @@ -95,6 +96,9 @@ void net_loop (int flags, int (*is_end)(void)) { } } connections_poll_result (fds + cc, x - cc); + #ifdef USE_LUA + lua_do_all (); + #endif if (safe_quit && !queries_num) { printf ("All done. Exit\n"); rl_callback_handler_remove (); @@ -448,6 +452,9 @@ int loop (void) { replay_log (); logprintf ("replay log end in %lf seconds\n", get_double_time () - t); write_binlog (); + #ifdef USE_LUA + lua_binlog_end (); + #endif } else { read_auth_file (); } @@ -580,8 +587,12 @@ int loop (void) { do_get_difference (); net_loop (0, dgot); + #ifdef USE_LUA + lua_diff_end (); + #endif send_all_unsent (); + do_get_dialog_list (); return main_loop (); diff --git a/lua-tg.c b/lua-tg.c new file mode 100644 index 0000000..c3ff97e --- /dev/null +++ b/lua-tg.c @@ -0,0 +1,445 @@ +#include "config.h" + +#ifdef USE_LUA +#include "lua-tg.h" + +#include "include.h" +#include +#include + + +#include +#include +#include +lua_State *luaState; + +#include "structures.h" +#include "interface.h" +#include "constants.h" +#include "tools.h" +#include "queries.h" + +extern int verbosity; + +static int have_file; + +#define my_lua_checkstack(L,x) assert (lua_checkstack (L, x)) +void push_user (peer_t *P UU); +void push_peer (peer_id_t id, peer_t *P); + +void lua_add_string_field (const char *name, const char *value) { + assert (name && strlen (name)); + if (!value || !strlen (value)) { return; } + my_lua_checkstack (luaState, 3); + lua_pushstring (luaState, name); + lua_pushstring (luaState, value); + lua_settable (luaState, -3); +} + +void lua_add_num_field (const char *name, double value) { + assert (name && strlen (name)); + my_lua_checkstack (luaState, 3); + lua_pushstring (luaState, name); + lua_pushnumber (luaState, value); + lua_settable (luaState, -3); +} + +void push_peer_type (int x) { + switch (x) { + case PEER_USER: + lua_pushstring (luaState, "user"); + break; + case PEER_CHAT: + lua_pushstring (luaState, "chat"); + break; + case PEER_ENCR_CHAT: + lua_pushstring (luaState, "encr_chat"); + break; + default: + assert (0); + } +} + +void push_user (peer_t *P UU) { + my_lua_checkstack (luaState, 4); + lua_add_string_field ("first_name", P->user.first_name); + lua_add_string_field ("last_name", P->user.last_name); + lua_add_string_field ("real_first_name", P->user.real_first_name); + lua_add_string_field ("real_last_name", P->user.real_last_name); + lua_add_string_field ("phone", P->user.phone); +} + +void push_chat (peer_t *P) { + my_lua_checkstack (luaState, 4); + assert (P->chat.title); + lua_add_string_field ("title", P->chat.title); + lua_add_num_field ("members_num", P->chat.users_num); +} + +void push_encr_chat (peer_t *P) { + my_lua_checkstack (luaState, 4); + lua_pushstring (luaState, "user"); + push_peer (MK_USER (P->encr_chat.user_id), user_chat_get (MK_USER (P->encr_chat.user_id))); + lua_settable (luaState, -3); +} + +void push_peer (peer_id_t id, peer_t *P) { + lua_newtable (luaState); + + lua_add_num_field ("id", get_peer_id (id)); + lua_pushstring (luaState, "type"); + push_peer_type (get_peer_type (id)); + lua_settable (luaState, -3); + + + if (!P || !(P->flags & FLAG_CREATED)) { + lua_pushstring (luaState, "print_name"); + static char s[100]; + switch (get_peer_type (id)) { + case PEER_USER: + sprintf (s, "user#%d", get_peer_id (id)); + break; + case PEER_CHAT: + sprintf (s, "chat#%d", get_peer_id (id)); + break; + case PEER_ENCR_CHAT: + sprintf (s, "encr_chat#%d", get_peer_id (id)); + break; + default: + assert (0); + } + lua_pushstring (luaState, s); + lua_settable (luaState, -3); // flags + + return; + } + + lua_add_string_field ("print_name", P->print_name); + lua_add_num_field ("flags", P->flags); + + switch (get_peer_type (id)) { + case PEER_USER: + push_user (P); + break; + case PEER_CHAT: + push_chat (P); + break; + case PEER_ENCR_CHAT: + push_encr_chat (P); + break; + default: + assert (0); + } +} + +void push_media (struct message_media *M) { + my_lua_checkstack (luaState, 4); + + switch (M->type) { + case CODE_message_media_photo: + case CODE_decrypted_message_media_photo: + lua_pushstring (luaState, "photo"); + break; + case CODE_message_media_video: + case CODE_decrypted_message_media_video: + lua_pushstring (luaState, "video"); + break; + case CODE_message_media_audio: + case CODE_decrypted_message_media_audio: + lua_pushstring (luaState, "audio"); + break; + case CODE_message_media_document: + case CODE_decrypted_message_media_document: + lua_pushstring (luaState, "document"); + break; + case CODE_message_media_unsupported: + lua_pushstring (luaState, "unsupported"); + break; + case CODE_message_media_geo: + lua_newtable (luaState); + lua_add_num_field ("longitude", M->geo.longitude); + lua_add_num_field ("latitude", M->geo.latitude); + break; + case CODE_message_media_contact: + case CODE_decrypted_message_media_contact: + lua_newtable (luaState); + lua_add_string_field ("phone", M->phone); + lua_add_string_field ("first_name", M->first_name); + lua_add_string_field ("last_name", M->last_name); + lua_add_num_field ("user_id", M->user_id); + break; + default: + lua_pushstring (luaState, "???"); + } +} + +void push_message (struct message *M) { + assert (M); + my_lua_checkstack (luaState, 10); + lua_newtable (luaState); + + static char s[30]; + tsnprintf (s, 30, "%lld", M->id); + lua_add_string_field ("id", s); + lua_add_num_field ("flags", M->flags); + + if (get_peer_type (M->fwd_from_id)) { + lua_pushstring (luaState, "fwd_from"); + push_peer (M->fwd_from_id, user_chat_get (M->fwd_from_id)); + lua_settable (luaState, -3); // fwd_from + + lua_add_num_field ("fwd_date", M->fwd_date); + } + + lua_pushstring (luaState, "from"); + push_peer (M->from_id, user_chat_get (M->from_id)); + lua_settable (luaState, -3); + + lua_pushstring (luaState, "to"); + push_peer (M->to_id, user_chat_get (M->to_id)); + lua_settable (luaState, -3); + + lua_pushstring (luaState, "out"); + lua_pushboolean (luaState, M->out); + lua_settable (luaState, -3); + + lua_pushstring (luaState, "unread"); + lua_pushboolean (luaState, M->unread); + lua_settable (luaState, -3); + + lua_pushstring (luaState, "date"); + lua_pushnumber (luaState, M->date); + lua_settable (luaState, -3); + + lua_pushstring (luaState, "service"); + lua_pushboolean (luaState, M->service); + lua_settable (luaState, -3); + + if (!M->service) { + if (M->message_len && M->message) { + lua_pushstring (luaState, "text"); + lua_pushlstring (luaState, M->message, M->message_len); + lua_settable (luaState, -3); + } + if (M->media.type && M->media.type != CODE_message_media_empty && M->media.type != CODE_decrypted_message_media_empty) { + lua_pushstring (luaState, "media"); + push_media (&M->media); + lua_settable (luaState, -3); + } + } +} + +void lua_binlog_end (void) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_binlog_replay_end"); + assert (lua_gettop (luaState) == 1); + + int r = lua_pcall (luaState, 0, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_diff_end (void) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_get_difference_end"); + assert (lua_gettop (luaState) == 1); + + int r = lua_pcall (luaState, 0, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_our_id (int id) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_our_id"); + lua_pushnumber (luaState, id); + assert (lua_gettop (luaState) == 2); + + int r = lua_pcall (luaState, 1, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_new_msg (struct message *M UU) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_msg_receive"); + push_message (M); + assert (lua_gettop (luaState) == 2); + + int r = lua_pcall (luaState, 1, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_secret_chat_created (struct secret_chat *C) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_secret_chat_created"); + push_peer (C->id, (void *)C); + assert (lua_gettop (luaState) == 2); + + int r = lua_pcall (luaState, 1, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_user_update (struct user *U) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_user_update"); + push_peer (U->id, (void *)U); + assert (lua_gettop (luaState) == 2); + + int r = lua_pcall (luaState, 1, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_chat_update (struct chat *C) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_chat_update"); + push_peer (C->id, (void *)C); + assert (lua_gettop (luaState) == 2); + + int r = lua_pcall (luaState, 1, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +extern peer_t *Peers[]; +extern int peer_num; + +#define MAX_LUA_COMMANDS 1000 +void *lua_ptr[MAX_LUA_COMMANDS]; +static int pos; + +static peer_t *get_peer (const char *s) { + int index = 0; + while (index < peer_num && Peers[index]->print_name && strcmp (Peers[index]->print_name, s)) { + index ++; + } + return index == peer_num ? 0 : Peers[index]; +} + +void lua_do_all (void) { + int p = 0; + while (p < pos) { + int l = (long)lua_ptr[p ++]; + assert (p + l + 1 <= pos); + int f = (long)lua_ptr[p ++]; + switch (f) { + case 0: + do_send_message (((peer_t *)lua_ptr[p])->id, lua_ptr[p + 1], strlen (lua_ptr[p + 1])); + tfree_str (lua_ptr[p + 1]); + p += 2; + break; + case 1: + do_forward_message (((peer_t *)lua_ptr[p])->id, (long)lua_ptr[p + 1]); + p += 2; + break; + default: + assert (0); + } + } + pos = 0; +} + + +static int send_msg_from_lua (lua_State *L) { + if (MAX_LUA_COMMANDS - pos < 4) { + lua_pushboolean (L, 0); + return 1; + } + int n = lua_gettop (L); + if (n != 2) { + lua_pushboolean (L, 0); + return 1; + } + const char *s = lua_tostring (L, -2); + const char *msg = lua_tostring (L, -1); + + peer_t *P = get_peer (s); + if (!P) { + lua_pushboolean (L, 0); + return 1; + } + + lua_ptr[pos ++] = (void *)2l; + lua_ptr[pos ++] = (void *)0l; + lua_ptr[pos ++] = P; + lua_ptr[pos ++] = tstrdup (msg); + logprintf ("msg = %s\n", msg); + + lua_pushboolean (L, 1); + return 1; +} + +static int fwd_msg_from_lua (lua_State *L) { + if (MAX_LUA_COMMANDS - pos < 4) { + lua_pushboolean (L, 0); + return 1; + } + int n = lua_gettop (L); + if (n != 2) { + lua_pushboolean (L, 0); + return 1; + } + const char *s = lua_tostring (L, -2); + long long num = atoll (lua_tostring (L, -1)); + peer_t *P = get_peer (s); + if (!P) { + lua_pushboolean (L, 0); + return 1; + } + + lua_ptr[pos ++] = (void *)2l; + lua_ptr[pos ++] = (void *)1l; + lua_ptr[pos ++] = P; + lua_ptr[pos ++] = (void *)(long)num; + lua_pushboolean (L, 1); + return 1; +} + +void lua_init (const char *file) { + if (!file) { return; } + have_file = 1; + luaState = luaL_newstate (); + luaL_openlibs (luaState); + + lua_register (luaState, "send_msg", send_msg_from_lua); + lua_register (luaState, "fwd_msg", fwd_msg_from_lua); + + int ret = luaL_dofile (luaState, file); + if (ret) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + exit (1); + } +} + +#endif diff --git a/lua-tg.h b/lua-tg.h new file mode 100644 index 0000000..35f3b09 --- /dev/null +++ b/lua-tg.h @@ -0,0 +1,16 @@ +#ifndef __LUA_TG_H__ +#define __LUA_TG_H__ + +#include +#include "structures.h" + +void lua_init (const char *file); +void lua_new_msg (struct message *M); +void lua_our_id (int id); +void lua_secret_chat_created (struct secret_chat *U); +void lua_user_update (struct user *U); +void lua_chat_update (struct chat *C); +void lua_binlog_end (void); +void lua_diff_end (void); +void lua_do_all (void); +#endif diff --git a/main.c b/main.c index d671af2..a832109 100644 --- a/main.c +++ b/main.c @@ -47,6 +47,10 @@ #include "interface.h" #include "tools.h" +#ifdef USE_LUA +# include "lua-tg.h" +#endif + #define PROGNAME "telegram-client" #define VERSION "0.01" @@ -349,9 +353,12 @@ FILE *log_net_f; int register_mode; int disable_auto_accept; + +char *lua_file; + void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:RfBL:E")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:RfBL:Es:")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -398,6 +405,9 @@ void args_parse (int argc, char **argv) { case 'w': allow_weak_random = 1; break; + case 's': + lua_file = tstrdup (optarg); + break; case 'h': default: usage (); @@ -410,13 +420,13 @@ void print_backtrace (void) { void *buffer[255]; const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); backtrace_symbols_fd (buffer, calls, 1); - exit(EXIT_FAILURE); } void sig_handler (int signum) { set_terminal_attributes (); printf ("Signal %d received\n", signum); print_backtrace (); + exit(EXIT_FAILURE); } @@ -439,6 +449,11 @@ int main (int argc, char **argv) { get_terminal_attributes (); + #ifdef USE_LUA + if (lua_file) { + lua_init (lua_file); + } + #endif inner_main (); diff --git a/mtproto-common.h b/mtproto-common.h index 5f7218d..d15c922 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -306,10 +306,15 @@ static inline char *fetch_str (int len) { static inline char *fetch_str_dup (void) { int l = prefetch_strlen (); assert (l >= 0); - char *s = talloc (l + 1); - memcpy (s, fetch_str (l), l); - s[l] = 0; - return s; + int i; + char *s = fetch_str (l); + for (i = 0; i < l; i++) { + if (!s[i]) { break; } + } + char *r = talloc (i + 1); + memcpy (r, s, i); + r[i] = 0; + return r; } static inline int fetch_update_str (char **s) { @@ -361,6 +366,7 @@ static inline int set_update_int (int *value, int new_value) { static inline void fetch_skip (int n) { in_ptr += n; + assert (in_ptr <= in_end); } static inline void fetch_skip_str (void) { @@ -382,6 +388,7 @@ static inline long have_prefetch_ints (void) { int fetch_bignum (BIGNUM *x); static inline int fetch_int (void) { + assert (in_ptr + 1 <= in_end); if (verbosity > 6) { logprintf ("fetch_int: 0x%08x (%d)\n", *in_ptr, *in_ptr); } @@ -392,37 +399,44 @@ static inline int fetch_bool (void) { if (verbosity > 6) { logprintf ("fetch_bool: 0x%08x (%d)\n", *in_ptr, *in_ptr); } + assert (in_ptr + 1 <= in_end); assert (*(in_ptr) == (int)CODE_bool_true || *(in_ptr) == (int)CODE_bool_false); return *(in_ptr ++) == (int)CODE_bool_true; } static inline int prefetch_int (void) { + assert (in_ptr < in_end); return *(in_ptr); } static inline void prefetch_data (void *data, int size) { + assert (in_ptr + (size >> 2) <= in_end); memcpy (data, in_ptr, size); } static inline void fetch_data (void *data, int size) { + assert (in_ptr + (size >> 2) <= in_end); memcpy (data, in_ptr, size); assert (!(size & 3)); in_ptr += (size >> 2); } static inline long long fetch_long (void) { + assert (in_ptr + 2 <= in_end); long long r = *(long long *)in_ptr; in_ptr += 2; return r; } static inline double fetch_double (void) { + assert (in_ptr + 2 <= in_end); double r = *(double *)in_ptr; in_ptr += 2; return r; } static inline void fetch_ints (void *data, int count) { + assert (in_ptr + count <= in_end); memcpy (data, in_ptr, 4 * count); in_ptr += count; } diff --git a/queries.c b/queries.c index 08ce056..96c3a91 100644 --- a/queries.c +++ b/queries.c @@ -904,7 +904,9 @@ void do_send_message (peer_id_t id, const char *msg, int len) { return; } } - long long t = -lrand48 () * (1ll << 32) - lrand48 (); + long long t; + secure_random (&t, 8); + logprintf ("t = %lld, len = %d\n", t, len); bl_do_send_message_text (t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); struct message *M = message_get (t); assert (M); diff --git a/tools.c b/tools.c index 74c5e2c..badf812 100644 --- a/tools.c +++ b/tools.c @@ -78,6 +78,9 @@ void tfree (void *ptr, int size __attribute__ ((unused))) { #ifdef DEBUG total_allocated_bytes -= size; ptr -= RES_PRE; + if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { + logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); + } assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); assert (*(int *)(ptr + 4) == size); diff --git a/tree.h b/tree.h index 3de93aa..fd79b75 100644 --- a/tree.h +++ b/tree.h @@ -24,6 +24,7 @@ #include #include +#pragma pack(push,4) #define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ struct tree_ ## X_NAME { \ struct tree_ ## X_NAME *left, *right;\ @@ -58,6 +59,7 @@ void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## }\ }\ \ +struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result));\ struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ if (!T) {\ return new_tree_node_ ## X_NAME (x, y);\ @@ -93,6 +95,7 @@ struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct }\ }\ \ +struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result));\ struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ assert (T);\ int c = X_CMP (x, T->x);\ @@ -150,4 +153,5 @@ void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ }\ #define int_cmp(a,b) ((a) - (b)) +#pragma pack(pop) #endif From 497a45f04db9f0991261da51f1c1f8cb037716f3 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sun, 12 Jan 2014 04:43:56 +0400 Subject: [PATCH 196/465] Added sample lua script --- test.lua | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 test.lua diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..90a3de5 --- /dev/null +++ b/test.lua @@ -0,0 +1,95 @@ +started = 0 +our_id = 0 + +function vardump(value, depth, key) + local linePrefix = "" + local spaces = "" + + if key ~= nil then + linePrefix = "["..key.."] = " + end + + if depth == nil then + depth = 0 + else + depth = depth + 1 + for i=1, depth do spaces = spaces .. " " end + end + + if type(value) == 'table' then + mTable = getmetatable(value) + if mTable == nil then + print(spaces ..linePrefix.."(table) ") + else + print(spaces .."(metatable) ") + value = mTable + end + for tableKey, tableValue in pairs(value) do + vardump(tableValue, depth, tableKey) + end + elseif type(value) == 'function' or + type(value) == 'thread' or + type(value) == 'userdata' or + value == nil + then + print(spaces..tostring(value)) + else + print(spaces..linePrefix.."("..type(value)..") "..tostring(value)) + end +end + +print ("HI, this is lua script") + + + +function on_msg_receive (msg) + if started == 0 then + return + end + if msg.out then + return + end + if (msg.text == 'ping') then + if (msg.to.id == our_id) then + print ('sending pong to ' .. tostring (msg.from.print_name)) + send_msg (msg.from.print_name, 'pong') + else + print ('sending pong to ' .. tostring (msg.to.print_name)) + send_msg (msg.to.print_name, 'pong') + end + return + end + if (msg.text == 'PING') then + if (msg.to.id == our_id) then + fwd_msg (msg.from.print_name, msg.id) + else + fwd_msg (msg.to.print_name, msg.id) + end + return + end + --vardump (msg) + --print ( "Message # " .. msg.id .. " (flags " .. msg.flags .. ")") +end + +function on_our_id (id) + our_id = id +end + +function on_secret_chat_created (peer) + --vardump (peer) +end + +function on_user_update (user) + --vardump (user) +end + +function on_chat_update (user) + --vardump (user) +end + +function on_get_difference_end () +end + +function on_binlog_replay_end () + started = 1 +end From c23d34ca14c4c5a857dbdc08e60b4dae6fe85a16 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sun, 12 Jan 2014 04:44:47 +0400 Subject: [PATCH 197/465] Fixed travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f453581..475b337 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ install: - sudo apt-get install libconfig8-dev - sudo apt-get install libreadline6-dev - sudo apt-get install libssl-dev + - sudo apt-get install liblua5.2-dev script: - ./configure From 39ed32ec5796209d9bea4ed4bb915103de2f4b57 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sun, 12 Jan 2014 04:56:36 +0400 Subject: [PATCH 198/465] Fixed travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 475b337..ec28eea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: - sudo apt-get install libconfig8-dev - sudo apt-get install libreadline6-dev - sudo apt-get install libssl-dev - - sudo apt-get install liblua5.2-dev + - sudo apt-get install liblua5.2-dev lua5.2 script: - ./configure From 46163db14d807d71eb45bf46142a9fcfc34600d6 Mon Sep 17 00:00:00 2001 From: antma Date: Mon, 13 Jan 2014 16:09:33 +0400 Subject: [PATCH 199/465] fix small memory leaks in the function do_send_photo for the cases of invalid, empty or large file --- queries.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/queries.c b/queries.c index 96c3a91..50fd1de 100644 --- a/queries.c +++ b/queries.c @@ -1462,6 +1462,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { rprintf ("No such file '%s'\n", file_name); + tfree_str (file_name); return; } struct stat buf; @@ -1469,6 +1470,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { long long size = buf.st_size; if (size <= 0) { rprintf ("File has zero length\n"); + tfree_str (file_name); close (fd); return; } @@ -1483,6 +1485,14 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { f->part_size *= 2; } + if (f->part_size > (512 << 10)) { + close (fd); + rprintf ("Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000); + tfree (f, sizeof (*f)); + tfree_str (file_name); + return; + } + f->id = lrand48 () * (1ll << 32) + lrand48 (); f->to_id = to_id; f->media_type = type; @@ -1496,11 +1506,6 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { f->key = talloc (32); secure_random (f->key, 32); } - if (f->part_size > (512 << 10)) { - close (fd); - rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); - return; - } if (f->media_type == CODE_input_media_uploaded_video && !f->encr) { f->media_type = CODE_input_media_uploaded_thumb_video; send_file_thumb (f); From 4ccacb146c9145ff5ed5976bbbeaae293056a753 Mon Sep 17 00:00:00 2001 From: antma Date: Mon, 13 Jan 2014 16:26:48 +0400 Subject: [PATCH 200/465] add functions tstrndup (auto check return value of strndup calls) --- binlog.c | 2 +- interface.c | 10 +++++----- queries.c | 2 +- tools.c | 17 +++++++++++++++++ tools.h | 1 + 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/binlog.c b/binlog.c index 00dc12b..5e908db 100644 --- a/binlog.c +++ b/binlog.c @@ -100,7 +100,7 @@ void replay_log_event (void) { if (verbosity) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } - alloc_dc (id, strndup (ip, l2), port); + alloc_dc (id, tstrndup (ip, l2), port); } rptr = in_ptr; break; diff --git a/interface.c b/interface.c index 53a245c..71e699c 100644 --- a/interface.c +++ b/interface.c @@ -675,7 +675,7 @@ void interpreter (char *line UU) { printf ("Empty file name\n"); RET; } - do_send_photo (CODE_input_media_uploaded_photo, id, strndup (s, t)); + do_send_photo (CODE_input_media_uploaded_photo, id, tstrndup (s, t)); } else if (IS_WORD("send_video")) { GET_PEER; int t; @@ -684,7 +684,7 @@ void interpreter (char *line UU) { printf ("Empty file name\n"); RET; } - do_send_photo (CODE_input_media_uploaded_video, id, strndup (s, t)); + do_send_photo (CODE_input_media_uploaded_video, id, tstrndup (s, t)); } else if (IS_WORD ("send_text")) { GET_PEER; int t; @@ -693,7 +693,7 @@ void interpreter (char *line UU) { printf ("Empty file name\n"); RET; } - do_send_text (id, strndup (s, t)); + do_send_text (id, tstrndup (s, t)); } else if (IS_WORD ("fwd")) { GET_PEER; int num = next_token_int (); @@ -950,7 +950,7 @@ void interpreter (char *line UU) { printf ("Empty file name\n"); RET; } - do_send_photo (CODE_input_media_uploaded_audio, id, strndup (s, t)); + do_send_photo (CODE_input_media_uploaded_audio, id, tstrndup (s, t)); } else if (IS_WORD("send_document")) { GET_PEER; int t; @@ -959,7 +959,7 @@ void interpreter (char *line UU) { printf ("Empty file name\n"); RET; } - do_send_photo (CODE_input_media_uploaded_document, id, strndup (s, t)); + do_send_photo (CODE_input_media_uploaded_document, id, tstrndup (s, t)); } else if (IS_WORD ("load_audio")) { long long num = next_token_int (); if (num == NOT_FOUND) { diff --git a/queries.c b/queries.c index 50fd1de..339e214 100644 --- a/queries.c +++ b/queries.c @@ -386,7 +386,7 @@ int send_code_on_answer (struct query *q UU) { if (phone_code_hash) { tfree_str (phone_code_hash); } - phone_code_hash = strndup (s, l); + phone_code_hash = tstrndup (s, l); want_dc_num = -1; return 0; } diff --git a/tools.c b/tools.c index badf812..f4a4c0a 100644 --- a/tools.c +++ b/tools.c @@ -166,6 +166,23 @@ char *tstrdup (const char *s) { #endif } +char *tstrndup (const char *s, size_t n) { +#ifdef DEBUG + size_t l = 0; + for (l = 0; l < n && s[l]; l++) { } + char *p = talloc (l + 1); + memcpy (p, s, l); + p[l] = 0; + return p; +#else + char *p = strndup (s, n); + if (p == NULL) { + out_of_memory (); + } + return p; +#endif +} + void ensure (int r) { if (!r) { logprintf ("Open SSL error\n"); diff --git a/tools.h b/tools.h index 8105c27..09f2b2b 100644 --- a/tools.h +++ b/tools.h @@ -24,6 +24,7 @@ void *talloc (size_t size); void *trealloc (void *ptr, size_t old_size, size_t size); void *talloc0 (size_t size); char *tstrdup (const char *s); +char *tstrndup (const char *s, size_t n); int tinflate (void *input, int ilen, void *output, int olen); void ensure (int r); void ensure_ptr (void *p); From 850c5f8eb5754d5f25bc1859e0a09d785ad50eb7 Mon Sep 17 00:00:00 2001 From: antma Date: Mon, 13 Jan 2014 16:36:29 +0400 Subject: [PATCH 201/465] don't output backtrace in out of memory case --- tools.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tools.c b/tools.c index f4a4c0a..208036f 100644 --- a/tools.c +++ b/tools.c @@ -30,6 +30,8 @@ #include "tools.h" #ifdef DEBUG +#define RES_PRE 8 +#define RES_AFTER 8 #define MAX_BLOCKS 1000000 void *blocks[MAX_BLOCKS]; void *free_blocks[MAX_BLOCKS]; @@ -37,18 +39,13 @@ int used_blocks; int free_blocks_cnt; #endif -#ifdef DEBUG -#define RES_PRE 8 -#define RES_AFTER 8 -#endif - extern int verbosity; long long total_allocated_bytes; static void out_of_memory (void) { - logprintf ("Out of memory\n"); - assert (0 && "Out of memory"); + fprintf (stderr, "Out of memory\n"); + exit (1); } int tsnprintf (char *buf, int len, const char *format, ...) { From eb2bc7f0ff7c2b9380b6cea55d46bff7f5a38bc9 Mon Sep 17 00:00:00 2001 From: antma Date: Mon, 13 Jan 2014 17:05:25 +0400 Subject: [PATCH 202/465] fix #include "config.h" for all source files --- binlog.c | 4 ++++ interface.c | 3 +++ loop.c | 7 +++++-- lua-tg.c | 2 ++ main.c | 6 +++++- mtproto-client.c | 5 +++++ mtproto-common.c | 5 +++++ net.c | 5 +++++ queries.c | 5 +++++ structures.c | 2 ++ tools.c | 4 ++++ 11 files changed, 45 insertions(+), 3 deletions(-) diff --git a/binlog.c b/binlog.c index 5e908db..36407f7 100644 --- a/binlog.c +++ b/binlog.c @@ -16,7 +16,11 @@ Copyright Vitaly Valtman 2013 */ + +#ifdef HAVE_CONFIG_H #include "config.h" +#endif + #ifdef USE_LUA # include "lua-tg.h" #endif diff --git a/interface.c b/interface.c index 71e699c..24ac58f 100644 --- a/interface.c +++ b/interface.c @@ -17,7 +17,10 @@ Copyright Vitaly Valtman 2013 */ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif + #define _GNU_SOURCE #include diff --git a/loop.c b/loop.c index fa06a2c..c8bc2e7 100644 --- a/loop.c +++ b/loop.c @@ -16,13 +16,16 @@ Copyright Vitaly Valtman 2013 */ -#define READLINE_CALLBACKS + +#ifdef HAVE_CONFIG_H #include "config.h" +#endif + +#define READLINE_CALLBACKS #define _GNU_SOURCE #include #include - #include #include #ifdef READLINE_GNU diff --git a/lua-tg.c b/lua-tg.c index c3ff97e..62d9bb7 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -1,4 +1,6 @@ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif #ifdef USE_LUA #include "lua-tg.h" diff --git a/main.c b/main.c index a832109..88410be 100644 --- a/main.c +++ b/main.c @@ -16,8 +16,12 @@ Copyright Vitaly Valtman 2013 */ -#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H #include "config.h" +#endif + +#define _GNU_SOURCE #include #include diff --git a/mtproto-client.c b/mtproto-client.c index 7f1d592..844af9c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -17,6 +17,11 @@ Copyright Nikolay Durov, Andrey Lopatin 2012-2013 Copyright Vitaly Valtman 2013 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #define _FILE_OFFSET_BITS 64 #include diff --git a/mtproto-common.c b/mtproto-common.c index 6d958de..12efcca 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -17,6 +17,11 @@ Copyright Nikolay Durov, Andrey Lopatin 2012-2013 Copyright Vitaly Valtman 2013 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #define _FILE_OFFSET_BITS 64 #include diff --git a/net.c b/net.c index 6c672fc..bbc9a48 100644 --- a/net.c +++ b/net.c @@ -16,6 +16,11 @@ Copyright Vitaly Valtman 2013 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #define _GNU_SOURCE #include #include diff --git a/queries.c b/queries.c index 339e214..de0232b 100644 --- a/queries.c +++ b/queries.c @@ -16,6 +16,11 @@ Copyright Vitaly Valtman 2013 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #define _FILE_OFFSET_BITS 64 #include #include diff --git a/structures.c b/structures.c index 0bde616..81af89b 100644 --- a/structures.c +++ b/structures.c @@ -17,7 +17,9 @@ Copyright Vitaly Valtman 2013 */ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif #include #include diff --git a/tools.c b/tools.c index 208036f..74ff5d2 100644 --- a/tools.c +++ b/tools.c @@ -17,6 +17,10 @@ Copyright Vitaly Valtman 2013 */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #define _GNU_SOURCE #include From 622dec3e7021c88ea86d6f15bab63340bbd4406a Mon Sep 17 00:00:00 2001 From: antma Date: Mon, 13 Jan 2014 17:12:39 +0400 Subject: [PATCH 203/465] remove useless #define _GNU_SOURCE from not using asprintf sources --- loop.c | 1 - main.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/loop.c b/loop.c index c8bc2e7..f23f0f3 100644 --- a/loop.c +++ b/loop.c @@ -22,7 +22,6 @@ #endif #define READLINE_CALLBACKS -#define _GNU_SOURCE #include #include diff --git a/main.c b/main.c index 88410be..de39372 100644 --- a/main.c +++ b/main.c @@ -21,8 +21,6 @@ #include "config.h" #endif -#define _GNU_SOURCE - #include #include #include From fdaca01c59452176e68fff6443b17851fe448e48 Mon Sep 17 00:00:00 2001 From: antma Date: Mon, 13 Jan 2014 17:28:24 +0400 Subject: [PATCH 204/465] fix some autoscan warnings --- configure.ac | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b4a9ca7..d56598d 100644 --- a/configure.ac +++ b/configure.ac @@ -99,15 +99,17 @@ AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], ]) # Checks for header files. -AC_CHECK_HEADERS([fcntl.h malloc.h stdlib.h string.h sys/socket.h unistd.h]) +AC_CHECK_HEADERS([fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T +AC_TYPE_UID_T +AC_C_INLINE # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS([memset select strdup strndup]) +AC_CHECK_FUNCS([alarm endpwent memset memmove mkdir select socket strdup strndup uname]) AC_SUBST(EXTRA_LIBS) AC_CONFIG_FILES([Makefile]) From f06c96fa73662d9c8324ae433b900f1c15bd96d0 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 13 Jan 2014 16:58:14 +0300 Subject: [PATCH 205/465] restored _GNU_SOURCE for getline in FreeBSD --- loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/loop.c b/loop.c index f23f0f3..3375756 100644 --- a/loop.c +++ b/loop.c @@ -21,6 +21,7 @@ #include "config.h" #endif +#define _GNU_SOURCE #define READLINE_CALLBACKS #include From 2c05a3c65a0967e54efda0342f5f2c2ca94d691f Mon Sep 17 00:00:00 2001 From: antma Date: Tue, 14 Jan 2014 14:46:13 +0400 Subject: [PATCH 206/465] fix sending a lot of spaces in version string --- queries.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries.c b/queries.c index de0232b..76fcde9 100644 --- a/queries.c +++ b/queries.c @@ -315,8 +315,8 @@ void do_insert_header (void) { struct utsname st; uname (&st); out_string (st.machine); - static char buf[65536]; - tsnprintf (buf, 65535, "%999s %999s %999s", st.sysname, st.release, st.version); + static char buf[4096]; + tsnprintf (buf, sizeof (buf), "%.999s %.999s %.999s\n", st.sysname, st.release, st.version); out_string (buf); out_string (TG_VERSION " (build " TG_BUILD ")"); out_string ("En"); From 54144b5f1c9f33c4cc307c494444330ed1006c6a Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 15 Jan 2014 15:04:59 +0300 Subject: [PATCH 207/465] Update README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0be4923..03aca69 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,17 @@ or download and extract zip #### Linux -Install libs: readline openssl and (if you want to use config) libconfig. +Install libs: readline openssl and (if you want to use config) libconfig and lublua. +If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively On ubuntu use: - $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev + $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 lublua5.2-dev On gentoo: - $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl + $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua + +Default Makefile uses liblua5.2 from ubuntu. If you use different version of liblua or linux you have to run ./configure script or you will get some strange compilation error. + Then $ ./configure From 48c2619bf82f6a2dbcbeac481a2a8055c212f60b Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 15 Jan 2014 16:10:52 +0400 Subject: [PATCH 208/465] strutures.c: fixed bad flags in get chat query --- structures.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/structures.c b/structures.c index 81af89b..057d90a 100644 --- a/structures.c +++ b/structures.c @@ -469,12 +469,12 @@ void fetch_chat (struct chat *C) { int version = -1; if (x == CODE_chat) { - unsigned y = fetch_int (); - if (y == CODE_chat_photo_empty) { + unsigned z = fetch_int (); + if (z == CODE_chat_photo_empty) { small.dc = -2; big.dc = -2; } else { - assert (y == CODE_chat_photo); + assert (z == CODE_chat_photo); fetch_file_location (&small); fetch_file_location (&big); } From c91d47839c2d8a417151bede6039425ceee52a5e Mon Sep 17 00:00:00 2001 From: antma Date: Wed, 15 Jan 2014 19:29:26 +0400 Subject: [PATCH 209/465] improve portability by removing rdtsc calls https://github.com/vysheng/tg/issues/8 --- mtproto-client.c | 3 +-- mtproto-common.c | 12 ++++++------ mtproto-common.h | 6 ------ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 844af9c..e8e692c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -90,14 +90,13 @@ struct connection_methods auth_methods = { }; long long precise_time; -long long precise_time_rdtsc; + double get_utime (int clock_id) { struct timespec T; my_clock_gettime (clock_id, &T); double res = T.tv_sec + (double) T.tv_nsec * 1e-9; if (clock_id == CLOCK_REALTIME) { precise_time = (long long) (res * (1LL << 32)); - precise_time_rdtsc = rdtsc (); } return res; } diff --git a/mtproto-common.c b/mtproto-common.c index 12efcca..991e6d8 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -67,6 +67,9 @@ int get_random_bytes (unsigned char *buf, int n) { } } close (h); + if (r < 0) { + r = 0; + } } if (r < n) { @@ -105,18 +108,15 @@ void my_clock_gettime (int clock_id UU, struct timespec *T) { #endif } - void prng_seed (const char *password_filename, int password_length) { unsigned char *a = talloc0 (64 + password_length); - long long r = rdtsc (); struct timespec T; my_clock_gettime (CLOCK_REALTIME, &T); memcpy (a, &T.tv_sec, 4); - memcpy (a+4, &T.tv_nsec, 4); - memcpy (a+8, &r, 8); + memcpy (a + 4, &T.tv_nsec, 4); unsigned short p = getpid (); - memcpy (a + 16, &p, 2); - int s = get_random_bytes (a + 18, 32) + 18; + memcpy (a + 8, &p, 2); + int s = get_random_bytes (a + 10, 32) + 10; if (password_filename) { int fd = open (password_filename, O_RDONLY); if (fd < 0) { diff --git a/mtproto-common.h b/mtproto-common.h index d15c922..011aed3 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -375,12 +375,6 @@ static inline void fetch_skip_str (void) { fetch_str (l); } -static __inline__ unsigned long long rdtsc(void) { - unsigned hi, lo; - __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); - return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); -} - static inline long have_prefetch_ints (void) { return in_end - in_ptr; } From b855a7347376ed2adff912bbe61375a067a60818 Mon Sep 17 00:00:00 2001 From: antma Date: Fri, 17 Jan 2014 16:19:12 +0400 Subject: [PATCH 210/465] use rdtsc for seeding prng only at i386 and x86_64 platforms https://github.com/vysheng/tg/issues/8 --- mtproto-common.c | 59 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/mtproto-common.c b/mtproto-common.c index 991e6d8..7ca8bee 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -65,11 +65,10 @@ int get_random_bytes (unsigned char *buf, int n) { if (verbosity >= 3) { logprintf ( "added %d bytes of real entropy to secure random numbers seed\n", r); } - } - close (h); - if (r < 0) { + } else { r = 0; } + close (h); } if (r < n) { @@ -79,13 +78,12 @@ int get_random_bytes (unsigned char *buf, int n) { } int s = read (h, buf + r, n - r); close (h); - if (s < 0) { - return r; + if (s > 0) { + r += s; } - r += s; } - if (r >= (int)sizeof (long)) { + if (r >= (int) sizeof (long)) { *(long *)buf ^= lrand48 (); srand48 (*(long *)buf); } @@ -108,35 +106,62 @@ void my_clock_gettime (int clock_id UU, struct timespec *T) { #endif } +/* RDTSC */ +#if defined(__i386__) +#define HAVE_RDTSC +static __inline__ unsigned long long rdtsc (void) { + unsigned long long int x; + __asm__ volatile ("rdtsc" : "=A" (x)); + return x; +} +#elif defined(__x86_64__) +#define HAVE_RDTSC +static __inline__ unsigned long long rdtsc (void) { + unsigned hi, lo; + __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); + return ((unsigned long long) lo) | (((unsigned long long) hi) << 32); +} +#endif + void prng_seed (const char *password_filename, int password_length) { - unsigned char *a = talloc0 (64 + password_length); struct timespec T; my_clock_gettime (CLOCK_REALTIME, &T); - memcpy (a, &T.tv_sec, 4); - memcpy (a + 4, &T.tv_nsec, 4); + RAND_add (&T, sizeof (T), 4.0); +#ifdef HAVE_RDTSC + unsigned long long r = rdtsc (); + RAND_add (&r, 8, 4.0); +#endif unsigned short p = getpid (); - memcpy (a + 8, &p, 2); - int s = get_random_bytes (a + 10, 32) + 10; - if (password_filename) { + RAND_add (&p, sizeof (p), 0.0); + p = getppid (); + RAND_add (&p, sizeof (p), 0.0); + unsigned char rb[32]; + int s = get_random_bytes (rb, 32); + if (s > 0) { + RAND_add (rb, s, s); + } + memset (rb, 0, sizeof (rb)); + if (password_filename && password_length > 0) { int fd = open (password_filename, O_RDONLY); if (fd < 0) { logprintf ( "Warning: fail to open password file - \"%s\", %m.\n", password_filename); } else { - int l = read (fd, a + s, password_length); + unsigned char *a = talloc0 (password_length); + int l = read (fd, a, password_length); if (l < 0) { logprintf ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename); } else { if (verbosity > 0) { logprintf ( "read %d bytes from password file.\n", l); } - s += l; + RAND_add (a, l, l); } close (fd); + tfree_secure (a, password_length); } } - RAND_seed (a, s); BN_ctx = BN_CTX_new (); - tfree_secure (a, 64 + password_length); + ensure_ptr (BN_ctx); } int serialize_bignum (BIGNUM *b, char *buffer, int maxlen) { From 50695685906312800e36ff20d754e7c678c3dec6 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 17 Jan 2014 18:16:35 +0400 Subject: [PATCH 211/465] Fixed load audio --- interface.c | 4 ++-- queries.c | 16 ++++++++++++++++ queries.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/interface.c b/interface.c index 24ac58f..8174a6d 100644 --- a/interface.c +++ b/interface.c @@ -971,7 +971,7 @@ void interpreter (char *line UU) { } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { - do_load_video (&M->media.video, 1); + do_load_audio (&M->media.video, 1); } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { do_load_encr_video (&M->media.encr_video, 1); } else { @@ -986,7 +986,7 @@ void interpreter (char *line UU) { } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { - do_load_video (&M->media.video, 2); + do_load_audio (&M->media.video, 2); } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { do_load_encr_video (&M->media.encr_video, 2); } else { diff --git a/queries.c b/queries.c index 76fcde9..53bfdcd 100644 --- a/queries.c +++ b/queries.c @@ -1936,6 +1936,22 @@ void do_load_video (struct video *V, int next) { load_next_part (D); } +void do_load_audio (struct video *V, int next) { + assert (V); + assert (next); + struct download *D = talloc0 (sizeof (*D)); + D->offset = 0; + D->size = V->size; + D->id = V->id; + D->access_hash = V->access_hash; + D->dc = V->dc_id; + D->next = next; + D->name = 0; + D->fd = -1; + D->type = CODE_input_audio_file_location; + load_next_part (D); +} + void do_load_document (struct document *V, int next) { assert (V); assert (next); diff --git a/queries.h b/queries.h index bb8f9d6..2f63963 100644 --- a/queries.h +++ b/queries.h @@ -89,6 +89,7 @@ struct photo; struct video; void do_load_photo (struct photo *photo, int next); void do_load_video_thumb (struct video *video, int next); +void do_load_audio (struct video *V, int next); void do_load_video (struct video *V, int next); void do_load_document (struct document *V, int next); void do_load_document_thumb (struct document *video, int next); From ccfc81da887b24707e7e08255c009419f6da4031 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 17 Jan 2014 19:46:33 +0000 Subject: [PATCH 212/465] Fixed get_peer from lua --- lua-tg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua-tg.c b/lua-tg.c index 62d9bb7..264d565 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -343,7 +343,7 @@ static int pos; static peer_t *get_peer (const char *s) { int index = 0; - while (index < peer_num && Peers[index]->print_name && strcmp (Peers[index]->print_name, s)) { + while (index < peer_num && (!Peers[index]->print_name || strcmp (Peers[index]->print_name, s))) { index ++; } return index == peer_num ? 0 : Peers[index]; From ceb9422ae93b1072363f0b8c4dd90d1554af509d Mon Sep 17 00:00:00 2001 From: antma Date: Tue, 21 Jan 2014 18:24:40 +0400 Subject: [PATCH 213/465] add check that BN_is_prime return value is not negative fix memory leak (BN_clear doesn't release allocated memory) --- mtproto-client.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index e8e692c..5f1a997 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -428,6 +428,12 @@ int process_respq_answer (struct connection *c, char *packet, int len) { return rpc_send_packet (c); } +int check_prime (BIGNUM *p) { + int r = BN_is_prime (p, BN_prime_checks, 0, BN_ctx, 0); + ensure (r >= 0); + return r; +} + int check_DH_params (BIGNUM *p, int g) { if (g < 2 || g > 7) { return -1; } BIGNUM t; @@ -440,7 +446,7 @@ int check_DH_params (BIGNUM *p, int g) { int x = BN_get_word (&t); assert (x >= 0 && x < 4 * g); - BN_clear (&dh_g); + BN_free (&dh_g); switch (g) { case 2: @@ -462,15 +468,15 @@ int check_DH_params (BIGNUM *p, int g) { break; } - if (!BN_is_prime (p, BN_prime_checks, 0, BN_ctx, 0)) { return -1; } + if (!check_prime (p)) { return -1; } BIGNUM b; BN_init (&b); ensure (BN_set_word (&b, 2)); ensure (BN_div (&t, 0, p, &b, BN_ctx)); - if (!BN_is_prime (&t, BN_prime_checks, 0, BN_ctx, 0)) { return -1; } - BN_clear (&b); - BN_clear (&t); + if (!check_prime (&t)) { return -1; } + BN_free (&b); + BN_free (&t); return 0; } From 33dac4b4a35e0475996ec7d086cfabaf28db5126 Mon Sep 17 00:00:00 2001 From: antma Date: Tue, 21 Jan 2014 18:26:56 +0400 Subject: [PATCH 214/465] fix memory leak during replaying CODE_binlog_set_chat_title --- binlog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/binlog.c b/binlog.c index 36407f7..c3b2f37 100644 --- a/binlog.c +++ b/binlog.c @@ -628,6 +628,7 @@ void replay_log_event (void) { struct chat *C = &_C->chat; if (C->title) { tfree_str (C->title); } C->title = fetch_str_dup (); + if (C->print_title) { tfree_str (C->print_title); } C->print_title = create_print_name (C->id, C->title, 0, 0, 0); #ifdef USE_LUA lua_chat_update (C); From 2a817354ffcff2d2285e5cf3413ee43b5e635b07 Mon Sep 17 00:00:00 2001 From: antma Date: Tue, 21 Jan 2014 18:36:46 +0400 Subject: [PATCH 215/465] fix free in the hypotetic case when binlog message contain NUL character in the middle --- structures.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/structures.c b/structures.c index 057d90a..47eb941 100644 --- a/structures.c +++ b/structures.c @@ -1327,6 +1327,7 @@ void fetch_geo_message (struct message *M) { fetch_message_action (&M->action); } else { M->message = fetch_str_dup (); + M->message_len = strlen (M->message); fetch_message_media (&M->media); } } @@ -1691,7 +1692,7 @@ void free_message_action (struct message_action *M) { void free_message (struct message *M) { if (!M->service) { - if (M->message) { tfree_str (M->message); } + if (M->message) { tfree (M->message, M->message_len + 1); } free_message_media (&M->media); } else { free_message_action (&M->action); From 9f7aede32e0152020828600772ecbe0a2060bc01 Mon Sep 17 00:00:00 2001 From: Alejandro Leiva Date: Thu, 23 Jan 2014 10:47:45 +0100 Subject: [PATCH 216/465] Fixed typo in linux lib install instructions in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 03aca69..0397964 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Install libs: readline openssl and (if you want to use config) libconfig and lub If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively On ubuntu use: - $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 lublua5.2-dev + $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev On gentoo: $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua From d8b16d5738dd6d9b54df7c2059561413d3195c83 Mon Sep 17 00:00:00 2001 From: antma Date: Tue, 21 Jan 2014 20:02:34 +0400 Subject: [PATCH 217/465] AES_KEY structure clean up --- mtproto-common.c | 2 ++ queries.c | 9 +++++---- structures.c | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mtproto-common.c b/mtproto-common.c index 7ca8bee..ceeb5c5 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -348,6 +348,7 @@ void init_aes_unauth (const char server_nonce[16], const char hidden_client_nonc } else { AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key); } + memset (aes_key_raw, 0, sizeof (aes_key_raw)); } void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt) { @@ -387,6 +388,7 @@ void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt) { } else { AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key); } + memset (aes_key_raw, 0, sizeof (aes_key_raw)); } int pad_aes_encrypt (char *from, int from_len, char *to, int size) { diff --git a/queries.c b/queries.c index 53bfdcd..fddc565 100644 --- a/queries.c +++ b/queries.c @@ -746,6 +746,7 @@ char *encrypt_decrypted_message (struct secret_chat *E) { AES_KEY aes_key; AES_set_encrypt_key (key, 256, &aes_key); AES_ige_encrypt ((void *)encr_ptr, (void *)encr_ptr, 4 * (encr_end - encr_ptr), &aes_key, iv, 1); + memset (&aes_key, 0, sizeof (aes_key)); return (void *)msg_key; } @@ -1290,15 +1291,14 @@ void send_part (struct send_file *f) { if (f->encr) { if (x & 15) { assert (f->offset == f->size); - if (x & 15) { - secure_random (buf + x, (-x) & 15); - x = (x + 15) & ~15; - } + secure_random (buf + x, (-x) & 15); + x = (x + 15) & ~15; } AES_KEY aes_key; AES_set_encrypt_key (f->key, 256, &aes_key); AES_ige_encrypt ((void *)buf, (void *)buf, x, &aes_key, f->iv, 1); + memset (&aes_key, 0, sizeof (aes_key)); } out_cstring (buf, x); if (verbosity >= 2) { @@ -1803,6 +1803,7 @@ int download_on_answer (struct query *q) { AES_KEY aes_key; AES_set_decrypt_key (D->key, 256, &aes_key); AES_ige_encrypt (ptr, ptr, len, &aes_key, D->iv, 0); + memset (&aes_key, 0, sizeof (aes_key)); if (len > D->size - D->offset) { len = D->size - D->offset; } diff --git a/structures.c b/structures.c index 47eb941..ddb8f1f 100644 --- a/structures.c +++ b/structures.c @@ -1376,6 +1376,7 @@ int decrypt_encrypted_message (struct secret_chat *E) { AES_KEY aes_key; AES_set_decrypt_key (key, 256, &aes_key); AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); + memset (&aes_key, 0, sizeof (aes_key)); int x = *(decr_ptr); if (x < 0 || (x & 3)) { From 7de612f5f8944255861c96449e17c289de85eb86 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 24 Jan 2014 19:05:41 +0400 Subject: [PATCH 218/465] added delete/restore messages queries --- interface.c | 32 +++++++++++++++++++++++++++++--- queries.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ queries.h | 3 ++- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/interface.c b/interface.c index 8174a6d..7848258 100644 --- a/interface.c +++ b/interface.c @@ -46,7 +46,7 @@ #include "mtproto-common.h" -//#define ALLOW_MULT 1 +#define ALLOW_MULT 1 char *default_prompt = "> "; int unread_messages; @@ -86,14 +86,14 @@ char *next_token (int *l) { char *s = line_ptr; int in_str = 0; while (*line_ptr && (*line_ptr != ' ' || neg || in_str)) { - if (*line_ptr == '\\') { +/* if (*line_ptr == '\\') { neg = 1 - neg; } else { if (*line_ptr == '"' && !neg) { in_str = !in_str; } neg = 0; - } + }*/ line_ptr++; } *l = line_ptr - s; @@ -320,6 +320,8 @@ char *commands[] = { "view_document", "set", "chat_with_peer", + "delete_msg", + "restore_msg", 0 }; int commands_flags[] = { @@ -368,6 +370,8 @@ int commands_flags[] = { 07, 07, 072, + 07, + 07 }; @@ -1067,6 +1071,28 @@ void interpreter (char *line UU) { GET_PEER; in_chat_mode = 1; chat_mode_id = id; + } else if (IS_WORD ("delete_msg")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + do_delete_msg (num); + } else if (IS_WORD ("restore_msg")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + do_restore_msg (num); + } else if (IS_WORD ("delete_restore_msg")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + do_delete_msg (num); + do_restore_msg (num); } else if (IS_WORD ("quit")) { exit (0); } else if (IS_WORD ("safe_quit")) { diff --git a/queries.c b/queries.c index 53bfdcd..274ba8a 100644 --- a/queries.c +++ b/queries.c @@ -2746,6 +2746,53 @@ void do_create_secret_chat (peer_id_t id) { } /* }}} */ +/* {{{ Delete msg */ + +int delete_msg_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + fetch_skip (n); + logprintf ("Deleted %d messages\n", n); + return 0; +} + +struct query_methods delete_msg_methods = { + .on_answer = delete_msg_on_answer +}; + +void do_delete_msg (long long id) { + clear_packet (); + out_int (CODE_messages_delete_messages); + out_int (CODE_vector); + out_int (1); + out_int (id); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &delete_msg_methods, 0); +} +/* }}} */ + +/* {{{ Restore msg */ + +int restore_msg_on_answer (struct query *q UU) { + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + fetch_skip (n); + logprintf ("Restored %d messages\n", n); + return 0; +} + +struct query_methods restore_msg_methods = { + .on_answer = restore_msg_on_answer +}; + +void do_restore_msg (long long id) { + clear_packet (); + out_int (CODE_messages_restore_messages); + out_int (CODE_vector); + out_int (1); + out_int (id); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &restore_msg_methods, 0); +} +/* }}} */ int update_status_on_answer (struct query *q UU) { fetch_bool (); return 0; diff --git a/queries.h b/queries.h index 2f63963..d631cd4 100644 --- a/queries.h +++ b/queries.h @@ -111,7 +111,8 @@ void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); void do_update_status (int online); void do_contacts_search (int limit, const char *s); void do_send_msg (struct message *M); - +void do_delete_msg (long long id); +void do_restore_msg (long long id); // For binlog From 59e9053910f54feccd41f82260043ad4b9e930f8 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 27 Jan 2014 19:10:02 +0400 Subject: [PATCH 219/465] Deleted aio.h include --- mtproto-client.c | 1 - mtproto-common.c | 1 - 2 files changed, 2 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 5f1a997..dc2d22d 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -35,7 +35,6 @@ #include #endif #include -#include #include #include #include diff --git a/mtproto-common.c b/mtproto-common.c index 7ca8bee..3b5f015 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include From 24e7f07560dc2892c8d357a1f7089ee2227905ce Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 27 Jan 2014 21:23:58 +0400 Subject: [PATCH 220/465] maybe fixed conn restart --- net.c | 4 ++++ net.h | 1 + 2 files changed, 5 insertions(+) diff --git a/net.c b/net.c index bbc9a48..fa02e87 100644 --- a/net.c +++ b/net.c @@ -66,6 +66,7 @@ int ping_alarm (struct connection *c) { if (verbosity > 2) { logprintf ("ping alarm\n"); } + assert (c->state == conn_ready || c->state == conn_connecting); if (get_double_time () - c->last_receive_time > 20 * PING_TIMEOUT) { if (verbosity) { logprintf ( "fail connection: reason: ping timeout\n"); @@ -97,10 +98,13 @@ void start_ping_timer (struct connection *c) { void restart_connection (struct connection *c); int fail_alarm (void *ev) { + ((struct connection *)ev)->in_fail_timer = 0; restart_connection (ev); return 0; } void start_fail_timer (struct connection *c) { + if (c->in_fail_timer) { return; } + c->in_fail_timer = 1; c->ev.timeout = get_double_time () + 10; c->ev.alarm = (void *)fail_alarm; c->ev.self = c; diff --git a/net.h b/net.h index 181c46c..d89029f 100644 --- a/net.h +++ b/net.h @@ -124,6 +124,7 @@ struct connection { int packet_num; int out_packet_num; int last_connect_time; + int in_fail_timer; struct connection_methods *methods; struct session *session; void *extra; From db585c6d804f3acee8919d25a2ea51f8308ff4ad Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 28 Jan 2014 16:40:35 +0400 Subject: [PATCH 221/465] Added mark_read to lua functions --- lua-tg.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ tools.c | 15 +++++++++++++++ tools.h | 1 + 3 files changed, 60 insertions(+) diff --git a/lua-tg.c b/lua-tg.c index 264d565..73153e3 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -365,6 +365,13 @@ void lua_do_all (void) { do_forward_message (((peer_t *)lua_ptr[p])->id, (long)lua_ptr[p + 1]); p += 2; break; + case 2: + #ifdef DEBUG + texists (lua_ptr[p], sizeof (peer_t)); + #endif + do_mark_read (((peer_t *)lua_ptr[p])->id); + p += 1; + break; default: assert (0); } @@ -384,6 +391,10 @@ static int send_msg_from_lua (lua_State *L) { return 1; } const char *s = lua_tostring (L, -2); + if (!s) { + lua_pushboolean (L, 0); + return 1; + } const char *msg = lua_tostring (L, -1); peer_t *P = get_peer (s); @@ -414,6 +425,10 @@ static int fwd_msg_from_lua (lua_State *L) { } const char *s = lua_tostring (L, -2); long long num = atoll (lua_tostring (L, -1)); + if (!s) { + lua_pushboolean (L, 0); + return 1; + } peer_t *P = get_peer (s); if (!P) { lua_pushboolean (L, 0); @@ -428,6 +443,34 @@ static int fwd_msg_from_lua (lua_State *L) { return 1; } +static int mark_read_from_lua (lua_State *L) { + if (MAX_LUA_COMMANDS - pos < 4) { + lua_pushboolean (L, 0); + return 1; + } + int n = lua_gettop (L); + if (n != 1) { + lua_pushboolean (L, 0); + return 1; + } + const char *s = lua_tostring (L, -1); + if (!s) { + lua_pushboolean (L, 0); + return 1; + } + peer_t *P = get_peer (s); + if (!P) { + lua_pushboolean (L, 0); + return 1; + } + + lua_ptr[pos ++] = (void *)1l; + lua_ptr[pos ++] = (void *)2l; + lua_ptr[pos ++] = P; + lua_pushboolean (L, 1); + return 1; +} + void lua_init (const char *file) { if (!file) { return; } have_file = 1; @@ -436,6 +479,7 @@ void lua_init (const char *file) { lua_register (luaState, "send_msg", send_msg_from_lua); lua_register (luaState, "fwd_msg", fwd_msg_from_lua); + lua_register (luaState, "mark_read", mark_read_from_lua); int ret = luaL_dofile (luaState, file); if (ret) { diff --git a/tools.c b/tools.c index 74ff5d2..c9c4255 100644 --- a/tools.c +++ b/tools.c @@ -245,4 +245,19 @@ void tcheck (void) { } logprintf ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt); } + +void texists (void *ptr, int size) { + ptr -= RES_PRE; + if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { + logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); + } + assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); + assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); + assert (*(int *)(ptr + 4) == size); + int block_num = *(int *)(ptr + 4 + RES_PRE + size); + if (block_num >= used_blocks) { + logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); + } + assert (block_num < used_blocks); +} #endif diff --git a/tools.h b/tools.h index 09f2b2b..e63b133 100644 --- a/tools.h +++ b/tools.h @@ -39,5 +39,6 @@ int tasprintf (char **res, const char *format, ...) __attribute__ ((format (prin #ifdef DEBUG void tcheck (void); +void texists (void *ptr, int size); #endif #endif From 09b5ff710ff1ef9e5da29d4cb36aac529dad9f51 Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 29 Jan 2014 14:15:56 +0300 Subject: [PATCH 222/465] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0397964..ff1fcde 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Clone GitHub Repository or download and extract zip $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip - $ tar xzf tg-master.zip && cd tg-master + $ unzip tg-master.zip && cd tg-master #### Linux From 8726d10c207db95f8b66aa79d0ec5d25ee56d2ad Mon Sep 17 00:00:00 2001 From: Alejandro Navarro Date: Wed, 29 Jan 2014 21:15:30 +0100 Subject: [PATCH 223/465] Little typo error in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff1fcde..f5c6408 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ or download and extract zip #### Linux -Install libs: readline openssl and (if you want to use config) libconfig and lublua. +Install libs: readline openssl and (if you want to use config) libconfig and liblua. If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively On ubuntu use: From 0b5a70e3d935ee46e568ae6cf600fbf67573c48c Mon Sep 17 00:00:00 2001 From: Akshay S Dinesh Date: Thu, 30 Jan 2014 11:09:16 +0530 Subject: [PATCH 224/465] Added chat_with_peer in commands. Also explained what peer is. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f5c6408..66c2709 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ By default public key is stored in the same folder named tg.pub: ./telegram -k tg.pub Client support TAB completion and command history. + +Peer refers to the name of the contact and can be accessed by TAB completion. ### Supported commands @@ -84,6 +86,7 @@ Client support TAB completion and command history. * **msg** \ Text - sends message to this peer * **fwd** \ \ - forward message to user. You can see message numbers starting client with -N +* **chat_with_peer** \ starts one on one chat session with this peer. /exit or /quit to end this mode. * **add_contact** \ \ \ - tries to add contact to contact-list by phone * **rename_contact** \ \ \ - tries to rename contact. If you have another device it will be a fight * **mark_read** \ - mark read all received messages with peer From 0c6efc623416374d055a9c6796eadacf68727187 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 30 Jan 2014 15:01:16 +0400 Subject: [PATCH 225/465] Added cygwin fixes --- config.h | 51 +++++++++++++++++++++++++++++-- config.h.in | 51 +++++++++++++++++++++++++++++-- configure | 86 ++++++++++++++++++++++++++++++++++++++++++++++------ configure.ac | 5 +-- interface.h | 1 - main.c | 6 ++++ net.c | 2 +- 7 files changed, 183 insertions(+), 19 deletions(-) diff --git a/config.h b/config.h index 3ee4d79..c3e95d2 100644 --- a/config.h +++ b/config.h @@ -4,6 +4,15 @@ /* enable libconfig */ #define ENABLE_LIBCONFIG 1 +/* Define to 1 if you have the `alarm' function. */ +#define HAVE_ALARM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the `endpwent' function. */ +#define HAVE_ENDPWENT 1 + /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 @@ -19,9 +28,6 @@ /* Define to 1 if you have the `edit' library (-ledit). */ /* #undef HAVE_LIBEDIT */ -/* Define to 1 if you have the `execinfo' library (-lexecinfo). */ -/* #undef HAVE_LIBEXECINFO */ - /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 @@ -34,6 +40,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_LUA_H 1 +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 @@ -41,12 +50,24 @@ /* Define to 1 if you have the header file. */ #define HAVE_MALLOC_H 1 +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #define HAVE_REALLOC 1 @@ -54,6 +75,9 @@ /* Define to 1 if you have the `select' function. */ #define HAVE_SELECT 1 +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 @@ -72,6 +96,9 @@ /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_FILE_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 @@ -81,6 +108,12 @@ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define to 1 if you have the `uname' function. */ +#define HAVE_UNAME 1 + /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 @@ -114,6 +147,15 @@ /* use lua */ #define USE_LUA 1 +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + /* Define to rpl_malloc if the replacement function should be used. */ /* #undef malloc */ @@ -122,3 +164,6 @@ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ diff --git a/config.h.in b/config.h.in index 26115be..b77cede 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,15 @@ /* enable libconfig */ #undef ENABLE_LIBCONFIG +/* Define to 1 if you have the `alarm' function. */ +#undef HAVE_ALARM + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the `endpwent' function. */ +#undef HAVE_ENDPWENT + /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H @@ -18,9 +27,6 @@ /* Define to 1 if you have the `edit' library (-ledit). */ #undef HAVE_LIBEDIT -/* Define to 1 if you have the `execinfo' library (-lexecinfo). */ -#undef HAVE_LIBEXECINFO - /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM @@ -33,6 +39,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LUA_H +/* Define to 1 if you have the header file. */ +#undef HAVE_MACH_MACH_H + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC @@ -40,12 +49,24 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET +/* Define to 1 if you have the `mkdir' function. */ +#undef HAVE_MKDIR + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC @@ -53,6 +74,9 @@ /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H @@ -71,6 +95,9 @@ /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H @@ -80,6 +107,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the `uname' function. */ +#undef HAVE_UNAME + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H @@ -113,6 +146,15 @@ /* use lua */ #undef USE_LUA +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc @@ -121,3 +163,6 @@ /* Define to `unsigned int' if does not define. */ #undef size_t + +/* Define to `int' if doesn't define. */ +#undef uid_t diff --git a/configure b/configure index cc99b1e..f40b39a 100755 --- a/configure +++ b/configure @@ -3306,15 +3306,11 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_execinfo_backtrace" >&5 $as_echo "$ac_cv_lib_execinfo_backtrace" >&6; } if test "x$ac_cv_lib_execinfo_backtrace" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBEXECINFO 1 -_ACEOF - - LIBS="-lexecinfo $LIBS" - + EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; +else + CFLAGS="${CFLAGS} -DNO_BACKTRACE" ; fi - EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_save_prompt in -lreadline" >&5 @@ -5305,7 +5301,7 @@ fi # Checks for header files. -for ac_header in fcntl.h malloc.h stdlib.h string.h sys/socket.h unistd.h +for ac_header in fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -5331,6 +5327,78 @@ _ACEOF fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +$as_echo_n "checking for uid_t in sys/types.h... " >&6; } +if ${ac_cv_type_uid_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then : + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +$as_echo "$ac_cv_type_uid_t" >&6; } +if test $ac_cv_type_uid_t = no; then + +$as_echo "#define uid_t int" >>confdefs.h + + +$as_echo "#define gid_t int" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if ${ac_cv_c_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + # Checks for library functions. for ac_header in stdlib.h @@ -5467,7 +5535,7 @@ $as_echo "#define realloc rpl_realloc" >>confdefs.h fi -for ac_func in memset select strdup strndup +for ac_func in alarm endpwent memset memmove mkdir select socket strdup strndup uname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.ac b/configure.ac index d56598d..82b8117 100644 --- a/configure.ac +++ b/configure.ac @@ -24,8 +24,9 @@ AC_CHECK_FUNC([backtrace], ) if test "x$BT" = "x" ; then - AC_CHECK_LIB([execinfo], [backtrace]) - [ EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; ] + AC_CHECK_LIB([execinfo], [backtrace], + [ EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; ], + [ CFLAGS="${CFLAGS} -DNO_BACKTRACE" ; ]) fi AC_CHECK_LIB([readline], [rl_save_prompt], diff --git a/interface.h b/interface.h index a61f968..80c7ee2 100644 --- a/interface.h +++ b/interface.h @@ -39,7 +39,6 @@ char **complete_text (char *text, int start, int end); void interpreter (char *line); void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void iprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); void hexdump (int *in_ptr, int *in_end); diff --git a/main.c b/main.c index de39372..edb576c 100644 --- a/main.c +++ b/main.c @@ -418,11 +418,17 @@ void args_parse (int argc, char **argv) { } } +#ifndef NO_BACKTRACE void print_backtrace (void) { void *buffer[255]; const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); backtrace_symbols_fd (buffer, calls, 1); } +#else +void print_backtrace (void) { + printf ("No libexec. Backtrace disabled\n"); +} +#endif void sig_handler (int signum) { set_terminal_attributes (); diff --git a/net.c b/net.c index fa02e87..881f670 100644 --- a/net.c +++ b/net.c @@ -45,7 +45,7 @@ #include "tree.h" #include "interface.h" -#if defined(__MACH__) || defined(__FreeBSD__) +#ifndef POLLRDHUP #define POLLRDHUP 0 #endif From f42ef2de5f2e592ab5f739abf20fefec47e28f38 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 30 Jan 2014 15:45:01 +0400 Subject: [PATCH 226/465] mtproto-client: do not use TCPQUICKACK in cygwin --- mtproto-client.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index dc2d22d..97ea4fa 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1711,7 +1711,7 @@ int rpc_execute (struct connection *c, int op, int len) { logprintf ( "have %d Response bytes\n", Response_len); } -#if !defined(__MACH__) && !defined(__FreeBSD__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif int o = c_state; @@ -1719,19 +1719,19 @@ int rpc_execute (struct connection *c, int op, int len) { switch (o) { case st_reqpq_sent: process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; case st_reqdh_sent: process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; case st_client_dh_sent: process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; @@ -1741,7 +1741,7 @@ int rpc_execute (struct connection *c, int op, int len) { } else { process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); } -#if !defined(__MACH__) && !defined(__FreeBSD__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; @@ -1769,7 +1769,7 @@ int tc_becomes_ready (struct connection *c) { assert (write_out (c, &byte, 1) == 1); flush_out (c); -#if !defined(__MACH__) && !defined(__FreeBSD__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif int o = c_state; From 43106219220e489e05f626092472c89dfc85da5a Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 30 Jan 2014 15:49:26 +0400 Subject: [PATCH 227/465] main.c: deleted include execinfo if no backtrace needed --- main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.c b/main.c index edb576c..01b571e 100644 --- a/main.c +++ b/main.c @@ -38,7 +38,9 @@ #include #include #include +#ifndef NO_BACKTRACE #include +#endif #include #ifdef ENABLE_LIBCONFIG #include From 015b3a455bce895341b22d647493ef5a0a688211 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 30 Jan 2014 16:01:15 +0300 Subject: [PATCH 228/465] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 66c2709..57179fd 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,12 @@ By default public key is stored in the same folder named tg.pub: Client support TAB completion and command history. -Peer refers to the name of the contact and can be accessed by TAB completion. +Peer refers to the name of the contact or dialog and can be accessed by TAB completion. +For user contacts peer name is Name Lastname with all spaces changed to underscores. +For chats it is it's title with all spaces changed to underscores +For encrypted chats it is Name Lastname with all spaces changed to underscores. + +If two or more peers have same refers that number is added to ther end of it. (for example A_B, A_B#1, A_B#2 and so on) ### Supported commands From 5ed76c6a8c9df12b087180d9d641f5b7d7f248c9 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 30 Jan 2014 16:01:50 +0300 Subject: [PATCH 229/465] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57179fd..02ec34f 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ For user contacts peer name is Name Lastname with all spaces change For chats it is it's title with all spaces changed to underscores For encrypted chats it is Name Lastname with all spaces changed to underscores. -If two or more peers have same refers that number is added to ther end of it. (for example A_B, A_B#1, A_B#2 and so on) +If two or more peers have same name that number is added to ther end of it. (for example A_B, A_B#1, A_B#2 and so on) ### Supported commands From eb0de3c7bd1db61376aa6879a9c6cb54aba42470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20G=C3=B3mez=20Vilches?= Date: Thu, 30 Jan 2014 17:46:09 +0100 Subject: [PATCH 230/465] Update interface.c Fix typo in help command --- interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 7848258..de6a925 100644 --- a/interface.c +++ b/interface.c @@ -868,7 +868,7 @@ void interpreter (char *line UU) { "msg Text - sends message to this peer\n" "contact_list - prints info about users in your contact list\n" "stats - just for debugging \n" - "history [limit] - prints history (and marks it as read). Default limit = 40\n" + "history [limit] - prints history (and marks it as read). Default limit = 40\n" "dialog_list - prints info about your dialogs\n" "send_photo - sends photo to peer\n" "send_video - sends video to peer\n" From 714daf2426ecab098fe01b9d167b6cf9d729e5f9 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 31 Jan 2014 01:11:17 +0300 Subject: [PATCH 231/465] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02ec34f..e65eac7 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,9 @@ Client support TAB completion and command history. Peer refers to the name of the contact or dialog and can be accessed by TAB completion. For user contacts peer name is Name Lastname with all spaces changed to underscores. For chats it is it's title with all spaces changed to underscores -For encrypted chats it is Name Lastname with all spaces changed to underscores. +For encrypted chats it is Name Lastname with all spaces changed to underscores. -If two or more peers have same name that number is added to ther end of it. (for example A_B, A_B#1, A_B#2 and so on) +If two or more peers have same name, number is appended to the name. (for example A_B, A_B#1, A_B#2 and so on) ### Supported commands From e10ce5aa69574889723d7a324a48b39ec64b6fad Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 31 Jan 2014 20:03:40 +0400 Subject: [PATCH 232/465] Use tree for peer_name search --- binlog.c | 16 ++++++++++++++-- mtproto-client.c | 6 +++++- structures.c | 34 ++++++++++++++++++++++++---------- structures.h | 3 +++ 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/binlog.c b/binlog.c index c3b2f37..b544876 100644 --- a/binlog.c +++ b/binlog.c @@ -224,6 +224,7 @@ void replay_log_event (void) { tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = create_print_name (U->id, "!", buf, 0, 0); } + peer_insert_name ((void *)U); } }; break; @@ -280,6 +281,7 @@ void replay_log_event (void) { tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = create_print_name (U->id, "!", buf, 0, 0); } + peer_insert_name ((void *)U); } rptr += 2; }; @@ -315,7 +317,9 @@ void replay_log_event (void) { } U->first_name = fetch_str_dup (); U->last_name = fetch_str_dup (); + assert (!U->print_name); U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); + peer_insert_name ((void *)U); U->access_hash = fetch_long (); U->phone = fetch_str_dup (); if (fetch_int ()) { @@ -452,6 +456,7 @@ void replay_log_event (void) { U->user_id = *(rptr ++); peer_t *Us = user_chat_get (MK_USER (U->user_id)); + assert (!U->print_name); if (Us) { U->print_name = create_print_name (id, "!", Us->user.first_name, Us->user.last_name, 0); } else { @@ -459,6 +464,7 @@ void replay_log_event (void) { tsnprintf (buf, 99, "user#%d", U->user_id); U->print_name = create_print_name (id, "!", buf, 0, 0); } + peer_insert_name ((void *)U); U->g_key = talloc (256); U->nonce = talloc (256); memcpy (U->g_key, rptr, 256); @@ -559,6 +565,7 @@ void replay_log_event (void) { peer_t *Us = user_chat_get (MK_USER (P->encr_chat.user_id)); assert (Us); P->print_name = create_print_name (P->id, "!", Us->user.first_name, Us->user.last_name, 0); + peer_insert_name (P); memcpy (P->encr_chat.key, rptr, 256); rptr += 64; P->encr_chat.g_key = talloc (256); @@ -598,7 +605,9 @@ void replay_log_event (void) { struct chat *C = &_C->chat; C->flags = FLAG_CREATED | fetch_int (); C->title = fetch_str_dup (); + assert (!C->print_title); C->print_title = create_print_name (id, C->title, 0, 0, 0); + peer_insert_name ((void *)C); C->users_num = fetch_int (); C->date = fetch_int (); C->version = fetch_int (); @@ -628,8 +637,12 @@ void replay_log_event (void) { struct chat *C = &_C->chat; if (C->title) { tfree_str (C->title); } C->title = fetch_str_dup (); - if (C->print_title) { tfree_str (C->print_title); } + if (C->print_title) { + peer_delete_name ((void *)C); + tfree_str (C->print_title); + } C->print_title = create_print_name (C->id, C->title, 0, 0, 0); + peer_insert_name ((void *)C); #ifdef USE_LUA lua_chat_update (C); #endif @@ -1778,7 +1791,6 @@ void bl_do_create_message_service (int msg_id, int from_id, int to_type, int to_ out_ints (data, len); add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); } - void bl_do_create_message_service_encr (long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { clear_packet (); out_int (CODE_binlog_create_message_service_encr); diff --git a/mtproto-client.c b/mtproto-client.c index 97ea4fa..809e009 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -840,10 +840,14 @@ void work_update_binlog (void) { struct user *U = &UC->user; if (U->first_name) { tfree_str (U->first_name); } if (U->last_name) { tfree_str (U->last_name); } - if (U->print_name) { tfree_str (U->print_name); } + if (U->print_name) { + peer_delete_name (UC); + tfree_str (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); + peer_insert_name ((void *)U); } else { fetch_skip_str (); fetch_skip_str (); diff --git a/structures.c b/structures.c index ddb8f1f..cff88bb 100644 --- a/structures.c +++ b/structures.c @@ -38,7 +38,9 @@ static int id_cmp (struct message *M1, struct message *M2); #define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) +#define peer_cmp_name(a,b) (strcmp (a->print_name, b->print_name)) DEFINE_TREE(peer,peer_t *,peer_cmp,0) +DEFINE_TREE(peer_by_name,peer_t *,peer_cmp_name,0) DEFINE_TREE(message,struct message *,id_cmp,0) @@ -48,6 +50,7 @@ struct message message_list = { }; struct tree_peer *peer_tree; +struct tree_peer_by_name *peer_by_name_tree; struct tree_message *message_tree; struct tree_message *message_unsent_tree; @@ -165,16 +168,8 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha int fl = strlen (s); int cc = 0; while (1) { - int ok = 1; - int i; - for (i = 0; i < peer_num; i++) { - assert (Peers[i]); - if (cmp_peer_id (Peers[i]->id, id) && Peers[i]->print_name && !strcmp (Peers[i]->print_name, s)) { - ok = 0; - break; - } - } - if (ok) { + peer_t *P = peer_lookup_name (s); + if (!P || !cmp_peer_id (Peers[i]->id, id)) { break; } cc ++; @@ -1980,3 +1975,22 @@ void __send_msg (struct message *M) { void send_all_unsent (void ) { tree_act_message (message_unsent_tree, __send_msg); } + +void peer_insert_name (peer_t *P) { + //if (!P->print_name || !strlen (P->print_name)) { return; } + //logprintf ("+%s\n", P->print_name); + peer_by_name_tree = tree_insert_peer_by_name (peer_by_name_tree, P, lrand48 ()); +} + +void peer_delete_name (peer_t *P) { + //if (!P->print_name || !strlen (P->print_name)) { return; } + //logprintf ("-%s\n", P->print_name); + peer_by_name_tree = tree_delete_peer_by_name (peer_by_name_tree, P); +} + +peer_t *peer_lookup_name (const char *s) { + static peer_t P; + P.print_name = (void *)s; + peer_t *R = tree_lookup_peer_by_name (peer_by_name_tree, &P); + return R; +} diff --git a/structures.h b/structures.h index 3b529ff..96aa362 100644 --- a/structures.h +++ b/structures.h @@ -374,6 +374,9 @@ void message_add_peer (struct message *M); void message_del_peer (struct message *M); void free_message (struct message *M); void message_del_use (struct message *M); +void peer_insert_name (peer_t *P); +void peer_delete_name (peer_t *P); +peer_t *peer_lookup_name (const char *s); #define PEER_USER 1 #define PEER_CHAT 2 From a334bed1f6a9f3b9ff1844b051a120602c0b861d Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 1 Feb 2014 00:19:55 +0400 Subject: [PATCH 233/465] Fix for non-binlog version --- loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/loop.c b/loop.c index 3375756..d82d1bc 100644 --- a/loop.c +++ b/loop.c @@ -355,6 +355,7 @@ void read_secret_chat_file (void) { P->print_name = talloc (t + 1); assert (read (fd, P->print_name, t) == t); P->print_name[t] = 0; + peer_insert_name (P); assert (read (fd, &E->state, 4) == 4); assert (read (fd, &E->user_id, 4) == 4); From 44b237bb249b936e427862813b827052ab757bf8 Mon Sep 17 00:00:00 2001 From: Pablo Date: Sat, 1 Feb 2014 16:49:35 +0100 Subject: [PATCH 234/465] Adding initial spec to build from source --- telegram.spec | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 telegram.spec diff --git a/telegram.spec b/telegram.spec new file mode 100644 index 0000000..748a562 --- /dev/null +++ b/telegram.spec @@ -0,0 +1,43 @@ +Name: Telegram +Version: Beta +Release: 1%{?dist} +Summary: Private fast and open platform for instant messaging + +Group: Internet/Messaging +License: GPL +URL: https://github.com/vysheng/tg +Source: master.zip + +BuildRequires: lua-devel, openssl-devel, libconfig-devel, readline-devel +Requires: wget + +%description +Telegram is an Open Source messaging platform for mobile, desktop focused on privacy. + +Packager: Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) + + +%prep +[ -d %{name} ] && rm -Rfv %{name} +mkdir %{name} +cd %{name} +wget -O master.zip https://github.com/vysheng/tg/archive/master.zip +unzip master.zip +cd tg-master +./configure +make %{?_smp_mflags} + + +%install +cd %{name} +cd tg-master +%{__install} -D -m0550 telegram %{buildroot}/usr/bin/telegram + +%files +/usr/bin/telegram + + +%changelog +* Sat Feb 1 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) +- Initial SPEC file + From 92f2880afa65696afbbe8e97e2a301875b805379 Mon Sep 17 00:00:00 2001 From: Pablo Date: Sat, 1 Feb 2014 16:51:10 +0100 Subject: [PATCH 235/465] Add RPM for F20 x86_64 --- rpm/Telegram-Beta-1.fc20.x86_64.rpm | Bin 0 -> 354764 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 rpm/Telegram-Beta-1.fc20.x86_64.rpm diff --git a/rpm/Telegram-Beta-1.fc20.x86_64.rpm b/rpm/Telegram-Beta-1.fc20.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..49453245a5dede1bd828e494bac91962d0517c61 GIT binary patch literal 354764 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%0A`vvAeK5#7S`}Yz!me8+N5iq-Wk^3F- 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�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

=}a6)ObvuG7X$~rV&RXQ z5nr!*K_IF}>#++I)IrZknuWi@rm@;@MTXFw?Wcx1n}SjQ!TJr@X*=QAEG$~vw!!%Z z$-0Sofej`t+bXe|)3d^@1*UIU_9xB9x>Yfv+WvFRe0(Z|JUnt6wO`>gKJW%Ml` z{n`cqM?kp0Nn6sivotDpr-8pwN2S%eD2j1UT2Uqx3zI*3M?`*_w0XojX zcJFyr?5Do)2qH=H5ReR-T8r*nURrINRoxyp)tugK!8_d)pC9IbeNY9?Dg10=qhzv| z0Gb|hFxZ$wqEm!=gl{qt=;HKnkq)z1WeStii4*`dF#ti6-#*rKc~l4;;NyFk?M0mOB1<8E{~f*_^I z5)gOOVgc;HMsd!w>=?vUWxPxlcn-KbjbtEAz{I?0qc!uTTP_qCPgab4UY&RXz7id9`q|0+?U3w2cs!j^Sl99A!;AX)zcN4-&pp$d=Hx4i4Qf8w9MK}L<|(sqea=t0opCtg_X|2vyK~DjnyUJ=2FAVf;UWN=BaWGf!Jk zhbP0Yxum{AdQ&dJd`a|k;;Nkz@@4iks*`!f43lG`>b!|vOO(5+^hONVp4nMvLClUY zusUvU4cf9D`NBimQz>D-+oOakN!GXA&WCV0W6MHGtL1{!WUG4SP`)V@ql*V=$Je`` zT1&4RXEnr6KX3o-mmjD!53(ianrf6@e*>ho{ir)WRT84;1 z=}CVYR7iieb?`)y2}~bfj8g_*+ui}%tPFe~<7@^L3>uG*ASs1gAT5Rf&Xc>?km1>k zlr2Q{u#~E^_<#sz#}ddFJSXQ!To174jTP>XyMJw91g&XI$r67dUIO<^0+}ywdv~Ln zk%>CVlJbSI0?^h8#W2J5tBBHFv&Y_AHBvJ}MCJ@4m;CWJK{C>L+EC24x7KkWo@tS` zsY_Fk^A`LYDVO?S^+9OG1j+t%zH$<&hi<$Y7prpK=x(d)o@v7NVny6%o!ulYRl+pA zVxxMR2ig2Y8PS3(0~btuVOA&>WR-<{&#O!Ro}JbyR$8OZaoEqcuOU%Wg1#nfhe~QK zKmm2?ek#{egK4v3Sk1~xnFb=WCfD0@mj0Yn^lOrWlL(0FwXF-1`wFT!cZuyDyr{_5 zh1ecFwl!OJtKGFt=6{CIvebtGt5+R5CXUdEGu+C8tswLPQ3o z(-C@nA12a4*x)Xz;eKZWk-revo_mjz5_c4HP=oSu;Je7uF-TE9(wWov3uIZh?|n(1 zkQ_3cF>h&fXAp6KHGSu|s3-R<&F@KHC#QuzSheik71m>jct4pj3arR(&C}g^dLsy_ zC2Qw$uCDm&+5`8Hc&o>)XWZ*aQZi~|GIF-K{^8;)O?x5fBFblLklA0j)oQ3fSal{4 zLVl+E+?Rhe_Vvl&8l;~6|2}KjNuT&J31)REJJ1{N@=`n7Dj~I zFHLFd&W_e-KTP=92qT!|eMlhQ9*RN;UqMc0knVqOn`WRg6;dDbKi&0dI=#@|R7VSH zdHmIj405oUzfn);R!`1;!5P61e5B+9Cedc;oYqV3p|~^@nr4hzH+j@X^~?nBJHu_U zs4ZHswG<>1HPVu9DEu1<6BKKV^>|&(JDoy@;HpX$9ETNqNkHMHt!2?S3{~zuq=wcf zcXeFQ+S;@zf+VcT8EZkl7h{8e`2;FnjRQ})7wOb}`R$zK^kEWH;x*qMNXOFpC@1{? z5#UL(0ZjZ zJFbaA*5jh!2&Ay&z9&m*PJZ`L+^Zly($BhxqPam|Nf!EI+-4M*wnm~1-q&+;I@r(B zccCDaWBokJ^h*U(=;yn%3n47oKbtf(wgHBun{ufW{khS&7W;~S@{}_^I@eta@I&qgJ5}A4Jh>&QStCnyr3V)1UAv+)2F=xrA90T&STA&GqlE4nnSm+~ zg^Imb{t)fG3YIB+q*?0Z82^FE{!iK*G%SGI5NuATHtatGL1g9Ymj!GCN5z^UPfkK1 zxXPXbsb0OuMtE%Hd9dfIRA$A(sILJ26*Iqze?Yos@P?qSRA(0FvcU#UPG%|58h;P7 zE8+#@9G7Hh2>!$A{>;6b<5N4EjR$ose%}>r2g#`ti)PMDQGVwkq$OuJbA1lD>%NvJ zVo5!%#ZW`JB+s*@I3*c&Wtkd-&5U<$;H;=Kw~CCU!6bbW!C`iV z0o}9$>3qt^iE(Su&&)6(+a^Fj%Z?06dIhI-3>nG6iXk6j)bXkAJK6XM>AF0&Zf4u^ zQHlx8rR{g%v05`t~2 z>NwFq|MUkwkml=duc~5<+2qSR(g<|n=&EVt2=uqS8`@ean2oh&Ey}A0JBL9uiEL;? zKVTb#DKXgZ4qorC#k1h2ZBNruMXhvs{vdo|EMasLNT(Lxs$?Y-9(Oqkw>e9=FooXZ_g38u`*$&~=!)WDBobQoz(Y(OPx=#RqJ+)gHSKfs%xs$7N)5d z@-^F7<#bIGBbC3NPiGRb3i7Rn;@Kb5!Jr2mjs$fW6}4n?AnYOasYDlD?Z82fCwxo- z$VL=5^a&d;;=^?nvRKI5N!Fp)F2ir&ur!2-shr&#dVIWL7MQN=T@j*MwV@B3pdZ>; zCnyE^D=SVlvi}CgY9Z0bFH5fLVF;Bf%V2*2Oyv7dcq;Jblt!|(IjZJ0ZjUE8R`I;L zqU)d4TrfarRy*E9izS|6DyB{S1aP#LX|Tus7jI0lmWR zyUaKY=*Kvq3Z7N8@Wrj_eVo)Ua;8!&<~9#D#`TiI#*sJVB0ko61PfG2O9EKqlWoSi zn0u!~!I2h7a(?NkJSGT*xMX83J{!nMe+l9D@oJ$o@kdSRKN-$d)Y;_^4)+AYFLooA z{9+Jf+dFL`&VTs2M6+tX5Et@wUc&E0%TfLE$R=3;McjPGmL-Q)tiEha^M-K}!ON@1 zoFmGY+Wd^nb8R+X1=5flqZ{`+&9<0ffATO%b?p}0Md7*+fJk-vqIfF$F-RKP-Nngb#c_ODN ztk$5XzBM4^3kyl>SG34)ggME&iCm%3IPyS2&P^;VqkE^-*Kb~Urm&q)`*h^r5D8rZT=2*le0NHj%pYkPo}?iJ_+#|e4z6Ug=HraYCDJ@332{D~C`>N-p#sbY z2GLl-Xi=S>6Nb!~OvqI^upre{=nov>6?m(ENhw8Y05v2QLN!v9x{}06g}S!i zo$DIoeuv4n%rK*(#72KD5fmos$XJ+%dH2ztVmPQ)l~G1o1d_NQDHYIk(q_;6g+{Ln zdksYoxuB|jj<-qnXy=_8qLXwxRP_P^8N8u5PDpZvMtFkWgiiQUcjgi8=r@YoJC-rD zKWOOmi^JqKt*aqu;a}z_J^Q0%EyW^uiF#FIhw#gUY8GR^Z@n>{y)qF0#7CpdO#P)F zwd5xhy9OyLh)xXJ>=Y5sw6t^RYTCtGLeOO8pKR_&pN^jImp70CyxCKtM_!DsN2I1F z`n;eD^>@FA!{OG_H!){E;$a&h1Ekn)6FKKu|CQ0!*Ppja{Jk#}bWwkb*u0`5pq?vr z6DK8yPN{yJQW|;RFl5Y`U2<-BPcb_|b5k;QM)tdtIMSkCV>ljovn^+W>96;uvY>AU zBmlVkG^w}oLuJrMNBr?ELaM_F0*hb6BOb-tbqx!d0LjL^%LY^GmAjby-;X1YN1|nt z23FFL*oY*;G_>OR*#=iYRRYq?v8UcvuyiOy5Qot$@PH*d`!RAvWDoFELZI#*pR-LN zZ4Ns9e@)y*fgN&;p0Vqj_W6t?jQ= z*zlMD_Bn+7xCIa{X%IgN{Td#P4S_B+K{Rg_qYe9moLMxLJYEvc6KFqhLu~E zUDy{i(s;Y6D^CGbe~2Vz z;`c(x2H~>X&6ovK!IIn#5Gssl4A59BPiB^5Gwx_^rB#I&PonmE{rGNRy#8i1oI~(C z!wGzvw~KDV=?H5N56M5_wu?3*OG=o4S;gqd*EtD7M<-QdqoVO*wpLC|rB+%Q!P5nINr z?a|e;&KeW=Mt^)|w;+Aom&yiOn@@m$nnCj(NI+Zu(YqvS4K*VtqR>w(vGl`(2&yE? zF^(Hvi9wG)RU1|LhQF0+_NUGn&sb#Cp8K^bGH_DZuOdQmUor@S9aaLgx=^VDhr?vq zajFaFuaNVc{u?8qc3wP4{|tV-T5x*9Zm+t|_Nuy3+<1C5XVEU&`i;Xusi+5T14!5r2G;rgP z?B){LM4v>H2~&Y}-)#OTJ0Vl!2pMS(BegZe?Y}peGuSmTgjfkVD%(&|_Iu+WyejzJ zA^KNvG=J&2;RFQ6UnnYmE!FNJX=O8~NdZWvLv( z1sb%AdmM~ZvtOuPqTo_XzSCV04oxl?4Xo6y zcapRgoJo!n>?UD^swkHpX2st~IJGgKQ)WXKpceL&Hh0qUJSvI! zD5P%CEJmxGrS;Vf#F#E}N1Z+@HfDs{fAt2?J0y+TDu^<)n}m+ppN2&Pg7Nn@Al7_F zwc|^wNV^AR!$MXCWdF)n=r6(qAy=IRFqZkdNz#Y8z}n*f29)yrH2H{1gtSU4xY|TL zqriSN7?4lqDmKntGSsH8+IvS{6ohW246AVgipjHJXEkSwMnxRi>dbX3I1X|(^6g)Y zV)*^<5CcbDyeH=lBt4iJegU$Vt*wZ}-&$Y7Md_q4y?Y)a_CetdwA{@=Y7|d1FY=)8 z9FSe;YsZ(TpHHcliI<2bNkK#!{jN2yH315n?YTgu8FiYm=JgGcw;NV;^7|?we_cP| z#wn8ef(PDUG?}4PpZQ_EAu2(~l#p&IkT%zAjy?=}x)?4ZSGvRU*cL~0mz?e$2{6T1 z8junJK8Tf7++Y@wn~H7TtB6dqq&dDT=+e1UkTf(z=G*2oAp6o9aan zaLb%^x*pui13x2Y{<`=fy2$Gc6}uWfOdZ|8I9jvgF+cnz>A#<*pxn#C!H7Q;BR?E; zS;l$QOo}72qdFe!c8p90ptSsp=WyyYKJWGI8TTh<&UJyE{`b%gU70UOrnQY&?_4po z^!An}3$l!EJQRcn;e$KN&(*zuSTqd?XN`Ya%yZ(bJuU(&eQUU=8m1=|<04GcAt%!xrll$rKHxXygSJt=rL! zcoG*5d6en7G1qv&wf8>mfC|iadA*SfY;kb6$fxW~L6bO`+xX^|+ap6q*YfV57Q@<4 z_iz4@t-0Cw z-0dVb5mCwThjd9mwS8LQ@zB{{9vjU?H0?pMeZ2uW{cXUH$uVedYygRC%STEXFg z3kfKF2p=~!WOV5<1HEiX4fP_W> zoG54>#(4()ziLH_`zJATKEDL$MXGe>c=Rfhb{r3UmRN85$0{giB467krnDmrd_FL4 zhSR1(o~uC;mzMGYx8a9d*oYo#r-nNYu+i`J?cZzRNJ3skNg0)jI&FwTu=e++)-~&R zhQw*a#&A=Gkzc*X*&<9Uw_gEJFRNQ~=Enr3<&{^beJp3J!N#+tPRH-M%_kaJ4%v@19Hy zk1mQ!rQ6V;dvr*fQ~r_Q5QS<%Azn3^h_B5Wl1-tQ>XF zES+^UM`Nn;QDIiW;1c(&u8A?3@wfY%579P3P(86F4h(>aWm0l8X#- zkmSA8&^VJoT<>k}2AyIk^JTEN?MJc=p)@QuR)OSH<|Sr8D|MkdMLCi$u{F_FPWX6Q zLvo~<)FY*K{>lZyK&HJ?jr1ixfHhsi1QX)uoeDl}V?Q!Awkr=NVSD}ZJjoJ+GfqD& zcBM~D&J!PjuUj%4!Wlj-Z>iVRq`enkgbZj!n`e-vc3yv%uHiPfRElxd`*3ny>hJ;! zjgoCZv=8Bs;s^OjWW7T!O)=oPjuw$C(%%|fE@l4}VUv7g)ks|k#~E6rRYMi*AaeYw z^wXWKH7uGm!zr{I2^S${Z&C6s(h8!|v>TJsRxoYzrgFm`F_!I)x3J4b$Q|}3aW-vs zfAS@)PpTMJZLdMA0y(%Ii@cgC&`eBlDBWRPUACn~1O<2Jc8ZP2TbMH3QMZ|bgR%Oo z#q~D9xVDDfW$*nef079u1nKOW)Q)9Z0*WuB=_qHUnrN>#;ZXJz%QJAwL3Ffv)0r7n z=?}WRlwdljd{@uJk=i_Q^>%Ee$Oy`<_*I2wU2dW6nv5M}soSLHNe$}qg*~rYF)^D} zjc%Kk*;IxjhuZl5Pt#Oh7ViyWQTs)^$u07(RaNGdNY_;yNdTh30C~b)bZ<@jUxD%7 zdR=Xzp{lpBU9+1<8mtB6N}q9hK#Vm)sT*lUP7SR0643)marTIhD=kXicNg~HY6BP# zPRfnj+)H1E@eSc)P{@QIHy6V`k0-*=|H^$(!gN&NDXp^De=MF z44RRzB~E-yUC(}JEU)MTmuRmXcMGZ8fFl@j42D^fr^WaWMFt(%n6yJ=1bCoP z3vT0)zHPG*|JG0^%BQK7s^ZIYF^~DYDuS{F5voo36ZPqm(?T*`* z{ABzDO%?Gk6TzZaj4Ih!xkCzA;&c-RaQOA4+xCXAAnM~Sjo_mW%putdtmLbPM)Q=N zPbur&~ zQ1y_c=oMbr|E%WV?E3A@L8%4~c!DS-pCT+*ud`p&^|`&Odl-sx@D=2NA<`VB%T?Kg zpda-5Q@!p8CK&nDa#8P8(uy=PmQMr9?f!Rr1DN`PgT#jO$mi7WwSe*f_Yf9i(iiVP zcvQ6~q|6aF$Uok8Z|vuQRjGFLjJsOgyG{s!aIPn_SS5sgy#gjjtqT3LQpr0-r0*_MYqqHPc$+6Fsx+WhW{T40-t@e zl0{T>#jZ(!?8~c0d`}da-tRuFG+8V-pwlN11oevG@+o zpS|8z9s_EyfSa)NUF?zgQ@Ef@e0g+W-e0I}fqau3_^$%}&F z@P{S*#oBp%x|PArFjaR;*4Qq@eb4#ar*3*AR5@&2jJw;?HTiybZD4I968d(Ofe1zN z2tG6U`f=Luu*JZ>rDc3jdQ0Ax`#46g$mCmlYmeluTr~s%KlR_1ybRxyU>76cz#4iE zL|L%T>>@q+cnSIyAiYUTWF06DhlZpZU1|x@yM+HXU+~3!{sqPQ?UNaodAIfs$cM`r zIESvNsRqAhH;K$Ll?xL=LMYuk`90$6j(b2FncWSS%_=S-ma-9vnQ8qNkXGxo=2)2skh}`2&C%uPk2e)}q=IRPnxhEAFFgyk zK)Ww(OT1D{G{6(}S!YfquB!C^{GPTILRDtv3r7@wg#5(jz}pjOz?+Wz&rL=XrEobN zImoE(Cso@ki28)p`R(mLEoj@~98Di)sWk^Qg`0x?c$CEEQKb_MP#|5o=bqtTvppQgMb>q@5ar5@Wx_>xVx&f`+ zCG*daf}wc3t>{2hQdSOUNob9rE+)=-kdmqVg5l2$^ql~F+Y zkV?q`Uw>_mzgR89pEeqZ=h=4^HEg*{8+M2pDEw<0;41_tTyRiX!tB~6V~r+zd(@wS z%>6zOZ#5-`U8^Lwlh)zjD2k#QoA+lz9fo^AQo(ocV5p9==xvl4p=t#JClyp1?pib+ zbFBDnNv`OKT&pInm^qX~D*%U0C|zgBi!iZ}D4|FwpsY2|BcN-n_F9k>kGh1-i*y9E zk;>0Fl|!u%nJEg#{ym8Gk^c=qxBE#ANAl0unD>vjX)e_nyxn~`ekiul z@hVaxf!u(RK(t4e0u(E#2GL0D1cdhM({jdw-8`=`lE*ajZ$?TzTt-R{JLS4V$#s>a z^&qcjC(D$_sK!=eOrTc@2LVn6XT~RDyuTW*_0g&;rkcXhs6dxCbemx+#2HTxrk=n)Yh7dtRZNL4{p^TP>+C~G1u zeUgEO-b@?Itnq$Xajw7gY)UHUocJ_Y$@KX2(^lckDT5WN$ruGaVwAJ4R#JBThY-o?QVelGQ~de~=zkSZkfzEE4V8;b=5a=u z8L4Cs^+Z-RXp#C?kGabFiPv=!c`Bz#?WQmG(gXll46SCj^|jGEZPkXR&vw#`_RrS}8In z(Tkr}YntZg^<9cO(_~_&rv->*M)OhYJT$-K69Y%~R4m5q$5PwJ+835}H~YP2am3qx z(InisP*Z32jW}nT)-Cp19P?mDIjz2CdsGeZPcS5UP&CysCIBW}TvJy(xypR`BVS^# zK)?W>#$7S%9)QK&5Vh04z2E`i3Ogx*@o;jEk?ZQ-fn>KF#s+{U9=v5}L^KV_AVnoF z5g|O^9`HJm^AA_nphDjCCgnPt5QzA2y69-JX@*5;6m_(N^aOX`#YXfsK%t9RTokTj zf|c`Q%9()QX3n!|Ua7Ex0D}g+e8bX<{yT}XODE06)j>DRN(XuUR2!BR(t8sbn4mZ+S z%#K(=RDJZ#w%}=`%I)urrd7rztMA1Tf>zi#ETD*}!@ZW$_xqSNFfnw$z3m8MinU-( z@dNJ!(Xf-G1Zjq|F2LXnK3Z1B5$P5QeuL>>H_?_`{$D2z4;gZVvOv;yap+-7%zI9u zqv;o`a}!T}hFTMbiLo9xgArwDj;AkRj@X6<{Ty+qia-C1&U5c|cF@`a2HtZQt79A- z9?E391Y&--R1j z3qLX#Oc&?@B&O3-i-^vp{&42Rw7G9|eck_iFt1Uh`uuukzfyXea3O7l?dMx4Y$YGGC&IlJIFVk4g>>Nz20yKO*iM44X$MxTt>cQ2dI9JVw$&1Cm;qTuO*VT zE>{$<9A3CZo&cte$z6o{#k31OPM80O({h8n-)_uNV|5%R+ z!ulx}CGF=+@=(LGVCYu0(_#WYZ%}LsMzGaT`wsR)q1~(I22+vHwZAXC7pB13{{sgg z^HI$YyW}agoYn3Ustsw~=pZ#?(Iw4_;zATJvzc*__q&y0-A&2R3$)yPr*af&2J&b! z(@Y>bUU!>QkxZcN@J`20WBQ)arFVpb?N_nV=7XC5qL-v~{@#!NpRPkpvE==+E5+)K&eo)Z z=->BN`wJKqmr!Z$op&OEKI{H0PYj?rOOekkLtV@JJ(&2>D*tP1R)_yvvnBJX=WbOt ziLw7K+(Q_2TKpyRK~Wb6)?Yd;MtYwlW@;;;W8Ts2Y-Yu{5+on7&riKAh*B}| zMCYPVr~KrIIp{P>!tpx2k$xLE)4E2%y5Q5NLZ{!MvU1ZNRERiBqLvO`F*v}M9qgDD z!SXQj8mx_P^;Knf*6h~LK7E?v(izh&J43Gco(<6 zb`B>2GQ&|L@=&!~l|K&4cNP1^l=Inj8>cP}DSOk%qp@7Xnw7@9aLR>-$PCE2#7*4J z>ZrRhQUn1lZV#Zo%VN#?zOVENvCp!9fc>*L@u-$wD4Lih+UHl-2jW4 zJ9YELEH%{;axWwl699h_VFtnFGT&A1SMZo+&?jf${_HCi;Bqz`4mvL$p~LxuH#Y^L zMdK1!%j|su)?xZw`2R5Pl*5M0rpo0EAf4GeSj^zn6Kol^(*<>MQD`kG=c7&jol`i; z$Gj%)GZ&!dw$5MqGhRoODf~7YhG16K;hKWL7<3{RrjPvnte7j)B###EIIu6)RO0*| zR)KENu>$}RIE@J;VXd%n#VUTIdV{-_Y> zYQi*<8C;!jL5vp{VA-QcdQtPTm#qOj6@dqUfaA#ieuAtb^>OIqa|M6(#N^j|ot)e( zp>m!Wi!KC4n4e-~c6hJd+U9kt+b#3S!Di+{={zF}Pmaz7$d}3MvO@j(Rq#uUoS+3? z6Qde;7g$AF~`VDz*D9NYX zdWRAU!KNAISP-4kPwDw`iUqadS8V(O6ZcKxMYScRoqh2pEdBAd}cqzH@H}C58 zqs?F5kJuhRwf$qTjFl?7D2(3QNHZtrS&-B#y2ha;)0sM>E*|+bCl1OIf_mHDpi{Fr zrSK_(GPQ0Vz#_GODK7Dq1opYhnoS{#jsD@qlwn+<$a*NV%V&pD=0jC~qPu#9E6S%D z(M`lQE2Zo#9w0RU{dSn$wW-Ae9D}gR5Schz^(I#;xz$IU9{y4i%CgU}8`UjV0w#`7 z=*Rra6MA^KyV%-MFBg&hXH)Pr+X+_YY`*@MwXI^;fuPWeK}Qy5?AnkmvUiFKlcKj2 z=n3|rSY%n?mOw=7EQ`d666A&8mq$8D@f5_8@{GdE3$$Z*-}uY|ds(>|o1yu(m)xW>%-w|9Q1x z8e~eI7;|?x&shm>SkrXZMa5aint4ApS>A7hnv~x&!G^-Zk?gAc*4k7v!0%C=IuGF6gL}@n%F_Pax65wVQDAk1G#yO+Qhco3 zpU3Z_XNAwKSMO0VP?b4J5-jS=dQMK|y70+*LxJh*!`lb8*YwK+Cmy%lJZC;IFr6bN zA;j|EjDi7Ux4>^0uN@5c^;+A{ul;BE*a(bo4ylyST(NCFeyJTK(?6!Aa4|NedvwrG zc6bJ0ko$3WMOEY-D!`e=qR{3fuS^`E71~}w9BShMq>2y#$QNyK^oKp4iyAJuRQ{>( zyslxOR&@am`Uj<6B+;&qj?$soo)10~eC(jHd|ll?->>Z-N+vJ9*2m}XuiD&`p2bha z36G1Dnd5dWItwl-7ZTQQrjw^kB+bz8POcc-Z{_eo4#HS6W!%h7&VdGXW6_>T!Co5t z^hIz<3J({4;jq)((A=OFel}SV_h#b`LmbiX*9s#Dm=R^n@z9e(ywbijH&%bw%(6#F zLkZcad{1R<5kKSg{Ak;*-0YpNTrhJ?<1dsAMv&%@F%u{<959b1j>%NDGO?}3` zaZ#g2Qbd?P;D-@2LYRtd5PX`bmWVz*m845OuLOCAN4VV=UWgH!Sq`%Bfqy zPdI35C-a%@b9P39OoVMm?(xT8Q<@gl^hHh7U@<6*rtCZViMR?7)Mu0ZCn714!haH(`ey(p*4jlI7-td{hIy7ngePAA`}Te%QrQHRZep z!^l3q`m3#@39A42BP>p+Y!|-OvbVgVeq{-Li2X%b;ySlu`#uUm3R^~uA zj9%gi{SWUFNvl#UVIw8pi-kV% zfF&KDR5*>%!s}bOnp0EmEmeDC9za5ylh`|y;&p>Z80^|2Y%yqB>BQ-uA2F-Ke7}I} zb}?P8psdg8X4XHR7e$Zty2)(hX5a}iM3DbmDu!p#!y_1qXX+(%J6%x>4s8~~?7D-^ zPWQlobq}c5zza~d>Cs3b(`EHF#>TT3Q2NZ-nf7lDa}AHh6tSy@uhR?f{U(|FO2h67 z%B=?JnbcY#J5hNCx|&{lcRMTbMTSQ0B8w)Z%y9EiAt=meG@id-z*4x}sk=9jX%IPJ zuL|!jnm6VUm)g!o3ELbFp898b==n%4ZTqHiia1vTFTM0SvU|#5BAS?&Eb4`@p6g8#h2- zcSw{2M9GO6$%{M+?MW)RJyTE-cf=&`(ymxBN_Mk17=aTb`A1VwZ4l5`eY5fbT^C{= zgSQpjp417E_$=tjDRAjj?@xrvz*)hx4Qa7CI;&>=m|p92$L-(wg?Lm;pxRu^T_&=) z&03)5EILlu97{WJLZ&{*S;hfcLZnd4D~5wynzEGC+!fr#*K-9|CC zv23Jf2~l71QHT_04*_K>K*wjv$}ErXr%Zb(@8P>$Ka+_(JtF;oBxxdav&n&i_HC$Z?+NJnzXX)01gvnfl&Lq%-$&nKKRo=FcaO6>hF^Avq|ZUFkb9c z>P((@%cr4Pw${^9eihiaU9T{w`^~7_d;{5x9%MDqkW^Dqf(t~_!rI+Z0c@Xy67C5T z27LYilH*cKXhAN*aEqL#Wx0iG z;8QAEAZ+PIm;QP zq;Q?`Hpn3oc2{){1lLnK*Gg-`qd?jry+y?^<0L{4z9iZ>jnHsuVVRFDR;qd%;e%Q(2B1mwS`dCcTwqVDlYk{U0KVIzg4~ zjqh8R#it=%U7Ea13&iYdqBtutk8QDabfRY??jRFhXvhZO52&2~d>28jdmIB$WW0!VMIkZ~+vAxUy(|gcFtr`*AeA`PX{-WO%zWrA zBFc*HsDL?u(3h3#Q7VZ*y*}ybpA_rztIBm5^XV4h(cOjEM@Pe>Aow0z&J4&@USNRU zv4pGYV)XqrNE1V#0gk{WQ+GElh{e9Q8!F$~_`J3K`GET@peO*2985WZ7Gpb%bh!da zmv(eaz6rgT6jUMFSJMyx$32v*L!o_+mG*uZ)MEG>JS2PLi6z$(k9+7oL)IW1izS$2 zygp!qGPRE@9yf#kqwQxFHK&MnhB|FzI)?Z6u|ssmJ#lnOdp2+yc*un#+|<=;NEw?V z3IMPy!b($L7hYPp2jqAb%rxSqN1(9zteflW3-=N5Y$r_}b&c*bstSQM7&RMl|Fy^B zrZDcS8^e9PU_S$7mDy5D*^_~SV^8Rsm=v1;a&qDEHv!|5?VyF7-z%*aAJWiDO@l}k zAJ4xnjWOv-Bb=b2EVsKLvqJUpKTv0_t^$*=FXH!k)lVt_Pqf_sDQb@?(W-U8CG-D( zJ(8Qvm}&%`(9#^MUznZTb=YJ4Zv)Q!P);h%`pUwmIw8{a@o#e1Ir`A`-6iscydQ*|5GL$veAb368Vjo7v2Ltqf zYqo>WVF=UHTnvs7+H>Xf@|xvxPf#6#$kqIggfzpzwY6RJ?bZNSMwF?lKu#gONeoy^ zEJ?`u>&ov?M1ZZ3<zLoJ+e|ClYJk@i2p3L&OG-6ui`#|i`Dnsf?p)BGLBO(XH9i#m(Lwd_t%isp%oTAJGl$)hh<8xCt`GN6cYH9&CH(h0nq>Ax|f0Ye=^K#wq>4b2m$NGcmT{COG@O zPrCkU-h|?!+^syp^-(xyM%YP!#ifx@Kwla}DT0mJnFvai$V`*SsFGZ&De^YAV@AHiEA_AyFDK|=J zdBI1D%LYy(eJ09a`-oSn`m6z$kl9Xuj+~!S0Mx#1Xb*;r`k056wunI2f^;m z>9HLQkog}NOwyJMIc?;b?Ye<6_puT>-y)`dkHYn0kHhg`k`YY;Nu4GhXFzTxVWz9n zQFQX?PllG4Q=o};>hA*aQ&^3AF;8If0EAmtQ}KP63pMXV zllH0wPpkk@Cr2?>Z>T(;59?&TE`0@l;%Ip)bQ_o`f_TUB;tJ4HoKW}pJDP?XdCMca z$E|+>E-EjRo+0{}aVOA+LkJ;tOkH2NniS4#`CRpu#(*3$wIRRcKnP}%d=**9XTziI+ zwLH<_0n(*!{A?($;mwLm4b8DAISB*)SI?>(>l9nk0cWwz`i(*oc|Yu9HPm^W4iy-Fm=$tQ+|@1h`u_=wy)y_#WZ(ccxmO`~qR zo%sXXy3ZG2AsCP2mz~@Oh3Z1PAZDQi$+@)$3w3)P_rVfap>Ut-H+~$w!B5hzttb|= zPzJ);j{2L;nm~Cu`LH3SMgY@qF;9s1_hFmx)0tLS-Ko+5jriDWi>bS*9@}JYX){9U zI;YQniHv`f8se|WQG>~nu%zmOL}ILPIYj*GsG=`;`VH=1fTch2Ert=*{ZWj*#9x_I z(#_k)=lcA2m`+t}Q`}$b3EP=9<})zFT$5(@;S#MaZmPlJ0cSatO^%f@iC)YVp~p+{ zZV8-l3!9$lYGCb?9E7HL(^4@2J0sn7pE^1!nfVTb6~HH3`P1MHcYQ@T2hz5}D9*X= z(AG+5u(~BJql3+Y6@^H>W)PR_7zTm3*+#(IC2@OOgrgbi)T~EZ^nend{|D>cbt0$5WDet zn<9*nh^Q8&YzFSu!kR#sJ8ZG2pg`GoK}oD6-zOH}}<6k7qD|qIGg!P-xBW93hf`{&Z6M8o@oQk8##Bf;Y`)6W$YXKSU5`b|bZna$V&=4Dr|oOa|QcSr@dC;B9#O9IkB z|Ev>A4p_o`xqo*{)xN3;koISpB9d6y23CaZiB~Df%eVSff6U>k=Bw3u7L_xNvSdwl;wxl;YIe~|vEeTIWbGC{tX3fM(cv8YJXh-_WAU+ZQNYAZJR~Tus2wuw% zFS_u|cs&MfyTGD5nkyb!BW%AE+NP4i0{lliIt>m;T${i7V>eN?8EWXq|?vMo8yw(2U`nc=P*}M9uw=lY<)GA=pSZ7_|z7w;fw7x_Z?cU z=BZGSueL~V6>-DPXe+yJp?m|^D%;FU!;DR)pU zHnsWyPfSZ!=2>&qSiN8?NABQOyteoAdKOXAwqA6|g`Oy(Tk*&)u;nU{PvjYBs|j z8t=$%s`m5{$07167@$w)%iY2tTx6ZtTc^QN1*%tuqCe|}Rw!j0X``mSq1B5jM-aA> zYH2P0m+v+4YACcDLM8c*Us(tz?Fao3O%W!WgD9Fc5<%>p*gg7)RfKIC{r2X<=v$ zbq}{n0JNlMx*Wqt*SO4nI7nTtA&qbfa*L!pJ6dx=QF@xELw80jksdwFg1fIozHb|$ z+&P%Qmh0rao{`}g%nq~hXh7hZULW-<;<#A0Dn84ecE9Ru{m%VwiRim!It*b}MYK3m zV(>JFb+~Z5M+-l{tewu|`%bB8Bx$`h4YXfU1q#(My$C3xKp$)pol|q9)o1}0!G0s4 z4yo8!;JfAgj?Ga(vozEgj=|3f3maw!%Xw=3WLkZFp9+HiQMIv^fZRUkR6N!iVufB< z&~pw{JVf8PBIO2+pU45$tq8658j98ksaxW}9@$WEjdF@yId+ahGzl^kEBRgYW3~2g z$CgxkJ;RjW6QRbD(6cikC{x{gqd#{nHo^}^!4}CoD_X*JH)D(Gll3}ub#dtOb#Nw( z|4KdZNr{~-1F5mmO-fQLl~@uWF`^_g=9+$DsZW|J8T*X@Dd=nrpQwwu{R|Oq#NhV? zd|qA|P-KA@VZ&-#m#;x_c}Z8>dW3(MR#iDQk=CY0VN&b^Hh*Q*?U_<5zEW-Ypjb1U zgtv#YqAkd^p$!W8`i@P?(AeGL?I2v~+P1(4Bu3->YP8Fk^!+8b1CB0Dk%U}54z<5^ zBLi;YtQ$}bYOOq(n39gNd&CA+z`(cF-t9FDA((V}!)@}<3D?eK#~CFs1CXsK9jVHW zrOvshYE5wEjTK{jRd>7lJ=}bU_9y8bWiGmIpVfvy)!D&RB)_bRq*4~5R3@uj-ap#Y zIr(+#{v9kVX*6U*$z~>j%|+d*im|e*T108!-Y;BO^8)kx>`?kAzd+a@Hqa^*>gN7? zID%@u%WzS()|&c=V;TCPtiSy(R2T(wbjsJb;gzI%UC{BuVA3!AuNe;leQ)_#0lQJ zGokZ@urxME6w)KbL5l_jtYUQJ`|l&3fR*T{FssPyWW3Do5+>fH!hVcVvU2OQ{NAsR zCTJv7t()`QUHT%beXA0tCQOPMItU350N9&4d4N!VcFXkP`q-szD*oZOP3y6|Fy7jp z%d4R}q)%7Bq~+j1bCXT#;}w=)KyHqE0CF0l6=DMiTZirYA2WjnE z4`XC1pksSLCbecR31BVSH@={i_A9pIkF9nMY?{w!)RH8-6Xj$rhXegyCvFwIR)v8C zMQG;5z&g(}msF4x3m6#WeP%O`;5tK2a#8A$UySkLO3wZwX=^a}fWS;KT|lcu>y=Iv zzhEY+=L)+kE|ZH^(M-Xh=p{rTQ_mL~Pg2a->uZDb5m+tXbwE43Yq}7mw~*f^THO%T zh-aqQ&j!7Sq)VM|*$%5)|81y4XjkHBp3G`^)qhVnsqx=zfc4}NTUn*m6FQ|#_?4kS z=*xG%dbm08Kg)tzMoV+=q5w*YS;6kwy7k-LBf1j>&_*V%u`|x%&uQ8rbLuoPxl2)_ zi>r`z)e6X~r%{ML?UOMmzzQ3{{k2QgjIpsrR8<6#Cd+mmDgxLumEeJ>lf1u^F?8#l z!7-43u#t{60utL8LO@ZKW@Yt9XfR}v)1c)hx#Km6V4@+@ui_-#;xF(B(&OQ@z&~e} zZi&}T%C7sw95-Mv&^0!LH$!J6L3#)w>lekBT}IyI1N_tRI}4@i6UI2lJ2j`-I#&Re zr4@rs1hKh208>9L7^PUAB3EA;JoRWW&;eUJeA^mq5vQJQlIhLE8UOdtd|7!n-8S@H zy29U0h{x62aP9(0D0za|5R_CuGpB(e0;>QtB5L^w$rv*l4V_0xr&p`)y5(Qwu>8s8 z^fydIm>Gawsu;!YZe`smn8b~kD5|p4w}V0$etFyDZCE=T_Z%_C=6w-qe1ebMw9GM@ zCn@5*w8s0DxuY%$W8XZWCm4=e!Dn{J2H`q0lB5xWTQO2daZ9PehdWek2X#Qly?X|2 z^Cvwk95dymhELuIsXRv3$_{76x+kes+zcU?2&NAxHq+ty$8EX+VPv|c!JjGCsRXPb z>$7y=0s-LW^Oz^i7$!bSzlEfEM%Atm0}|BhVNqqM7R$#faU@L zYK?$oZ^pr$j6*@NnZdzXZ~lR0&?M2(7}^_-7IHTsVqQ=IWH}=UY3gXi9_(so$)v|( zB(QHlPHR<*AE@*M++gSoh zy-q?vE2gwNbdz(&yPdYN#$KfOOXel~JpwQlrr$ht9y1@N++unBf*=0~FXB(1s`MLH z!rq+qd#u$C!9TGLpah@q&*3WCT!$=A1>lhpU)UdrT!L_4Q`?MZjP>Q`;@*scIAHk0 zY&}V_szeX;lN|!U)m79kc4u36y3s72NSQ$u z#o5V#_RBH*ikE@+wy}l_J5!+>)`B-gjenFdE1>t@NxO~be!#sN7dZN&#QaC%HH~Fj zAHCF7c(tDN^UP&jQTLvUk6er3<$c@n44J5YMb;%&8ry;$pIyTNA7xkZd9UC^3Bxl@ zy7m9%4z+Q2Q~Gt!!APeoCc4L#cYFUYDXKSepOCaQdpeiCyZkl~o$~)N9*5|kA{P%O zv9F_yInnoYwnnIlr^gaiHfEXO*Nc@K(q$m}%ZWy!)m+8=)g>OkezlJ||G%-130;9M z%28;o2SRAj&rtsjEtYd};arUK>a~G{dCc1$nd&@YTZDu&U8z*40orHUTYK2}pLZnM z&#UstrMxK>dd-5bNi24`X_FR+ro#0aSE0PiOq5T&&xr!tSDIY@QoQK#1=&AuwK8A! zz|SAm9_>L&xN1{)am|OY5<|eVoK%#!?i^SMj%U=KQbZHNZS7wjvfSy!``%M`&*zfN zT_JU;ghFV_UL#~Y@K>s>+r$9UZ>91@mr0Z$#Z3HH*8LkqO!5=8`Tvuj$XjkLi3+XG z09&@LwHSq^s9J~{yAh>2w{*uRDOR5UjqsVc7#~l@RP;`+Uuvv-j{o8C1UWxb5k@Z3 zh}{kh>AaT?rHS!s>KXBxxKT)zJg){3+#?Xi9#RFUsWN58CtiGZ#T0zjBgzC^=V9h% z3_;%0>s9_+wnuN4`=2?{`Uu0CI|}rB%HF=!DNlXm_}IV2e-vS()N=s3Epo^MAz@|9 zDrdhu8diOs>@Ep9L!|fp=6zX+G}aV{CI@_j>+~Gw;zImK^W-3nHJS=L+Hd4 z4h(a37myV*@tqzVsw8U7EVaE|NkmOcp z^q;6TDM-v4NY64@VL&A7h&Y+650r>X$UqydO0t<|0mwFSK4oSZl>QPD9a+eUx^Y78 z$TypFYF^-8QmH!1@4=I&@ID0oh6a>%{?j#>PIs)T0=}V1Etg|G*uPhXLGk6^W}Uvw z)Go>GC0YaWQLn^Db~oe~j(q;990)4PZ_j}U6=nkgzL>0fZViUo!6B~4|Ah7T3C!iu zJ1*zCGmzdd9(%UCb1!+<%X(6zFc{r{VYVlGFSv8g!S|@$Wl~&=fo>#VI7ZHf=1LB& z5eOga9Hyy;-}6?4R^Hu7-X(&26gj}vU3^LQQoa*g^*A=P!RK`iM)c^#`0Dzm^?50SODle!Yn3y6Bnk zY9mo;u-bkzzu<9D>ar37I>e{hArIzm0UPzD=>!9n1W_REgbg*y@B6^)yhO!qWfK}> zqL6hX1-=ou8+ozzYfT)GHXtla6YirJ1jKGtMBI>(!z>$aWNA@c}z$)=8DU3U`&Qn{KKpXKB>wF9m)4Cp5}-DW%z(B#Sao8zGLnJ%zHDxb|i@$!tS#Cz@wR2}uzPJpz` zQ)ljZzjOv1?r=F7Wef>Hx%~&))LX^ZqJ+v6Ur$lj!Aj{u-|D?u>QP^c_@`9<9GrqK z)n1UuXuUy?UQ08ITBt0GyvMODRR@Zzi2nzP9`j&pyqDvdUa9=%MSP^1vA5!J7}^$- z=Ezp%;<_gUNvvj+MHGiX1Q!h45RF@}Uy2`I2@z9rFa~Ic{S~>rVHC=rF0>#Xp`$#W ztANPxWGe8YLt>{uSW;u@InJWdf@)kw@?gESiop$?cz((OQ8}H;(Oy6zmjvDRLm0h> zH)hInhxt^tm&oP|XH)ZxICsWYbs1ov-!Lqn;f@zQvEpeh%mxP&xD|~gwZMmq10!(Z zpCe@bc1t%$G7!0zO&^a~fUy&5rnPuI9NLKQPju_ETcWx;E7>6Bry%uYgT#a28XgJ> zy0!;=bodFz6UC^fXW|BQ^6d;)+V#^@z9#pe{(W9*=-y|wa25X8a0=3%oHMLZvNqtw zTS{Uf=}U9Mk6(K_K|E>*U56E~{1xk|<2dl__gmyj?LON0L=ZTX`%8k5cr`1bSR|dL z7ennmUNWhhwL@T0yM*6feHWo7;$kDWt@|T4t^|v&m%~Ba6T$NyOD*L9nebGuv)(>V z6~2JHJo!TD`s4-)GXLu;91A&oM}sqV5pyC*9nc+WQZ(9b`gQ4i?vJ;C$a5ldP#NF! z9uxdkHH?S5>}Ue(CguEFKXyj$gF|GG6oRUXs<+j0M?s->ReEFlj5j%0X*r;q>d$J< z!7`1XDib0S_=2zvkuPxpP5zGhk2z)(wNP2-!nLc3J9`yjJy(AB7l3%>css?i)n0#9 zJ;c5b=V~NX&QeDg4|f}~nDR&ABZFpi6bqen12wKVt(O$};h;A~O~%CTqw;%J^&(<7 zR;_5Gh0(e)shIMw;k>Cz?Swz|BhmAy{B_*T-BDM_BWIbsY#b=zQ_`^9vW7=9%C~`w zfa4lse*~7Q0!^TQX8^Sh3gO6jn(87Zi0#Mq%jAz6)BtZ`7 zXg)0$M-lsJ3a?6dQ=VZ-?vAqY5SfZ6`@X;N^=I>-pVhp6lf=LZHo{jF84+)9ba6&!RQ=;G@;sqJmQyRwI5Qn}WD^5>)v+-@1a;deH|4MCLHJyAzC%q0_|krAC|qvXU%FiJj2#Hq z=hG;j*`gDwOniGX!G;Lhoh8XcWH(o2csauBF0r&1E=z!1Kn*9EniVao+Gg;1fQ@FJ z=6@Vsh8v$wDm@&|BVN(6x_2?)p^8bB9AUqVnL+szJV36L=RT)I1W{6;CN3(B+85@o zq+-uCG$-B?&Ad}5w|EKl`L->N;~c*N<%-2|a&^KMZWSL)8|yVRlk?Fmf9lY=x5^oB z+UJv}KM+FMuea0*S%qqkL&vBu;@Cgk+%ZXSTIwLy1N%q$*+pvx!&+`oa@Wc2{Qp z+wX48l-uN`N?Aps2p&&kZ4Cmb3gea*@%3uf9*be|nL>|vkg$fw+@IbX(mg@O&)xzuq?ecUvpvc=?$i_D!|7S@79 zkMCbq^G|)*s=rCOE~MQ7f@PVTrXil8lU%;P+zaW5*1l;JNwD^sr1bp;35;*cpH$UD zWyOQwp1Nbp=+nFa#NR4<4}Y==O5&7j@dMH?4brT0wWx1VY8v(@uwZ`k@7nB-@~?IK zRz&U(wBNcjBVIVq=a~|y6R>T&^eXQSE#zNQ$snPN9(K(&$(Y~x?XVDW*}31mX4ys+ z6(bu8*G1>mrNtaF8qpH{EpTg$B%&k0{HFk)3G;907i1F*^2F>TP&4s9OUwgvtn9$fA;|-tZw`>cX3#oT^SdRZDUs1deRl0p#T15(A~N}$vI~y zTy>3--Qt1gJXbgRK-hJIe_hr_MUUSY{>!A-%zOQ}80C9zd*J9QR2kBvj;_&N0%5A_ zII03)x-;xC!cTudk69yA&JMcYmdhOZfcWzsJ~7G(t<7`5|I;XH+#f%bi#nr%S|-Yz zD1l%h5xkpxq|_E*sx|vpY^;E(we)EaRfC;j&SX;fX7PTv$orZmr83~d0l_HPPi}kx z)|v)q#~?cE6r9~&=)E$wj|53HusfS+mYpW1^-4FfFO$E|QcITx0^-KrbZ;FPJpWRbTLUH!5YPR3nGpg7W1Kzmy;pF}zW%6bCj z;z03DGj+0Y8pEVA?L!IjWN9ES?VG5bk$B8g?m|xV%9_1C*+@a=RNs9iAfa-fvD4k8 z{c_Ti)I90!CV+IN43_i%{ypi_dp^2Jl){91vM7R z4NXTSgwkN4F|u7;T1s5|kU*ok9$1`=90xW)o~Ytrta2c2d35gl$E zuGg#iqr%*?aUUn*K>8mgnsn#3=HnAf568PxFEw#5JW?K!*c>Z#aB{(knvpmvsn@JPOu~=C{>a!wgCPsfTtB;_{)`7jbD&`?mTN^Lyq-oWAPgs4#4N`tARZ`?xlAR1dZg7UlSo^U)+N(u6IDTl!@>`JkSdkB)>dzPG@)SpJN zu=ZIaD6N1V4{6gWg;xv9ExR(*zM8EKl z-Vo7ET6HCjJ55rw-LJS8mG!_)g#-6j+<~$M=Ym4llZiu-{_wpTwr*qB`#;JVSazjE%P9@t2 zk%6NysQ<5~-@3_Xt&fCBCc>?FhM)#Wqokb&lg)08vsJYBlKbN)S9}bo4?yp^nEuP8 zWt(pQ>fk6DH$Lmshu9NQ^G_DWZCBA8LSZEJM@VPs;bl&1<52LEndUN^ng@|MoMQF zi24&{BIdB_ay;Q+7sGa!@=Kc0*1ZXbZ7n6D^ad-Uv3~nXR+Z=nluIg36h3gjmN^2l zw~KOo=0ppz(2N$b2>$$tYB(aaGyZJKJ}_@RW7MN=cJ%kk_tj_DM~*Y0{*h40i`>N3 z&N^~KsXF^899&q{O`Wf-5HNSt@%rC}uTXC})#?c4e?wCUV!CR-SHWNrSZ-`Z*Gts7 zGbJ5rm;8i_9;3iRhAMM*E(Pq#B#D-~b8VMdtWzT$HSB9j9^jz8+K@(Yp{bc63gGpWFBKB&&se#v9T+8F>v(F@{9p&WK(4Hr)yM81(V*f4z zb=T!Ms3RM#VdgVe27pfS;4m90-N?jyV>rtRnK}@ zIr;h*>%~Z@7Qe{8Y~NXn+@UNR?e-dITLuAFZ6$Aw zTg12^sS2c`2cLl)P{9WSyR?O3**kY^0Tj8VPD2?MgEkbYo>Si~>yJ^>07WXT3o2>8 z60f?bzwRaiLdIbr6WNbbl0O?Mp$i+6Xdzuhrg&jEGvy-W^^ppMzsWN>YCG5MTlelJ z3DL|IRhyKXyUh4D2R~O1?mK;RJ=t$`BL+{evY7N4Z$1aV`KMgg25lk*^RECzEKu}c zM$bzzeUPQXmRf4(VK{=-t1K<8pD1X3>}tyV+$xK$jM_hj$-U1Z%~JGO@c#MJzuM++ESY8{3z89 z`nptDu~;k{+=_xAZ-hS7S>!|keNWp$&_q{mdQuv$hKd{$6egb-&Prmr3_hJ%y*j!* zNh25ypFY<+vhcvWy5Cl>QUPwNq#4k6f6lbVKKY^`*M3ax_68}v0=ri{1QUb>G1pDn z)O7gYK3-iSX#Yg|UJ)i2#r7l2!HkN?V2+AJ6hr0XzF1m;m?SRNx&Y+!#WkfK!2B_V zGwTQjy!K0N6AXb(KM)rd({%v0>ugW?v7$Cem%zVk9?bS@0NG0>Wqd|xWMbx*15Y;g zam$$~m#7oEkUdUSJnF|=xr#~}7{wif5d|JtG?W7K7MwAC6ONTgavMRL*kzf+0(#nY zx3hKK%~EaO8t9U$vhIn5!;pZ-uY^&tvdcti+${;yas>C9+RYQiPTPs-?Xwix-sK2U zhKC<=0#PFh7!g6)G*rqzWJeLY5NTin_RSZCaH2(Qcmo+MK-LH#NcmfXjf#kKhwi$} zgAX^@Hv46rm@w-Cni4Z!yVBErp|Xi9?);{#Ys%OHlOHRg^rahZmA7~~Fa*^HUi<20 zacK8*`jhz|mPyrPNP~)fBpdTxqtegI8LaBseOVXvRe+$ZjN0UH#hC<(c%tARpnL{O5=}Tar^c^bL6GR12+|^i70FKXCH(Qh_mO z^qbugsKHM6eDV;2HJ2UO4o_9xQrs*{LzhAtLxh>gE35+ZLwp@7Ol}(?Gn1T2zpMrv zo&M&(H*<4=1n0z-ZuSA7v)T2Ksahu@HXu%PQ2SIdSy#hQs(8(u_b@qnOjwmW&IZ2e(kUUZ^gW-r_^w1D$D zjvFeeukbEXzkl3V>{b7mmrqzBG;%54q9<0JQb87ZRCLU}|2h_PxQrEKb<@>r2$QXEN;YU2qFQh2V7!t197F^RU{fl#hwzGg z>GPEZN^Pni9ijuA!q^URS~@4mR#z**L779}XwZ=G#vl9-c%lNv_-cjtrm)T1eAxMt zMzeG~d;arTb-74cG&n$vQTVdg)!F-$D{KZsKMNveCE&xfqeK_HJ#HgRN1Pxn)vnNf)sn^4GGTjg5QNk`DI~(7 z0C-dbQJyfJU&YB4;%BCiUVGp7jx_@vA&n>8?s5htzWmzy#|683e(A2z^+R0*xSW>y zn^@@OK5oF++mq4A^N*kn%FbEBu;ehMfI@L3v$4{^iuMr^6=th$*Q|CMrj7nqu9K$s z=>&(=9X?6?mN~WUsAuodvm`MhSMa90dKy?R#xA(abiucUcwpMs{X22!Hajo9hWDlQ zn{3^jy~V-izHX3>Bfk&8Gi9Loh;(+Myb4pryY3z;$!BsD^EU9~l1C9uK~)#f^rro2 zMYtR815gV^c|#4m1}uGFeJ+D)avlGdcTq_)cP;IybT#;#1_!+Cn;XRSGQ6k<%%D!n zx?LSnC^3VNgd(Q#iK)4GYqXuQjwed5Yu(9=+*Gr=A z=yQx_D1I?LQoLJgfcnJdIT+W=+Gtx3X`SgnI&fRUTL-OisM=E951C_%WDN|EWzDAF zxBt)c%yAnoXKv+(e^m+rW4JeQv}f|j1M9TePmz5W{r6L3u^y1JIE+9fz%|f>C9>hL zYG>Z+{=;Jo3VLRCZAlxX&8|)>x(FL;kA5!;96@0%rg;HD+@vvi0>g30WyeI z|1{zd)+0s(!T*YqCSq@ruSy}~o{(dXg+t~_rN@D^g&b(oFTikb6eT1WUS&vhA9vkaVQ$2`o!s}h@c z-MgBbJykP@8TE9paV#87eZu?)n6oV%aHWe_>tQY+izHR_v-@U@%mkJZ>ityLU}^NN z!|a5J@8&@K-0-KNk@O%X8xcMExx2}bf6CF0HC<3NhUKLv@#aJUPt<96EIHcIN`c+E z{O5yHO3wltvx%3LtDeY-R1`+fq}9W|PET#8*Xp5i{5?JGb#+Isv3yCp>oW%scM5R6 z3Gg+4Z+%t8nd$+rk|>TF`8I7c8~*kv+t=MSKz%f@Xgp}WSVjj%^J?le&nIPhjSUx_ zp6Y0GQh4Qe%e!L5ot{xOp62sfB%b}Y$SB<)9s&f{2v#f7_}{JQ_KfGgkMid}c#cBO z3A2Pw*LV9$RH_Gf_pEXOm%{*#R8r$k7{Uu6wp5?T7`p#oXvRCQ9|r$Lhr)2=Mb`oo zGGRHOU(VezqxHp1)Y|=L!}@$8SsJ?L8E7fyakz{LLej}wAdZV}fH>U%bCqJ_gR;J6gnm}80^l((n zDj-{n&ovx)C*@*KX41=d293JDlSE?_=B`NqVK%q@U^|goF6AblVe_*8QUwSSV@6N< z>$H~#-~nfCs$S^k;u!s!qF}VM{>qR(Cj-#*7i^+$g4UA%XG_S2>jr@uf;kHISx2$( z^21JR@BS~QhFh&gwHAdQCV!`XvQ{M90u;V+g72H4RF^~ax_DX)w(UAFdY?F!k3Az(xml8TZ=Nm}s_?OF0f%uKVH#ot=e} zPIci(tH)+>WK=hBo~wvnmHAuHvppBdWhAU-(tU!nGsYuA^FWo^#D@hjx&{7yb%E;4 zMx(7*)&J{T?9t<=)3T-vHhn2bwtlQHKF8nDkdrFw2Eq07grBH~1e6w>Rt|b&8X>pr zyWG2b2~})bCMJjdB-w+!Uuc60K{s4D!nwCFhZkwo_JMqAQjVjREK#eVIS0VQ?dO0K znZpn;9~Jch3F+C{!oDkQZfFfZ~3hS2$|`g~))f8o^UxmFn8{P?dl) zlub|_dybxd1rot-18BH%`md?>7jQ8CD~T$pUZYMk;#-Fi{Q4+1i@+KUp(Fij5bQ|< z@qb=F!hA%CMlp(xYuPk}89(I=W&VojTQ2jaz9$QiIFvWS;O?Fzc5=ywM6Ulz1!L3g zeYw_2-T(aI*+2<3z=U|+ygF=&6#cU`m1MynJQ7zwty^6<(m63xN3%Qg0j-kmrev9x z(ZV)k=ha7)V`xS0?968ZbgdabYDpQnd2J~9u_SkQzH!|fXe7Ss0XMkumY$AR#ovG* zDY?&k8SoTO9<3p!GmaWA8QiJU66mi&QhY z&MET}P0$q^CGAoCd1&XQj&X5AEbY$~G)Qyg<=6k?3)%OY%d8^7UlaI?dGk-CsobQE zXKuE~h(+!(@ehX0cHVDh8k9aGKrbwSv)L7bb{xb+F|%pf)NJxV7xnTc0#|QTMniDW zE+J*%d@IHoEa|AcYAvVRxPW~Xz+n_$+W5knW1r4F)6rP!D)vH89lH5AUNNhqflgbu zLf`f6kIh>pHD)l&aI)WaQ8xy)Z^(8A!sC598jIvd({B9;xB$g`-7w%|-N&Mo&HQ7Q zegjVhKIz*$2LilL71M2hjt{2Ig+20Hdd>!P*IbI6z0(uJI$f1GAgScjS>k90C6fp# zsm%+(CaiXCU`l5EF?H#g0|DaJc7^CplF$k~1g-e-?h$K&CjWpx&tVx}2w63OKUyNG zdN9Uvr~C~Y*E+6vRcS)ml0_0)L1#1sS#g7Z% z+l8&MnmBN~D0F|Mxe&-LQ{0gb>HZPRBjo>=7eYGF@;5RH;dtPegtA#+s226`L5mH|UYeSjuHJF3b6|WB)JuzDQYfVGp?Y&jrW*`*kyC zsP4%yz;_rQBv`eZJMW}+DkuTGng*L-JfJ9`m48{83j#KGjq*x9i_;A&04scfO!YRQ z`W%HA@}|WPVk_dk({~D)@0^MSpV1%$$cVcy|MKbqOb>2BJ9l%;f-fVNtm_$2xu5|{ zD0DN15x)_rG(-UTrSi+g%?818p?B8Gz^g-ELt+?xB6g!WtAN1FJ`IU_Qd+&WGN9+A zuzf(N?KUcLTJ|@MUr0(!HBRDDB0j_*i-CMiR%xcL@nU=&3P5~tL$M3!arrFoT2LJ? zz#akfD6gWTWmIFqjsdKi3)diFg{TyfMUpViN}kw!{zM}p1+I6`{M?W6hbV!5Yaqtc z0!i={cw;8)8G*JnrnVYM?@QuLmQ#%A%FE$d@6ECn;4;DS-V{P^o0+VX5%VM4}2 z5+28fQnZNlcSJlkd9>jU!zTY)Tq%HBxH$5!?}T9IU&`NX-t69ID^wD=c_B;e;9%^x zOSDDbbcvDnW4zHM2KcWgJ-vReT&Wp*Vn>?=>+Q99@auEV+Dy!A$DnP(^P$$OyQf`>u87q;v!sq2n8_)C#Y_Xjrc(+Pm1X%20_Ay z?Zw28ko`KiO(9=xL(#vEPxq=DPHe3&blww}aShcxdaT&pt43}Ujqj0;R^Zonawpk9 zwwI@X<5@GzXvB$Sezju0p7V1HS*ER!=8|wSu5~#=Wo@0+1!SFZ`#fXrkxhHjasqN|)~}-v(lRDUGuc0oLxA1ReS%$uA_}j2 zOnlLP^BX%=uY{Nsq+$FXRezDen*>;}odrz^fB!;40h;-Pr>~arT(Vu09DZ@RDYYty z<+eatc|0=fpxVcSshxqNh)|Zz;}m0!;7vX~UPIsEm5?JY0-BW%iEtGemi+gdY+K~c zzOodAk7Ope(gxw;2JN51@}-3YS&UKQL;RQoX*mOzFG-Y$lIw)oPWaMbjVRi)Fa*`y zM;5h=*4YA=oWkPdWks}QLF zBSVnWnuj_hevW3Xq*Zf*5$_p+FsmA}_pOI^E>APFbH^w7;i>!}+m}ykFowq#nN-He zmOUrQNTU+pZvaehqP{l!Z@$%lb<5K*isXP>W{2E@?_gGJLcn%Yg>-`Nw~H5{#8-lm zn8x=ErKN8pNf+N6dicMTO|s=)pb6wl^U!3dR`wq-mR^nab2hB>hu%L%-?iOh`^ZAIE%w@F2%Is$1HAp8?#!kp#dU918}Y3y?mzao1u46B@l)Z6HUj5Cd9hX(xIM#J>kFTb z_>VVG;Hx!wZqcjJqHi5e*scbUYk62V>6$bQRmN*6nB}fGKFA4SSWdW<3IY$=Z*FJ3 z$tTEr%(lRfYFB$>p)=@0p7HxAg<-V%VPnO`!BeBeT!4NuORRs7vxo%#4~;aNlyOd& zIQGiwK$tokMluo39Hl2@&K8pTOzK)Lq!5@p1^O&F%=n~6z}h6{08nfSuqgZh^e`;{ zX#=|SI*r>7c6$Kgj`d5ZCpC4M56@gW0^Un(Bh=AaU!sbx+e0S3~Qo_V9WCuO0O zo72$7IC&*$5fZ)EO^Je+M4K8QA)$`8TdK_{3QQUK51XfTvTBoC*K zrjTZtBN@JIMk#IP2+Uo0FksWhUSz4kNGW}WKEe)}0a9Qja^&er;q^5B*N`%e_ZBYdE z&Lp8%)6UN|!FJ{^1%-!lU%<(ojc8PFuQ8KsQ#bJ36m=m>wv4`o+FR4iQLxKpmO`1O z-!`m9EK(?9<&^N{1&&=XEt3aIKYV0{9}5>r4Gm&ZJQd+!g6eq@V>?sjDzWrSrMdpe z(=DHk<{L9XTdawXWryroSd(#I3}n(&4+{*~3Qhoaxof}?<<`l|hj>n+qb}^!gIYRL zUJ!0V>btunautxmWo+3A#V~Ex3*^@ho$OJHEaiW(atmiRnl1AQp2vSGJ}!N zDJ-0U4J;ZJBeyveS2x-029Rejz#fV0wzPoD$eVJkwK>C|x3{uh2VwcM3cFg?+gwnb zA1hq-Oa)?fxlS$*VD4{H>-=b`YP8*jb#rV!Lref5v%F{cqp*o(5#zSogoRsEh&SN|eb7tZ15FjGm2c-CpL(y69a z52ReRXqfJ>*&{8twQTIc|Ia#WRBi$Tw^@I4fvHmh8-HrIWnk6IYJAPKL~3b{`SG)c z(qfz0}d8Lp>557BuMm(;v#ZO}&y-PQ-GjFMK86qw^fc1afd`sa?uiq4UcxEQ+|fG8U{ z;Jz%bB$eQwwsFg)?K#di3Wq3(uEwHayOTX2Pg4SWS;G8?c@WV-f4cZ&~dx>Zv-bz?kKGDy}i|weGA~8#_WUwar9nj>5Zi7t}+5Br1#9JvgD7 z@1%XRf-+t;5OX7cG9xeH`P#}-(<0xa*Z+S0o|ip;FMFYijkucvkeCT~5Px;*Ks4dz z6QOb7=2ElW(f!-|9ad1B^vJ4s7~xwIj96WF`SI+el|`aW_Y-=roo1MU*g?#E<<{BI zI@n;vN0XD(buRvLAoEfq48P!VnV5Z+<2fL+sKcwd+l(z1BE@i!?-`oq|OFp zRu3cZk{#8=md!Do9^ysH%DBB>Wt}IT5}LU`d4rkl`tAT(f^e-=ryDo)y%XZ;4qVNuB%^UqB!iAML7z_2L(6Yu|LIH3LD^jMZh;{QLJJUDkdp zifB(Y(IFGn zE=<{x>vsqzK}rw^zNn%XD+a5^zWjBrt^&c?KFLh=jgja=XGtrgACTofDF-2^5`g^1 z;(Yi>fdUBsZM}aSZt_jzI1f1DJ>Z+Z$W{X8K{KZv|8Ph$AMo9rCW!Y4#9t_ zw6WbgjDv6g_PU!}nY06zHx%{}N~bO|s*5dv+0g(QS?pJ=yx*OHJYX;RL5q-wQMR^< zH4zPTIa2Vrx{}*-Uvu?Rf4H82ty+VG_0_+}n%t5c$Lg&KC^GGmR&w=E&&vQ>@ zW;~8ge_mQz5e-%Fl3EruRStV)dqmQ;TuMxeOUa)5!O91vA1oN29P*u%q6FQV zpi%yY2(hdK_DZY)atA(m@gBkc<{u!1fK#NHDKE;y={JbQX_FA5;eR$jc?_j8!&;oBqe|+ z^;|)g>+VEdvGfnKXpm;-d$XA6LANa-dj$x2oM&}(aU|E3_Rq#vGagDuZ~k{m_vjV& z757RSvx1vDYAt)Jk@MJOJGhi6)Tc(k1NCayYO)}t~u`vbAX$493s(;udk z%)$7{{LhHRBGDHS6|38m_sw`Py?+G+D%|M=ZObJ5_V5?qdI|mN2p3)ip^_Z>jfkBs zV8UFle#4K2AjOKVNS31i$0k!yZO(Yy^6;@Gm_Ga5TJWL7Z9X_LvEA>GogBcX5A|3A zB=#1Z+6^bI$nBW9B+W888GgR%d54616Y$ZU;l;h2^k8dzAkJ3^FlUfE^hIfKvN*%X zybXh;s%{DrI%=g%$OrHC`e4i>xCyW6P@JGCES>RS z^{yv?N%Tyv;Ug?MW-z%9A-ms#-5DZ2UYJEe_B${e;T-vcHohCUmQ7X5qnYJWPIR0y z4j*Snf(R&ashqg*xfC!NGoqO$Y)V4`Fh(^BkU=-~)TsG2E?52*M6riZ#SZ#Jj`0NpFN(*^OlxY70yKd6xajwJ(#<-q<}BXROF; z=Ua^BPQvb9kwSeZs`DC8XC0z50gg_D#lR)yq!i4EX4Aa3H}gaQ114+6WCOxIbb@fI z^$KxjYaPcA^r5>~xDXJcc5?_m@rfv%Tb5q*-;zi%n8T=d|~K*1{v% zdHbMT2NCy4{;^*bU>5hA^@d2R(Q$C@9AGF+O?aLQoL(&;NpF;Rq*>3X{@#W0L4qG= zq$cdN(b?-B?PyZ6J5S?GT(GqHEj}TtlI>q8%jYCgv)9-Vot#37|6z8HuIME6wM2Ka zjmVs$ElT?T5^F~a5XZ=&fpb6=Ld8)vlahNP4=S`z)^amsX2bl4kCa5vP`11U^xJ~5 ztxnnSD*rf!Bv#4l!@zLFO`H>i8S}L|96{DiGbQV~xwRY$**hjlsTaWDp-7!Zl(h85 zbKpxOh&m0khxi7BwocDK-38Pjypp=ZsoRD=LRAe}m(EfqKuaABmt(M+oq26q^IyFb z5x3T;jKGW!ptjM9ASQtuV=VzgqtU~dEMIt1-+W#u&!sFP>=E?Y*HpPQ?bHgiU4dx+WAu~wiBiy7>#T)oi9zNXE2?}D|8KWpaZ{Vr$$!zps5=(e zc)e|0rx{2<0ra|a_5!~nBFM`e7~cQsa-cnMkYk1L$1kc(r!; zLRhDdzE$L(xg87;#G*$Z)m%o`fHcw{IfcSncD@#zOs@5^NTEMddjWfRo?S5f(se%z zi|5rzJ7u$|!4+PF7$<$n+*h!OTngH`8VOf@$C_LJ;KKx8+8B`8Zj} z`Z3duUU~Btmn-2z3!eZfx)!YNoC#Z%j$eo;S%xvg&AU2DW__peG9S#3oo{r>dpi?? zfe^m|pQ#R)oSsCt0+LoabT2souN!#xfBi!CcM~t|e-Ft>SY*E7y zOa&BUMan~a>DUp`Q~++(tt3}#4^fPD7LAecyTcCclGGBNEh5tf%0XP=d&`&fDg?1b z06Sh&o{*6y25f@x6)3UAKpA5SE>J$!Y-?;;5j|O#GLW-(1ko&D-6j=KKk=p@@%6V0 zfr|0;oz&CL7iMsP^X9&yOthLTyJhRR$+Nj^zZbP6M904~f`ypyT0ol$9fj&*P@sz@R5ef6q9Z zrR}TXZVR{Kvbn6zT2t=3?eGXP#3yc9$@WLMU&eQK=Z?N?F zcQXs29ZTP9@s1HT54$pr!gcleBRa-W+m>2)hVnPx5Tur*Zt&WcOmcCGaxd!3+dWw! zSq^OLwC}BaIgMX?6($g5s{ta%S21u73UCP=z#t*t2M$TdByxH1aa^SwVvo6;` z+DgrcEv~O`jpt0Q4Y(vth@-{tRDO}qwUi6EZR3Liy0oaU4z`cUqTw0fFD~l*m*)dnmcf4<3|(OO_bf!1DktG z;Atu5^^Dp*-!S)=CxnC83{3HQF8w3khnu?legP#&uh3jQg^ z;~00oq)_Uk(QKK8wCvE&xdXZ^>`Q2`KL5G)|jQ4@X zwlX&)iuR-*_0+<#+_2H9_X0D%Eq9o(|1PQrUQd&qHF-3UWW*U6uaADHuhzaEf-}sV zhA1V4b6;B$N>wx;8E+X&l-Ya|nie|Y-&pLRO$VBeT*Uy7$bpmSM+O@L{)(AOfv(gL zsKmzZbSTOUs+l%)iJC7_bMW*=BX*7ylJ#eZHQ_K1PckJRU45~CyA+Rm*(Kea3%Yad zu@NaXyBC>~K(`zDvDC%LiDomm&=yb_zhur6oJNwbm1bVa;%o9%cYs#6Nz_1-AeK%l z-)a$PBpzg=E?7(=yDIk;NU%mT{p#ROVDWnjaaE0DhNVyj+=^zUkl*5&4ijPF9+uTQ z6dsQEYi>A+o+1z6jjBp0alS5tr&5ejpS`he%90QCGjQqEhc(LmDM#6OGS1HvEWox6 zT2(vOCn~2xVFL$rzv`q~ZVwCuUaBqD;>|Rt=97m3o{s9%$42 z8E(yRiU@(b9QU~VLs1yfM#`|*-y;*MJFre;oJ*4Di&Wr<-%%FYvtdaMLBo`YMC8V^ z*%V(nng^2o#RZu1tP%oc4N3^rHPu`Ex(D*rZHfG5>d=}j#=4~A+Alsshmn0^B3%0; z(A}e=KN@QpHyRJ<$@In|C!yGSy=YK>HVFP z9K?)O>pv&Us3e>_36F^?Z7h=uKEUqkCeyhkjudvr*Bko-f0oofTzWFhKBose5md|s zL;HaNwbOv0Mz66bydahYf|!0j3tdFSb~6G>_L5PJ$;5XfObACLE@o!at(UjrUf4=NvVd3+HcB=u0)9!qQjkz zRakJnbTNW_sx-@V5RYtBwvx3MyNajQr7#bDfF}`JVdOqU|1g95Wznx~hJwZjb$WRy zvFOh#F^ljmrR=3w0H@%`rO#m8lRil-(8&9oj|7LS;?M5=@QOV5UBsk$x1S=EExxVf9Ex`78?{1s;0@Qhk)QAG;M! z{<3{ivZCX|%qWS)(^RHAAqytWq##1qZ(p*c&DWMU`g+x_gapYVR-_e5-$j?etlF46 z)N(l-4Yo{ifbR3fBFLIuWsLAFcUK z-rZ0!d6bvU54j3?bi2UUBg^24GgWAMNT!_)m=xMYFs8&2%&lBHvBn2wmWoK8>fFnK zID&6Nq(T#P>AN5MOZkWo-Y{eDC=&Y|J1Akq6A&<7i7h&b`ZZuq_^BLZX>r`)wuD?n zU(=q|f9@u3qD27Ule~`F)4ov=CICHR#!!2dlAvp_u*Jf3l9D?+drziA@1-CYf+q+; zrH3v>(xa~ZEP+!9lP*DAsA~+JqyETDc`C!wrx3z*_j7*hGzfilrOen&frt79qp}ZV zXpqa;(awmWYGejMt&VuM<;o1g(UYA$q5-Abm^1kX(mhw#EV^Ho2xK;q6NDtPuFu!s zuzGrcKKeGk{w-DcC|-5d)AlAiaDO1LKhOoK`1d=a+ag2=v&A&8n%))?*X!ny;DjjN zZ(5>W@jtq2TuCz3JC{;Ii8dgrC2`JU(ARbAYVSzG*5cvrPseVGd<98^LhI_S&Ob&pYnIg4JQuZ>n z?d#Z@hb-O>L`oSHABheDU^d*}z1M3j&YrUlo&ifEg?aW_r$PyM*{!uN)7TnJ+z(ad zD<-nP&R&W9W>E7B$XX#^u8%gir_0SE&q+O7u~J3#;Q<8?j0N~{99@NzEdgII+k}449&0i_|JPScNOu z;M5Vi2hv7x4#`druXw8jg4&SMHMSTA`+gYwr9okn_mjI3E&#JD30qYFL6OcNV&lcR9+o!PV^$lp;}6!J#ApLBeq9?*eR? zEZq;FwFMPERfKmt^{9;Ftqucc`>P5~qw4p95_FLC!i2_B#FuS5iwwHs>$G-JFVSE) zb+pwi;Ch3UB1*a&`*Qj{lHgeoKf+Bm-4DP$+sZy5<{B3#5ZuiC4~fj4#gBaXhEh}r zLuw6a>+hImGmCD%g|w!x8iUpvX+s*^{_l@7rYmoV<{+Ft#=E&rwSvfedw-FFbWovw zcRncEo$s|EIdKPz2@b!yHH01!&YWqOKjcmKD)4PYdT8n63G*_$AATky%7RAolzNa@ zm+drfZN?yAsPItacJ#ETVqRO$A?2mg5R}kHT+V8Mn^M<6&%c`w)rqo$`Yx?#RNLTtZ8gM?;o-_^-l7Z6j{kids3Y{DaB-%)Sc zms!}G;%iWBD{k)x$0Q7HG(Rz{ zxaXW*%3@%S?URLpZVi~Lc&B>tol7SW+rUVzpcMnqsf--JA|VrI4oxFN@4#{iE`o9e zw}_0FIj`>!r#UlCjs7|{!6taTe2KYPv3-B$O?s= zGG1u|sg9`|^T0G*P=B%~u4>nz{ey9jIlHpe6eoQ{-y zbhREgAUApW?qQ^A2AJ?iJ$Gt&%C#`*zTiVIEzgJ`mADBEbvRx;hnLi6X*aSpOP^~9 zm%p*n997g4(c=3i&{|GhsfCH?0-Ly435BTgps0@e(z+u ztJK)q1z$&ts-k9sR-ou@&2%nf@sO}qEmOteT?na{duVGgnoywq8~ujLv(op?WmTL8 z3))aM`VfN>xHd%G(SVX|& zI`QRqfc>7O*{;PFNq|-WL3o^vr~3B934Ury2%1g1jOkYqz4QT!^L<18=XF}54w2tM zuYx#-B*&iG)P#rSw=hXQ)o|Wd_XPYNNb)Dr+_a9K2C5M3fnVcn^K(PC+uTm)xAq z%}Y&cVxLq~<;xkDY$22h>CqVWzU6&}<8hhjF5RH_GMBia;5M?@1>m$?|3$Mw3tYVe z@Vt(@U~-E7&Kxx@wQL4HV$94zQ|*c&kQgZP2*OY9LiyzjDywoccn@a|(i}Em%V|^{ z7>?k-G@rb90@I|+cn~aSCX7$1vndlFZ7CFy+pA4TlMQ#^VvI0a9)Z`D6RK)sySNUw z1m5CmGUNu0OmoR3U5*p1+S%jBXhiyB(qu3M(VSTUiluYY-WHqSwuB2!)ZbNEQ>a#7 zae;nUarWba)lVhRI8)lLJ z+>KA$IbaaCA#_4C2rHwmiOkmN$zP2l%5o!a8b6f8VN1E2eh7e;z1PsnIdojlOc`5r zB9XdFTd@+ePIOV;={Q<x`G z4)P`?7kdeaE^t4<1n-Sixgbd;&WI4ygmqFnYST)~yaD_~|8aA3TH576Glf1ZbT(M} zv8g%Nd;#cc4kd+R{~GGaD9t<(db|6aKCnFJzCd6zRpVS7sFWA}{RUJb1C4%OS~MbQ zeHWyEkEa5~RqZ;)SYr(MTOrE>(r~5xA>esH9>#{x=vVNUQ08x}_6Ni0pGt5C&7YgK z!VDgOIFv(cJB&$kWWMQcs$xfT6MjGE+82+HtuP5t6b=Z$jq-_u1?I?ZYs1GZoc464uCXG0$Eu(*0`1P!bmiPVFQY{EJ zyyRx-a;A6NHyY8JPpvZMaOuljsl=4F4l*;6Lh2t3IT5!{%_xM46)WN#dMvAYFRhyp~F*KA3YC>X|RI5Erw_ilp;n7I)sTvabk2+ zMoMb^KvKd4n*~Eta0v3vCwEU=)_|j$2po)Z;P*AvGeCO%x{B=_ z9hEH2;PP;uT0smH>jYC0Ja*DV1pBYi?jDA$!yOJct`gDmx2MD-wqLDlCf6V;G<1r$IQN{=*-X!EPFQT1(a?uR+yhH5}uc zP6f4U$)^UY^%!jNNvhVBwN!-q+O_=br`lk8(-2M{OEnW_a4Ff4%tf0hF-&BpggcUfTUXqlmGCkWH0zg2YmIIbVsm zUPs)&q!DEh;Nk-sCN^u^DRH!LqjFArR7tz}Q6^bb>@=gV1bFXBQZ;KkxB71al%C<} z>8Xu2J5CIt8^$(YSsw}IR|+)vyUX3(?Fc>Chk(3T!c)AVz!^;3O&{c1w!nB+@&xWO zk6QarY*&)!LM6o662z1$#O|1oU*yOuCtC5I;Kd#o!0{6ZI5N9>q0Gl%Z5jjEaUE1z zx276ECLPuUnzAzicbsDsq*B!fb;S}HU>Stavh(8&#khsXKfFp3aHQ%*SlgO^bzV#7 zeA;dac_hYvn{25nlbV56)iX9<9bLQzDtfrDDpbOd_?yAAK0BP3Sia*eRKMGE4<)ecAsiuT#bcs8n8TD<#k zGdmprPC!0e4KMG9ux}WPE@loG4MY9lp3sqKu6~lwa3a&l+js^OCPttC zPhdp%C&UYhES)J-0d@gyKTj4`foh*nh^RB$8kEobvRgu&#Ta)(|Y2TafF;>*BT8!_?DF zne&ugVcHbZjGrJNPKCf;F@;~LldLQ&1SfDxHN(%T-{nc>+_v{xhx?AYFPT&y;z>F6 z!ZZklm;Z6EV3DDlHj$T3;l2F!r>~s_{hKDE84nKl_9=Epl@n9AJs!Gi|C$ppQoIi7 zACJCSAv~ZlmU={n6EwUm4wSt%(g286-nHXT|OMGC@^RG@FZ-0qZsFjM@i!8a5Z|s~gG+y}Hj(Aw8fk#~ zt3zhDpQ>vBN|DI`sIJHQTj{KQ0F}gr5Jc_8W{DlF2z=TwK)2W`#5Ia=zClUR7SQt} z#Fm&cK!Yf7>w8P*0)NFV#^!Bs#4yyKzv6B^RY9=ste4oRw*JX~WSnN(i7sbOd8=9bL&oh0MSp1x=LO~(|HV)oN+q5(7w@Zt5;l2OQIg|lIsIA5kgoZ;wNbILhJ?jczz57!_D zGxo_1#Z)5>;nB+}qS)GTW_i|9eDJ?$(JLst3<>5vEPm(#&cZJ)j1-+ zF)sJ6SuQ&6Uf(piFJPr;^9G6L=tOy4iMVBwLY#|{lSAuL1W~ZFzuSNGT8sXXs`AaB z)pOX$}?0ixl;0uD^n{!W?bVw6+kdog1dr+;YgNQGh%rsLUlLr?s=fZmM6RvmMJ6#z)Wpk9g`==akJDygocIpc)Vt{UYrNcAz1THs&o9XkhDifrhyA4zT6&jnhFz*C z`Z54bMTeVYh;Bp4?FHu_IG6-uWN)%%+1|_p1Lj7y&^$rYVT>{+kqI$et%${abk1(n zARS`TD)&DNz)kT_f=L$J1oN8jrGh#n%HW9s!oT`_nf3FePG2IHwj!sQ_0jcFx;Geh zMCcM!%cMG_ep=Ja|FGq~eVJV)vEypBaTd$bkyjl8djago&8liLOz5)T-bc{J?7@MG zwG}^&)Y7xCS_7R|Atf)1v1s9x_pZc<#qb6aPSMj?)Nq}J`20@bq9Bis+rPcTXZ#-! z(sM+!aV6Ba=-y{PMc}0k>8r??{cfdG!@0GrLm+jm<*X7 z7OsD+c3ge{#`EM!NkGJXm+oh)J93Jd_OmK(VVs`-`-(BGdZJ#PuKCwdl^P?oIObe% zvCVKM7ewYA{H%D#z=Uz8pDf$^s+MFY!)<1o*&~bOR!+3vaUPozi}J+DgOK#V?9ben z3cMPbf5dHBM|ddgrDP%CC0(m6(h@_1Qzei1eyk+kao^X1V9mQPC0cJfA8^pE8>yu7nxPqK6tM$l12zICLNcHn?%i1FUfisc?|u3hwCgD9 zR_Mr0I4Vl35FEup`Q({}vQW*YSkHv|)3a&cyGykPEWf5Q5ga}XV(HjjdVbf}0okwS zowsfD{Rc8UHLtN1lVC<#Pc6xCM=T+Fh)jKYmi$gyK$x{b+AjYFv$||Q=eq$%OD#ZbJwSc+^ej{ zFGk!-jpUSOd++OlODi&st7qI4n7Tf!?&9<@U$n9<_K|z=rX1DJmgCIi(l3#2wWWzX z?5h;6VGWA!&TFUdc)Vd`7D(33&rKb5cHy_Di6*(T*lQq?-c{Xn$Y2f=*}4W{bnXoX z2`7+DpA0?=JC&cnS14ij4C7{2K@!Kcyd+)x+GW;jE`|qJ2oU}w2j9@WiGnZg=G^>C z^HBy6dRa`ulmC?3@YAIo1OG*x&l;x7biaV#A2Cr3l~(Qj$8=i?4I-kWSW_PCY90b~ z284;37^$k$J}41unVen**t7F6A00V#43FA=m9>Z}#aR*!ADORVr@LMX1Hf(ml6?CG zXdIH%f>Nu&LxEiN8M`dy_PdEia*C&zu=07#p6@8)@O40H!d#G`sQ9vUJjLTM^Rp{o zCK8FVINCq8ulxa+mUsMVPOcNnX)I3Rs`~iwzo{F)&$OX); zKdslY@Z`O}bf`AdfywrWv44I`Dbe|~f*TJ^TH({J$O@NHHMzB4na#R&2vN`gUd zu%>mtdk>LVx}osbhIP)V9%|ra>|KEC6CKfWb}qq6tsXi(PU2;1uq~Ab=ZGO*AF=5j zzK)h`y1y4^i7XJrQBxz5X4UJXl<)AwE&aW}wY7RIkU$+w>f2ITn0A&5H(#G^mInxa z4yon0Z-9ZtS+mCu@tu^>xLNLbtPj%=Eza7Nf_+7AUFan?DR|h4TA8sBg6FbBXemR4 zEYvhmBK2A{gu^B9V`1;VIg=vylPbK073*T)#sWTE$I~;iLUMYQ3PF@UgI_Qf>Q|ia zF3@+1JHQH#6}4{xA(s7GF^Rf6%LWJ)Z+q4vSy%sIAS=_m%vcojh5G17po*4+E&qZH`Aa5`-HdQJ?!n{Ojn}qg}V{`c4x{ ztcKHu-z#CxdDDo?{uevs?PzQOR7=yTPM{%y`T#Ew zlZB=J`uR8^>)>$c(N%Vp#CoE8Sx&>{&eR0^vbl>!2T&5a-d>WLwBpWGdi)7tK&g4x zq)ly)&ykipZUWb}7RS~`>y=yy5#&^or5_mMspOQeLlzMRe5*mewGsY#B`r6@{%#lN ztF`64>#S;6&M$#b{p|-JwD6bz9SB)vwx^+TX72Vz`ZHh-K*}da3;PE6pGC>&!xgW2 z+sgQBhXbZX{GoBF;#s{qTGnFkjxIq2^ny7G60Wk!%~1AVE3>Qv6jHIx+TweKeiJap z)%jaipFY}oCL!x{{mxOc5gaFmb(qD7Us7yh1h_5%HQZhKpge9rDTZZFA4jo=fM?8; znK#V7m$lt1LwFAtJy9*8@60xC?=ThAYw>-xdZH$b&KI}xeR7x^rB^(?1E&M|JMVY% z1Tl{OXD7$a;5p7#0b;;OUcKs3BHk-@Mlx~Z?OzoBOZ6$B4dRi7f)3}v*^`PzML#EQ zeG9PP=R_H(Pi05{IUtMu#T6z4(kB!-*K`_U3S-ju1%h?xA=5KH2=Z1Wa_B0q9!4Nz z9lZGWF$=#vNOU^L+M0r`7BoVHu?iGZnr0@kz!QU;rwH ziHrN|z-&H%sIyUm0OxNc3SM%P6V^6n?P}|l*x=Z*`5_p`7qvG zi~UQacuS|d#=RMt9>x3`-z2I0NFJPP+_s&J(_EPlaAHe%^c0-lovZZC9Nai3SDp?E zPuCL|lwK+H(6jo3WoxPjemL}!5JL66S1nzJz_cj6HbX7#mD((AGE&%NY88CJqfAjg z&9)@D?sHhci=p(4T$XVF5Ltp2f)uHQrmnSI%jnPeD9ofzdswq_3cx321`5+IclX!6 zgK+t)qO?5ib;v%1shCfTS+;olW*s#TatG8gNeM1*=dvu8i02CZe{~_!`i4}NGKAq= zF)_t3^gbIv|K7b*{54>aS2;+aV^F4VL+OTX{sFQmhgtloCz|FM#LzLbGYaH(hVx;X zm)HwGq}ggHEM5RRXV_&L+ptzwnwXvr_WD*RER^Vfy-|}bLm(C|_XtQpQ&d7;!*@}e zX&B&J1KPKORUwBg@16c^jBpk`&>+!(URHs!HJh*_p7X{d$mIqmDp%?V)Axjy1}H42 zLDkKDo}%mniOKhcwRDcTd;)!I@e(uh7MM$8c+Gc&a3;PifK^?eFpOF3Ft?(sMvhto zd>$$4^ewsp$fP0!2M?*Dy4i#6!YBm$GbrRg|9-EYsn@=w@P2fj=U(k)z#F~lXR88* zmfNCIpi;IwkU;kNmx|7TmOWrdB8u~q03@1SKfU79dC*Th(QMJRa64N23ZywIDmG}F zz#m*FbVG;c{LAUmePFvdo7k82npe(T29Bu+IwYD&n%{nX2clImZTL+j?25Hm?inGWLmhs#k zhG?E0I4ZpnbqIfRw0YN7$#V5bQ9YYR)IU8QSDNL_nLS4YvkST8SpuRN( zgfP1)aa{fV-4PdH&n*IvencH?MxWi*U^T@g-`%Hbhzec9%F??3Zr;|?sFkT~-MVCf zy!@Vvl)x!To|?Vagz`P{bRHu2GUyzcG=5_O3~QMNOMd7Ib_~EN;H#&(MS|<+8fB^? zfQNx9o~Q>sU(Ww&8Jq_|4`Bk9S1;W8JrV^_$TFlvB+G|-!hHb$y-6m$ zoIp3^5pB9=AKu*^OqT)B8p-}I-YR9z-N>G`ImIE|)0*IR0qlZy^JyA3sbK7?RhERr zoapX~SLCavS4TS3AnLaqy;6?0apT~k{Va!OqgS#5DvW;w?{C4giChGunyia!oSsCd?R-2n$x%sWTYjlGzH1V7^Qnh~=P z;Op%7{(JaW{8ujW^CQxuE+RJphkHLdnGj>6Gk9_=@9~%!A|tiU&K5EbkoI|b(IY$6P(DLFuk?Ah zrQQfjf6ILkoo4lFn=m#KteZyof26 zQPn!G!~y+~`?PJrn1L9GrtU#4jCM);ACS*^);R?_}-|5iIgDGPjeY-gp)xv1Wz9NJEl-W5@yDJcaW z>q~tv-OB*jA&1a9ZM_29Nr-dD296mja$&THexvV5VWgm~ocAPydG;ci0?ILaN3#YM z(iew!-qUQgJZ}^7!6?rHhxn4Uye= z_*|5tbJD4Ny|k|S)J65XTw|UF=s3aPpq|yCOOGo!rr(!GZ^Cq6G(F<%tQcA5Eo}q{ zPoMj6wAkXVp6!K=5EvDO{--=C5}dzQnv+zY%(91M9&y;$@=U&QdrsBAkZC&umz>c4 z4duvej#)D4eAIKec_){H)rjE~aKHXDw;(#nZRz?rmE}0XC6y(w>gtLLHZ^Tg?GY6= zexb9+EnIb?^t;jRJP3zeRMSCWbK5@N{LWkV!>#7=3Kyp+;c2QH>yTzM8LQm zAXw3;+=Ps;u&LEv*XO96&Iv0!O0Fd0uqkLN)*RTMiYRG~cqf!_xC}5vMwUNP7j~u& zP3}R!{9VVB^+V69R1F0QAiTZ}AwVKy#yy%8mBGXA3AgrCl+devsMK~{3B_4+l!e>y z3qSocbD_DY(6D2Q(${vMSD_X*2ADa{?wO0g+o<^ce4d7$Kt+HzKbTV(CiAPryF*%; z>10Yq!N0$SRmJ?bM_obMq%f-P`*5K~S6ByvoY-Pcdr>Kd$RB&8O4a*0eeZr9Gp3Fx z9=RQCrcC!DxqOL8ESMek&aeqin|fCdlSS&KW>-20q@a!>cdLzZ@43<%867?G!m1&u z$N-1earaSFw4na6%SH<$haR<(olkEo(ZXO#J+=tPjGyW@Bm;lPcC%-vVOr1r!4-bW zrmcTjpIl-dn080%6hRw#15wio(m)OHEnv8U=#KF5n9Ot*Ghe*xAA5Otp^3~ZY`#&? z?}?yoK3{v0fbEYeOb*g9-IWuCB7x(B@9!jPN}-Z7^fwOQ&n^%5m7{9pmdE$9soB$$iG(T zcjl$t1(Rw-I^UmZZ>pPDN+g}?9^=Zg06xNxVnX_6gCpI26|)C37?S(40n@3xjQT7D zey77S>r6MdM*01p`d)>(J2WD1gWt^^ha8{#?7p0lOaCUHgu&2PcL&@$QNoMQ$(g9G zjRW;qDSNbCQ}}azjhH2hzfJx8#lpEt(g3<=OmnzrC=(&>+jMeQp&R~Dhco{P^1Pc=6rUsRY+Q0&dlo3V2bn;U^j~<7Sa@@$k}v}4bEZn zmH=5j-HYGXd&^e=MRuo+&by>oq8VKl9-r=TZ{;Kr#CJuaT8i<=CxtF6VSj(yRTktyBU5{b&I;p`JAO_H0s7|yT2?xJ&g-8~` zrU~qqHss%e^$)=j(*BBklU=k|16pT1ZC$P`0k3DzLuErI8Dptft=6xkCV%Ta;+{(E z@&*e_OT8Rs@SGSuw3*U5(UvsbiyR*fBV7+~w{=V)m|01Ad;x!^@$+%a3LXWem&V89GeRovRf8aYJG1h&`@}y+#~^;#%GP78_oT(vE|gm+;rOPaX#Db zm`XcO)|Jwq1H+Ss;3lSTCGf{x;1BIN-l&cRGqctalf=MQ6cWOrs!F9w$k#LfyD+?&H5kGjPteS+USju1`v#$pLl5nn#ZNcMjj7iyX?cIz=x! zPZdf5v|r+8P8>aEy>b3bPJ= zwnN30PJ|`tN#IItr%)*P&dIr7*!b-*x$~@Wy@dI%xN9JrS9URqCpxuNh`67G@mG~8 zXx07{T|}jh^UfT1(4my#YAKO)eZR#_=^TpsbIHh~HJSB5ra;ESl;;WiN$-RCwXxO$ z?f(ei%uLA5BL)x@7wAH{w1rU__X-6ScUpPlKmPUl^9q#}Cl$xddX)*; z$D1f^eV(#Kg&@5%dJllzx8K9tvj>Zz%psF^NbCnD=1TB;JKI-Nc3xu62GDOh%!GlP;;N_&#FmHW)t6QLBYVF-HrfE?hgBgsWc>8 zx^fTf0MIX}MXL1Caa0a@-#rxt|3jJ70zY|B_lfRS2)Ztu@$rv{X z#>RDK;Z@h`aOspt`Ef_z^sQM#K_+s2m{g;lJjIB&5oOr2^rKx=?9tpu5tzf;fvD`&S%>k zLTCf47Ezltdzt}R=-EoF<+VKG>uT+2FePgFGW=Qfi;|vxfz)r@`+oK5PQ;1DG3=DOBX=7yscX2~=(#`0_sm!a z#}J__V_{oti7-LKuL?NTe$L(>8LhchESb{vMiI&vw^UhMIV@pF0PB$=Bfk?W!}_lq zY&HS6H~KW{e#pI(8uZ>f*$z{Xg4D&70mn&2cQs20{%q}tM?&3Us*rSv9x|~wprubq zGmAxc-slL-OK-)8^e7aHYg9Ddfny<#nUFNoR}er`Y77LgfD01#9H*MZ%O6B^DC;SP zaZB<*EPXgxBKx9-=GRX&`XpuZ{j}vvAKXFYXDKd&Rxs<tZUGJ zkt9-@%7DEmPZhvngoPwkwS?AhL?XwIxTdHA>Y1`^H0HRM9nRxfKqq#hp!ByzPQ&ea zqvO7x5ZXC}(=vQ@vD`uzG1v63Z9qu8I@3-7Wml_A)cjnD^`ZW>RQXOGp!(?mEwDp} zzo)HkRvKW)b{$Fmw%9>lX{u7;RGE?-w4jP&;pVw*2wGHXj%EfSo;~mYy^iBt=V#)6 z2yT$mtev+v63e|b_W*rrB%gebY`zE71 zKSY)f1NZVx4$(&>RTrF;k&!@ktBz+dU0f){e%*E8?#`8X|CRat#v04mL{%`@y9RF+ zuoFIt&C}~hI0Q~}u|Pl|blBU-3ZJsi5(aSI${{bn+ASrZE?lTxBbY4hhT}f0*V59noBOVQ7yiiUcdOToQC@Tp7eu z6uSexugVX-&^Cib4PaiaTcVQqOmQszmZ74sKkD$cJ9N(qp?FL52VrSt@@%<}RYTA} zc>*>6%ARGS4MzE;QGv30B(=5+erxjVM~PeLY_8iJe^qzxk%f6m53}m0Tpsj@E_+@oLH~ktxRHs<$UOEb} zx*|kFEpIsBYaf$fZHmU-x`dL2?v*XSkk=nPw@yUX>2CDQ(k3A1c!T)!iOjZ^BFz>B z!da(9$YVNVa%xY;I+|b&}3L`Y+DbdwXBD+ChLjXJ)7d=PcX+5b32#0SZ zRYFeIkAz_053<-ciC?^tq$j*ebNqxO*34gC95o%a1-l1qqM)8)=V7m-;kRx~=$x_3 zMYklT$0bi0CLnC!EAOYZaeUU~4vv2rH{Gg!;o$#U4sSl4_>DNOIb?9ko<885j>f2e zr!Qw6y#Hv_J6c@#3r$R{?D1(f{e%kVMbSu&Dm?is>uWJ;Md z$synTm9flRl2?4rD$02JA-DUT#_2y<<->f<#=^L7(w1jrr$dHK_4H0_kGZ*!UMQQF z&Pavp#W~l7*(isH7UhDxcTRV#4wx01t#8eW(Wf*dIMsADNZ)~Q!~0L#mBu1#I$-z` zGhpyFhYh(B#F8-m!d;w9ksRtJOomLsuzcPF)H)cB%#Z6pu-$${-d~LxP9(wM`lQtWxA{f7%PU&1BXF@fgR$M#U~)n$g2E%< zP8iT{+GJ6Wb~<%Uph0S{-s@27yI{?ap??fmmQ8?I!*i&bDj1#5`2xjhD&wc4Oj(8O zIeZ&HwECFw_Vnr*z312z*GjbT6j>S%db>BzwMggu=Fmq>h2>KA&Z~%f<+q!HfEe+) z@ToU_g@6PqjO(t4>N9Jh_8-qx85x<7a4eZk7v zkdv|U6S;OdT368b)z#MY-eeiCZKUcL{C*AiOkwAtAM^I~zi3)dIsC1T)|rx}1NHq{ zRVJ0?QqoghNE}qhJRBrAXFD7pg1!JLz+PESPb}of(A7?$MZu=K1=2q}H*RS=bHzrp9+xnZx3HZoxv0x=*V$1%d6%GRLG^MEQv*Gg=9% zw!z1?pohB%M1Si$(U$aTVzGKC>SU8Sc>O^QznmYSh}(XBj% zLR3oR@O1ZN1Gt2Pz8EZcf3A0)DbuI~*~&0Q-+EV+em&*Gu=dV=R=UBe=Mt#G}?o)Rs_*YGa1=!)=Smm`z0Em z!}r{^WSi&FdFIDqnSX+GKq)(+d5y;s1eG>#GalU*P6xjoY;rB__3OHxL@lh8?EoWQ zv)0-**fOssvn&bvZTj|RUf)w(~HjrXZT~6)4eXOp-x>3rVky}>qPG4be6Mb zC3-?_-If9H@$1YkE;8Pu?$Bz0G-|ww+VqMBpHBurwewRYQt<&IaBq*3tiS~wWh>$I9 z^=FVXbv*!M{GYdl4;TjKl>zfzuMg5W2D6S*p`K{#Y{ft~l}7H#Y7%d%i-mf-^#=TD z>Y6R5o6v>h7&32LHdwd4`Akv?I$bsdz=f82s^b7L{dq+0sReT4$Q{8fzO~2QVK01Z_oR zNqOoEWbnP8h#msB#-p)8v`!Y~l*cmkI&o)ZJ5Bn_N>JTWa?gbob4`6HB_11X*=?%I zUNccJO%+R}iA}cvhmTc5pdEoVm`oVqvo&>n7sH<7fbk_&cAkoJ9_CC`dC_?DzMzds zVnRqKM}eJaQvDR!^w6$eggD`uF@jl=yoUNy2Y7l3a-!h{Eh#dDOqUz`I*y8b$#zwn ze^<~5D&$(yxib56DWi!#R1>nsvE5DoaI7K>ENxMDvaSHZjE75`x94THP@F-6TI$xf z(=Qmljy)6a8{M zi6PiFJpSOWTAZJJj?bsF4h#$`-F;P&+z#QeH`jkh&A$eDgw9%p~5)h5qPjt)qOX9AQ zZ7%{?1l&d`FuL%I2`p! z*9BXT+};WPQNyRKl*myBBF59~q*eZn9wb%yx`IZD&~YnZBK+%$8hmPbZ_o{#UB>}W zTr1%oVGDQqR0@gN z$1CY2=-u(P)4QMH?3>J$nBBD_6x0cOWK%7u@n><^Hka-%>v46moOf7MlQ!x%9>ebMe26;`k+}T%T4q^6w-c>vllE*3|IQ0MLv!Lm|)K! zJKQQusq5Q(O)idb9GQuA`3*-hntHUeJnS03TCY+!5)AELs4qGEk|6Dwzj<02wGt_HgfT4r zIkN}&$`MSu*IGwUH{@JAJ2u8$!nahfe4t8}9~9ggCZf_@r``d0>#W`Pb6ST<#=B4S ze$M9D-msDOqPMwaYAj$s#EdzTn*cjnSa1Bqj93m6TU5?O#(OeJbYIz>&B~8IsSD1( zygRSJQd*GnM0_;408w1Xl9Aj;u=BlrxG!E}KZkWHQJ_^yE=4GCJp(!0FdUbusj)NU z-bKtFHH2+_-rzLJlRzFn{AnotOM) zP98tBosNd7KH}d{ByC)(?8spZ6zH-5#p|MUqO18F7i0wmb|iwlrg#ysZ2^=!Qs9yI z-#Z5ZBn+AA;Iq4`uBN!f4Q*wA~7Db5lxNqD-X zJTL9(b*;$lkzzOXv^oizqsjFG3;;(~@~_=Fv;(MxI32GevgGH>H2iQ3lTpW4Fbx0> zANYwVqsA1nHu9Yvj3SMnB?I5tTKI9XfUjG{xTSqN8~sWcxlwb0g~_-rr@DC}Iw5^Zfv1stj8MC;Kt)l?c zTc7CjFdLHW6PgX%RQbSdyQU-5^=L6eXHK+2w7sN#46m1MD|GU=)`ze&SScN7!=)r; zUN7#);sJ@wJ69AtaGy>Nv3toknO+(P()(kTOM<0Xp zGsd(IHtczY#(w%PXDYQah}FQyD#!iy*L8sT;R)BiQ&9()xX^Ll$tC$uim&UUbsbSF zU4FC^tS*WAM1PmRwAMnc1c`qq2g3=!*_V)bYZ4z*u+ZCvdmjLLD|_stF~I zz;aLr2oQV8oO2;V(|;a9SLsfGR3c3SH`1`-f6FDdduT>0bq62NS5ybL31P4nL&sh> zE@_cTUDC8Qvd3yqTy$^&JGwcUme5%zoyMKiki|Eq@W}W^HydOvU*jV9@hdjMqr#;R zkjZmtpl`@|nDwb-1AJObj*&Cuu=#=uknvT5hgG(*0c)p&X8ECzp)$ zkioI|AEAUX=M(RCtWtIrpyj*J9qwnelkdLlT1tV((F&QDco%EM8Id701V5{f#OS~u zs1tq`G6o-g5J3dGyvTTnU;ys;Q6YP%pbgjX1YS1S>+e8%r+p@DTkEs|?4fTaWlqH$ zsPbmnxNRG);PrYI&Qo4hnmHh9H;pHA|D2>!w9h?E&LiV~)c_THMU3D11d6pk^7##A zBIU1WvIB6}CsG3mLOT^|)8t(rH0{caqI875(M1gBgl?Yx0*AXM(*te0-MNjC^q&cw zw{-a50WgW8Bg@6!1U`;__gx}hL*rL?|8;FiBY<`htHSs+HSBYK_legVfb1@zSL`>z z2^i)IaT-+nPs*?=@m;h5x~aY|d6T{hj@p#VEu-z)E9z$y5)&d*DA6lkUa|_D{v~k< ztv|fw@KOP!WId#8NThFz1Xp*i1WOO^)b^xy&d!odxWG%8{tCqg>oCij;MC_^PAQnVaD^hLM{M^}o5ldgk)EMLAq91 zyFSka12#C)$J4VWyv(@<=yO`qjl z93NXrGp_dIwzUY`32NyXJDEo`Y>|YwDt06cmtB|FZ8u|`P%7`YVA);sZ_?3WM&8DE z2F8x(vRfxwW++1#t~D-@(o-jA_gy5iIJr!RE@rwd>gssD&B+&(DABnw|E}%iq+ce@ z*p{d|llOOl2beCI6YD;Dgo?ArvHXz*s|kE$*QySI zI67GMD5^6JJgx<4iUdlROVWl8*EW>>ER(5tb<{$SUA@-q_P~5xs^%MFefoE> zn2;Ou_Phs=Tt&#os>~4e$X8SNE179`7yI}0v`KA>Dg%l@V^ftS7p}#Ltg=XYPIX`F z8b2BNQ;pTO@jz#92ti5z)YF!l1bE;n`hPm7YcbcpX=$uR`1HffG+iOMh)bk$OY>k% zUW|E;^WZ<~ z=+e@=WT?s)Z{U_`{GDAQ!kN`&^}wW?UH5vcsJjQDtHN3dW6oNnxf0Zi?}_f zjePFB^iau@u=_;Hn-f8@Qqgc0f5;e{Z8w@6EHiqjes^EAqeM8rQ+%Vkl_MuQ!P- zJ7%*{nNmjkj`8F)vi^Jd3HN}-~o5#JHza;F*K_vWXJmBif9)Lwnb8*am(I3#^xwtuR|B&7GN1g_y^lhXhGldjxMFfC&V1FeHnJBpZFzu-z z8yw5vb98PYPf$ZMbj%&8Pm$k2*4&VsscybTktRkkl$K&kT)`(|HVjUTxmp6@!(nr0 zsyYnFbaX)Iv+SSLA}5-xssNYU%dF=_|0-r2ne8q`$dt4i+VF*qE7a24#Ny+Bnq7;0 z0V6Pq<2(dY9CE+=KD%h>leewo5R0R5n&a94`+5e~XT8}higoMo{Jh4?7AFaBaO3u@ zT~R;JP1<)|AFirWM1qex5?YaxrJ$%-~^1OZOt7Xt_0* zvXOLmdp4*O6WX)w#G~2XtKz76S7Xf1`h!7(FMkwRw0e&kgQ)SAZTThEXJ392anmzL zdlY8>SpIP~W&+be)C7%&gRJv37bL;q`HoDzfE|wVq*M063;ES3)l@D^`Yr&{OyPES zKd;3@U%OgjkiY&XsMU+Mtwx&M!6qD;)6Cik3Iv5{c4tnm0m)`BG}J|+=TuY|Bim9Q zt3;?hCyQ%(TH=!_a9V;Rn}RV{V*Gw)+2*{08rvdpaaU~T)E4=ntCh`eBMQ`LI-i$k zqY6=mIe#Kc4Gu$=rW=#@6#KCk7<@qJ^b?hBcuOgkQq&0NDWEK;CI6Qm_3C7zKOQ_pW4 z4E@U?J&;?fntjp$h=SoeRabAV?4E4>hpYt;M@kBSH18PnjJ7kBV+;h+{OrwQQBZuXvChTg z?>{#YQ$f1zkFL0=!>!rJ>Cte>ynnM0GKncxK6deU0LY-MldS^hgd#F#;rG3ZjRY`h zxXK9z=g=DBv)#a6V6g^vpm;nRlg8nAtXeDNQZ%0+m&~KcBU1~jskdi#v2j*$vMjc) z0tOVfeKev8YBa+PkYiU#CvL=)y?si^4(inWlkF17J~GLXV3Pd7Ugi*<55_Hfn~h#rjlqAaP)j;UJ}D<_tO6$x!V zJPeUNMI1T8XfLDnhVFdbC%sUPqOyRawr3ct=Q2hQC9!s5L?e3%>2~JKI5k&p&zNrF zPD^CJiA#RhR*g8Lx+*M<$#Ur_IKyHz0Ii+}CLK&gI0(g>JXz0*kqHAk&b>r@^K*rw zGdo^@_nAmprCDq~4i-k}Q_#5J$o6W9WI(QN_jaz$=RS8&NJSduDp{9#Mx%Et^#sk0 zgM;$GSb}I~re==x;$ag;$B?LV>H+uun#Tc9^WJvoVMXUoGf(i!C|nb296V2+bu6Uu z<}(D^S^1}7QUjLNXJ(R|+RqUMh0Z&))AYXWk=I6dk69db9lKm*Z~RaxJpGNY&+2uE z;Peqk56xr@Dcff`FXlpkxnWV0`E)moJ?d?SMUF{kq^yvwpEQvBAT%4Ch+();xkt|C z#CnoXwM~zu^?Bop6*HM^KPUT|A;8d84WW?bnht9w^n+GViN5HKxjJfY93@UdY(ypl zMz^T+NRk%}fiyapb}Q)@jWk^-dKnlo1a{VX|BEo$n(&M$Wj{{9%+7DQ{-%*`X_QiU zM(hw77IRe|%HN=lyA0`=QSd{;hJ=FSo26nTV1ThmT&Yye|C_OQR5u19q4}cXDQTu+ zD7CSE=>i5u3?_5AS05DztaMz{RoEAfIT~qQ*qW!ByF*vaMZ0sK*&F-)#9v#=fgBx` za9hLxi&-_NckXc1ESx18-H#8I8;ap!s^rOoS;BLjf+Mx$!FZa*qQ;E+f2N;TWGq^f zwHb3d))a97O*t_WblhQsi_&YO^v(c>A|a;Wem3RyKlJKC(cq;Un!_a|w_z6(^)oc) zgjPHxvpQ<~5CuR~;kQfPrCq+#3Eh!inFb+?w}a)sL-qWDx8Ohjjn0WF4WD4$XsfGb z?FHM%q|{rHWU&tCwroiL*kV{Tg1e2ZwtTU`_$ZiVK*+M&HpUC zj{!=P3CZSTZ6q#uZu|nj+GvU1EFclwQV;kB$7Kkgnz%CAfN#_+-yll-0{pF2*dCYm zVUlKG7DV-CX6Vke2y$q(jV<&fcE~a;*TsCL%_P8$RGkJ=Z{}A-Pn_EdQvvQjAste% z81i7R3lDviag~!|qh<+k15!BuiiRV-Ak$5D3H&MH&pkC=itm)s%=Dx1!H!XmszBaD zgEtLor{~y+Cc$uqM1C2y6E+=Q#xzv~fY#?wgF7%1xdmHhH{HYD76Us(V0%3Mx8Ezr zleb5j34)c{3FYrYf+tphf_*jd$qa%@C8)6Qi%X3hx1C%&Cy^W@!o4K+X@@L|$$qmH zO^YhWSP(oYS;!%HsT&=sQuJ&b6^bI1GJHu;y@dinWQ{X981qQehT-5&6G^aE)X06F zbn4k`^@p_vP~rfJ=Cm&qyR|{k0JbjPILPA5Iq$sMw>2 zB^t+L+6K;vwc)jOTjPhLR4420eJI|CT=PI*FBCGjDzJ)`L265tb8_=aYb$4+s49^e zRtN3M`XMK1hL7;TqkLX;YErRS5 z928inc=Rp8hY=|BRkyF3VNL#7Zk8GzqPmNdV{0KjCRe@SbIN7>zmpR$k{IkP)`KJCRQe!2)>eZnsvjgiC{WF& z=@rR<4zCo@LTI}a2YYbH&o=0y%L{Z)%;-J8gF#cZip1L0ulV(B-1X9{*>wYjLS{YX zYzL_{@qp-wMFHA>idl)WzuS|1fsWt5M8pyzxp#-pDPJRBKtkdS^OuI}!hl^Lt}N&! zzySWFj5j>&cc^kxQ+Fwa%^r5;c|Y?s%Ml=p&9Rxjrt$v?L3YzDf-4z8yfKi2?WOi2 zS-e<;Op)1|1|0z>8K&9ib}c)`MF`8(1b@scdy$r0y*cwA%A0wkQzLT3Jkwiic8Sx^ zW7OnUa4J}&vn%VS%TXk<5N3f3m|{$eKcaI%Ynz*&E!a~NgC&-g()aD7e(ADf?tSCe z-mtV?R8ynJxuC~0x*e%rf-^l~q+YhmwH3{5;Jb^_$$%{P? za8?oT7@FIiGyE{o6va$k!nnyEO^owbR*O3^KJl{RaX8ozIbSrd>7DI~T?bgtud1u< zr2Jt{pNT{W8ZMqMs{N;2mD)FTc%K2cMBfx4Ua*ONU0Zj}jZD z_5O~}@Qza(Ab4f?_jb~uqS2MXHUo$@Qz|C|ZR61li^ZQn*bTzABZQ&Hc z=!gyaQCtu@_e4hdSapJr(ZL1?;{s>GB{z(#8-%R;0odl1w|RW0WFn$7A{vs*M6imI z|F^dC7Go3>U|(k8qre(%;A%rF4rB7u%=(kk#gVSOu}>>M3&L27jV}4)NG5) zVhd&oV8+O+UrBBJ4mrxvPT}oo(uurO{33J`6m)@s;b{bI--CJX=~}Nr*AQ~m!+xqX zhgpa2u|&-6A_~=93S^VfR=x_tjWd4IwaFjmtWA{?CL^g-E7TovL`fXnEpE~!3EhkW zEPTK^$$+QAsgr(}sJo)_`kJwVN*Xu9YmQ*+osd0R$Phi4^-z7-#Sz>^# zIha&Wo1~#jDqvc9v9-U#LEU_b4?&Z*=UuhoF$uL$*%fUq=?^a+0m~*#{hh#@N>WH- zA8fiRdA*jH;_9=`$}3cM`{9TceTLkQM1%W(sxcJEBgj{?e5p>hO_l`YZIUZOd{UaZ z^rrUsHBZ{u$;%Sdju_KOaWI-h0j{;w^nxruIB!olEH@SnKNm@@Rl{){;7R-gV?8IC zyl51e&pFjgT-eI;^AyR1#ZNR2a5}?`Jrqff`~ZL@*aVWKM8{GV9~*nrG#_(8UKU^` zs$)?L={QHcNmZT*hKOKhXLlS8+8PAZn8v+BS2(!npxr3~mlja=f6cePrDm9IpZ~p3 z#Dbp*^m#I$T{$H_w;R5+K2dT!`Xb|{EY2x5={X5GU&Q#pp{0f=?&)p9?r5V4r<_c9 z4b)xyZaRSW7@}Y=+yhqnN z_G2R^{}B6M6WycHHEoixLqqAN8D-;%;4fM>vZ=_UYo)^!Otc;S(^R@4XJpw`I|VXR zE1$}hIh3QCYtti+Q5+7%@6r?4+?~;a{yUh!aqggt>0_{nm7{#Mm%sFcX_M~inh>M=>6h`O-bjBijt{r&UMm&@_gKh)Qc;P` zX|2npv-;M*^N@Gt-q^8TzxF4hi8W>ncN!~~&gj5zgsD4+LhALH@ffpFn3|1OV7^Lv zU%s^itN(z!>kL@$p)^#5}Z$&CEt4d8Pi z435e6rj0O6Dk^ma-Rc~!Hj&F+yxi|&)X;MmKHSvRYTSa-Zyn89sP&fR$%VP^d-#)? z(gOR!)tl$MH>v9W@;h0heXttdri@gO z(?6b2Uqm=2q~r~q$S(OMXvse#tgwEas_a^# zbaSQkZLY72>$p*_OlY z3b8`TWUAegCcOR^TuMo6)fgIm5~aUw_RT+riZiFHW?E8;Cjq7k49S#bvLLd!*-VFj zwaV-e-kP221>@meK4aHGjrQ}bE2NNOyiyt+!koRk6+K<^UqbXMxo6;yDFNGomrhPEZUFnDXz?_wCqaO_)5tzr>uhUH%2l1q_t4g1~dm4|6 zF5Ojmg|}fPH-PeG_Priu!}tKIMh{Jgq@fc-Q(x(vISj%JbiV6WEZ zJ?5+p(UEC%IEx_7=r7&l5|wYbh8-GB1%MZ7#ZVeFDRC&&7ySvd675>3VT(~4%jqnW zw=F2`NSR`>-||RbT=~RwSiZN=IGkaNB3K9u$Ns#b02uK0qMv=_v#B288*tBB3G5Xa z%p(`^C7gPUkKq7BIg3CU1++MsLxFsE9oOfkpaM^61TWX#3zDNXzBoq zuS~jVV37g+Xc1FOKA=zKB81nWTAcCoE%Pn}8AXmu8W#af>8i48%N{9msuk_2+UE7%in>qF}m>wdvMRqX8%gsI)L)z^d*(4|7I|p0B@2Y?bjy6_hA-z#T znjIli}PS)%ZF3PG7#_+D zHlkS4yPd%}sWe$FZlizar`hX_)%)z3Wd>?zI+RuE?}ez?L%vD+=>{x@CzT>~DP!h+ zKK8U3^M^)9YUvfoI$*E)h}helz~@56-POW=Y&iI-Lq%iC#FHS3+JJzx7&y3G^Ig0% zF_s(IHM=anE#+E6f@}J9|DV<`#Jaf|5mzh>J`q@cYe+?2xj>*4Rp2*0w37P5)XD}h zVL`g1;_YG;!96JFGSUh$Zf8#a@^kl=roA7~Z}L zbVWb%ZGQO@+ArHh>^v|Uyi1x%N5!3fbDt|Y$vxXlDh}#DEbmjN@|@tS3#v0mmnlu4 z!^j6nnxvwetgzniYiTK|Mqb+_M()r9;#U^lka<$bWQV~1W!@;l{>ne0%n6PRD-dYu z@DY73jZRO8Mo0 zh7o7Nb8ZtbAF4+uh}$UoQj7@nX7%4VU~KtOi1oVB87+0ay1bauO5EfZiM$b8mV zRVSEeq_KU%?{*`zBwHAxNX{La^8;b*;R+0YteFl5-1DK`?j{bzAp{h$OMS7+lhu6L z_y$cg_?b!52217{c!h3ssIZOGH2!td=OaTA*71^|IdByT0>!jd6XNBKK6|+yStKK7FSsZy9alTkz@?@WlY2 z6gx#7qelaD4}KB?_RQq0-n{`VXPzBaFVC;+-N0mmm$xwzpZmUf6tY;D z2@dptEfaGCsbsN&rF0%-8#NRes{vvszMR5=FU$iSbt|e+bKm#NBshp`_fGl|OBe!) zDXWeYRD;Yex*TyyGZfN;5f1qU+puFje@e=Uc-4CjkGp?yc)iR1AWJIpQs~33#5bd} zi3;g(sL^y;;bz~U#>7x{q>bG3UXf-_sVW-JfhkSHUQtZf@ZJ?0dJh^M1FUJ+ihO+6 zhYPIV4n1GgV#i48Q#*1jdr==P3%_^CIPDk-r2MHo13T2;$KrfcaZEN!zthaQG{@*N0wOHB08MIJpPlRxyn z6KYSiMr}EB`O@>Lh|cy=F$mEawlT^PK;aN6K7(APcUWN}ewVU*Ys4f(WRfS-HnDq9 z81%DG()j8pd94ny?ADIMk>}83&OQ|#+|1;(g*Qm3`|G;+>wu3(&)DH{(Q!S9#^#cs z429usFFqFVSkPlX&JpwCSU*b(!4ytd!e+`ooRY|l?C9r!5gbis4X8hKkmMre<1?vI z12;lURom^MFz%OXNU3pL>D9-yP$P)Hanlb#McW4i+Fbt(C@BgKYN26*zQQKo8llep z0YEZ5h5A~dN=ufbyB<%FZsYh9KyKD-TfEKwcI}M8qLLM6VvIwgkOwM%62}QjrBiGe zMUw9q?<4H3yiU}VV1bJHl+R=v&p1p5_F`w+044$FGZ8VT~Gu2|_ak+#!~ z1enA^Ccxe*F2_gwtry^yq89?7q+GI1!zB|R`o=&pTfmzR8UkNgg$W%G7-rf48^8A_ z4P|AZ8#Yr??m=|9%neyFt~gtp1$s>1YJCDRviF#7wQ?D+G&gg~p%8@2*X@&SJ$Yzs zsD$vhkm=yIN~7%mAt~SdX;itlzUe9~sH9z_cmzdq6@hn0ugb@~Vpwsb%O26F1k&Zn z@&)eF)J(VuM3L*er)I#@0C9TL9DrGIIekmDYW9IEuxLyt7zLU__pJaPfDl^{!lb0Q zBwmhXGub-etJN7o{Hi1{zmQXqJV2!g4XeMsQmlc);Z&rUFr)|`ESlGCa&MfnX}U*B z*@QHi@+eDYoRuLo_-$iK9zX48=B7I3)_&tlC~+ zzf1Ih#98ut8#O0^H)Bf}8L2U|OeY*pD}vekFrRaXPIApPbp)tX()sH@V5csk81`Xf z|4v@<1gY7B-D%QfEx?3y%*OlU9D_wY4Tyxl@LtNuelAeXl$llaT!Q<(<{X$F99@ZKj^xq#{y!xU&qasn;>k$Fm>}>F-wepl%M(x z3B}~i?8XV4Bc|Z#>rxfbMYSft-jBBkJF!S#V6E{pemk#9Vzf-ct##syuGS}tRie&; z5u+wnaCUhoNs!-Rk%Iy{YU?FSq(=`S@}^*c9-agK+f!Vv_2mU}hKo0RFbj&Zj#c(| zHu78OO~PBHE0|^E2O-cVxi^OGaO|G^~PA@zPu}nuq|ixzupqVC#RD3RUov|IAWKv^|vSb*HvpCms^IZ3t9sE z=AWdWbu)NIslbo==c&msiQ4A~%NlL>mknhlZG+q*t{6M&y(d2%_PpvocU@Ul_Y}n9 zB|a+Eov$Yu&ZvH{j4+{eVtd9Y(&w!vuw)>nnAl0~)FIpehIH0V^`cE; zo1Y`N_1aVnAM?0C`#SZXb#uz}$M*H${L3!W#-#$Ga?|NC`+EB{hcwu05ex|Mto(Vn z^Ajw_qhx`2cFSA5bqtzJz`{y;+$BtctlnBcQs5y`vF!*^-`ArNV+9EI6*!xAorJQ{ z|JzLS#My;pF}@3#j?e1pvuRu#&23*l>Y#qE;%A;2+?tbq-IOP>`l?QxF@)AULtKfd z?g+>_PfI#2M7~u#f2M&9b1%_W=GpfHxj3kK5*v*Q#q_GH1WDVa1XQ9GmVjfA*@k!@ zk+}Bn<|^Lm21`K+iO=>z%2ND}p{~XR2NY|=fjz7>fKc3#|9EPkuy}-UAPmS*K9^hL zb)mHh!yJ;=yMi!OqWjN$iv6GI95?Ys{rzDh`9@W6rrnNj)UTeq~WC1pwZ64(e~xF9ZB z7W+##rdR|_5kBew}}>t4;3QMoTps^oMX4XBoJ&m8rCm5_CnVW|0NBX^NU zk2ns4b?<_rxZL$2gTzizIV0|MS}}aXpoAvOk~GDM&j`31H_K{pL38N-_A089V5+5N z7@gN@!mGbT~Iv{)&Wt8mh`u2JQ$^oa*Oa^(htO`EGb`cM72 zp(c`{#3P9m45k4HG6MT%+pt}Gd@$xe;3x&B5-qj1@aic6KBptWdC>!-WftW9L;0sLA%QnJQ}TVDFv#QtLQU7|xBz0bTIrN&teQVapr0DF+}zxoT;Jsj6W*WjMnb&hPUX1Bd&`2G;Pv)rBbWPZzF!6si>SUa1} z8xdb7=K4QRC;*&`v0;Jcg6~OSHhTxWOJ$3)?_kXK$Yk<*bSEQ9AxGwjm)Ynn90s;E z+(ckOTu-Yqo1HH07+b&RFtslJWh^f&p%4G>fj5gu;=?9FNEEZW6QY`kJCTw=hV)%C z!LuwV9+i~_FYz@L=C$oLSleXQ^78ZydrAkU_%U(A&&9;No06wn#F*BH-a<<*2?pk_ zdR1TE1jEgW@7oX1X-hgOT+IuBb$XXbaOJ^62J-7)P6oRTdYvq~2b+{0HiCQzJFp2B zjr@rfF&);K6ldDo=6g`0Zg^D~vB405uMUDE6<|DPzhOY1J!iUXwE1q(Y}6x*A;Dy5k}XB@_2TyJV}+{)Ie20UPcQHsY`toaEK zU6^LTqT!M`%EruoS$Ltrd%N*Z87pKs@aLi1GorNgF~G;vmP6ahxTo$K%EiMLfb2(D zu&9RqwocAN3xSIAnG8#30R^~fP+d1$#$ipaj5X+@^Q$U+w5OsI6XxsvrJcNrwQQ#p zYHb^z9(S+zUrENSrBYt15ra>OYBk};7{K*10Mc=7d4DTG-YZ&@AS6^;govk>%#c9X zP;B`aRaBFikLX=qd5QxS2VV$SNkNap=M9C(KZV&f%IF{e(heK=JrEt|VGRjxNQ4jf zIj^9n>!@=RDL~N<5>!sA0_ql&pP|-ke3kCoulWD#{pGF6Uy}RP?U;H3?EZZX8OdJ= zwH!HT8(@#mY8IV*|0ql$o(&+$o{iNQVILCqg?r^2Xw3EFFD5%A3;y6aSw5f!!=f2Q zGQ6oMN2Pdz_$5h|45UTJB$EZp-N>3hVvZH;LVlbtOxKMS_Dg|Op?1WV1IoxSSbq8f zepAkXdW=R0R*sk7TDj{rb#9RHa2MG`He{fr6M?o`4Uj1`m8;#j{GT8aWEdr63>;GuUZ;Is`Zr7~bsK zMbK=$!xqc0R4+C&y@kj5K{aY6SUGvR55!3tm&>=|9m_*CJ9vZCA@n@ZmHnf>2_s zSCMs?u(3gx&T%Ap%|=5-@>j6+b&+BF`th&OiT`WaGRGS1vDW%G-_?M8XLj-yF=GyK zm`Bqr?}eNws?^VDnJ-)WiAl5}6YxaLe_{GaTDiU);w_-gf}6kc9H_eGY~iA@S-t;@ z$y6@vgT#B7Fysda8%;*mX%i!m`vr`d=<;6Zc2FJ7Z6UbW-q>tT3r&53;m3qb+oOiV zw}|*AT*%pqNq>?hH1X-H>M4*pAD5E4M2rLWx{z~am|9e=o}QMLYI8oNJN83&L+Z1h z%J$06BqgUB19E`;vs$bty@Z^B1e!>FknE{r{~1d`Q!r4X*fpkrJvqVOhI-n){T6(< zK9@k3;`cp<5iSW^+S891G>&M74fVl80OoI1Ry>2B!k(hDpS##4tE!pr51E9Na4X%) zc^L1be9VuhB8wVf&v)DfdXk0v1FEsMx{<483${b~!f6^L@nj2f_i^&)+EBXs*1w#m zP?=I)zPb>E9mF82BYXcj_$Z^Dr?&8yS`W?KINf%;`uU2apYaF3XC7j%Ln1tezSxm8 zvkIRoq+8ws5-P2w;_G3gm;3Mv`)5L0wHyWLA)53{Z5vXZ977Q-+UP|f+eY11X97HC z_1MJF4rCjXOGIwyI2!j24 z;ny9gmWo{a<1p}6k!;|(-q&3ctBh^zG1{R@Q(^ z&1bMds>8viF#71EEsDIt8qV&ZcP|>+U}Aw25zTZ)vhF1J%X7&kPEvL6FGxK{^Y?y}kGHx}kXpT^J_W{t|Nqfx^}sHKQ};P-Uf0~q9;5sqn_sW4}- zfsdBJI(;KB#BK2kdFALW(km}@F}SE_x*ptY4MiBV-a%HhC<>sIJb)9YFYec!hCYHn zIjIWU5%w!|Z-lIyR%zV1=OsQ-G`j$3O{;Pe2SGnFmVEzdFV#Lxl~^+6L@=n_XG*nTiM6 zg6C$~lPTefcJPZ20>aL!j?4qrZyz#g&b6aeQGh-pP{N4nUQrG#_O4AR*$0NeVXP<6 z@~yAREqaF*`@zP}h;MzTg&@$P%U|7Qr+QY+=IL3d#fiC&KMriHed0SQW@rB=RuA?V zOScz3ALsh~7>t&dTr2OB9j(mw&+$AwnO;UGkIN_+E7LM8{+*X~5q(_zI@e&{lOy-t znPTS0N^r9B2~~+=Sx1u;08yk{S?EdER&pni0x9lv=?x*yEk0hI9f0d>jVdYY1Zh8e zu34yB__weER|^ICCQCd!BVVm~vQk5-I84oX`U&l7&aYvEv5ZV&V2~x;N^V>{X{O&c zG+n?f4ryv;Iam^I6Ge%2sNraOmKnFXnmt~Ja8y(I&}#fWg5HnDP0E$`0XbLmnd3UX z)9K(%${NY|xH>mB8G#)%JMwZp%h7>PU-Y?#j4KmwuT!v42nb?gZS#sA`5YLqLi@hgpxlrPC zz9?J)H$wBR0`6?7HRH7CBH4l*fw2= zByL+VjQM#kZS%^s=ffe({?*;PeM}FH{Ny)Q;Mu$S5~alKvVod2)JD6h zZ#)>M5OU7w2zucItJ(ulFknJ};?EJd*Czu#wcowXtZh zKfQ;jhJ#V|lZ+TVnF}ch>Efo3`2NDUL{xcI;&UvsCc&M1y2_?0#D&KFrq=|zlIb_F zW5@l8n>&?4`JZx7!|LeHkrB~%1xuw8 zb+#$ZNbcJmymWO`2atEhUfmfGjfjEEO2!qZWk*X!^)byM;q8BWfCQ==IAsTt>FURU zgqy(83BdC;QCSqt#~%}uigo(CA#@xYZGJLD2JNq=BOD9H^V!O9ttueyHveq6wA)wn zEl`jNnm`0d-}!fPB>wPhe>sIa-Z69+%?8eyDqA(lY{V13CdGVCIWpgf=Duf`vQ2}G zO)(Nkd#Ll9AkWF05T-6tGovrvN2SBi<{R*ZRN2tA?la4lqImCci|QSbXCQ6 z&~SLY=Bisf$(C*<)bz5V&xdz)B-8Cou5bK5ymdd3gBei;NN7GdfcgGi7;JCFxnZ~%POsrV9>Qxcw?qlo1cR`BPKf?} zn{Z@fIzUnQ1jTU=?n>fdZGNEnH3Ht)$eq}4$97dC(%o<&5HP?x1kO)%eb$ZnFv3t1 zqd7`Me(udW{x9w*N6^D{db;0-QdO)ETQ2=Wbl!om|pbtp_(?sn2bTA?8CTlNR-+=1>7p@4}uhzF!OfayHJ?vOw7Nt{=`cW%{ z<935w1ZN_t_qkEUkTAky_0%^i{(v9Gg)tb^G5%hr1DM>XJQcMP;8FVU+)6o!b{~qR z@WRK4ziEZ;bfX@iCy$`Sa?JX&{t%OppB7x8Z$w78@7e(VLPxe-qA^WFrN)|CI3Dq< zk^ja=obmU@94Ja46io$O(yMV!e#2sO=TE^_18T&KdIO(_C3v9p1+(w+S)8E2)l}1~ zVd%Sf$~&4+2QQ(94wI|Bo@b1_78!R$Z>m6$%X&lo&m?c!%MaZ*N3^p9XxxjU%rXorATgXYOS&bj+i1FhertOD1uQ-;@-)--!HWd_|)hXud(3 z5Pesjx`$mLlWIM!Fxa0k@@{kl6#Uwj3@0U23k=6U7Jjo0oXTjJOs!+-ZA{;@DW-=b z`04H1-lQh4>dV)6x3NTjvt(oM*C%fe5Foh^&L1`Az<^X5Vb;L4U@RgJ*LUQ>q{4Ex zO9|zd3|{xScfCvJ)6DY$RpYz)M>s60>A^4TNY3)qLD3^)CA6mMY#o=(7jGt{x)*3B z>ONUr{f+i{3`|+BhyS)wpfp9y3rc&?{x$~w(=iu&VjL+wGKBFeMm7$}Y!zsB=szA? zZ0620eeuZ9E!aUdFC!&&d{ulSBdAly{wEmZ`eQ&S!7L=>OB#Bfcw`r~;lTo1T(Fv2 zZRhrQXU05AVa8(1wdnlKqcaiRb)hx3xo3J42rP4!gB#^j2-ZdqHPS2V zBP8)(K-C3=BAEf_LH)&Ff+1lo`99&FTO;MlnqO)W4~|t+(iE6k#d&;5DRRaLn2>8L z&ul9XycDoLJ?mTRJ^PK)0lLFDqOU3kxc1T;yZGN5p=x>pfeIPRzC%wrVmt>c>T5wmIzJie{~8NNSV37Z1Bh?lAnZAf58>DJok_7N zYd6E7M1la?E&bYQwI%xhOe7ns7rDN&yHRWrRm~^FFtrNM594qZ0jBAwLW^1#5ud8W z)L&H(?da<~w!AWVmVirN?F+e&=8EVEDQWW1Ok&Z%{I|~TVrK*}B(>{~$!+eIz5v;U zH$rgZF?f;;UVBa~lI?RXuub%?4>l!yiXL`VI^zE=mWzKvC1wjtrRcAjA_+CddwmHtP zTB6jHga6J&{pIuAC`BO!s?X={A@qi2-G3j^;~5l$EEHS`AU%eE34K(%Y#>}bORi#$ ztcP?~@{g-A2<0?G;4ziFlloGQ?LBQ0rT;PSSen)HL#Dm%A$NMsZ=1DDjWHI&wA2dI zS!>>6k|S-}E#Wb$XMH)e2e`O%G7sK<0H9be74e%ihWDKh6@j>&^C<^XOjtjV@Fvwb zcsISIe43d192m<3#zSVX$H+;@QrbXIXVnlo7AB9!~MfdsjL2uu^BfAM2-aSE31+ zj>Y+9rlLzTnV504NuOLeB-!4pTB{WDP@TDP;s9fWv!Lushb=-wJx=nRyzA`LWA&Zr z1A+6f(k+N?@ik8oO=o~YgGd*J&2+?)j4D|5biYOj zdjJ#?W3VF7a6v3v8_iphn&SeId#@n-;8s2xEwg;PWF z`$AMSmoRUg2ASNr8NzXF-r2TsBI#@9C-L%2r?ATZ2lDicjR3DRW4j7OwmHul8UqEf zSIkkx72nmY!m6lpm@L-#4%$iI){~DqORh-txfgmL0wUl(E>EYAJSf)A8<+DR1;1m5 z7R_>7I4G^52@>tgkNZT6a;vjYC#GI9)9WnCa)<*B!%k&Ns z-H;l^qjiYlysOmV)cXG%urZdt2eKeZBlc>x;!G>mwQCniyDuoS?WdJS02i{@~_06SjOFpVZpzOz49J@h0r$Z#v{>0Z*gRI1Ql$ zb%CMXs<)N!W)mqY-+2y^ale7+>js;p(NH@d|b#4q@z7HzOj--Y6(q zi-uWcOH|`*3b}v0pp@bp7sVNY#ava%ClbvA@Z`hrUp$NS8WYR0{Pvp;^Z${pPQu~{ zR09-`Kvb`D#<3(7Aqxl=uy4{^Cz%)OKKR9tP5}!XLeu}UhpJHG%zU3*t}T)KGS%{w zdO(hW#)~)fBBQ-Qz%V_~5eZ%G^1I`>vTSdp?7mkbgL~PbG%AIVU7DQ(tE?_)lwc)M zD2I?docebxQEJ`-Tu3YyvK6wOTKU%WHf4GP-dlQ}Zd9*7(*#y`^(kwLM7jg z;hzv17R!j5cL_49i=#qIv^i?tTTw~qst9TK_U1s}1v*sinzY;C@Fd9* z=q--TFwOvQUJ<0 zs;fu+2S*PuI{Zkn84|cTaj0nO)fcEocO^{gcjWyH!xl|NS`^jt4=@;MV!f(C${m#3 zqlJ;MsRu13)_C-Y2c~tl>v4XWa;^jWZkR{j=qkT={6HGZmOE5N+#0$Khe9!{lM0H1 za$d*k>`)F=1DwpF1qiOxex>~699urD^tG&m8C=+S{`| zR@hoCrVj_v2e!?d07E8Rf5SOa`W9<@THE*e;ia^N&D38kkSb1(iMKsMO}`UI$x3Ql z>uWD>C%%e0u8?8}!?B1bG*LTeCX}f0?O0~=)|CPy;@tH6>_Z0@M@@*5eSnAT$R8DvYe{2VJEtvTE`Pw$!{u@nL%POQ7*( z%@P_{N=_}y6MmO3X&F-PYr)-_^pSVFVs0&R>EBKFKNU=#ra5zOo+;mr4&t_Z^ud`llBg4?g zQ4XPkjmpoQy<*`}?^oglxHVDfc^i+esKZr7+rlvCQ#&GP3`XP6T2C$7;_IDdjTuHM z&9Pfo2blO`KI+MhT+L6Z?82jUr)Z!E&~LM^)|m32o2!%+u7S(AFU=~=9p%zzZtw5K zv)`89Xg_YPHgWnLhF%1JK-8g()XjJ4Ahh{6Ct z=yS(YQk0YBP^Edt5(Wp6#Q0|@9+Jr} zPgeI^{rU|OxT>Vp8&d&A@QL`?HYDjWnxR=bweTwt&LmErbU1ExEleiq2}m$_gt)b^ z2vAne`{>Wk)nW9y=(HuE^|7Dhr6&Z&PwCT9vBCm8nKAZjq44~1cp-{{i>kt!RBRSh zAzX-cInno)cQ8fmnMKbvZioD=cG0(y+lqTbbGwFM0UGTfd~X@vxI~Nduwr(T6Pft~ zLxN(f!sop;=bIwuju7?Wg!K_Wjfk&jgL(+}Bee@;?wfpkx;}|xvjke+;0NR?`5!3h zd4$+TrzZ6yf4lF7p3g`OZ;(NCn9Cs8Kz*veV=uC;paNIhPDa!V#6}qI`xERVw69XT z@d~{>@Y~h5SQEro^7f(UgO?KL)I~^-BlvhxxbheABEN$T!I)=kY*n6uOKAMCn-4t_ zw_9M48oQZXj+3+GQxSuN5kcrgZSVB=2M;BEUCAX5zLJPOsj)=IF~{8$DJSlcfsyI( zax~_7p~!5Inu9x9`mOL02izw-X8yR%Ia}5$i~}!nf62o{t=vfjNYD0Eoq!AMBv;z{!V$UeX7ciy7hHZ`FH|@OPov*SdcB454Fpg&`U`U82Ba-f3QA+ zrh`7)aT9fnr;NlFNtt^NX;^GSO`$L{%8Hze1WL2VyQ0EffWO9le@D#22tCFJ=8S^m zQg_bPgcFmkB0=X-pmU}q+FPxsAS~2bdi4XGn3~BF>(UYu%`>`@42PHIT7y#RiZqhw zY5>K91S4go9M;u0o;$(?p2~APqQ!Df4QMpx$;==mq87_`Joj`((4%xHYL~tAPnB|^ zYUqgLQ|gn!u_o6TGV)iKjfV=R6GN5>Swc8*dOvCS9)4yQJXa4#{G1BUK%(3#-o6P& zLY#Ix>5U4oQuaciZnJYYUY1LNpBBZdz|BJ=-fXd<-f){VtPYfB{kc3mvr(#Te&Kj4B%J7iw_o7a(>M}5liZeh!T!pZo8*Kx%`f!`<*R}No06fY; z{gC+4xv&PQyi?S=)id1bV6faC8TW4r{@sF$+cpT9@xuqrFX<~P;GOh?cXak%pR{qY_#j_*!ITxRWTIf2+Yl_5y_YV#;Ac=a|zD6K9g6|)mT z)QB!!n;YJ#h)W4pam9*C#=ba;SCt*UIr2(M_3t+P@lJzNZp3r zKLRN(jJpf6Dz|_-^vLzL+#+-5G4FdKnHbXb*VBSRJW%@KX9YIz)RXdWfvVjnG+!77 zayqc9n9teLr^u{y0n1eL@Yhq9dJ#XqAY19iS{%a+ zqq3JXu2JSh|E-OPqDA!I)tj74ra^JB_0; z_~#H8sI8I{5v|l-eMZ5O$02F3DxQ&y$!K;(tmNurGoeG@Mo`TxA|7Y$lP`JZTy+Vl zmlD#`&u%hCi6q|~rDlPNHT?9~OHuNu!C5W&oJ24P6aeNyyCdtQ%_s^M)6)?*W(N%4 zNF=vH*6Ppm-kt@?B_o?l+UTJe^TKD@Hi^6*tR`L#0n4$5k8SEr|J43?NY)+JnC`lx6$1c7{c{Rr{g4mb_uIRYYmF$bWrn>$|BOt%26%R6J%@XX7wI`8R4PQGwc(AI`0rP(G}XhE5o^@%K?GoE(o zTCIeS@AgDR+t#w|9<-~St4Jo8^?U7-q7Ug-y0Er5}`CuoK>$PW92Gy&teUY6RP63R3D6?q6+JP z!jkXo-f>Hg6CDqY-ergQ`u$2qp^&ZnyOD$FVj9SC(2ahNq_2*{zk3zB4$3q_tij!8 zuDf8{P-|+N#ap<0Jj5E)Mj;bx}=bLMO@sx?7Qp))E z6{2eSz@?IlkULOfF?-sljpBg)Ed=*8Z#rvi{OZoO`+`gYi`o1Ph++l;yZ7-R<7w7cSyVX+908CfO^cyAMEq-INch-KB!Gx1%leZgV; zl(?+fcb%`~SOlaOvR_^r&%}{TAiPA{6HfYQP33(rCz%Fr$jF~Z0Vd)s|AUaO&wduZ z8`k^eT%akJsUYXSCMyIL2vT(Y!**(+dRxFgE{Kvl$D?_cIhlzL5GVKEK{U5Rb8kXV z79pC246I$}k4@9L;~*O(m?Ehjx09LfAS(y5mL_@LsQ5;&Kf z23!Onw|`+mwi&|II)Ide6qrRCHUR1)*D0K}=IS(?3TSVFkda!&3G=?Mo;!X2KdVji zd12srzr7Tyt3;)S=7DXG(vn{%paO=WbnWquV8ye9foX_*UrpRzfGvM8N1$V4n z^n8XrVI-2~`isW8G(p6fN1!`96-tHiW|1+>+23i_?cD7h9~p^%KBG)~0D_B);fTvQ z2fd8|%Xu5>Xk|e6wggOq_vce*chsASJ+de}G9G5GWt>)YpD+s_fZ7eWJ%xO~C9 zd2bjg?G99aVn&_ol8b=pDy44_XzBS%Xx)dvl(CwQy~4T!F?q~iI!pmi=fD8MP*ODI zI?1cWaMPpPl{Y@xh_?c&`~4gJYQymJgQ_muHZqGfioY#TPX5%9uAmme_$(10rQ*iT zCOf6D3xJioFHJ}tbPnbnKELjxi4{jq(up;S6q7{JUINXB!{thI#HD{(OI3PM#fnoL zzrh4{W-L+|50h~%NK9&>-Jr2_+)#m81+dwaX?$js95-SWr*Z{=o*X$r77J3nf zqjaJO_WZ7nbBws=FPX@P18$i0Qo2)_BkpX{MJmHrSi?yYG6(&G^(N9Bp)>nX0TY&r zr&jghqgF@#;R`$oSsqLQtq|&->)Crn^*dl;rMKYs17!pF_lIFVjQ0a5mnTev*~-4npi! zpN-+7-)!!`Kfoy^2@&4`F52Njd>+~3*Lz2tS}Z_UGl?xEVNHg8vh~yV!uzY-(3dYa zPz0)$N!YYqIkoa<7#Ikzat2}z7>bR348{Ku$dl_5^ z|9RIXIzX^BnU(H&OufeK-uwHbl+IQJae2R1O~BmzvFvBDQB-*JsbYu1v?#rB?=t<(0mGf!80Mngeyz(Wrm!|}TY1S;#H z%tJYUM%J5+L?CW?A6f;iMnolEx|V>1^-|OY+Rx- z9EXT8T~`Q1bFz17KWz!P(?bs=w$S2^?}_PJb}NIrab~8@)@!)(oA2 zdbS%p0-nK3s*q2FM-k=`|EvPv^kWJ857is%OOqyeabEzuGh{@#M8`g>0cBEp3`nmnsXoCZ+dP|2LuT_r3otO8n%`@LN4iKbU8+w^hA# zwW-}mTa(MDz!d(P$wa*?q7yf6aMeRV{)d9M;p2K=t0l}MoPaI%NaGp^VI)Lk6Bd%J zx&Q#8RY>6wY4;H!)Dd0j8J)h<%tC=_PuWMkFU`+375#Vs0gvSfpzs(QHk;SB>E9dz K000003Rzlx-z4_{ literal 354764 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%0A`vvAeK5#7S`}Yz!me8+N5iq-Wk^3F- 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�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

FqrXg3wR(hiP=FxN#-+)?R|8W;0~# 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 UN1fEZ%C_m>90C9U000VETCGJ2r~m)} From 8ca4a475e7bc839b8c5beae98752b25307681a88 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 3 Feb 2014 19:50:57 +0400 Subject: [PATCH 242/465] Added -W key to wait dialog list before processing input --- loop.c | 12 +++++++++++- main.c | 6 +++++- queries.c | 3 +++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/loop.c b/loop.c index d82d1bc..5dcc97a 100644 --- a/loop.c +++ b/loop.c @@ -326,6 +326,7 @@ extern int peer_num; extern int encr_root; extern unsigned char *encr_prime; extern int encr_param_version; +extern int dialog_list_got; void read_secret_chat_file (void) { if (binlog_enabled) { return; } @@ -443,11 +444,16 @@ int mcs (void) { extern int difference_got; int dgot (void) { - return !difference_got; + return difference_got; +} +int dlgot (void) { + return dialog_list_got; } int readline_active; int new_dc_num; +int wait_dialog_list; + int loop (void) { on_start (); if (binlog_enabled) { @@ -598,6 +604,10 @@ int loop (void) { do_get_dialog_list (); + if (wait_dialog_list) { + dialog_list_got = 0; + net_loop (0, dlgot); + } return main_loop (); } diff --git a/main.c b/main.c index 562e351..91ddc3b 100644 --- a/main.c +++ b/main.c @@ -358,12 +358,13 @@ FILE *log_net_f; int register_mode; int disable_auto_accept; +int wait_dialog_list; char *lua_file; void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:RfBL:Es:")) != -1) { + while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:RfBL:Es:wW")) != -1) { switch (opt) { case 'u': set_default_username (optarg); @@ -413,6 +414,9 @@ void args_parse (int argc, char **argv) { case 's': lua_file = tstrdup (optarg); break; + case 'W': + wait_dialog_list = 1; + break; case 'h': default: usage (); diff --git a/queries.c b/queries.c index e830d34..35a36f4 100644 --- a/queries.c +++ b/queries.c @@ -1087,6 +1087,7 @@ void do_get_history (peer_id_t id, int limit) { /* }}} */ /* {{{ Get dialogs */ +int dialog_list_got; int get_dialogs_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); @@ -1147,6 +1148,8 @@ int get_dialogs_on_answer (struct query *q UU) { } pop_color (); print_end (); + + dialog_list_got = 1; return 0; } From ce8802b86406e3ea88b9d897309ef483cfa4fbd7 Mon Sep 17 00:00:00 2001 From: cleto Date: Mon, 3 Feb 2014 21:31:23 +0000 Subject: [PATCH 243/465] initial commit --- debian/changelog | 5 +++++ debian/clean | 1 + debian/compat | 1 + debian/control | 36 ++++++++++++++++++++++++++++++++++++ debian/copyright | 28 ++++++++++++++++++++++++++++ debian/docs | 1 + debian/install | 1 + debian/rules | 17 +++++++++++++++++ debian/source/format | 1 + debian/watch | 4 ++++ 10 files changed, 95 insertions(+) create mode 100644 debian/changelog create mode 100644 debian/clean create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/docs create mode 100644 debian/install create mode 100755 debian/rules create mode 100644 debian/source/format create mode 100644 debian/watch diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..c83e5f7 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +telegram-cli (0.1-1) unstable; urgency=low + + * Initial release (Closes #737563) + + -- Cleto Martín Mon, 03 Feb 2014 20:00:03 +0000 diff --git a/debian/clean b/debian/clean new file mode 100644 index 0000000..33ceb8f --- /dev/null +++ b/debian/clean @@ -0,0 +1 @@ +Makefile \ No newline at end of file diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..5e7e1f0 --- /dev/null +++ b/debian/control @@ -0,0 +1,36 @@ +Source: telegram-cli +Section: net +Priority: optional +Maintainer: Cleto Martín +Build-Depends: debhelper (>= 8.0.0), + autotools-dev, + autoconf-archive, + libreadline-dev, + libconfig-dev, + libssl-dev, + lua5.2, + liblua5.2-dev +Standards-Version: 3.9.4 +Homepage: https://github.com/vysheng/tg +Vcs-Git: git://github.com/vysheng/tg.git +Vcs-Browser: https://github.com/vysheng/tg + +Package: telegram-cli +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Command-line interface for Telegram messenger + Telegram messenger is a cloud-based instant messaging designed for + smart phones and similar to Whatsapp but more flexible, and + powerful. You can send messages, photos, videos and documents to + people who are in your phone contacts (and have Telegram). Telegram + also supports secret chats whose provide a private (encrypted) way of + communication. + . + This package contains a command-line based client for Telegram with + the following features: + * Colored terminal messages. + * Message management: history, stats, etc. + * Group chat: create and manage groups. + * Secret chat: secured and encrypted conversations. + * Contact management: add/edit/remove contacts. + * Multimedia support: send/load photos and videos. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..2e46990 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,28 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: telegram-cli +Source: https://github.com/vysheng/tg + +Files: * +Copyright: 2013 Vitaly Valtman +License: GPL-2.0+ + +Files: debian/* +Copyright: 2014 Cleto Martín +License: GPL-2.0+ + +License: GPL-2.0+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..b43bf86 --- /dev/null +++ b/debian/docs @@ -0,0 +1 @@ +README.md diff --git a/debian/install b/debian/install new file mode 100644 index 0000000..f0f94de --- /dev/null +++ b/debian/install @@ -0,0 +1 @@ +telegram usr/bin diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..0f41aca --- /dev/null +++ b/debian/rules @@ -0,0 +1,17 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') +PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') + +%: + dh $@ --with autotools-dev + +build-orig: + mkdir -p $(PACKAGE_NAME)-$(VERSION) + tar --exclude=ax_lua.m4 --exclude=debian --exclude=\.pc \ + --exclude=$(PACKAGE_NAME)-$(VERSION) -cf - . \ + | ( cd $(PACKAGE_NAME)-$(VERSION) && tar xf - ) + tar -cf ../$(PACKAGE_NAME)_$(VERSION).orig.tar $(PACKAGE_NAME)-$(VERSION) + $(RM) -r $(PACKAGE_NAME)-$(VERSION) + xz ../$(PACKAGE_NAME)_$(VERSION).orig.tar diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..2148331 --- /dev/null +++ b/debian/watch @@ -0,0 +1,4 @@ +version=3 + +opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/tg-$1\.tar\.gz/ \ + https://github.com/vysheng/tg/tags .*/v?(\d\S*)\.tar\.gz From 73a48816e4738d3424b5d31ea0ece1517549d25f Mon Sep 17 00:00:00 2001 From: Vysheng Date: Tue, 4 Feb 2014 20:35:16 +0400 Subject: [PATCH 244/465] Added /etc/telegram/server.pub as default server public key place --- main.c | 6 +++--- mtproto-client.c | 23 ++++++++++++++++------- telegram.h | 4 ++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/main.c b/main.c index 91ddc3b..e75e821 100644 --- a/main.c +++ b/main.c @@ -47,6 +47,7 @@ #include #endif +#include "telegram.h" #include "loop.h" #include "mtproto-client.h" #include "interface.h" @@ -59,7 +60,7 @@ #define PROGNAME "telegram-client" #define VERSION "0.01" -#define CONFIG_DIRECTORY ".telegram" +#define CONFIG_DIRECTORY "." PROG_NAME #define CONFIG_FILE "config" #define AUTH_KEY_FILE "auth" #define STATE_FILE "state" @@ -208,7 +209,6 @@ void running_for_first_time (void) { tasprintf (&config_filename, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, CONFIG_FILE); config_filename = make_full_path (config_filename); - static struct stat config_file_stat; int config_file_fd; char *config_directory = get_config_directory (); //char *downloads_directory = get_downloads_directory (); @@ -220,7 +220,7 @@ void running_for_first_time (void) { tfree_str (config_directory); config_directory = NULL; // see if config file is there - if (stat (config_filename, &config_file_stat) != 0) { + if (access (config_filename, R_OK) != 0) { // config file missing, so touch it config_file_fd = open (config_filename, O_CREAT | O_RDWR, 0600); if (config_file_fd == -1) { diff --git a/mtproto-client.c b/mtproto-client.c index 809e009..19c9a9c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -45,6 +45,7 @@ #include #include +#include "telegram.h" #include "net.h" #include "include.h" #include "queries.h" @@ -126,7 +127,7 @@ int Response_len; * */ -char *rsa_public_key_name = "tg.pub"; +char *rsa_public_key_name; // = "tg.pub"; RSA *pubKey; long long pk_fingerprint; @@ -144,6 +145,10 @@ static int rsa_load_public_key (const char *public_key_name) { return -1; } + if (verbosity) { + logprintf ( "public key '%s' loaded successfully\n", rsa_public_key_name); + } + return 0; } @@ -1807,12 +1812,16 @@ int auth_is_success (void) { void on_start (void) { prng_seed (0, 0); - if (rsa_load_public_key (rsa_public_key_name) < 0) { - perror ("rsa_load_public_key"); - exit (1); - } - if (verbosity) { - logprintf ( "public key '%s' loaded successfully\n", rsa_public_key_name); + if (rsa_public_key_name) { + if (rsa_load_public_key (rsa_public_key_name) < 0) { + perror ("rsa_load_public_key"); + exit (1); + } + } else { + if (rsa_load_public_key ("tg.pub") < 0 && rsa_load_public_key ("/etc/" PROG_NAME "/server.pub") < 0) { + perror ("rsa_load_public_key"); + exit (1); + } } pk_fingerprint = compute_rsa_key_fingerprint (pubKey); } diff --git a/telegram.h b/telegram.h index 41315ce..d72da12 100644 --- a/telegram.h +++ b/telegram.h @@ -18,3 +18,7 @@ */ #define MAX_DC_NUM 9 #define MAX_PEER_NUM 100000 + +#ifndef PROG_NAME +#define PROG_NAME "telegram" +#endif From e68ad3968725692578a55e27cf9da1d15c01b381 Mon Sep 17 00:00:00 2001 From: Pablo Date: Tue, 4 Feb 2014 18:28:11 +0100 Subject: [PATCH 245/465] Rename spec and add server key --- telegram.spec => telegram-cli.spec | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) rename telegram.spec => telegram-cli.spec (70%) diff --git a/telegram.spec b/telegram-cli.spec similarity index 70% rename from telegram.spec rename to telegram-cli.spec index afe56bd..241e5b6 100644 --- a/telegram.spec +++ b/telegram-cli.spec @@ -1,20 +1,21 @@ -Name: Telegram +Name: telegram-cli Version: Beta -Release: 1%{?dist} +Release: 2%{?dist} Summary: Private fast and open platform for instant messaging +Packager: Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) Group: Internet/Messaging License: GPL URL: https://github.com/vysheng/tg Source: master.zip -BuildRequires: lua-devel, openssl-devel, libconfig-devel, readline-devel -Requires: wget +BuildRequires: lua-devel, openssl-devel, libconfig-devel, readline-devel, wget +#Requires: wget %description Telegram is an Open Source messaging platform for mobile, desktop focused on privacy. -Packager: Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) + %prep @@ -32,12 +33,14 @@ make %{?_smp_mflags} cd %{name} cd tg-master %{__install} -D -m0755 telegram %{buildroot}/usr/bin/telegram +%{__install} -D -m0644 tg.pub %{buildroot}/etc/telegram/server.pub %files /usr/bin/telegram - +/etc/telegram/server.pub %changelog +* Tue Feb 4 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) +- Add server key to /etc/telegram/ * Sat Feb 1 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) - Initial SPEC file - From b091f978f1d04fe037b128ebfef7445e9c48a94d Mon Sep 17 00:00:00 2001 From: antma Date: Wed, 5 Feb 2014 15:07:58 +0400 Subject: [PATCH 246/465] replace ENABLE_LIBCONFIG by HAVE_LIBCONFIG (use macro AC_CHECK_LIBdefault ACTION-IF-FOUND behavior) fix unused write result in undefined HAVE_EXECINFO_H case --- config.h | 6 +++--- config.h.in | 6 +++--- configure | 12 ++++++++---- configure.ac | 6 ++---- main.c | 8 +++++--- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/config.h b/config.h index ee1ba04..bed34d6 100644 --- a/config.h +++ b/config.h @@ -1,9 +1,6 @@ /* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ -/* enable libconfig */ -#define ENABLE_LIBCONFIG 1 - /* Define to 1 if you have the `alarm' function. */ #define HAVE_ALARM 1 @@ -25,6 +22,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_LAUXLIB_H 1 +/* Define to 1 if you have the `config' library (-lconfig). */ +#define HAVE_LIBCONFIG 1 + /* Define to 1 if you have the `crypto' library (-lcrypto). */ #define HAVE_LIBCRYPTO 1 diff --git a/config.h.in b/config.h.in index dfb83e9..f67b9cb 100644 --- a/config.h.in +++ b/config.h.in @@ -1,8 +1,5 @@ /* config.h.in. Generated from configure.ac by autoheader. */ -/* enable libconfig */ -#undef ENABLE_LIBCONFIG - /* Define to 1 if you have the `alarm' function. */ #undef HAVE_ALARM @@ -24,6 +21,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LAUXLIB_H +/* Define to 1 if you have the `config' library (-lconfig). */ +#undef HAVE_LIBCONFIG + /* Define to 1 if you have the `crypto' library (-lcrypto). */ #undef HAVE_LIBCRYPTO diff --git a/configure b/configure index 2361488..8861a5a 100755 --- a/configure +++ b/configure @@ -3562,14 +3562,16 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_config_config_init" >&5 $as_echo "$ac_cv_lib_config_config_init" >&6; } if test "x$ac_cv_lib_config_config_init" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCONFIG 1 +_ACEOF -$as_echo "#define ENABLE_LIBCONFIG 1" >>confdefs.h + LIBS="-lconfig $LIBS" else as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 fi - EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; fi else @@ -3613,14 +3615,16 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_config_config_init" >&5 $as_echo "$ac_cv_lib_config_config_init" >&6; } if test "x$ac_cv_lib_config_config_init" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCONFIG 1 +_ACEOF -$as_echo "#define ENABLE_LIBCONFIG 1" >>confdefs.h + LIBS="-lconfig $LIBS" else as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 fi - EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; fi diff --git a/configure.ac b/configure.ac index 357b911..8780f33 100644 --- a/configure.ac +++ b/configure.ac @@ -35,13 +35,11 @@ AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], AC_MSG_RESULT([disabled]) else AC_MSG_RESULT([enabled]) - AC_CHECK_LIB([config],[config_init],AC_DEFINE(ENABLE_LIBCONFIG,1,[enable libconfig]),AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) - [EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; ] + AC_CHECK_LIB([config],[config_init],[],AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) fi ],[ AC_MSG_RESULT([enabled]) - AC_CHECK_LIB([config],[config_init],AC_DEFINE(ENABLE_LIBCONFIG,1,[enable libconfig]),AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) - [EXTRA_LIBS="${EXTRA_LIBS} -lconfig" ; ] + AC_CHECK_LIB([config],[config_init],[],AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) ]) AC_MSG_CHECKING([for liblua]) diff --git a/main.c b/main.c index e75e821..a8d23fe 100644 --- a/main.c +++ b/main.c @@ -43,7 +43,7 @@ #include #endif #include -#ifdef ENABLE_LIBCONFIG +#ifdef HAVE_LIBCONFIG #include #endif @@ -247,7 +247,7 @@ void running_for_first_time (void) { } } -#ifdef ENABLE_LIBCONFIG +#ifdef HAVE_LIBCONFIG void parse_config_val (config_t *conf, char **s, char *param_name, const char *default_name, const char *path) { static char buf[1000]; int l = 0; @@ -433,7 +433,9 @@ void print_backtrace (void) { } #else void print_backtrace (void) { - write (1, "No libexec. Backtrace disabled\n", 32); + if (write (1, "No libexec. Backtrace disabled\n", 32) < 0) { + // Sad thing + } } #endif From 6c2f4fed6b836af9811a07b01e97fc1504e220dd Mon Sep 17 00:00:00 2001 From: antma Date: Wed, 5 Feb 2014 15:12:01 +0400 Subject: [PATCH 247/465] remove -lssl from Makefile.in please add AC_CHECK_LIB([ssl], [function-name]) to configure.ac in the case of failed linkage --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 5ee1b03..23a97dc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,7 +6,7 @@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -EXTRA_LIBS=-lssl @LIBS@ @EXTRA_LIBS@ +EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} From a78e6b08979dd3f3a1cf98844c5d5cc56dedaf07 Mon Sep 17 00:00:00 2001 From: Pablo Date: Wed, 5 Feb 2014 16:14:07 +0100 Subject: [PATCH 248/465] Updated rpm with new spec --- rpm/Telegram-Beta-1.fc20.x86_64.rpm | Bin 146852 -> 0 bytes rpm/telegram-cli-Beta-2.fc20.x86_64.rpm | Bin 0 -> 147652 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 rpm/Telegram-Beta-1.fc20.x86_64.rpm create mode 100644 rpm/telegram-cli-Beta-2.fc20.x86_64.rpm diff --git a/rpm/Telegram-Beta-1.fc20.x86_64.rpm b/rpm/Telegram-Beta-1.fc20.x86_64.rpm deleted file mode 100644 index b80e259977c6df86fec470889632d71ecea1abd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146852 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

=}a6)ObvuG7X$~rV&RXQ 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 K000003Rzlx-z4_{ diff --git a/rpm/telegram-cli-Beta-2.fc20.x86_64.rpm b/rpm/telegram-cli-Beta-2.fc20.x86_64.rpm new file mode 100644 index 0000000000000000000000000000000000000000..0deaace0e3bfbd1184e064b665486bb52dc9ac2e GIT binary patch literal 147652 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

_Vt8K7?mvk= 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�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 O|(7c4`>_!C^ri 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 a0mE9dz000003RzmU%@`8^ literal 0 HcmV?d00001 From 97c782a965af5c06f693bc52424d46520baecc65 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 6 Feb 2014 13:54:52 +0300 Subject: [PATCH 249/465] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e2cd59f..d6b6fff 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea $ brew install libconfig $ brew install readline + $ brew install lua $ export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" $ export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" $ ./configure && make From b9a1ecf77707008f9f0bd8e014702ac455be8c69 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 6 Feb 2014 18:12:43 +0400 Subject: [PATCH 250/465] Added --with-progname="progname" option to configure. --- Makefile | 6 +++--- config.h | 3 +++ config.h.in | 3 +++ configure | 35 +++++++++++++++++++++++++++++++++++ configure.ac | 15 +++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1c4c05c..014677c 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ srcdir=. -CFLAGS=-g -O2 -I/usr/include/lua5.2 +CFLAGS=-g -O2 LDFLAGS= CPPFLAGS= DEFS=-DHAVE_CONFIG_H COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -EXTRA_LIBS= -lreadline -lrt -lconfig -llua5.2 -ldl -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} +EXTRA_LIBS=-lconfig -lcrypto -lz -lrt -lm -lreadline -llua +LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h diff --git a/config.h b/config.h index bed34d6..5f54b0c 100644 --- a/config.h +++ b/config.h @@ -141,6 +141,9 @@ /* Define to the version of this package. */ #define PACKAGE_VERSION "0.1" +/* Use custom prog name */ +/* #undef PROG_NAME */ + /* Use libedit */ /* #undef READLINE_EDIT */ diff --git a/config.h.in b/config.h.in index f67b9cb..1a20b5b 100644 --- a/config.h.in +++ b/config.h.in @@ -140,6 +140,9 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION +/* Use custom prog name */ +#undef PROG_NAME + /* Use libedit */ #undef READLINE_EDIT diff --git a/configure b/configure index 8861a5a..dd2e8ef 100755 --- a/configure +++ b/configure @@ -687,6 +687,7 @@ ac_user_opts=' enable_option_checking enable_libconfig enable_liblua +with_progname ' ac_precious_vars='build_alias host_alias @@ -1312,6 +1313,11 @@ Optional Features: --enable-libconfig/--disable-libconfig --enable-liblua/--disable-liblua +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) +--with-progname= + Some influential environment variables: CC C compiler command CFLAGS C compiler flags @@ -5363,6 +5369,35 @@ fi fi +#check for custom prog name + +# Check whether --with-progname was given. +if test "${with_progname+set}" = set; then : + withval=$with_progname; + if test "x$with_progname" = "xno" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 +$as_echo "default" >&6; } + elif test "x$with_progname" = "xyes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 +$as_echo "default" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_progname\"" >&5 +$as_echo "\"$with_progname\"" >&6; } + +cat >>confdefs.h <<_ACEOF +#define PROG_NAME "$with_progname" +_ACEOF + + fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 +$as_echo "default" >&6; } + +fi + + # Checks for header files. for ac_header in execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h do : diff --git a/configure.ac b/configure.ac index 8780f33..f17039d 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,21 @@ AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], AC_MSG_ERROR([No lua found. Try --disable-liblua]) ]) ]) + +#check for custom prog name +AC_ARG_WITH(progname,[--with-progname=], + [ + if test "x$with_progname" = "xno" ; then + AC_MSG_RESULT([default]) + elif test "x$with_progname" = "xyes" ; then + AC_MSG_RESULT([default]) + else + AC_MSG_RESULT(["$with_progname"]) + AC_DEFINE_UNQUOTED([PROG_NAME], ["$with_progname"], [Use custom prog name]) + fi + ],[ + AC_MSG_RESULT([default]) + ]) # Checks for header files. AC_CHECK_HEADERS([execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h]) From e3e0b5efb9310da0624179d2fbfbd287ab6d491d Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 6 Feb 2014 18:22:21 +0400 Subject: [PATCH 251/465] To complete pack: gentoo ebuild --- gentoo/telegram-cli/Manifest | 1 + gentoo/telegram-cli/telegram-cli-9999.ebuild | 31 ++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 gentoo/telegram-cli/Manifest create mode 100644 gentoo/telegram-cli/telegram-cli-9999.ebuild diff --git a/gentoo/telegram-cli/Manifest b/gentoo/telegram-cli/Manifest new file mode 100644 index 0000000..f39008c --- /dev/null +++ b/gentoo/telegram-cli/Manifest @@ -0,0 +1 @@ +EBUILD telegram-cli-9999.ebuild 641 SHA256 4597e2f84c36b1ee02ecc415c399408bb8536b456e94370e996d57477db621be SHA512 287da263c9a4ba2058bf2f5844599432619053abc9249fd5725ed7b5e920c5c02e2493ad7b07f89177933b2c15394d939e7dc7dbf05d5873c32e55c9ec614d4c WHIRLPOOL 73dee37f91f1d4b747afc35c0a0cb2efb141d37702c71a7a9d188d2e1d727375c0ee3e7a1192e6c4c34f17ba1303f3a0be47b24272b5378ff255bce1a4a281be diff --git a/gentoo/telegram-cli/telegram-cli-9999.ebuild b/gentoo/telegram-cli/telegram-cli-9999.ebuild new file mode 100644 index 0000000..bf8ed3d --- /dev/null +++ b/gentoo/telegram-cli/telegram-cli-9999.ebuild @@ -0,0 +1,31 @@ +# Copyright 1999-2013 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=5 + +EGIT_REPO_URI="https://github.com/vysheng/tg.git" +inherit git-2 +IUSE="lua" +DESCRIPTION="Command line interface client for Telegram" +HOMEPAGE="https://github.com/vysheng/tg" +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="~amd64 ~x86" + +DEPEND="sys-libs/zlib + sys-libs/readline + dev-libs/libconfig + dev-libs/openssl + lua? ( dev-lang/lua )" + +src_configure() { + econf $(use_enable lua liblua ) --with-progname=telegram-cli +} + +src_install() { + newbin telegram telegram-cli + + insinto /etc/telegram-cli/ + newins tg.pub server.pub +} From 3b4bf372ab1f229671d709b8190b8172b3c31843 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Thu, 6 Feb 2014 22:09:43 +0400 Subject: [PATCH 252/465] lua: added postpone message --- lua-tg.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ structures.c | 1 - 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/lua-tg.c b/lua-tg.c index 73153e3..1d7b6e9 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -20,6 +20,7 @@ lua_State *luaState; #include "constants.h" #include "tools.h" #include "queries.h" +#include "net.h" extern int verbosity; @@ -471,6 +472,62 @@ static int mark_read_from_lua (lua_State *L) { return 1; } +int lua_postpone_alarm (void *self) { + int *t = self; + + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[1]); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[0]); + assert (lua_gettop (luaState) == 2); + + int r = lua_pcall (luaState, 1, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, t[0]); + luaL_unref (luaState, LUA_REGISTRYINDEX, t[1]); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + tfree (*(void **)(t + 2), sizeof (struct event_timer)); + tfree (t, 16); + return 0; +} + +static int postpone_from_lua (lua_State *L) { + int n = lua_gettop (L); + if (n != 3) { + lua_pushboolean (L, 0); + return 1; + } + + double timeout = lua_tonumber (L, -1); + if (timeout < 0) { + lua_pushboolean (L, 0); + return 1; + } + + lua_pop (L, 1); + int a1 = luaL_ref (L, LUA_REGISTRYINDEX); + int a2 = luaL_ref (L, LUA_REGISTRYINDEX); + + struct event_timer *ev = talloc (sizeof (*ev)); + int *t = talloc (16); + t[0] = a1; + t[1] = a2; + *(void **)(t + 2) = ev; + + ev->timeout = get_double_time () + timeout; + ev->alarm = (void *)lua_postpone_alarm; + ev->self = t; + insert_event_timer (ev); + + lua_pushboolean (L, 1); + return 1; +} + void lua_init (const char *file) { if (!file) { return; } have_file = 1; @@ -480,6 +537,7 @@ void lua_init (const char *file) { lua_register (luaState, "send_msg", send_msg_from_lua); lua_register (luaState, "fwd_msg", fwd_msg_from_lua); lua_register (luaState, "mark_read", mark_read_from_lua); + lua_register (luaState, "postpone", postpone_from_lua); int ret = luaL_dofile (luaState, file); if (ret) { diff --git a/structures.c b/structures.c index cff88bb..71d5f2f 100644 --- a/structures.c +++ b/structures.c @@ -28,7 +28,6 @@ #include "telegram.h" #include "tree.h" #include "loop.h" -#include #include #include #include "queries.h" From 856fba7faec817c69347fb5f8104fc3eb0fc3954 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 7 Feb 2014 19:40:39 +0400 Subject: [PATCH 253/465] Fixed registration. Fixed possible SIGSEGV in create_print_name --- loop.c | 4 ++-- queries.c | 3 +++ structures.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/loop.c b/loop.c index 5dcc97a..be76da8 100644 --- a/loop.c +++ b/loop.c @@ -545,13 +545,13 @@ int loop (void) { exit (EXIT_SUCCESS); } char *first_name; - printf ("Name: "); + printf ("First name: "); if (net_getline (&first_name, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } char *last_name; - printf ("Name: "); + printf ("Last name: "); if (net_getline (&last_name, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); diff --git a/queries.c b/queries.c index 35a36f4..633f601 100644 --- a/queries.c +++ b/queries.c @@ -527,6 +527,9 @@ int do_auth_check_phone (const char *user) { check_phone_result = -1; send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, 0); net_loop (0, cr_f); + 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; } /* }}} */ diff --git a/structures.c b/structures.c index 71d5f2f..adda1a7 100644 --- a/structures.c +++ b/structures.c @@ -168,7 +168,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha int cc = 0; while (1) { peer_t *P = peer_lookup_name (s); - if (!P || !cmp_peer_id (Peers[i]->id, id)) { + if (!P || !cmp_peer_id (P->id, id)) { break; } cc ++; From 23c5b3b51f65651178db2fbe47afae5b954b7271 Mon Sep 17 00:00:00 2001 From: Pablo Date: Sat, 8 Feb 2014 11:57:04 +0100 Subject: [PATCH 254/465] Update README with new automatic path for server.pub --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6b6fff..8737a32 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ If you manage to launch it on other UNIX, please let me know. ./telegram -k -By default public key is stored in the same folder named tg.pub: +By default public key is stored in the same folder named tg.pub or in /etc/telegram/server.pub, if it's not, specify where to find it: ./telegram -k tg.pub From 059713097f4eef2fee76263a6da4edce596c43d5 Mon Sep 17 00:00:00 2001 From: falkartis Date: Sat, 8 Feb 2014 17:44:10 +0100 Subject: [PATCH 255/465] Help text updated. I just added "You can see message numbers starting client with -N" to the load_photo and the view_photo description. I've been in trouble because of not knowing how to download files so I think its use-full. I'm not sure if it's how github works my idea was to Propose this change to the main branch. --- interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface.c b/interface.c index de6a925..c6ffc67 100644 --- a/interface.c +++ b/interface.c @@ -877,8 +877,8 @@ void interpreter (char *line UU) { "user_info - prints info about user\n" "fwd - forward message to user. You can see message numbers starting client with -N\n" "rename_chat \n" - "load_photo/load_video/load_video_thumb - loads photo/video to download dir\n" - "view_photo/view_video/view_video_thumb - loads photo/video to download dir and starts system default viewer\n" + "load_photo/load_video/load_video_thumb - loads photo/video to download dir. You can see message numbers starting client with -N\n" + "view_photo/view_video/view_video_thumb - loads photo/video to download dir and starts system default viewer. You can see message numbers starting client with -N\n" "show_license - prints contents of GPLv2\n" "search pattern - searches pattern in messages with peer\n" "global_search pattern - searches pattern in all messages\n" From 347b79c79a3202102c50a15c993c0650a356c919 Mon Sep 17 00:00:00 2001 From: Aaron D Date: Sun, 9 Feb 2014 09:46:35 +0100 Subject: [PATCH 256/465] Update README.md Fedora don't use commas in his installation system to separate packages --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8737a32..b061bfc 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ On gentoo: On Fedora: - $ sudo yum install lua-devel, openssl-devel, libconfig-devel, readline-devel + $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel Default Makefile uses liblua5.2 from ubuntu. If you use different version of liblua or linux you have to run ./configure script or you will get some strange compilation error. From 56896228dc8aef89fbb603c6bdfd8df364160def Mon Sep 17 00:00:00 2001 From: AdrocNiimai Date: Sun, 9 Feb 2014 11:39:11 +0100 Subject: [PATCH 257/465] Spanish translation of README.md --- README.es | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 README.es diff --git a/README.es b/README.es new file mode 100644 index 0000000..3e55662 --- /dev/null +++ b/README.es @@ -0,0 +1,142 @@ +## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) + +Interfaz de línea de comandos para: [Telegram](http://telegram.org). Uses readline interface. + +### Documentación del API y el protocolo + +La documentación del APi de Telegram está disponible aquí: http://core.telegram.org/api + +La documentación del protocolo MTproto está disponible aquí: http://core.telegram.org/mtproto + +### Instalación + +Clona el Repositorio GitHub + + $ git clone https://github.com/vysheng/tg.git && cd tg + +o descarga y descomprime el zip + + $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip + $ unzip tg-master.zip && cd tg-master + +#### Linux + +Librerías requeridas: readline openssl y (si desea usar config) libconfig y liblua. +Si no desea usarlo, pase las siguientes opciones --disable-libconfig y --disable-liblua respectivamente. + +En Ubuntu use: + + $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev + +En gentoo: + + $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua + +En Fedora: + + $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel + +Por defecto Makefile utiliza liblua5.2 de ubuntu. Si utiliza una versión diferente de liblua o linux que tiene que ejecutar el script ./configure o recibirá un error de compilación extraño. + +Entonces + + $ ./configure + $ make + + +#### Mac OS X + +El cliente depende de [librería readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) y [libconfig](http://www.hyperrealm.com/libconfig/), las cuales no están incluídas en OS X por defecto. Debe instalar estas librerías de forma manual, usando por ejemplo [Homebrew](http://brew.sh/). + + $ brew install libconfig + $ brew install readline + $ brew install lua + $ export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" + $ export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" + $ ./configure && make + +Gracias a [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) por esta solución. + +#### FreeBSD + +Instalar estos puertos: + +* devel/libconfig +* devel/libexecinfo + +Entonces construir: + + $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure + $ make + +#### Otros UNIX + +Si logras ejecutarlo en otros UNIX, por favor házmelo saber. + + +### Uso + + ./telegram -k + + +Por defecto la clave pública se almacena en la misma carpeta con el nombre tg.pub o en /etc/telegram/server.pub, si no lo es, indique dónde encontrarlo: + + ./telegram -k tg.pub + +El Cliente soporta completamiento con TAB e historial de comandos. + +Peer se refiere al nombre del contacto o de diálogo y se puede acceder por completamiento con Tab. +Para los contactos de usuario el peer es el Nombre Apellido con todos los espacios cambiados a guiones bajos. +Para los chats es su título con todos los espacios cambiados a guiones bajos. +Para los chats encriptados es Nombre Apellido con todos los espacios cambiados a guiones bajos. + +Si dos o más peers tienen el mismo nombre, una almohadilla yun número es añadido al nombre. (por ejemplo A_B,A_B#1,A_B#2 y así sucesivamente). + +### Comandos soportados + +#### Mensajería + + +* **msg** \ texto - envía el mensaje a este usuario. +* **fwd** \ \ - reenviar un mensaje al usuario. Puede ver los número de mensajes iniciando el Cliente con -N +* **chat_with_peer** \ - inicia un chat con este usuario. /exit o /quit para salir de este modo. +* **add_contact** \ \ \ - intenta añadir este contacto a la lista de contactos. +* **rename_contact** \ \ \ - intenta renombrar el contacto. Si tiene otro dispositivo será una pelea. +* **mark_read** \ - marca todos los mensajes como recibidos de ese usuario. + +#### Multimedia + +* **send_photo** \ \ - manda una foto al usuario. +* **send_video** \ \ - envia un video al usuario. +* **send_text** \ \ - envia un archivo de texto como un mensaje en plano. +* **load_photo**/load_video/load_video_thumb \ - carga foto/video indicado del directorio de descarga. +* **view_photo**/view_video/view_video_thumb \ - carga foto/video indicado del directorio de descarga y lo abre con el vidor por defecto del sistema. + + +#### Opciones de chat de grupo + +* **chat_info** \ - imprime información del chat. +* **chat_add_user** \ \ - agrega un usuario al chat. +* **chat_del_user** \ \ - elimina un usuario del chat. +* **rename_chat** \ \ - cambia el nombre al chat. + +#### Search + +* **search** \ patrón - busca el patrón indicado en los mensajes con ese usuario. +* **global_search** patrón - busca el patrón indicado en todos los mensajes. + +#### Chat secreto + +* **create_secret_chat** \ - crea un chat secreto con el usuario indicado. +* **visualize_key** \ - Muestra la clave de cifrado. Debe compararla con la del otro usuario. + +#### Estadísticas e información varia. + +* **user_info** \ - muestra información sobre el usuario. +* **history** \ [limit] - muestra el historial (y la marca como leído). Limite por defecto = 40. +* **dialog_list** - muestra información acerca del dialogo +* **contact_list** - muestra información acerca de tu lista de contactos. +* **suggested_contacts** - muestra información sobre sus contactos, tiene un máximo de amigos comunes. +* **stats** - solo para depuración. +* **show_license** - muestra la licencia GPLv2. +* **help** - imprime esta ayuda. From 48b538123a3e66ba7ea4163d55f2c2c1e047e3e7 Mon Sep 17 00:00:00 2001 From: AdrocNiimai Date: Sun, 9 Feb 2014 13:06:18 +0100 Subject: [PATCH 258/465] Complete translation and small typing errors corrected --- README.es | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.es b/README.es index 3e55662..944a2a9 100644 --- a/README.es +++ b/README.es @@ -1,6 +1,6 @@ ## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) -Interfaz de línea de comandos para: [Telegram](http://telegram.org). Uses readline interface. +Interfaz de línea de comandos para: [Telegram](http://telegram.org). Usa interfaz readline. ### Documentación del API y el protocolo @@ -22,9 +22,9 @@ o descarga y descomprime el zip #### Linux Librerías requeridas: readline openssl y (si desea usar config) libconfig y liblua. -Si no desea usarlo, pase las siguientes opciones --disable-libconfig y --disable-liblua respectivamente. +Si no deseas usarlo, pasa las siguientes opciones --disable-libconfig y --disable-liblua respectivamente. -En Ubuntu use: +En Ubuntu usa: $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev @@ -36,7 +36,7 @@ En Fedora: $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel -Por defecto Makefile utiliza liblua5.2 de ubuntu. Si utiliza una versión diferente de liblua o linux que tiene que ejecutar el script ./configure o recibirá un error de compilación extraño. +Por defecto Makefile utiliza liblua5.2 de ubuntu. Si utilizas una versión diferente de liblua o linux, tienes que ejecutar el script ./configure o recibirás un error de compilación extraño. Entonces @@ -46,7 +46,7 @@ Entonces #### Mac OS X -El cliente depende de [librería readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) y [libconfig](http://www.hyperrealm.com/libconfig/), las cuales no están incluídas en OS X por defecto. Debe instalar estas librerías de forma manual, usando por ejemplo [Homebrew](http://brew.sh/). +El cliente depende de [librería readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) y [libconfig](http://www.hyperrealm.com/libconfig/), las cuales no están incluídas en OS X por defecto. Debes instalar estas librerías de forma manual, usando por ejemplo [Homebrew](http://brew.sh/). $ brew install libconfig $ brew install readline @@ -79,7 +79,7 @@ Si logras ejecutarlo en otros UNIX, por favor házmelo saber. ./telegram -k -Por defecto la clave pública se almacena en la misma carpeta con el nombre tg.pub o en /etc/telegram/server.pub, si no lo es, indique dónde encontrarlo: +Por defecto la clave pública se almacena en la misma carpeta con el nombre tg.pub o en /etc/telegram/server.pub, si no lo es, indica dónde encontrarlo: ./telegram -k tg.pub @@ -90,7 +90,7 @@ Para los contactos de usuario el peer es el Nombre Apellido con to Para los chats es su título con todos los espacios cambiados a guiones bajos. Para los chats encriptados es Nombre Apellido con todos los espacios cambiados a guiones bajos. -Si dos o más peers tienen el mismo nombre, una almohadilla yun número es añadido al nombre. (por ejemplo A_B,A_B#1,A_B#2 y así sucesivamente). +Si dos o más peers tienen el mismo nombre, una almohadilla y un número es añadido al nombre. (por ejemplo A_B,A_B#1,A_B#2 y así sucesivamente). ### Comandos soportados @@ -98,10 +98,10 @@ Si dos o más peers tienen el mismo nombre, una almohadilla yun número es añad * **msg** \ texto - envía el mensaje a este usuario. -* **fwd** \ \ - reenviar un mensaje al usuario. Puede ver los número de mensajes iniciando el Cliente con -N +* **fwd** \ \ - reenviar un mensaje al usuario. Puedes ver los número de mensajes iniciando el Cliente con -N. * **chat_with_peer** \ - inicia un chat con este usuario. /exit o /quit para salir de este modo. * **add_contact** \ \ \ - intenta añadir este contacto a la lista de contactos. -* **rename_contact** \ \ \ - intenta renombrar el contacto. Si tiene otro dispositivo será una pelea. +* **rename_contact** \ \ \ - intenta renombrar el contacto. Si tienes otro dispositivo será una pelea. * **mark_read** \ - marca todos los mensajes como recibidos de ese usuario. #### Multimedia @@ -110,7 +110,7 @@ Si dos o más peers tienen el mismo nombre, una almohadilla yun número es añad * **send_video** \ \ - envia un video al usuario. * **send_text** \ \ - envia un archivo de texto como un mensaje en plano. * **load_photo**/load_video/load_video_thumb \ - carga foto/video indicado del directorio de descarga. -* **view_photo**/view_video/view_video_thumb \ - carga foto/video indicado del directorio de descarga y lo abre con el vidor por defecto del sistema. +* **view_photo**/view_video/view_video_thumb \ - carga foto/video indicado del directorio de descarga y lo abre con el visor por defecto del sistema. #### Opciones de chat de grupo @@ -128,7 +128,7 @@ Si dos o más peers tienen el mismo nombre, una almohadilla yun número es añad #### Chat secreto * **create_secret_chat** \ - crea un chat secreto con el usuario indicado. -* **visualize_key** \ - Muestra la clave de cifrado. Debe compararla con la del otro usuario. +* **visualize_key** \ - Muestra la clave de cifrado. Debes compararla con la del otro usuario. #### Estadísticas e información varia. From 5baaabdd8aab21d660fa93ed428b965dcdcca5f0 Mon Sep 17 00:00:00 2001 From: Falk Date: Thu, 13 Feb 2014 00:52:25 +0100 Subject: [PATCH 259/465] Update interface.c to avoid error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When hitting enter (without writing anything) in an chat prompt always appears an error message telling you that the message is empty. Checking the content of the line can avoid this. I don't know is this behaviour is wrong or right. So please forgive me if it doesn’t make sense. --- interface.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index c6ffc67..59af7b2 100644 --- a/interface.c +++ b/interface.c @@ -576,7 +576,9 @@ void interpreter_chat_mode (char *line) { do_mark_read (chat_mode_id); return; } - do_send_message (chat_mode_id, line, strlen (line)); + if (strlen (line)>0) { + do_send_message (chat_mode_id, line, strlen (line)); + } } void interpreter (char *line UU) { From 0b90256a8b887e13dd324d85b63c4cc5be7d4d44 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Tue, 18 Feb 2014 22:59:18 +0800 Subject: [PATCH 260/465] Update FreeBSD build instruction for linking with lua --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b061bfc..0818a6e 100644 --- a/README.md +++ b/README.md @@ -61,10 +61,11 @@ Install these ports: * devel/libconfig * devel/libexecinfo +* lang/lua52 Then build: - $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure + $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure $ make #### Other UNIX From 8c597b293502c75d367b8e0b43500a0d0e730e79 Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 18 Feb 2014 21:06:00 +0300 Subject: [PATCH 261/465] Update interface.c --- interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface.c b/interface.c index 59af7b2..b387e1f 100644 --- a/interface.c +++ b/interface.c @@ -1338,7 +1338,7 @@ void print_encr_chat_name_full (peer_id_t id, peer_t *C) { static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; void print_date (long t) { - struct tm *tm = localtime (&t); + struct tm *tm = localtime ((void *)&t); if (time (0) - t < 12 * 60 * 60) { printf ("[%02d:%02d] ", tm->tm_hour, tm->tm_min); } else { @@ -1347,7 +1347,7 @@ void print_date (long t) { } void print_date_full (long t) { - struct tm *tm = localtime (&t); + struct tm *tm = localtime ((void *)&t); printf ("[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } From b94d64bd19b0a5daa583c071c8240c9faa824b39 Mon Sep 17 00:00:00 2001 From: Kartik Mistry Date: Thu, 20 Feb 2014 13:23:23 +0530 Subject: [PATCH 262/465] Added .gitignore file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e69de29..5761abc 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +*.o From 59b3d7e0c23a35036b025b3b808155eab6c11e0e Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 21 Feb 2014 14:23:37 +0300 Subject: [PATCH 263/465] Update interface.c --- interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.c b/interface.c index b387e1f..3f2067d 100644 --- a/interface.c +++ b/interface.c @@ -878,7 +878,7 @@ void interpreter (char *line UU) { "chat_info - prints info about chat\n" "user_info - prints info about user\n" "fwd - forward message to user. You can see message numbers starting client with -N\n" - "rename_chat \n" + "rename_chat \n" "load_photo/load_video/load_video_thumb - loads photo/video to download dir. You can see message numbers starting client with -N\n" "view_photo/view_video/view_video_thumb - loads photo/video to download dir and starts system default viewer. You can see message numbers starting client with -N\n" "show_license - prints contents of GPLv2\n" From 39cee4b6626fbb459cdc720436cc7d3e435f078e Mon Sep 17 00:00:00 2001 From: Anders Iver Gjermo Date: Sun, 23 Feb 2014 02:06:57 +0100 Subject: [PATCH 264/465] catch NULL input in interpreter_chat_mode --- interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 3f2067d..a7b468c 100644 --- a/interface.c +++ b/interface.c @@ -560,7 +560,8 @@ void work_modifier (const char *s, int l) { void interpreter_chat_mode (char *line) { - if (!strncmp (line, "/exit", 5) || !strncmp (line, "/quit", 5)) { + if (line == NULL || /* EOF received */ + !strncmp (line, "/exit", 5) || !strncmp (line, "/quit", 5)) { in_chat_mode = 0; update_prompt (); return; From 046b0ce10953250f6058b8e2454ed4ed1429670a Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Mon, 24 Feb 2014 07:59:20 +0100 Subject: [PATCH 265/465] Fully working phone call support, might need some tweaks and checks --- loop.c | 16 ++++++++++++++-- queries.c | 32 ++++++++++++++++++++++++++++++++ queries.h | 1 + 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/loop.c b/loop.c index be76da8..3cce8e3 100644 --- a/loop.c +++ b/loop.c @@ -517,12 +517,18 @@ int loop (void) { do_send_code (default_username); char *code = 0; size_t size = 0; - printf ("Code from sms: "); + printf ("Code from sms (if you did not receive an SMS and want to be called, type 0): "); while (1) { if (net_getline (&code, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } + if (*code == '0') { + printf ("You typed 0, switching to phone system.\n"); + do_phone_call (default_username); + printf ("Calling you! Code: "); + continue; + } if (do_send_code_result (code) >= 0) { break; } @@ -563,12 +569,18 @@ int loop (void) { DC_working = DC_list[dc_working_num]; do_send_code (default_username); - printf ("Code from sms: "); + printf ("Code from sms (if you did not receive an SMS and want to be called, type 0): "); while (1) { if (net_getline (&code, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } + if (*code == '0') { + printf ("You typed 0, switching to phone system.\n"); + do_phone_call (default_username); + printf ("Calling you! Code: "); + continue; + } if (do_send_code_result_auth (code, first_name, last_name) >= 0) { break; } diff --git a/queries.c b/queries.c index 633f601..f7aa8e3 100644 --- a/queries.c +++ b/queries.c @@ -468,6 +468,38 @@ void do_send_code (const char *user) { net_loop (0, code_is_sent); assert (want_dc_num == -1); } + + +int phone_call_on_answer (struct query *q UU) { + fetch_bool (); + assert(1); + return 0; +} + +int phone_call_on_error (struct query *q UU, int error_code, int l, char *error) { + logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); + assert (0); + return 0; +} + +struct query_methods phone_call_methods = { + .on_answer = phone_call_on_answer, + .on_error = phone_call_on_error +}; + +void do_phone_call (const char *user) { + logprintf ("calling user\n"); + suser = tstrdup (user); + want_dc_num = 0; + clear_packet (); + do_insert_header (); + out_int (CODE_auth_send_call); + out_string (user); + out_string (phone_code_hash); + + logprintf ("do_phone_call: dc_num = %d\n", dc_working_num); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &phone_call_methods, 0); +} /* }}} */ /* {{{ Check phone */ diff --git a/queries.h b/queries.h index d631cd4..17c1e74 100644 --- a/queries.h +++ b/queries.h @@ -64,6 +64,7 @@ void work_timers (void); extern struct query_methods help_get_config_methods; void do_send_code (const char *user); +void do_phone_call (const char *user); int do_send_code_result (const char *code); double get_double_time (void); From b8d827ed59b8f3b94ee0bad2aa7c197c4f4a3bf0 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 24 Feb 2014 15:27:30 +0400 Subject: [PATCH 266/465] Fixed 'call' method from jerbob92 --- Makefile | 4 ++-- loop.c | 8 ++++---- queries.c | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 014677c..bc91bb0 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ srcdir=. -CFLAGS=-g -O2 +CFLAGS=-g -O2 -I/usr/include/lua5.2 LDFLAGS= CPPFLAGS= DEFS=-DHAVE_CONFIG_H COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -EXTRA_LIBS=-lconfig -lcrypto -lz -lrt -lm -lreadline -llua +EXTRA_LIBS=-lconfig -lcrypto -lz -lm -lreadline -llua5.2 -ldl LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} diff --git a/loop.c b/loop.c index 3cce8e3..fe2c211 100644 --- a/loop.c +++ b/loop.c @@ -517,13 +517,13 @@ int loop (void) { do_send_code (default_username); char *code = 0; size_t size = 0; - printf ("Code from sms (if you did not receive an SMS and want to be called, type 0): "); + printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); while (1) { if (net_getline (&code, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } - if (*code == '0') { + if (!strcmp (code, "call")) { printf ("You typed 0, switching to phone system.\n"); do_phone_call (default_username); printf ("Calling you! Code: "); @@ -569,13 +569,13 @@ int loop (void) { DC_working = DC_list[dc_working_num]; do_send_code (default_username); - printf ("Code from sms (if you did not receive an SMS and want to be called, type 0): "); + printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); while (1) { if (net_getline (&code, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } - if (*code == '0') { + if (!strcmp (code, "call")) { printf ("You typed 0, switching to phone system.\n"); do_phone_call (default_username); printf ("Calling you! Code: "); diff --git a/queries.c b/queries.c index f7aa8e3..426a5d5 100644 --- a/queries.c +++ b/queries.c @@ -472,7 +472,6 @@ void do_send_code (const char *user) { int phone_call_on_answer (struct query *q UU) { fetch_bool (); - assert(1); return 0; } From aad11804a9176fcf650f35e3291202441d08ffa6 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 25 Feb 2014 14:11:37 +0100 Subject: [PATCH 267/465] Removed "-Wno-deprecated" from COMPILE_FLAGS This feature is new to GCC 4.4, while OpenBSD uses 4.2.1 --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 23a97dc..818c4fc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} From cba02b3fd5b3fd1d61eda0a51ba226ae258ec6c2 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 25 Feb 2014 16:33:29 +0100 Subject: [PATCH 268/465] Stop tracking generated files * files, generated as side-effect of running ``configure'' script, * files, generated by ``configure'' script (Makefile, config.h), * ``telegram'' binary. All these files are setup-dependent and differ between targets. --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 5761abc..09500b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ *.o +Makefile +autom4te.cache +config.h +config.log +config.status +telegram From 32c6b6a3b3a3c41fa134084ab4212224a67d3fc1 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 25 Feb 2014 14:44:26 +0100 Subject: [PATCH 269/465] Don't tracked Makefile and config.h Both files are generated by ``configure'' script. Given that they: 1. may change after running ``configure'' and 2. are setup-dependent there's no need to track them anyway. --- Makefile | 35 ----------- config.h | 178 ------------------------------------------------------- 2 files changed, 213 deletions(-) delete mode 100644 Makefile delete mode 100644 config.h diff --git a/Makefile b/Makefile deleted file mode 100644 index bc91bb0..0000000 --- a/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -srcdir=. - -CFLAGS=-g -O2 -I/usr/include/lua5.2 -LDFLAGS= -CPPFLAGS= -DEFS=-DHAVE_CONFIG_H -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb - -EXTRA_LIBS=-lconfig -lcrypto -lz -lm -lreadline -llua5.2 -ldl -LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} -LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} - -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h -INCLUDE=-I. -I${srcdir} -CC=gcc -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o - -.SUFFIXES: - -.SUFFIXES: .c .h .o - -all: telegram - -${OBJECTS}: ${HEADERS} - -telegram: ${OBJECTS} - ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ - -.c.o : - ${CC} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ - - -clean: - rm -rf *.o telegram config.log config.status > /dev/null || echo "all clean" - diff --git a/config.h b/config.h deleted file mode 100644 index 5f54b0c..0000000 --- a/config.h +++ /dev/null @@ -1,178 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the `alarm' function. */ -#define HAVE_ALARM 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ARPA_INET_H 1 - -/* Define to 1 if you have the `endpwent' function. */ -#define HAVE_ENDPWENT 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_EXECINFO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LAUXLIB_H 1 - -/* Define to 1 if you have the `config' library (-lconfig). */ -#define HAVE_LIBCONFIG 1 - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -#define HAVE_LIBCRYPTO 1 - -/* Define to 1 if you have the `edit' library (-ledit). */ -/* #undef HAVE_LIBEDIT */ - -/* Define to 1 if you have the `m' library (-lm). */ -#define HAVE_LIBM 1 - -/* Define to 1 if you have the `z' library (-lz). */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LUACONF_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LUALIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LUA_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MACH_MACH_H */ - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MALLOC_H 1 - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETDB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#define HAVE_REALLOC 1 - -/* Define to 1 if you have the `select' function. */ -#define HAVE_SELECT 1 - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strndup' function. */ -#define HAVE_STRNDUP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_FILE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_TERMIOS_H 1 - -/* Define to 1 if you have the `uname' function. */ -#define HAVE_UNAME 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "telegram" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "telegram 0.1" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "telegram" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.1" - -/* Use custom prog name */ -/* #undef PROG_NAME */ - -/* Use libedit */ -/* #undef READLINE_EDIT */ - -/* Use gnu libreadline */ -#define READLINE_GNU 1 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* use lua */ -#define USE_LUA 1 - -/* Define to `int' if doesn't define. */ -/* #undef gid_t */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to rpl_malloc if the replacement function should be used. */ -/* #undef malloc */ - -/* Define to rpl_realloc if the replacement function should be used. */ -/* #undef realloc */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ - -/* Define to `int' if doesn't define. */ -/* #undef uid_t */ From 333f48e82692b14884d582e478a1854de6038f26 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 25 Feb 2014 15:25:57 +0100 Subject: [PATCH 270/465] Added support for OpenBSD --- mtproto-client.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 19c9a9c..6ea6def 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -31,7 +31,7 @@ #include #include #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) #include #endif #include @@ -58,6 +58,10 @@ #define __builtin_bswap32(x) bswap32(x) #endif +#if defined(__OpenBSD__) +#define __builtin_bswap32(x) __swap32gen(x) +#endif + #define sha1 SHA1 #include "mtproto-common.h" @@ -1720,7 +1724,7 @@ int rpc_execute (struct connection *c, int op, int len) { logprintf ( "have %d Response bytes\n", Response_len); } -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif int o = c_state; @@ -1728,19 +1732,19 @@ int rpc_execute (struct connection *c, int op, int len) { switch (o) { case st_reqpq_sent: process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; case st_reqdh_sent: process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; case st_client_dh_sent: process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; @@ -1750,7 +1754,7 @@ int rpc_execute (struct connection *c, int op, int len) { } else { process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); } -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif return 0; @@ -1778,7 +1782,7 @@ int tc_becomes_ready (struct connection *c) { assert (write_out (c, &byte, 1) == 1); flush_out (c); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined (__CYGWIN__) +#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif int o = c_state; From 7db28cf9f4aaffa4bee93e4d47af16bdbffaba5e Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 25 Feb 2014 16:45:50 +0100 Subject: [PATCH 271/465] Update ax_lua.m4 Updated ax_lua.m4 to current version from GNU Autoconf Archive's git repository with additional patch to support OpenBSD.[1] Regenerated ``configure'' script. DOcumented changes. --- [1] https://savannah.gnu.org/patch/index.php?8355 --- README.md | 15 ++++++++++++++- ax_lua.m4 | 25 ++++++++++++++++--------- configure | 29 ++++++++++++++++++++--------- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 0818a6e..4c8375d 100644 --- a/README.md +++ b/README.md @@ -65,9 +65,22 @@ Install these ports: Then build: - $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure + $ env CC=clang CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure $ make +#### OpenBSD + +Install these packages (or *ports*): + +* libconfig (*devel/libconfig*) +* libexecinfo (*devel/libexecinfo*) +* lua >= 5.2 (*lang/lua/5.2*) + +Then build: + + $ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ./configure + $ make + #### Other UNIX If you manage to launch it on other UNIX, please let me know. diff --git a/ax_lua.m4 b/ax_lua.m4 index c6f5974..d9f4773 100644 --- a/ax_lua.m4 +++ b/ax_lua.m4 @@ -109,6 +109,7 @@ # * /usr/include/lua/X.Y # * /usr/include/luaXY # * /usr/local/include/luaX.Y +# * /usr/local/include/lua-X.Y # * /usr/local/include/lua/X.Y # * /usr/local/include/luaXY # @@ -182,7 +183,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 20 +#serial 21 dnl ========================================================================= dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION], @@ -195,7 +196,7 @@ AC_DEFUN([AX_PROG_LUA], dnl Find a Lua interpreter. m4_define_default([_AX_LUA_INTERPRETER_LIST], - [lua lua5.2 lua5.1 lua50]) + [lua lua5.2 lua52 lua5.1 lua51 lua50]) m4_if([$1], [], [ dnl No version check is needed. Find any Lua interpreter. @@ -259,7 +260,7 @@ AC_DEFUN([AX_PROG_LUA], AC_CACHE_CHECK([for $ax_display_LUA version], [ax_cv_lua_version], [ ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ sed "s|^Lua \(.*\)|\1|" | \ - grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"` + grep -E -o "^@<:@0-9@:>@+\.@<:@0-9@:>@+"` ]) AS_IF([test "x$ax_cv_lua_version" = 'x'], [AC_MSG_ERROR([invalid Lua version number])]) @@ -364,7 +365,7 @@ dnl ========================================================================= AC_DEFUN([_AX_LUA_CHK_VER], [ _ax_test_ver=`$1 -e "print(_VERSION)" 2>/dev/null | \ - sed "s|^Lua \(.*\)|\1|" | grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"` + sed "s|^Lua \(.*\)|\1|" | grep -E -o "^@<:@0-9@:>@+\.@<:@0-9@:>@+"` AS_IF([test "x$_ax_test_ver" = 'x'], [_ax_test_ver='0']) AX_COMPARE_VERSION([$_ax_test_ver], [ge], [$2]) @@ -431,6 +432,7 @@ AC_DEFUN([AX_LUA_HEADERS], /usr/include/lua/$LUA_VERSION \ /usr/include/lua$LUA_SHORT_VERSION \ /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua-$LUA_VERSION \ /usr/local/include/lua/$LUA_VERSION \ /usr/local/include/lua$LUA_SHORT_VERSION \ ]) @@ -490,7 +492,7 @@ int main(int argc, char ** argv) ], [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ sed "s|^Lua \(.*\)|\1|" | \ - grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"` + grep -E -o "^@<:@0-9@:>@+\.@<:@0-9@:>@+"` ], [ax_cv_lua_header_version='unknown']) CPPFLAGS=$_ax_lua_saved_cppflags @@ -575,10 +577,15 @@ AC_DEFUN([AX_LUA_LIBS], dnl Try to find the Lua libs. _ax_lua_saved_libs=$LIBS LIBS="$LIBS $LUA_LIB" - AC_SEARCH_LIBS([lua_load], [lua$LUA_VERSION lua$LUA_SHORT_VERSION lua], - [_ax_found_lua_libs='yes'], - [_ax_found_lua_libs='no'], - [$_ax_lua_extra_libs]) + AC_SEARCH_LIBS([lua_load], + [ lua$LUA_VERSION \ + lua$LUA_SHORT_VERSION \ + lua-$LUA_VERSION \ + lua-$LUA_SHORT_VERSION \ + lua], + [_ax_found_lua_libs='yes'], + [_ax_found_lua_libs='no'], + [$_ax_lua_extra_libs]) LIBS=$_ax_lua_saved_libs AS_IF([test "x$ac_cv_search_lua_load" != 'xno' && diff --git a/configure b/configure index dd2e8ef..0b1cb9b 100755 --- a/configure +++ b/configure @@ -2279,6 +2279,7 @@ ac_config_headers="$ac_config_headers config.h" # * /usr/include/lua/X.Y # * /usr/include/luaXY # * /usr/local/include/luaX.Y +# * /usr/local/include/lua-X.Y # * /usr/local/include/lua/X.Y # * /usr/local/include/luaXY # @@ -2352,7 +2353,7 @@ ac_config_headers="$ac_config_headers config.h" # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 20 +#serial 21 @@ -4049,7 +4050,7 @@ $as_echo "enabled" >&6; } if test "x$LUA" = 'x'; then : - for ac_prog in lua lua5.2 lua5.1 lua50 + for ac_prog in lua lua5.2 lua52 lua5.1 lua51 lua50 do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -4126,7 +4127,7 @@ if ${ax_cv_lua_version+:} false; then : else ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ sed "s|^Lua \(.*\)|\1|" | \ - grep -o "^[0-9]\+\\.[0-9]\+"` + grep -E -o "^[0-9]+\.[0-9]+"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_version" >&5 @@ -4290,6 +4291,7 @@ done /usr/include/lua/$LUA_VERSION \ /usr/include/lua$LUA_SHORT_VERSION \ /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua-$LUA_VERSION \ /usr/local/include/lua/$LUA_VERSION \ /usr/local/include/lua$LUA_SHORT_VERSION \ ; do @@ -4363,7 +4365,7 @@ _ACEOF if ac_fn_c_try_run "$LINENO"; then : ax_cv_lua_header_version=`./conftest$EXEEXT p | \ sed "s|^Lua \(.*\)|\1|" | \ - grep -o "^[0-9]\+\\.[0-9]\+"` + grep -E -o "^[0-9]+\.[0-9]+"` else ax_cv_lua_header_version='unknown' @@ -4643,7 +4645,11 @@ return lua_load (); return 0; } _ACEOF -for ac_lib in '' lua$LUA_VERSION lua$LUA_SHORT_VERSION lua; do +for ac_lib in '' lua$LUA_VERSION \ + lua$LUA_SHORT_VERSION \ + lua-$LUA_VERSION \ + lua-$LUA_SHORT_VERSION \ + lua; do if test -z "$ac_lib"; then ac_res="none required" else @@ -4713,7 +4719,7 @@ $as_echo "enabled" >&6; } if test "x$LUA" = 'x'; then : - for ac_prog in lua lua5.2 lua5.1 lua50 + for ac_prog in lua lua5.2 lua52 lua5.1 lua51 lua50 do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -4790,7 +4796,7 @@ if ${ax_cv_lua_version+:} false; then : else ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ sed "s|^Lua \(.*\)|\1|" | \ - grep -o "^[0-9]\+\\.[0-9]\+"` + grep -E -o "^[0-9]+\.[0-9]+"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_version" >&5 @@ -4954,6 +4960,7 @@ done /usr/include/lua/$LUA_VERSION \ /usr/include/lua$LUA_SHORT_VERSION \ /usr/local/include/lua$LUA_VERSION \ + /usr/local/include/lua-$LUA_VERSION \ /usr/local/include/lua/$LUA_VERSION \ /usr/local/include/lua$LUA_SHORT_VERSION \ ; do @@ -5027,7 +5034,7 @@ _ACEOF if ac_fn_c_try_run "$LINENO"; then : ax_cv_lua_header_version=`./conftest$EXEEXT p | \ sed "s|^Lua \(.*\)|\1|" | \ - grep -o "^[0-9]\+\\.[0-9]\+"` + grep -E -o "^[0-9]+\.[0-9]+"` else ax_cv_lua_header_version='unknown' @@ -5307,7 +5314,11 @@ return lua_load (); return 0; } _ACEOF -for ac_lib in '' lua$LUA_VERSION lua$LUA_SHORT_VERSION lua; do +for ac_lib in '' lua$LUA_VERSION \ + lua$LUA_SHORT_VERSION \ + lua-$LUA_VERSION \ + lua-$LUA_SHORT_VERSION \ + lua; do if test -z "$ac_lib"; then ac_res="none required" else From b0b1e394130ef3cbe1c4842300688083bcd1784f Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 25 Feb 2014 16:57:35 +0100 Subject: [PATCH 272/465] On OpenBSD `telegram` should be linked with '-lcurses' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c8375d..232ec0f 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Install these packages (or *ports*): Then build: - $ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ./configure + $ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" LIBS="-lcurses" ./configure $ make #### Other UNIX From a76d6337050f78f100d0b9df774e801d1f2827f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Tue, 25 Feb 2014 21:09:59 +0100 Subject: [PATCH 273/465] Added command create_group_chat . Currently it supports only 1 user on creation. Use chat_add_user to add more users to the chat. --- README.md | 1 + interface.c | 12 ++++++++++++ queries.c | 30 ++++++++++++++++++++++++++++++ queries.h | 1 + 4 files changed, 44 insertions(+) diff --git a/README.md b/README.md index 0818a6e..59580a8 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ If two or more peers have same name, number is appended to the name. (for * **chat_add_user** \ \ - add user to chat * **chat_del_user** \ \ - remove user from chat * **rename_chat** \ \ +* **create_group_chat** \ \ - creates a groupchat with user, use chat_add_user to add more users #### Search diff --git a/interface.c b/interface.c index a7b468c..4a70849 100644 --- a/interface.c +++ b/interface.c @@ -322,6 +322,7 @@ char *commands[] = { "chat_with_peer", "delete_msg", "restore_msg", + "create_group_chat", 0 }; int commands_flags[] = { @@ -371,6 +372,7 @@ int commands_flags[] = { 07, 072, 07, + 072, 07 }; @@ -888,6 +890,7 @@ void interpreter (char *line UU) { "mark_read - mark read all received messages with peer\n" "add_contact - tries to add contact to contact-list by phone\n" "create_secret_chat - creates secret chat with this user\n" + "create_group_chat - creates group chat with this user, add more users with chat_add_user \n" "rename_contact - tries to rename contact. If you have another device it will be a fight\n" "suggested_contacts - print info about contacts, you have max common friends\n" "visualize_key - prints visualization of encryption key. You should compare it to your partner's one\n" @@ -938,6 +941,15 @@ void interpreter (char *line UU) { } else if (IS_WORD ("create_secret_chat")) { GET_PEER; do_create_secret_chat (id); + } else if (IS_WORD ("create_group_chat")) { + GET_PEER; + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty chat topic\n"); + RET; + } + do_create_group_chat (id, s); } else if (IS_WORD ("suggested_contacts")) { do_get_suggested (); } else if (IS_WORD ("status_online")) { diff --git a/queries.c b/queries.c index 426a5d5..e7ad64e 100644 --- a/queries.c +++ b/queries.c @@ -2784,6 +2784,36 @@ void do_create_secret_chat (peer_id_t id) { } /* }}} */ +/* {{{ Create group chat */ +struct query_methods create_group_chat_methods = { + .on_answer = fwd_msg_on_answer +}; + +void do_create_group_chat (peer_id_t id, char *chat_topic) { + assert (get_peer_type (id) == PEER_USER); + peer_t *U = user_chat_get (id); + if (!U) { + rprintf ("Can not create chat with unknown user\n"); + return; + } + clear_packet (); + out_int (CODE_messages_create_chat); + out_int (CODE_vector); + out_int (1); // Number of users, currently we support only 1 user. + if (U && U->user.access_hash) { + out_int (CODE_input_user_foreign); + out_int (get_peer_id (id)); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_user_contact); + out_int (get_peer_id (id)); + } + out_string (chat_topic); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &create_group_chat_methods, 0); +} +/* }}} */ + + /* {{{ Delete msg */ int delete_msg_on_answer (struct query *q UU) { diff --git a/queries.h b/queries.h index 17c1e74..afcc64e 100644 --- a/queries.h +++ b/queries.h @@ -84,6 +84,7 @@ void do_rename_chat (peer_id_t id, char *name); void do_load_encr_video (struct encr_video *V, int next); void do_create_encr_chat_request (int user_id); void do_create_secret_chat (peer_id_t id); +void do_create_group_chat (peer_id_t id, char *chat_topic); void do_get_suggested (void); struct photo; From c9116d55f108d6f0750ccf34665c5b7d85a336af Mon Sep 17 00:00:00 2001 From: vysheng Date: Tue, 25 Feb 2014 23:31:27 +0300 Subject: [PATCH 274/465] Update loop.c --- loop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loop.c b/loop.c index fe2c211..1ed78e5 100644 --- a/loop.c +++ b/loop.c @@ -524,7 +524,7 @@ int loop (void) { exit (EXIT_FAILURE); } if (!strcmp (code, "call")) { - printf ("You typed 0, switching to phone system.\n"); + printf ("You typed \"call\", switching to phone system.\n"); do_phone_call (default_username); printf ("Calling you! Code: "); continue; @@ -576,7 +576,7 @@ int loop (void) { exit (EXIT_FAILURE); } if (!strcmp (code, "call")) { - printf ("You typed 0, switching to phone system.\n"); + printf ("You typed \"call\", switching to phone system.\n"); do_phone_call (default_username); printf ("Calling you! Code: "); continue; From e57ccb05411e0e7c43dbcf86aebc45f991c22ca0 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Wed, 26 Feb 2014 10:15:35 +0100 Subject: [PATCH 275/465] Added "-Wno-deprecated-declarations" to COMPILE_FLAGS --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 818c4fc..200252c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} From 9e6efc5fa7df9aafbd59c8d266d44e2a8bb437a7 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Thu, 27 Feb 2014 00:46:44 +0100 Subject: [PATCH 276/465] When using libedit also search for curses --- README.md | 2 +- configure | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 232ec0f..4c8375d 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Install these packages (or *ports*): Then build: - $ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" LIBS="-lcurses" ./configure + $ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ./configure $ make #### Other UNIX diff --git a/configure b/configure index 0b1cb9b..e774e18 100755 --- a/configure +++ b/configure @@ -3467,6 +3467,62 @@ $as_echo "#define READLINE_GNU 1" >>confdefs.h else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetnum" >&5 +$as_echo_n "checking for library containing tgetnum... " >&6; } +if ${ac_cv_search_tgetnum+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char tgetnum (); +int +main () +{ +return tgetnum (); + ; + return 0; +} +_ACEOF +for ac_lib in '' ncursesw ncurses curses; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_tgetnum=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_tgetnum+:} false; then : + break +fi +done +if ${ac_cv_search_tgetnum+:} false; then : + +else + ac_cv_search_tgetnum=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetnum" >&5 +$as_echo "$ac_cv_search_tgetnum" >&6; } +ac_res=$ac_cv_search_tgetnum +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_set_prompt in -ledit" >&5 $as_echo_n "checking for rl_set_prompt in -ledit... " >&6; } if ${ac_cv_lib_edit_rl_set_prompt+:} false; then : diff --git a/configure.ac b/configure.ac index f17039d..f3cf689 100644 --- a/configure.ac +++ b/configure.ac @@ -22,6 +22,7 @@ AC_CHECK_LIB([readline], [rl_save_prompt], [ EXTRA_LIBS="${EXTRA_LIBS} -lreadline" ; ] ], [ + AC_SEARCH_LIBS([tgetnum], [ncursesw ncurses curses]) AC_CHECK_LIB([edit], [rl_set_prompt]) AC_DEFINE([READLINE_EDIT], [1], [Use libedit]) [ EXTRA_LIBS="${EXTRA_LIBS} -ledit" ; ] From 218048576c20effef5d20922568bb9ec733c8d17 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Thu, 27 Feb 2014 00:52:30 +0100 Subject: [PATCH 277/465] LUA_INCLUDE belongs to CPPFLAGS, not CFLAGS --- configure | 4 ++-- configure.ac | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index e774e18..a8fbb6a 100755 --- a/configure +++ b/configure @@ -4755,7 +4755,7 @@ else fi EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; - CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; + CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; $as_echo "#define USE_LUA 1" >>confdefs.h @@ -5424,7 +5424,7 @@ else fi EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; - CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; + CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; $as_echo "#define USE_LUA 1" >>confdefs.h diff --git a/configure.ac b/configure.ac index f3cf689..61465b0 100644 --- a/configure.ac +++ b/configure.ac @@ -55,7 +55,7 @@ AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] - [CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; ] + [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] AC_DEFINE(USE_LUA,1,[use lua]) ], [ @@ -69,7 +69,7 @@ AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] - [CFLAGS="${CFLAGS} ${LUA_INCLUDE}" ; ] + [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] AC_DEFINE(USE_LUA,1,[use lua]) ], [ From 839e535f731e65ae597ec85bb0ed02419bcda680 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Thu, 27 Feb 2014 01:06:44 +0100 Subject: [PATCH 278/465] Add /usr/local/include and /usr/local/lib to CPPFLAGS and LDFLAGS This allows to avoid extra options for BSDs and strangle Linux systems, where some libraries may be installed under "/usr/local" prefix. --- configure | 4 ++++ configure.ac | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/configure b/configure index a8fbb6a..0a54e9f 100755 --- a/configure +++ b/configure @@ -3171,6 +3171,10 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu +# BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff. +CPPFLAGS="$CPPFLAGS -I/usr/local/include" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + # Checks for libraries. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 diff --git a/configure.ac b/configure.ac index 61465b0..6b0f5d7 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,10 @@ m4_include([ax_lua.m4]) # Checks for programs. AC_PROG_CC +# BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff. +CPPFLAGS="$CPPFLAGS -I/usr/local/include" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + # Checks for libraries. AC_CHECK_LIB([m], [sqrt]) AC_SEARCH_LIBS([clock_gettime], [rt]) From 926a97fe08556effb5cff414eeca7fc9d42e8e87 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Thu, 27 Feb 2014 01:09:56 +0100 Subject: [PATCH 279/465] Clean up and merge Linux and BSD instructions * Now BSDs don't require setting environment for configure. * No default Makefile any more. --- README.md | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 4c8375d..748d6e3 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,15 @@ or download and extract zip $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip $ unzip tg-master.zip && cd tg-master -#### Linux +#### Linux and BSDs + +Install libs: readline or libedit, openssl and (if you want to use config) libconfig and liblua. +If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively. -Install libs: readline openssl and (if you want to use config) libconfig and liblua. -If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively On ubuntu use: $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev + On gentoo: $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua @@ -34,7 +36,13 @@ On Fedora: $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel -Default Makefile uses liblua5.2 from ubuntu. If you use different version of liblua or linux you have to run ./configure script or you will get some strange compilation error. +On FreeBSD: + + $ pkg install libconfig libexecinfo lua52 + +On OpenBSD: + + $ pkg_add libconfig libexecinfo lua Then @@ -55,31 +63,6 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. -#### FreeBSD - -Install these ports: - -* devel/libconfig -* devel/libexecinfo -* lang/lua52 - -Then build: - - $ env CC=clang CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure - $ make - -#### OpenBSD - -Install these packages (or *ports*): - -* libconfig (*devel/libconfig*) -* libexecinfo (*devel/libexecinfo*) -* lua >= 5.2 (*lang/lua/5.2*) - -Then build: - - $ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ./configure - $ make #### Other UNIX From 625d30c375028c2e133acd4a1edcb956bb613367 Mon Sep 17 00:00:00 2001 From: vcuculo Date: Thu, 27 Feb 2014 09:48:05 +0100 Subject: [PATCH 280/465] added support to sound notifications --- interface.c | 15 ++++++++++++++- interface.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 4a70849..b692ae3 100644 --- a/interface.c +++ b/interface.c @@ -51,6 +51,7 @@ char *default_prompt = "> "; int unread_messages; int msg_num_mode; +int alert_sound; int safe_quit; @@ -901,6 +902,7 @@ void interpreter (char *line UU) { "\t\tLevel 2: prints line, when somebody is typing in chat\n" "\t\tLevel 3: prints line, when somebody changes online status\n" "\tmsg_num - enables/disables numeration of messages\n" + "\talert - enables/disables alert sound notifications\n" "chat_with_peer - starts chat with this peer. Every command after is message to this peer. Type /exit or /quit to end this mode\n" ); pop_color (); @@ -1081,6 +1083,8 @@ void interpreter (char *line UU) { log_level = num; } else if (IS_WORD ("msg_num")) { msg_num_mode = num; + } else if (IS_WORD ("alert")) { + alert_sound = num; } } else if (IS_WORD ("chat_with_peer")) { GET_PEER; @@ -1483,6 +1487,9 @@ void print_message (struct message *M) { } else { printf (" »»» "); } + if (alert_sound) { + play_sound(); + } } } else if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { peer_t *P = user_chat_get (M->to_id); @@ -1516,8 +1523,10 @@ void print_message (struct message *M) { } else { printf (" »»» "); } + if (alert_sound) { + play_sound(); + } } - } else { assert (get_peer_type (M->to_id) == PEER_CHAT); push_color (COLOR_MAGENTA); @@ -1558,6 +1567,10 @@ void print_message (struct message *M) { print_end(); } +void play_sound (void) { + printf ("\a"); +} + void set_interface_callbacks (void) { readline_active = 1; rl_callback_handler_install (get_default_prompt (), interpreter); diff --git a/interface.h b/interface.h index 80c7ee2..99f0319 100644 --- a/interface.h +++ b/interface.h @@ -57,6 +57,7 @@ void print_end (void); void print_date_full (long t); void print_date (long t); +void play_sound (void); void update_prompt (void); void set_interface_callbacks (void); #endif From 7274e179b8f7bbc276a0390a37a95829a197b61e Mon Sep 17 00:00:00 2001 From: Dennis Koot Date: Thu, 27 Feb 2014 09:50:32 +0100 Subject: [PATCH 281/465] ignore files created by compiling telegram --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5761abc..f6153df 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ +telegram *.o +Makefile +config.log +config.status From 2d85f4fe8348d50fe0232b6bdbb0cd2ac3c36ded Mon Sep 17 00:00:00 2001 From: Dennis Koot Date: Thu, 27 Feb 2014 09:55:53 +0100 Subject: [PATCH 282/465] added .idea for jetbrains --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f6153df..897064e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ telegram Makefile config.log config.status +.idea/ From c150d00a51a39160ab869b5eaccd560dd36b4823 Mon Sep 17 00:00:00 2001 From: Dennis Koot Date: Thu, 27 Feb 2014 10:17:07 +0100 Subject: [PATCH 283/465] better list of options for -h --- main.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index a8d23fe..44de05a 100644 --- a/main.c +++ b/main.c @@ -345,7 +345,26 @@ void inner_main (void) { } void usage (void) { - printf ("%s [-u username] [-h] [-k public key name] [-N] [-v] [-l log_level]\n", PROGNAME); + printf ("%s Usage\n", PROGNAME); + + printf (" -h this help list\n"); + printf (" -u username specify username\n"); + printf (" -k public-key specify server public key\n"); + printf (" -v verbose\n"); + printf (" -l [1-3] log level\n"); + printf (" -L log-file log net file\n"); + printf (" -N message num mode\n"); + printf (" -c config-file specify config file\n"); + printf (" -p prefix specify prefix\n"); + printf (" -R register mode\n"); + printf (" -f sync from start\n"); + printf (" -B enable binlog\n"); + printf (" -E disable auto accept\n"); + printf (" -w allow weak random\n"); + printf (" -s specify lua script\n"); + printf (" -W wait dialog list\n"); + printf ("\n"); + exit (1); } From 64aca0427d991310fcbc89284afb3123ff827e9c Mon Sep 17 00:00:00 2001 From: Dennis Koot Date: Thu, 27 Feb 2014 11:13:48 +0100 Subject: [PATCH 284/465] extra ignores --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 897064e..aed48ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ telegram *.o Makefile +autom4te.cache +config.h config.log config.status .idea/ From cbac13c8fcd4e1b224bb69a0ddea66f651a6b47b Mon Sep 17 00:00:00 2001 From: Dennis Koot Date: Thu, 27 Feb 2014 11:14:35 +0100 Subject: [PATCH 285/465] netbeans ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index aed48ae..3c8bc12 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ config.h config.log config.status .idea/ +nbproject/ From 17c624bd9ed5dd3b4a44c19463ae953b600ad2d1 Mon Sep 17 00:00:00 2001 From: Kartik Mistry Date: Tue, 4 Mar 2014 17:17:09 +0530 Subject: [PATCH 286/465] Whitespace cleanups --- README.md | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 59580a8..f45ac0a 100644 --- a/README.md +++ b/README.md @@ -13,35 +13,34 @@ Documentation for MTproto protocol is available here: http://core.telegram.org/m Clone GitHub Repository $ git clone https://github.com/vysheng/tg.git && cd tg - + or download and extract zip $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip $ unzip tg-master.zip && cd tg-master - + #### Linux Install libs: readline openssl and (if you want to use config) libconfig and liblua. If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively On ubuntu use: - + $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev On gentoo: - - $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua - -On Fedora: + $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua + +On Fedora: +d $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel -Default Makefile uses liblua5.2 from ubuntu. If you use different version of liblua or linux you have to run ./configure script or you will get some strange compilation error. +Default Makefile uses liblua5.2 from ubuntu. If you use different version of liblua or Linux you have to run ./configure script or you will get some strange compilation error. -Then +Then, $ ./configure $ make - #### Mac OS X The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) and [libconfig](http://www.hyperrealm.com/libconfig/), which are not included in OS X by default. You have to install these libraries manually, e.g. using [Homebrew](http://brew.sh/). @@ -52,7 +51,7 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea $ export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" $ export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" $ ./configure && make - + Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. #### FreeBSD @@ -67,12 +66,11 @@ Then build: $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure $ make - + #### Other UNIX If you manage to launch it on other UNIX, please let me know. - ### Usage ./telegram -k @@ -94,7 +92,6 @@ If two or more peers have same name, number is appended to the name. (for #### Messaging - * **msg** \ Text - sends message to this peer * **fwd** \ \ - forward message to user. You can see message numbers starting client with -N * **chat_with_peer** \ starts one on one chat session with this peer. /exit or /quit to end this mode. @@ -110,7 +107,6 @@ If two or more peers have same name, number is appended to the name. (for * **load_photo**/load_video/load_video_thumb \ - loads photo/video to download dir * **view_photo**/view_video/view_video_thumb \ - loads photo/video to download dir and starts system default viewer - #### Group chat options * **chat_info** \ - prints info about chat From fde21397ab45d1303d3d08abf7a705e4efff4d2e Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 5 Mar 2014 01:54:45 +0400 Subject: [PATCH 287/465] delted text about Makefile --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 81652c3..2cd9865 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,6 @@ or download and extract zip Install libs: readline or libedit, openssl and (if you want to use config) libconfig and liblua. If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively. -Default Makefile uses liblua5.2 from ubuntu. If you use different version of liblua or Linux you have to run ./configure script or you will get some strange compilation error. - On ubuntu use: $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev From 7773adf5f2498189544b243ef07d81001fd0543b Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 5 Mar 2014 00:58:47 +0300 Subject: [PATCH 288/465] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2cd9865..b69176e 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,15 @@ On gentoo: $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua On Fedora: -d + $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel On FreeBSD: + $ pkg install libconfig libexecinfo lua52 On OpenBSD: + $ pkg_add libconfig libexecinfo lua Then, From ceca0589d8a12d61bb900819457708b55c2342ee Mon Sep 17 00:00:00 2001 From: rmsrepliedtomeonce Date: Wed, 5 Mar 2014 14:50:49 +0200 Subject: [PATCH 289/465] Remove biased shell signs Not everybody uses bash, you know. Especially the people on *BSD, which you still listed as '$' --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index b69176e..aa1a6bb 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ Documentation for MTproto protocol is available here: http://core.telegram.org/m Clone GitHub Repository - $ git clone https://github.com/vysheng/tg.git && cd tg + git clone https://github.com/vysheng/tg.git && cd tg or download and extract zip - $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip - $ unzip tg-master.zip && cd tg-master + wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip + unzip tg-master.zip && cd tg-master #### Linux and BSDs @@ -26,39 +26,39 @@ If you do not want to use them pass options --disable-libconfig and --disable-li On ubuntu use: - $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev + sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev On gentoo: - $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua + sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua On Fedora: - $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel + sudo yum install lua-devel openssl-devel libconfig-devel readline-devel On FreeBSD: - $ pkg install libconfig libexecinfo lua52 + pkg install libconfig libexecinfo lua52 On OpenBSD: - $ pkg_add libconfig libexecinfo lua + pkg_add libconfig libexecinfo lua Then, - $ ./configure - $ make + ./configure + make #### Mac OS X The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) and [libconfig](http://www.hyperrealm.com/libconfig/), which are not included in OS X by default. You have to install these libraries manually, e.g. using [Homebrew](http://brew.sh/). - $ brew install libconfig - $ brew install readline - $ brew install lua - $ export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" - $ export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" - $ ./configure && make + brew install libconfig + brew install readline + brew install lua + export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" + export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" + ./configure && make Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. @@ -71,8 +71,8 @@ Install these ports: Then build: - $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure - $ make + env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure + make #### Other UNIX From e0d109e450404c879b81d3d7219cc03a8d0ce29c Mon Sep 17 00:00:00 2001 From: vysheng Date: Wed, 5 Mar 2014 16:18:53 +0300 Subject: [PATCH 290/465] Update interface.c --- interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.c b/interface.c index b692ae3..02b36f6 100644 --- a/interface.c +++ b/interface.c @@ -1574,6 +1574,6 @@ void play_sound (void) { void set_interface_callbacks (void) { readline_active = 1; rl_callback_handler_install (get_default_prompt (), interpreter); - rl_attempted_completion_function = (CPPFunction *) complete_text; + rl_attempted_completion_function = (void *) complete_text; rl_completion_entry_function = (void *)complete_none; } From 69fb759b9e69972208007668b7b98b8028cfb8c1 Mon Sep 17 00:00:00 2001 From: Dennis Koot Date: Wed, 5 Mar 2014 14:21:01 +0100 Subject: [PATCH 291/465] re-added jetbrains .idea/ and netbeans nbproject/ to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d90274a..3c8bc12 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ autom4te.cache config.h config.log config.status +.idea/ +nbproject/ From 6677355f44df66e9f85047a1cc334d6138da8e6b Mon Sep 17 00:00:00 2001 From: Thomas Wentzel Date: Thu, 6 Mar 2014 22:07:04 +0100 Subject: [PATCH 292/465] Change type in message_action and message_media from int to unsigned. --- interface.c | 36 ++++++++++++++++++------------------ structures.h | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/interface.c b/interface.c index 02b36f6..2be2268 100644 --- a/interface.c +++ b/interface.c @@ -722,9 +722,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + if (M && !M->service && M->media.type == CODE_message_media_photo) { do_load_photo (&M->media.photo, 1); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_photo) { do_load_encr_video (&M->media.encr_video, 1); // this is not a bug. } else { printf ("Bad msg id\n"); @@ -737,9 +737,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + if (M && !M->service && M->media.type == CODE_message_media_photo) { do_load_photo (&M->media.photo, 2); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_photo) { do_load_encr_video (&M->media.encr_video, 2); // this is not a bug. } else { printf ("Bad msg id\n"); @@ -752,7 +752,7 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + if (M && !M->service && M->media.type == CODE_message_media_video) { do_load_video_thumb (&M->media.video, 1); } else { printf ("Bad msg id\n"); @@ -765,7 +765,7 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + if (M && !M->service && M->media.type == CODE_message_media_video) { do_load_video_thumb (&M->media.video, 2); } else { printf ("Bad msg id\n"); @@ -778,9 +778,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + if (M && !M->service && M->media.type == CODE_message_media_video) { do_load_video (&M->media.video, 1); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_video) { do_load_encr_video (&M->media.encr_video, 1); } else { printf ("Bad msg id\n"); @@ -793,9 +793,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + if (M && !M->service && M->media.type == CODE_message_media_video) { do_load_video (&M->media.video, 2); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_video) { do_load_encr_video (&M->media.encr_video, 2); } else { printf ("Bad msg id\n"); @@ -991,9 +991,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { + if (M && !M->service && M->media.type == CODE_message_media_audio) { do_load_audio (&M->media.video, 1); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_audio) { do_load_encr_video (&M->media.encr_video, 1); } else { printf ("Bad msg id\n"); @@ -1006,9 +1006,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { + if (M && !M->service && M->media.type == CODE_message_media_audio) { do_load_audio (&M->media.video, 2); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_audio) { do_load_encr_video (&M->media.encr_video, 2); } else { printf ("Bad msg id\n"); @@ -1047,9 +1047,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + if (M && !M->service && M->media.type == CODE_message_media_document) { do_load_document (&M->media.document, 1); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_document) { do_load_encr_video (&M->media.encr_video, 1); } else { printf ("Bad msg id\n"); @@ -1062,9 +1062,9 @@ void interpreter (char *line UU) { RET; } struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + if (M && !M->service && M->media.type == CODE_message_media_document) { do_load_document (&M->media.document, 2); - } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { + } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_document) { do_load_encr_video (&M->media.encr_video, 2); } else { printf ("Bad msg id\n"); diff --git a/structures.h b/structures.h index 96aa362..7033872 100644 --- a/structures.h +++ b/structures.h @@ -264,7 +264,7 @@ struct document { }; struct message_action { - int type; + unsigned type; union { struct { char *title; @@ -279,7 +279,7 @@ struct message_action { }; struct message_media { - int type; + unsigned type; union { struct photo photo; struct video video; From 11ab0194eb01e01179f7734208d74a7daa679531 Mon Sep 17 00:00:00 2001 From: Thomas Wentzel Date: Thu, 6 Mar 2014 22:19:27 +0100 Subject: [PATCH 293/465] Got into a situation where telegram would crash upon startup, since fetch_encrypted_message_file would end up being called with a message_media of type CODE_decrypted_message_media_document. --- structures.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/structures.c b/structures.c index adda1a7..5a980ac 100644 --- a/structures.c +++ b/structures.c @@ -1482,15 +1482,29 @@ void fetch_encrypted_message_file (struct message_media *M) { if (x == CODE_encrypted_file_empty) { assert (M->type != CODE_decrypted_message_media_photo && M->type != CODE_decrypted_message_media_video); } else { - assert (M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video); - M->encr_photo.id = fetch_long (); - M->encr_photo.access_hash = fetch_long (); - fetch_int (); - //assert (M->encr_photo.size == fetch_int ()); - //M->encr_photo.size = fetch_int (); // Why it is not the same? - M->encr_photo.dc_id = fetch_int (); - M->encr_photo.key_fingerprint = fetch_int (); - + assert (M->type == CODE_decrypted_message_media_document || M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video); + + switch (M->type) { + case CODE_decrypted_message_media_document: + // Not at all sure these entries are correct. + // Especially since values are not fetched into structures rigidly for photo and video. + M->encr_document.id = fetch_long(); + M->encr_document.access_hash = fetch_long(); + M->encr_document.dc_id = fetch_int(); + M->encr_document.size = fetch_int(); + M->encr_document.key_fingerprint = fetch_int(); + break; + case CODE_decrypted_message_media_photo: + case CODE_decrypted_message_media_video: + M->encr_photo.id = fetch_long (); + M->encr_photo.access_hash = fetch_long (); + fetch_int (); + //assert (M->encr_photo.size == fetch_int ()); + //M->encr_photo.size = fetch_int (); // Why it is not the same? + M->encr_photo.dc_id = fetch_int (); + M->encr_photo.key_fingerprint = fetch_int (); + break; + } } } From 3383755b21e66f221250ead8f2957619682b424a Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 7 Mar 2014 02:43:15 +0400 Subject: [PATCH 294/465] Fixed merge structures.c --- structures.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/structures.c b/structures.c index 5a980ac..858fb9c 100644 --- a/structures.c +++ b/structures.c @@ -1482,29 +1482,13 @@ void fetch_encrypted_message_file (struct message_media *M) { if (x == CODE_encrypted_file_empty) { assert (M->type != CODE_decrypted_message_media_photo && M->type != CODE_decrypted_message_media_video); } else { - assert (M->type == CODE_decrypted_message_media_document || M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video); + assert (M->type == CODE_decrypted_message_media_document || M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video || M->type == CODE_decrypted_message_media_audio); - switch (M->type) { - case CODE_decrypted_message_media_document: - // Not at all sure these entries are correct. - // Especially since values are not fetched into structures rigidly for photo and video. - M->encr_document.id = fetch_long(); - M->encr_document.access_hash = fetch_long(); - M->encr_document.dc_id = fetch_int(); - M->encr_document.size = fetch_int(); - M->encr_document.key_fingerprint = fetch_int(); - break; - case CODE_decrypted_message_media_photo: - case CODE_decrypted_message_media_video: - M->encr_photo.id = fetch_long (); - M->encr_photo.access_hash = fetch_long (); - fetch_int (); - //assert (M->encr_photo.size == fetch_int ()); - //M->encr_photo.size = fetch_int (); // Why it is not the same? - M->encr_photo.dc_id = fetch_int (); - M->encr_photo.key_fingerprint = fetch_int (); - break; - } + M->encr_photo.id = fetch_long(); + M->encr_photo.access_hash = fetch_long(); + M->encr_photo.dc_id = fetch_int(); + M->encr_photo.size = fetch_int(); + M->encr_photo.key_fingerprint = fetch_int(); } } From 8ff2ac447be6045b00570848f8b9758ce9ff5900 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 7 Mar 2014 02:44:41 +0400 Subject: [PATCH 295/465] fix to prev fix --- structures.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/structures.c b/structures.c index 858fb9c..687155e 100644 --- a/structures.c +++ b/structures.c @@ -1486,8 +1486,12 @@ void fetch_encrypted_message_file (struct message_media *M) { M->encr_photo.id = fetch_long(); M->encr_photo.access_hash = fetch_long(); + if (!M->encr_photo.size) { + M->encr_photo.size = fetch_int (); + } else { + fetch_int (); + } M->encr_photo.dc_id = fetch_int(); - M->encr_photo.size = fetch_int(); M->encr_photo.key_fingerprint = fetch_int(); } } From 2d7fbe769e764a814bdd044940db6a3c0578dba5 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 7 Mar 2014 23:15:57 +0400 Subject: [PATCH 296/465] added support for update_dc --- mtproto-client.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mtproto-client.c b/mtproto-client.c index 6ea6def..ab55774 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1382,6 +1382,17 @@ void work_update (struct connection *c UU, long long msg_id UU) { print_end (); } break; + case CODE_update_dc_options: + { + assert (fetch_int () == CODE_vector); + int n = fetch_int (); + assert (n >= 0); + int i; + for (i = 0; i < n; i++) { + fetch_dc_option (); + } + } + break; default: logprintf ("Unknown update type %08x\n", op); ; From d8d1d42327d48cfa983c26487df3be87dab3abbf Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 7 Mar 2014 23:41:59 +0400 Subject: [PATCH 297/465] deleted unused code --- mtproto-common.h | 112 ----------------------------------------------- 1 file changed, 112 deletions(-) diff --git a/mtproto-common.h b/mtproto-common.h index 011aed3..340af62 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -104,118 +104,6 @@ struct encrypted_message { int message[MAX_MESSAGE_INTS]; }; -struct worker_descr { - int addr; - int port; - int pid; - int start_time; - int id; -}; - -struct rpc_ready_packet { - int len; - int seq_num; - int type; - struct worker_descr worker; - int worker_ready_cnt; - int crc32; -}; - - -struct front_descr { - int addr; - int port; - int pid; - int start_time; - int id; -}; - -struct rpc_front_packet { - int len; - int seq_num; - int type; - struct front_descr front; - long long hash_mult; - int rem, mod; - int crc32; -}; - -struct middle_descr { - int addr; - int port; - int pid; - int start_time; - int id; -}; - -struct rpc_front_ack { - int len; - int seq_num; - int type; - struct middle_descr middle; - int crc32; -}; - -struct rpc_front_err { - int len; - int seq_num; - int type; - int errcode; - struct middle_descr middle; - long long hash_mult; - int rem, mod; - int crc32; -}; - -struct rpc_proxy_req { - int len; - int seq_num; - int type; - int flags; - long long ext_conn_id; - unsigned char remote_ipv6[16]; - int remote_port; - unsigned char our_ipv6[16]; - int our_port; - int data[]; -}; - -#define PROXY_HDR(__x) ((struct rpc_proxy_req *)((__x) - offsetof(struct rpc_proxy_req, data))) - -struct rpc_proxy_ans { - int len; - int seq_num; - int type; - int flags; // +16 = small error packet, +8 = flush immediately - long long ext_conn_id; - int data[]; -}; - -struct rpc_close_conn { - int len; - int seq_num; - int type; - long long ext_conn_id; - int crc32; -}; - -struct rpc_close_ext { - int len; - int seq_num; - int type; - long long ext_conn_id; - int crc32; -}; - -struct rpc_simple_ack { - int len; - int seq_num; - int type; - long long ext_conn_id; - int confirm_key; - int crc32; -}; - #pragma pack(pop) BN_CTX *BN_ctx; From eb7ce437af2196a620b08c8e7d76cabe61edc017 Mon Sep 17 00:00:00 2001 From: mk-pmb Date: Tue, 25 Feb 2014 15:58:54 +0100 Subject: [PATCH 298/465] Enhance naming to show that the pubkey is the server's. While I'm at it, also label the magic constants for prng_seed to avoid confusion with srand(0). --- mtproto-client.c | 11 ++++++++--- tg.pub => tg-server.pub | 0 2 files changed, 8 insertions(+), 3 deletions(-) rename tg.pub => tg-server.pub (100%) diff --git a/mtproto-client.c b/mtproto-client.c index ab55774..13cf983 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -131,7 +131,8 @@ int Response_len; * */ -char *rsa_public_key_name; // = "tg.pub"; +#define TG_SERVER_PUBKEY_FILENAME "tg.pub" +char *rsa_public_key_name; // = TG_SERVER_PUBKEY_FILENAME; RSA *pubKey; long long pk_fingerprint; @@ -1824,8 +1825,11 @@ int auth_is_success (void) { return auth_success; } + +#define RANDSEED_PASSWORD_FILENAME NULL +#define RANDSEED_PASSWORD_LENGTH 0 void on_start (void) { - prng_seed (0, 0); + prng_seed (RANDSEED_PASSWORD_FILENAME, RANDSEED_PASSWORD_LENGTH); if (rsa_public_key_name) { if (rsa_load_public_key (rsa_public_key_name) < 0) { @@ -1833,7 +1837,8 @@ void on_start (void) { exit (1); } } else { - if (rsa_load_public_key ("tg.pub") < 0 && rsa_load_public_key ("/etc/" PROG_NAME "/server.pub") < 0) { + if (rsa_load_public_key (TG_SERVER_PUBKEY_FILENAME) < 0 + && rsa_load_public_key ("/etc/" PROG_NAME "/server.pub") < 0) { perror ("rsa_load_public_key"); exit (1); } diff --git a/tg.pub b/tg-server.pub similarity index 100% rename from tg.pub rename to tg-server.pub From a50c7c37d215541b3e0d263e76b79e60bc7a4957 Mon Sep 17 00:00:00 2001 From: mindrunner Date: Sun, 16 Mar 2014 13:44:44 +0100 Subject: [PATCH 299/465] telegram-cli gentoo ebuild pubkey fix --- gentoo/telegram-cli/telegram-cli-9999.ebuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gentoo/telegram-cli/telegram-cli-9999.ebuild b/gentoo/telegram-cli/telegram-cli-9999.ebuild index bf8ed3d..17e3288 100644 --- a/gentoo/telegram-cli/telegram-cli-9999.ebuild +++ b/gentoo/telegram-cli/telegram-cli-9999.ebuild @@ -27,5 +27,5 @@ src_install() { newbin telegram telegram-cli insinto /etc/telegram-cli/ - newins tg.pub server.pub + newins tg-server.pub server.pub } From 2fd40ea3e74db7bd435e48198f9143f065897aae Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 17 Mar 2014 00:45:10 +0400 Subject: [PATCH 300/465] structures.h: fixed foolish bug in structures defenition, leading to SIGSEGV --- structures.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/structures.h b/structures.h index 7033872..ad4360f 100644 --- a/structures.h +++ b/structures.h @@ -297,8 +297,10 @@ struct message_media { struct encr_audio encr_audio; struct encr_document encr_document; struct encr_file encr_file; - void *data; - int data_size; + struct { + void *data; + int data_size; + }; }; }; From 1722bbc3f253fb45ad2b0aa43dea2605b4b3cca6 Mon Sep 17 00:00:00 2001 From: vysheng Date: Thu, 20 Mar 2014 19:33:08 +0400 Subject: [PATCH 301/465] added layer 12 support --- constants.h | 3 ++- mtproto-common.h | 1 + queries.c | 9 +++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/constants.h b/constants.h index 54d7372..327885b 100644 --- a/constants.h +++ b/constants.h @@ -201,7 +201,7 @@ #define CODE_photos_photo 0x20212ca8 #define CODE_upload_file 0x96a18d5 #define CODE_dc_option 0x2ec2a43c -#define CODE_config 0x232d5905 +#define CODE_config 0x2e54dd74 #define CODE_nearest_dc 0x8e1a1775 #define CODE_help_app_update 0x8987f311 #define CODE_help_no_app_update 0xc45a6536 @@ -379,4 +379,5 @@ #define CODE_invoke_with_layer9 0x76715a63 #define CODE_invoke_with_layer10 0x39620c41 #define CODE_invoke_with_layer11 0xa6b88fdf +#define CODE_invoke_with_layer12 0xdda60d3c #endif diff --git a/mtproto-common.h b/mtproto-common.h index 340af62..619be74 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -78,6 +78,7 @@ #define CODE_input_peer_notify_settings_old 0x3cf4b1be #define CODE_peer_notify_settings_old 0xddbcd4a5 #define CODE_user_profile_photo_old 0x990d1493 +#define CODE_config_old 0x232d5905 #define CODE_msg_new_detailed_info 0x809db6df diff --git a/queries.c b/queries.c index e7ad64e..a4475dd 100644 --- a/queries.c +++ b/queries.c @@ -294,6 +294,7 @@ void work_timers (void) { } int max_chat_size; +int max_bcast_size; int want_dc_num; int new_dc_num; extern struct dc *DC_list[]; @@ -308,7 +309,7 @@ void out_random (int n) { int allow_send_linux_version; void do_insert_header (void) { - out_int (CODE_invoke_with_layer11); + out_int (CODE_invoke_with_layer12); out_int (CODE_init_connection); out_int (TG_APP_ID); if (allow_send_linux_version) { @@ -346,7 +347,8 @@ void fetch_dc_option (void) { } int help_get_config_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_config); + unsigned op = fetch_int (); + assert (op == CODE_config || op == CODE_config_old); fetch_int (); unsigned test_mode = fetch_int (); @@ -364,6 +366,9 @@ int help_get_config_on_answer (struct query *q UU) { fetch_dc_option (); } max_chat_size = fetch_int (); + if (op == CODE_config) { + max_bcast_size = fetch_int (); + } if (verbosity >= 2) { logprintf ( "chat_size = %d\n", max_chat_size); } From aa68c2c6aeb30aa317250d571a20ec1ebd202e87 Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 21 Mar 2014 01:03:23 +0400 Subject: [PATCH 302/465] Fixed sentCode parse in 12 layer --- constants.h | 2 +- queries.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/constants.h b/constants.h index 54d7372..bfc295b 100644 --- a/constants.h +++ b/constants.h @@ -117,7 +117,7 @@ #define CODE_geo_point_empty 0x1117dd5f #define CODE_geo_point 0x2049d70c #define CODE_auth_checked_phone 0xe300cc3b -#define CODE_auth_sent_code 0x2215bcbd +#define CODE_auth_sent_code 0xefed51d9 #define CODE_auth_authorization 0xf6b673a4 #define CODE_auth_exported_authorization 0xdf969c2d #define CODE_input_notify_peer 0xb8bc5b0c diff --git a/queries.c b/queries.c index e7ad64e..6db08db 100644 --- a/queries.c +++ b/queries.c @@ -384,7 +384,9 @@ void do_help_get_config (void) { /* {{{ Send code */ 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_auth_sent_code); + fetch_bool (); + fetch_int (); fetch_bool (); int l = prefetch_strlen (); char *s = fetch_str (l); From 0ca3a4dc48876cbc4327b610f865bb6e013b0fee Mon Sep 17 00:00:00 2001 From: vysheng Date: Fri, 21 Mar 2014 15:33:06 +0400 Subject: [PATCH 303/465] fixed login --- queries.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries.c b/queries.c index cc331bc..5087531 100644 --- a/queries.c +++ b/queries.c @@ -391,14 +391,14 @@ char *phone_code_hash; int send_code_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_auth_sent_code); fetch_bool (); - fetch_int (); - fetch_bool (); int l = prefetch_strlen (); char *s = fetch_str (l); if (phone_code_hash) { tfree_str (phone_code_hash); } phone_code_hash = tstrndup (s, l); + fetch_int (); + fetch_bool (); want_dc_num = -1; return 0; } From 3fe6641dbebcc4b54c4022434534ac6027f07ae5 Mon Sep 17 00:00:00 2001 From: Dennis Koot Date: Fri, 21 Mar 2014 16:29:53 +0100 Subject: [PATCH 304/465] use the right .pub file since commit #ff14a08d53ac9e223ffada8a41e69ebb673aa7d7 changed tg.pub to tg-server.pub --- README.es | 4 ++-- README.md | 4 ++-- mtproto-client.c | 2 +- telegram-cli.spec | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.es b/README.es index 944a2a9..ede5809 100644 --- a/README.es +++ b/README.es @@ -79,9 +79,9 @@ Si logras ejecutarlo en otros UNIX, por favor házmelo saber. ./telegram -k -Por defecto la clave pública se almacena en la misma carpeta con el nombre tg.pub o en /etc/telegram/server.pub, si no lo es, indica dónde encontrarlo: +Por defecto la clave pública se almacena en la misma carpeta con el nombre tg-server.pub o en /etc/telegram/server.pub, si no lo es, indica dónde encontrarlo: - ./telegram -k tg.pub + ./telegram -k tg-server.pub El Cliente soporta completamiento con TAB e historial de comandos. diff --git a/README.md b/README.md index aa1a6bb..263a24e 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ If you manage to launch it on other UNIX, please let me know. ./telegram -k -By default public key is stored in the same folder named tg.pub or in /etc/telegram/server.pub, if it's not, specify where to find it: +By default public key is stored in the same folder named tg-server.pub or in /etc/telegram/server.pub, if it's not, specify where to find it: - ./telegram -k tg.pub + ./telegram -k tg-server.pub Client support TAB completion and command history. diff --git a/mtproto-client.c b/mtproto-client.c index 13cf983..d19a26f 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -131,7 +131,7 @@ int Response_len; * */ -#define TG_SERVER_PUBKEY_FILENAME "tg.pub" +#define TG_SERVER_PUBKEY_FILENAME "tg-server.pub" char *rsa_public_key_name; // = TG_SERVER_PUBKEY_FILENAME; RSA *pubKey; long long pk_fingerprint; diff --git a/telegram-cli.spec b/telegram-cli.spec index 241e5b6..c187dc3 100644 --- a/telegram-cli.spec +++ b/telegram-cli.spec @@ -33,7 +33,7 @@ make %{?_smp_mflags} cd %{name} cd tg-master %{__install} -D -m0755 telegram %{buildroot}/usr/bin/telegram -%{__install} -D -m0644 tg.pub %{buildroot}/etc/telegram/server.pub +%{__install} -D -m0644 tg-server.pub %{buildroot}/etc/telegram/server.pub %files /usr/bin/telegram From 0bc969918a0800d831e7e2d17e4b42722e9c22e8 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 8 May 2014 13:17:11 +0200 Subject: [PATCH 305/465] Add files from telegram-purple-skeleton --- README.md | 192 ++++++---------- telegram-purple.c | 554 ++++++++++++++++++++++++++++++++++++++++++++++ telegram.png | Bin 0 -> 3145 bytes telegram.svg | 177 +++++++++++++++ telegram16.png | Bin 0 -> 671 bytes telegram22.png | Bin 0 -> 1032 bytes telegram48.png | Bin 0 -> 2268 bytes 7 files changed, 804 insertions(+), 119 deletions(-) create mode 100644 telegram-purple.c create mode 100644 telegram.png create mode 100644 telegram.svg create mode 100644 telegram16.png create mode 100644 telegram22.png create mode 100644 telegram48.png diff --git a/README.md b/README.md index 263a24e..e88538d 100644 --- a/README.md +++ b/README.md @@ -1,144 +1,98 @@ -## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) - -Command-line interface for [Telegram](http://telegram.org). Uses readline interface. - -### API, Protocol documentation - -Documentation for Telegram API is available here: http://core.telegram.org/api - -Documentation for MTproto protocol is available here: http://core.telegram.org/mtproto - -### Installation - -Clone GitHub Repository - - git clone https://github.com/vysheng/tg.git && cd tg - -or download and extract zip - - wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip - unzip tg-master.zip && cd tg-master - -#### Linux and BSDs - -Install libs: readline or libedit, openssl and (if you want to use config) libconfig and liblua. -If you do not want to use them pass options --disable-libconfig and --disable-liblua respectively. - -On ubuntu use: - - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev - -On gentoo: - - sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua - -On Fedora: - - sudo yum install lua-devel openssl-devel libconfig-devel readline-devel - -On FreeBSD: - - pkg install libconfig libexecinfo lua52 - -On OpenBSD: - - pkg_add libconfig libexecinfo lua - -Then, - - ./configure - make - -#### Mac OS X - -The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) and [libconfig](http://www.hyperrealm.com/libconfig/), which are not included in OS X by default. You have to install these libraries manually, e.g. using [Homebrew](http://brew.sh/). - - brew install libconfig - brew install readline - brew install lua - export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" - export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" - ./configure && make - -Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. +telegram-purple +=============== -Install these ports: +# Installieren -* devel/libconfig -* devel/libexecinfo -* lang/lua52 +1. Sicherstellen dass Pidgin installiert ist. +2. Dieses Git-Repository klonen. -Then build: - env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure - make + git clone https://bitbucket.org/telegrampurple/telegram-purple -#### Other UNIX -If you manage to launch it on other UNIX, please let me know. +3. Im Ordner von **telegram-purple** make ausführen: -### Usage - ./telegram -k - -By default public key is stored in the same folder named tg-server.pub or in /etc/telegram/server.pub, if it's not, specify where to find it: + cd telgram.purple + sudo make install - ./telegram -k tg-server.pub -Client support TAB completion and command history. +Der Befehl kompiliert telegram-purple und kopiert die Dateien in den globale Plugin-Ordner von Pidgin. Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. -Peer refers to the name of the contact or dialog and can be accessed by TAB completion. -For user contacts peer name is Name Lastname with all spaces changed to underscores. -For chats it is it's title with all spaces changed to underscores -For encrypted chats it is Name Lastname with all spaces changed to underscores. -If two or more peers have same name, number is appended to the name. (for example A_B, A_B#1, A_B#2 and so on) - -### Supported commands +# Testen und Debuggen -#### Messaging +Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: -* **msg** \ Text - sends message to this peer -* **fwd** \ \ - forward message to user. You can see message numbers starting client with -N -* **chat_with_peer** \ starts one on one chat session with this peer. /exit or /quit to end this mode. -* **add_contact** \ \ \ - tries to add contact to contact-list by phone -* **rename_contact** \ \ \ - tries to rename contact. If you have another device it will be a fight -* **mark_read** \ - mark read all received messages with peer -#### Multimedia + sudo chmod 777 -R `pkg-config --variable=plugindir purple` + sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol + -* **send_photo** \ \ - sends photo to peer -* **send_video** \ \ - sends video to peer -* **send_text** \ \ - sends text file as plain messages -* **load_photo**/load_video/load_video_thumb \ - loads photo/video to download dir -* **view_photo**/view_video/view_video_thumb \ - loads photo/video to download dir and starts system default viewer +## Testen -#### Group chat options -* **chat_info** \ - prints info about chat -* **chat_add_user** \ \ - add user to chat -* **chat_del_user** \ \ - remove user from chat -* **rename_chat** \ \ -* **create_group_chat** \ \ - creates a groupchat with user, use chat_add_user to add more users +Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: -#### Search -* **search** \ pattern - searches pattern in messages with peer -* **global_search** pattern - searches pattern in all messages + make run + -#### Secret chat +Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: -* **create_secret_chat** \ - creates secret chat with this user -* **visualize_key** \ - prints visualization of encryption key. You should compare it to your partner's one -#### Stats and various info + sudo killall pidgin -* **user_info** \ - prints info about user -* **history** \ [limit] - prints history (and marks it as read). Default limit = 40 -* **dialog_list** - prints info about your dialogs -* **contact_list** - prints info about users in your contact list -* **suggested_contacts** - print info about contacts, you have max common friends -* **stats** - just for debugging -* **show_license** - prints contents of GPLv2 -* **help** - prints this help + + +### Filtern der Lognachrichten + +Wenn Pidgin einfach mit **make run** ausgeführt wird, werden alle Debugnachrichten des gesamten Programms ausgegegeben. Libpurple verwendet interne Loggingfunktionen die den Lognachrichten automatisch einen Prefix hinzufügen, z.B. "plugins:" für Nachrichten des Pluginsloaders und "prpl-telegram:" für Nachrichten dieses Plugins. + +Wenn man nur Ausgaben des Plugin-Loaders und von telegram-purple haben möchte kann man unnötige Nachrichten mit **grep** herausfiltern. + + + make run | grep -i 'prpl-telegram:\|plugins:' + + +# Deinstallieren + +Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: + + + sudo make uninstall + + + +# Coding-Guidelines + +## Coding Style + +Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. + + unsigned int some_function(int a, int b) + { + if (true) { + // ... + } else { + // ... + } + } + + +## Logging + +Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). + + + #include "debug.h" + #define PLUGIN_ID "prpl-telegram" + + // ... + + purple_debug_info(PLUGIN_ID, "Debugnachricht"); + +## Troubleshooting + +Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden diff --git a/telegram-purple.c b/telegram-purple.c new file mode 100644 index 0000000..33591e7 --- /dev/null +++ b/telegram-purple.c @@ -0,0 +1,554 @@ +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include + +// TODO: check if we really need all those includes... +#include "notify.h" +#include "plugin.h" // NEEDED? +#include "version.h" +#include "account.h" +#include "accountopt.h" +#include "blist.h" +#include "cmds.h" +#include "conversation.h" +#include "connection.h" +#include "debug.h" +#include "privacy.h" +#include "prpl.h" +#include "roomlist.h" +#include "status.h" +#include "util.h" +#include "prpl.h" + +#define PLUGIN_ID "prpl-telegram" + +#define TELEGRAM_APP_API_ID 16944 +#define TELEGRAM_APP_API_HASH "457b5a190c750ed0a772bc48bbdf75dc" +#define TELEGRAM_TEST_SERVER "173.240.5.253" +#define TELEGRAM_PRODUCTION_SERVER "173.240.5.1" +#define TELEGRAM_DEFAULT_PORT 443 +#define TELEGRAM_PUBLIC_KEY "-----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daSan9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTwEfzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3nSlv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB-----END RSA PUBLIC KEY-----" + + +typedef struct { + PurpleAccount *account; + PurpleConnection *gc; + PurpleSslConnection *gsc; +} telegram_conn; + +static PurplePlugin *_telegram_protocol = NULL; + +/** + * Returns the base icon name for the given buddy and account. + * If buddy is NULL and the account is non-NULL, it will return the + * name to use for the account's icon. If both are NULL, it will + * return the name to use for the protocol's icon. + * + * This must be implemented. + */ +static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) +{ + purple_debug_info(PLUGIN_ID, "tgrpl_list_icon()\n"); + return "telegram"; +} + +/** + * Gets a short string representing this buddy's status. This will + * be shown on the buddy list. + */ +static char *tgprpl_status_text(PurpleBuddy * buddy) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_status_text()\n"); + return "status text"; +} + +/** + * Allows the prpl to add text to a buddy's tooltip. + */ +static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); +} + +/** + * This must be implemented. + */ +static void tgprpl_login(PurpleAccount * acct) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); + PurpleConnection *gc = purple_account_get_connection(acct); + + const char *username = purple_account_get_username(acct); + const char *sms_key = purple_account_get_string(acct, "sms_key", ""); + const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); + int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); + + purple_debug_info(PLUGIN_ID, "logging in %s\n", username); + + if (sms_key[0] == "") { + purple_debug_info(PLUGIN_ID, "no sms key -> send sms key request\n"); + } + + purple_debug_info(PLUGIN_ID, "Connect\n"); + purple_connection_update_progress(gc, "Connecting", 0, 4); + telegram_conn *conn; + conn = g_new0(telegram_conn, 1); + conn->gc = gc; + conn->account = acct; + purple_connection_set_protocol_data(gc, conn); + + gc->proto_data = conn; + purple_connection_set_state(gc, PURPLE_CONNECTED); + + purple_debug_info(PLUGIN_ID, "Connected\n"); +} + + +/** + * This must be implemented. + */ +static void tgprpl_close(PurpleConnection * gc) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_close()\n"); +} + +/** + * This PRPL function should return a positive value on success. + * If the message is too big to be sent, return -E2BIG. If + * the account is not connected, return -ENOTCONN. If the + * PRPL is unable to send the message for another reason, return + * some other negative value. You can use one of the valid + * errno values, or just big something. If the message should + * not be echoed to the conversation window, return 0. + */ +static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_send_im()\n"); + return -1; +} + +/** + * Send a message to a chat. + * This PRPL function should return a positive value on success. + * If the message is too big to be sent, return -E2BIG. If + * the account is not connected, return -ENOTCONN. If the + * PRPL is unable to send the message for another reason, return + * some other negative value. You can use one of the valid + * errno values, or just big something. + * + * @param id The id of the chat to send the message to. + * @param message The message to send to the chat. + * @param flags A bitwise OR of #PurpleMessageFlags representing + * message flags. + * @return A positive number or 0 in case of success, + * a negative error number in case of failure. + */ +static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_send_chat()\n"); + return -1; +} + +/** + * Add a buddy to a group on the server. + * + * This PRPL function may be called in situations in which the buddy is + * already in the specified group. If the protocol supports + * authorization and the user is not already authorized to see the + * status of \a buddy, \a add_buddy should request authorization. + * + * @deprecated Since 2.8.0, add_buddy_with_invite is preferred. + * @see add_buddy_with_invite + */ +static void tgprpl_add_buddy(PurpleConnection * gc, PurpleBuddy * buddy, PurpleGroup * group) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_add_buddy()\n"); +} + +static void tgprpl_add_buddies(PurpleConnection * gc, GList * buddies, GList * groups) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_add_buddies()\n"); +} + +static void tgprpl_remove_buddy(PurpleConnection * gc, PurpleBuddy * buddy, PurpleGroup * group) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_remove_buddy()\n"); + +} + +static void tgprpl_remove_buddies(PurpleConnection * gc, GList * buddies, GList * groups) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_remove_buddies()\n"); + +} + +static void tgprpl_convo_closed(PurpleConnection * gc, const char *who) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_convo_closed()\n"); + +} + +static void tgprpl_add_deny(PurpleConnection * gc, const char *name) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_add_deny()\n"); + +} + +static void tgprpl_rem_deny(PurpleConnection * gc, const char *name) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_rem_deny()\n"); + +} + +/** + * @return If this protocol requires the PURPLE_TYPING message to + * be sent repeatedly to signify that the user is still + * typing, then the PRPL should return the number of + * seconds to wait before sending a subsequent notification. + * Otherwise the PRPL should return 0. + */ +static unsigned int tgprpl_send_typing(PurpleConnection * gc, const char *who, PurpleTypingState typing) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_send_typing()\n"); + return 0; +} + +/** + * Set the buddy icon for the given connection to @a img. The prpl + * does NOT own a reference to @a img; if it needs one, it must + * #purple_imgstore_ref(@a img) itself. + */ +static void tgprpl_set_buddy_icon(PurpleConnection * gc, PurpleStoredImage * img) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_set_buddy_icon()\n"); + +} + +/** + * File transfer callback + */ +static gboolean tgprpl_can_receive_file(PurpleConnection * gc, const char *who) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_can_receive_file()\n"); + return FALSE; +} + +/** + * Checks whether offline messages to @a buddy are supported. + + * @return @c TRUE if @a buddy can be sent messages while they are + * offline, or @c FALSE if not. + */ +static gboolean tgprpl_offline_message(const PurpleBuddy * buddy) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_offline_message()\n"); + return FALSE; +} + +/** + * Returns a list of #PurpleStatusType which exist for this account; + * this must be implemented, and must add at least the offline and + * online states. + */ +static GList *tgprpl_status_types(PurpleAccount * acct) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_status_types()\n"); + GList *types = NULL; + PurpleStatusType *type; + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, "available", NULL, TRUE, TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); + types = g_list_prepend(types, type); + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, "unavailable", NULL, TRUE, TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); + types = g_list_prepend(types, type); + + type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE); + types = g_list_append(types, type); + + return g_list_reverse(types); +} + +static void tgprpl_set_status(PurpleAccount * acct, PurpleStatus * status) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_set_status()\n"); +} + +/** + * Should arrange for purple_notify_userinfo() to be called with + * @a who's user info. + */ +static void tgprpl_get_info(PurpleConnection * gc, const char *username) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_get_info()\n"); + +} + +/** + * change a buddy's group on a server list/roster + */ +static void tgprpl_group_buddy(PurpleConnection * gc, const char *who, const char *old_group, const char *new_group) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_group_buddy()\n"); + +} + +/** + * rename a group on a server list/roster + */ +static void tgprpl_rename_group(PurpleConnection * gc, const char *old_name, PurpleGroup * group, GList * moved_buddies) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_rename_group()\n"); + +} + +/** + * Returns a list of #proto_chat_entry structs, which represent + * information required by the PRPL to join a chat. libpurple will + * call join_chat along with the information filled by the user. + * + * @return A list of #proto_chat_entry structs + */ +static GList *tgprpl_chat_join_info(PurpleConnection * gc) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_chat_join_info()\n"); + return NULL; +} + +/** + * Returns a hashtable which maps #proto_chat_entry struct identifiers + * to default options as strings based on chat_name. The resulting + * hashtable should be created with g_hash_table_new_full(g_str_hash, + * g_str_equal, NULL, g_free);. Use #get_chat_name if you instead need + * to extract a chat name from a hashtable. + * + * @param chat_name The chat name to be turned into components + * @return Hashtable containing the information extracted from chat_name + */ +static GHashTable *tgprpl_chat_info_defaults(PurpleConnection * gc, const char *chat_name) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_chat_info_defaults()\n"); + return NULL; +} + +/** + * Called when the user requests joining a chat. Should arrange for + * #serv_got_joined_chat to be called. + * + * @param components A hashtable containing information required to + * join the chat as described by the entries returned + * by #chat_info. It may also be called when accepting + * an invitation, in which case this matches the + * data parameter passed to #serv_got_chat_invite. + */ +static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_chat_join()\n"); +} + +/** + * Invite a user to join a chat. + * + * @param id The id of the chat to invite the user to. + * @param message A message displayed to the user when the invitation + * is received. + * @param who The name of the user to send the invation to. + */ +static void tgprpl_chat_invite(PurpleConnection * gc, int id, const char *message, const char *name) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_chat_invite()\n"); +} + +/** + * Returns a chat name based on the information in components. Use + * #chat_info_defaults if you instead need to generate a hashtable + * from a chat name. + * + * @param components A hashtable containing information about the chat. + */ +static char *tgprpl_get_chat_name(GHashTable * data) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_get_chat_name()\n"); + return "chat name"; +} + +/** + * File transfer callback. + */ +static PurpleXfer *tgprpl_new_xfer(PurpleConnection * gc, const char *who) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_new_xfer()\n"); + return (PurpleXfer *)NULL; +} + +/** + * File transfer callback. + */ +static void tgprpl_send_file(PurpleConnection * gc, const char *who, const char *file) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_send_file()\n"); + +} + +// SEE prpl.h +static PurplePluginProtocolInfo prpl_info = { + OPT_PROTO_NO_PASSWORD, /* options */ + NULL, /* user_splits, initialized in tgprpl_init() */ + NULL, /* protocol_options, initialized in tgprpl_init() */ + + { /* icon_spec, a PurpleBuddyIconSpec */ + "png", /* format */ + 1, /* min_width */ + 1, /* min_height */ + 512, /* max_width */ + 512, /* max_height */ + 64000, /* max_filesize */ + PURPLE_ICON_SCALE_SEND, /* scale_rules */ + }, + tgprpl_list_icon, + NULL, + tgprpl_status_text, + tgprpl_tooltip_text, + tgprpl_status_types, + NULL, /* blist_node_menu */ + tgprpl_chat_join_info, + tgprpl_chat_info_defaults, /* chat_info_defaults */ + tgprpl_login, /* login */ + tgprpl_close, /* close */ + tgprpl_send_im, /* send_im */ + NULL, /* set_info */ + tgprpl_send_typing, /* send_typing */ + tgprpl_get_info, /* get_info */ + tgprpl_set_status, /* set_status */ + NULL, /* set_idle */ + NULL, /* change_passwd */ + tgprpl_add_buddy, /* add_buddy */ + tgprpl_add_buddies, /* add_buddies */ + tgprpl_remove_buddy, /* remove_buddy */ + tgprpl_remove_buddies, /* remove_buddies */ + NULL, /* add_permit */ + tgprpl_add_deny, /* add_deny */ + NULL, /* rem_permit */ + tgprpl_rem_deny, /* rem_deny */ + NULL, /* set_permit_deny */ + tgprpl_chat_join, /* join_chat */ + NULL, /* reject_chat */ + tgprpl_get_chat_name, /* get_chat_name */ + tgprpl_chat_invite, /* chat_invite */ + NULL, /* chat_leave */ + NULL, /* chat_whisper */ + tgprpl_send_chat, /* chat_send */ + NULL, /* keepalive */ + NULL, /* register_user */ + NULL, /* get_cb_info */ + NULL, /* get_cb_away */ + NULL, /* alias_buddy */ + tgprpl_group_buddy, /* group_buddy */ + tgprpl_rename_group, /* rename_group */ + NULL, /* buddy_free */ + tgprpl_convo_closed, /* convo_closed */ + purple_normalize_nocase, /* normalize */ + tgprpl_set_buddy_icon, /* set_buddy_icon */ + NULL, /* remove_group */ + NULL, /* get_cb_real_name */ + NULL, /* set_chat_topic */ + NULL, /* find_blist_chat */ + NULL, /* roomlist_get_list */ + NULL, /* roomlist_cancel */ + NULL, /* roomlist_expand_category */ + tgprpl_can_receive_file, /* can_receive_file */ + tgprpl_send_file, /* send_file */ + tgprpl_new_xfer, /* new_xfer */ + tgprpl_offline_message, /* offline_message */ + NULL, /* whiteboard_prpl_ops */ + NULL, /* send_raw */ + NULL, /* roomlist_room_serialize */ + NULL, /* unregister_user */ + NULL, /* send_attention */ + NULL, /* get_attention_types */ + sizeof(PurplePluginProtocolInfo), /* struct_size */ + NULL, /* get_account_text_table */ + NULL, /* initiate_media */ + NULL, /* get_media_caps */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ +}; + +static void init_plugin(PurplePlugin *plugin) +{ + PurpleAccountOption *option; + + prpl_info.user_splits = NULL; + + option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_string_new("SMS-Key", "sms_key", "0000"); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + _telegram_protocol = plugin; +} + +/* +static gboolean plugin_load(PurplePlugin *plugin) { + purple_notify_message(plugin, PURPLE_NOTIFY_MSG_INFO, "Hallo Telegram", + "Das ist nur ein Test des Build-Systems, bitte einfach weiter gehen.", NULL, NULL, NULL); + return TRUE; +} +*/ + +static GList *tgprpl_actions(PurplePlugin * plugin, gpointer context) +{ + // return possible actions (See Libpurple doc) + return (GList *)NULL; +} + +static PurplePluginInfo info = { + PURPLE_PLUGIN_MAGIC, + PURPLE_MAJOR_VERSION, + PURPLE_MINOR_VERSION, + PURPLE_PLUGIN_PROTOCOL, + NULL, + 0, + NULL, + PURPLE_PRIORITY_DEFAULT, + PLUGIN_ID, + "Telegram", + "0.1", + "Telegram integration.", + "Includes support for the Telegram protocol into libpurple.", + "Christopher Althaus , Markus Endres , Matthias Jentsch ", + "https://bitbucket.org/telegrampurple/telegram-purple", + NULL, // on load + NULL, // on unload + NULL, // on destroy + NULL, // ui specific struct + &prpl_info, // plugin info struct + NULL, // prefs info + tgprpl_actions, // actions + NULL, // reserved + NULL, // reserved + NULL, // reserved + NULL // reserved +}; + + +PURPLE_INIT_PLUGIN(telegram, init_plugin, info) diff --git a/telegram.png b/telegram.png new file mode 100644 index 0000000000000000000000000000000000000000..b4ae1e548f1bd0e183d0a323293dac9227a7d6e2 GIT binary patch literal 3145 zcmV-P47T%$P)~K&XAN-4t9>qu zjQdCs?gXO|0Eh~0Uph`uo(o4JPafIaFgYg-aA{k2r6foX0kj=}Q=d4Fe1VNINx{!Dy3k0kZWx0Lzt0%Y3UIaYC!evdpk23H;GLI&NeG3&Jr7QLn@rT7HGX)a=iTgHWu?X!1$R( zJHg5(jVP-u)8b^rOqf$+lkrmFoW`aB%c}oNZmOIzML+=JRtA@G%oQ=;m?A*cp&<`2vcp+7 zQ)!y33!N5hTkgWIS}M`xvgXrV&5MM6dM=O*i->!{0D-}p6*a7xmRYwg69Hflr@$b9 zl3*>gRUGYF(_@Du;<_3;Zm6?kS(#NQRxA=8`eaC*Q@v6xYFNK=Jt}k~2-pVT_qqX= z?P+fT^Rg)C81Wb}fH+62c~F-_atx4aaLriJUnXK)R#A)_>Ks_Js1z14vDRBf(yI@^ zQKC#{3_|qM3|PVP%m3Pc*^!&;KaW54^yX1111$o#c5o>E5*to=r zMpseRjs7urP}jYYD6~8hF9#!LTo2$ERR8RuDvNA66aA*4s#09eri2`hoU26~Zg3T0 zLtPoZUFSfVHTj~=ACe)t4h52j z!y@8awNBi)qzp~vsl6>TW7O?~*B?err6b|k19^x5u32oy4fSPMRaFX$kbd#v_69NP_Cb;a)Gu^G6cd*$UG5NMMFG-P zlO)7V@*rLzG0>!?Qc7kB12Hm8W~vq`szV0779ILle{R1tTaf zl2BdgfRJRRM*up<{V^{al4vZqP{urllwyv3{6ZU7?J@1F1rm2%1cbmtdY2O+&LOh`RCVMQM4bZkeJ!7 z@AT@#GT|ukc{ULn8_Ka^i3{~*HsmrCg)uVegWDU_&sDgJG2c;~;B_MN@kk(oL4P=o zc;@CRK^}lZ0>d5+Wn&(QVXZV8)lRIaERB}7$pFT^e#CFl60)pe}${a=h-7Vr_TDfYr%*-2wEv19Vbqls;r_49Lrs$A$7T_6 zL4^YrHF;*^byN8p3uvpK886Kh!f}BF?lRt6O`ivlh>?i)#{>dFAfRJRm6UvtrzU5N45ZxoBcXPV) zoTWUDjQUKiulC*U!ATtI9YiQBXY{)9{Lx{bCT{gNkXjCzUE=$ zUg^ZYPfePK{*so$K$i64A9N;D|6IATzun z8T(FnFzAmMR(+-$hzLX&Z=9F_16Z}lZrTz0d(SuyobkfExl6fYqF?uJY1*Ik_IT~? z56TJFE(TX(R!6MQPla0-JMh@G7h++F1rdd@;gwGGOa$^LuHGJ3iUN&2w_V{$`G`#I z69;Yw;{}|Pk=_uc77^FgyU^zj;0v{+#z#$h9Cx3CgdcWq{rXGkpAllF+T8~~0-+V> za3nm~kQ33&QNX|ly?0%@21K0x86hH;BE*$|GySfBZ<=LT*>DZ z0j6kp{F99!`U8Oa^F+K4%nuCgXnj3@;mmL}?)}i=3y41@q6Y!YKS#vJ0POU$f7i&4 zZ+d5zISMoy_kQT`2gU6GZ2_XM&dx&eKMv5d#kTMhU3YzBsxYZ@7Dn|GAGZiB+zJ%v zM jiV*kr?`WCT*XRESGmU`i0(n3D00000NkvXXu0mjfNxH)x literal 0 HcmV?d00001 diff --git a/telegram.svg b/telegram.svg new file mode 100644 index 0000000..1331624 --- /dev/null +++ b/telegram.svg @@ -0,0 +1,177 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/telegram16.png b/telegram16.png new file mode 100644 index 0000000000000000000000000000000000000000..91de69dd304e95b47bf417f8289b819614bcb72a GIT binary patch literal 671 zcmV;Q0$}}#P)s)M1L`Fo!6A`Km!GcUw^11tOZ}$Xy0-ZC9QNI#- zCL(>|!NUyM&J}}=fyJAhWdpztk5z4-s^$MwoO9r~nus(!0+2IL-kmqbEFfZPy0iN> z#e527t=6r0bo=Ub*eRygP_oXaKi$CfbR!K>!;Q>JwZ{|3u&=7UBJRMTXM~=X1lKx} zTxm^^+t}eq%&=70LDhzhdVN)GtGYGEqYR!t%D|~4$LgcxHv@8OMN-K)@unmBaZfh?^FGlanvU zaonQ@JR?LrL!j)hFFgEs>%yo3NEv?=$kYevo!c>USqE9(#bI;Qp2jWL0dYMg&* z;h0GI{=s7kqiynampD5F^aCA#%F7}y<3y&iBNq>x^KV`i2y`;sEtdcQ002ovPDHLk FV1kv6JC6VW literal 0 HcmV?d00001 diff --git a/telegram22.png b/telegram22.png new file mode 100644 index 0000000000000000000000000000000000000000..709f356a12d9fc397d23f1d4cf76377da7de73f9 GIT binary patch literal 1032 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 Date: Sat, 10 May 2014 15:37:43 +0200 Subject: [PATCH 306/465] Move plugin into separate directory --- .gitignore | 4 +++ Makefile.in | 5 ++-- libtg.h | 1 + main.c | 28 +++++++++--------- .../telegram-purple.c | 28 +++++++++++------- telegram.png => purple-plugin/telegram.png | Bin telegram.svg => purple-plugin/telegram.svg | 0 .../telegram16.png | Bin .../telegram22.png | Bin .../telegram48.png | Bin 10 files changed, 40 insertions(+), 26 deletions(-) create mode 100755 libtg.h rename telegram-purple.c => purple-plugin/telegram-purple.c (97%) rename telegram.png => purple-plugin/telegram.png (100%) rename telegram.svg => purple-plugin/telegram.svg (100%) rename telegram16.png => purple-plugin/telegram16.png (100%) rename telegram22.png => purple-plugin/telegram22.png (100%) rename telegram48.png => purple-plugin/telegram48.png (100%) diff --git a/.gitignore b/.gitignore index 3c8bc12..7345b6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ telegram *.o +*.so +*.a Makefile autom4te.cache config.h @@ -7,3 +9,5 @@ config.log config.status .idea/ nbproject/ +tags +.DS_Store diff --git a/Makefile.in b/Makefile.in index 200252c..0c1e907 100644 --- a/Makefile.in +++ b/Makefile.in @@ -29,7 +29,8 @@ telegram: ${OBJECTS} .c.o : ${CC} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ +libtg.a: ${OBJECTS} + ar rs $@ ${OBJECTS} clean: - rm -rf *.o telegram config.log config.status > /dev/null || echo "all clean" - + rm -rf *.a *.o telegram config.log config.status > /dev/null || echo "all clean" diff --git a/libtg.h b/libtg.h new file mode 100755 index 0000000..13b1fb5 --- /dev/null +++ b/libtg.h @@ -0,0 +1 @@ +int runtg (int argc, char **argv); diff --git a/main.c b/main.c index 44de05a..7f6f32a 100644 --- a/main.c +++ b/main.c @@ -92,7 +92,7 @@ int sync_from_start; int allow_weak_random; void set_default_username (const char *s) { - if (default_username) { + if (default_username) { tfree_str (default_username); } default_username = tstrdup (s); @@ -238,7 +238,7 @@ void running_for_first_time (void) { close (auth_file_fd); printf ("[%s] created\n", config_filename);*/ - + /* create downloads directory */ /*if (mkdir (downloads_directory, 0755) !=0) { perror ("creating download directory"); @@ -249,7 +249,7 @@ void running_for_first_time (void) { #ifdef HAVE_LIBCONFIG void parse_config_val (config_t *conf, char **s, char *param_name, const char *default_name, const char *path) { - static char buf[1000]; + static char buf[1000]; int l = 0; if (prefix) { l = strlen (prefix); @@ -277,7 +277,7 @@ void parse_config_val (config_t *conf, char **s, char *param_name, const char *d void parse_config (void) { config_filename = make_full_path (config_filename); - + config_t conf; config_init (&conf); if (config_read_file (&conf, config_filename) != CONFIG_TRUE) { @@ -299,12 +299,12 @@ void parse_config (void) { test_dc = 0; strcpy (buf + l, "test"); config_lookup_bool (&conf, buf, &test_dc); - + strcpy (buf + l, "log_level"); long long t = log_level; config_lookup_int (&conf, buf, (void *)&t); log_level = t; - + if (!msg_num_mode) { strcpy (buf + l, "msg_num"); config_lookup_bool (&conf, buf, &msg_num_mode); @@ -318,10 +318,10 @@ void parse_config (void) { parse_config_val (&conf, &secret_chat_file_name, "secret", SECRET_CHAT_FILE, config_directory); parse_config_val (&conf, &downloads_directory, "downloads", DOWNLOADS_DIRECTORY, config_directory); parse_config_val (&conf, &binlog_file_name, "binlog", BINLOG_FILE, config_directory); - + strcpy (buf + l, "binlog_enabled"); config_lookup_bool (&conf, buf, &binlog_enabled); - + if (!mkdir (config_directory, CONFIG_DIRECTORY_MODE)) { printf ("[%s] created\n", config_directory); } @@ -417,7 +417,7 @@ void args_parse (int argc, char **argv) { binlog_enabled = 1; break; case 'L': - if (log_net_file) { + if (log_net_file) { usage (); } log_net_file = tstrdup (optarg); @@ -460,7 +460,7 @@ void print_backtrace (void) { void sig_segv_handler (int signum __attribute__ ((unused))) { set_terminal_attributes (); - if (write (1, "SIGSEGV received\n", 18) < 0) { + if (write (1, "SIGSEGV received\n", 18) < 0) { // Sad thing } print_backtrace (); @@ -469,19 +469,19 @@ void sig_segv_handler (int signum __attribute__ ((unused))) { void sig_abrt_handler (int signum __attribute__ ((unused))) { set_terminal_attributes (); - if (write (1, "SIGABRT received\n", 18) < 0) { + if (write (1, "SIGABRT received\n", 18) < 0) { // Sad thing } print_backtrace (); exit (EXIT_FAILURE); } -int main (int argc, char **argv) { +int runtg (int argc, char **argv) { signal (SIGSEGV, sig_segv_handler); signal (SIGABRT, sig_abrt_handler); log_level = 10; - + args_parse (argc, argv); printf ( "Telegram-client version " TG_VERSION ", Copyright (C) 2013 Vitaly Valtman\n" @@ -502,6 +502,6 @@ int main (int argc, char **argv) { #endif inner_main (); - + return 0; } diff --git a/telegram-purple.c b/purple-plugin/telegram-purple.c similarity index 97% rename from telegram-purple.c rename to purple-plugin/telegram-purple.c index 33591e7..287ad80 100644 --- a/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -34,6 +34,8 @@ #include "util.h" #include "prpl.h" +#include + #define PLUGIN_ID "prpl-telegram" #define TELEGRAM_APP_API_ID 16944 @@ -90,31 +92,38 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info static void tgprpl_login(PurpleAccount * acct) { purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); + + purple_debug_info(PLUGIN_ID, "calling runtg()\n"); + runtg(0, NULL); + purple_debug_info(PLUGIN_ID, "returned from runtg()\n"); + + /* PurpleConnection *gc = purple_account_get_connection(acct); const char *username = purple_account_get_username(acct); const char *sms_key = purple_account_get_string(acct, "sms_key", ""); const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); - int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); + int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); purple_debug_info(PLUGIN_ID, "logging in %s\n", username); - if (sms_key[0] == "") { + if (strcmp(sms_key[0], "")) { purple_debug_info(PLUGIN_ID, "no sms key -> send sms key request\n"); } - purple_debug_info(PLUGIN_ID, "Connect\n"); + purple_debug_info(PLUGIN_ID, "Connect\n"); purple_connection_update_progress(gc, "Connecting", 0, 4); telegram_conn *conn; conn = g_new0(telegram_conn, 1); conn->gc = gc; - conn->account = acct; + conn->account = acct; purple_connection_set_protocol_data(gc, conn); gc->proto_data = conn; purple_connection_set_state(gc, PURPLE_CONNECTED); - purple_debug_info(PLUGIN_ID, "Connected\n"); + purple_debug_info(PLUGIN_ID, "Connected\n"); + */ } @@ -273,12 +282,12 @@ static GList *tgprpl_status_types(PurpleAccount * acct) types = g_list_prepend(types, type); type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, "unavailable", NULL, TRUE, TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_prepend(types, type); + types = g_list_prepend(types, type); - type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE); - types = g_list_append(types, type); + type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE); + types = g_list_append(types, type); - return g_list_reverse(types); + return g_list_reverse(types); } static void tgprpl_set_status(PurpleAccount * acct, PurpleStatus * status) @@ -550,5 +559,4 @@ static PurplePluginInfo info = { NULL // reserved }; - PURPLE_INIT_PLUGIN(telegram, init_plugin, info) diff --git a/telegram.png b/purple-plugin/telegram.png similarity index 100% rename from telegram.png rename to purple-plugin/telegram.png diff --git a/telegram.svg b/purple-plugin/telegram.svg similarity index 100% rename from telegram.svg rename to purple-plugin/telegram.svg diff --git a/telegram16.png b/purple-plugin/telegram16.png similarity index 100% rename from telegram16.png rename to purple-plugin/telegram16.png diff --git a/telegram22.png b/purple-plugin/telegram22.png similarity index 100% rename from telegram22.png rename to purple-plugin/telegram22.png diff --git a/telegram48.png b/purple-plugin/telegram48.png similarity index 100% rename from telegram48.png rename to purple-plugin/telegram48.png From 02296e3774de0cc206f3ef4d1810b95495d16aca Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 10 May 2014 19:56:29 +0200 Subject: [PATCH 307/465] Link header files of the telegram cli tool --- .gitignore | 2 +- Makefile.in | 4 ++- purple-plugin/Makefile | 80 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100755 purple-plugin/Makefile diff --git a/.gitignore b/.gitignore index 7345b6b..e35cfab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ telegram *.o *.so *.a -Makefile +/Makefile autom4te.cache config.h config.log diff --git a/Makefile.in b/Makefile.in index 0c1e907..cdf6230 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,10 +27,12 @@ telegram: ${OBJECTS} ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ .c.o : - ${CC} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ + ${CC} -fPIC -DPIC ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ libtg.a: ${OBJECTS} ar rs $@ ${OBJECTS} +library: libtg.a + clean: rm -rf *.a *.o telegram config.log config.status > /dev/null || echo "all clean" diff --git a/purple-plugin/Makefile b/purple-plugin/Makefile new file mode 100755 index 0000000..cf6ec88 --- /dev/null +++ b/purple-plugin/Makefile @@ -0,0 +1,80 @@ +# Include libs from tg (--disable-liblua --disable-lib) + +# TODO: These flags should depend on the used configuration flags +EXTRA_LIBS = -lcrypto -lz -lm -lreadline +LDFLAGSTG = -L/usr/local/lib +CPPFLAGSTG = -I/usr/local/include +OBJECTSTG = ../main.o ../loop.o ../interface.o ../net.o ../mtproto-common.o ../mtproto-client.o ../queries.o ../structures.o ../binlog.o ../tools.o ../lua-tg.o +INCLUDE = -I. -I.. +# + +LIBNAME = telegram-purple.so +ARCH = "" + +ifeq ($(ARCH),i686) + ARCHFLAGS = -m32 +else ifeq ($(ARCH),x86_64) + ARCHFLAGS = -m64 +else + ARCHFLAGS = +endif + +.PHONY: all +all: $(LIBNAME) + +C_SRCS = telegram-purple.c +C_OBJS = $(C_SRCS:.c=.o) + +STRIP = strip +CC = gcc +LD = $(CC) +CFLAGS_PURPLE = $(shell pkg-config --cflags purple) +CFLAGS = \ + $(ARCHFLAGS) \ + -fPIC \ + -DPURPLE_PLUGINS \ + -DPIC \ + $(CFLAGS_PURPLE) + +LIBS_PURPLE = $(shell pkg-config --libs purple) +LDFLAGS = $(ARCHFLAGS) -shared + +%.o: %.c + $(CC) -c $(INCLUDE) $(CFLAGS) -o $@ $< + +$(LIBNAME): $(C_OBJS) + $(LD) $(LDFLAGS) $(INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $^ $(OBJECTSTG) + +.PHONY: strip +strip: $(LIBNAME) + $(STRIP) --strip-unneeded $(LIBNAME) + +.PHONY: debug +debug: CFLAGS += -g -DDEBUG +debug: $(LIBNAME) + +PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) +DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple) + +.PHONY: install +install: $(LIBNAME) + install -D $(LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(LIBNAME) + install -D telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png + install -D telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png + install -D telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png + +.PHONY: uninstall +uninstall: $(LIBNAME) + rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(LIBNAME) + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png + +.PHONY: clean +clean: + -rm -f *.o *.a + -rm -f $(LIBNAME) + +.PHONY: run +run: all install + pidgin -d | grep -i 'plugins\|telegram' From da57c79053f0f373d60a4b85c7c1b08216e21dba Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 10 May 2014 19:58:52 +0200 Subject: [PATCH 308/465] Update readme for new build process --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e88538d..6bb221f 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,14 @@ telegram-purple 3. Im Ordner von **telegram-purple** make ausführen: - cd telgram.purple - sudo make install + cd telgram-purple + ./configure --disable-liblua --disable-libconfig + make + cd purple-plugin + make install -Der Befehl kompiliert telegram-purple und kopiert die Dateien in den globale Plugin-Ordner von Pidgin. Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. +Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. # Testen und Debuggen From 377c809ba760368c118cb21c286ab3a5f45ff15e Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 11 May 2014 22:18:21 +0200 Subject: [PATCH 309/465] Add options for user verification, refactor header file-name to include functions into the purple-plugin and copy server.pub into the /etc/telegram directory when installing. --- Makefile.in | 10 ++--- README.md | 20 ++++----- interface.c | 80 +++++++++++++++++---------------- libtg.h | 1 - main.c | 19 ++++---- mtproto-client.c | 74 +++++++++++++++--------------- purple-plugin/Makefile | 5 ++- purple-plugin/telegram-purple.c | 53 ++++++++++++---------- purple-plugin/telegram-purple.h | 38 ++++++++++++++++ tg-cli.h | 3 ++ 10 files changed, 178 insertions(+), 125 deletions(-) delete mode 100755 libtg.h create mode 100644 purple-plugin/telegram-purple.h create mode 100755 tg-cli.h diff --git a/Makefile.in b/Makefile.in index cdf6230..e710bd7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,6 +6,9 @@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +# include libpurple headers for debugging purposes +CFLAGS_PURPLE = $(shell pkg-config --cflags purple) + EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} @@ -27,12 +30,9 @@ telegram: ${OBJECTS} ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ .c.o : - ${CC} -fPIC -DPIC ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ + ${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ -libtg.a: ${OBJECTS} - ar rs $@ ${OBJECTS} - -library: libtg.a +objects: ${OBJECTS} clean: rm -rf *.a *.o telegram config.log config.status > /dev/null || echo "all clean" diff --git a/README.md b/README.md index 6bb221f..2550852 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ telegram-purple cd telgram-purple - ./configure --disable-liblua --disable-libconfig - make - cd purple-plugin - make install + ./configure --disable-liblua --disable-libconfig + make objects + cd purple-plugin + make install Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. @@ -31,7 +31,7 @@ Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorhe sudo chmod 777 -R `pkg-config --variable=plugindir purple` sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol - + ## Testen @@ -40,7 +40,7 @@ Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausfü make run - + Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: @@ -48,7 +48,7 @@ Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die M sudo killall pidgin - + ### Filtern der Lognachrichten Wenn Pidgin einfach mit **make run** ausgeführt wird, werden alle Debugnachrichten des gesamten Programms ausgegegeben. Libpurple verwendet interne Loggingfunktionen die den Lognachrichten automatisch einen Prefix hinzufügen, z.B. "plugins:" für Nachrichten des Pluginsloaders und "prpl-telegram:" für Nachrichten dieses Plugins. @@ -86,14 +86,14 @@ Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Fun ## Logging -Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). +Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). #include "debug.h" #define PLUGIN_ID "prpl-telegram" - + // ... - + purple_debug_info(PLUGIN_ID, "Debugnachricht"); ## Troubleshooting diff --git a/interface.c b/interface.c index 2be2268..cd7635e 100644 --- a/interface.c +++ b/interface.c @@ -21,7 +21,7 @@ #include "config.h" #endif -#define _GNU_SOURCE +#define _GNU_SOURCE #include #include @@ -46,6 +46,10 @@ #include "mtproto-common.h" +// libpurple debugging-messages +#include "debug.h" +#include "purple-plugin/telegram-purple.h" + #define ALLOW_MULT 1 char *default_prompt = "> "; @@ -79,7 +83,7 @@ int is_same_word (const char *s, size_t l, const char *word) { char *next_token (int *l) { while (*line_ptr == ' ') { line_ptr ++; } - if (!*line_ptr) { + if (!*line_ptr) { *l = 0; return 0; } @@ -110,7 +114,7 @@ long long next_token_int (void) { if (!s) { return NOT_FOUND; } char *r; long long x = strtoll (s, &r, 10); - if (r == s + l) { + if (r == s + l) { return x; } else { return NOT_FOUND; @@ -123,7 +127,7 @@ peer_id_t next_token_user (void) { if (!s) { return PEER_NOT_FOUND; } if (l >= 6 && !memcmp (s, "user#", 5)) { - s += 5; + s += 5; l -= 5; int r = atoi (s); if (r >= 0) { return set_peer_id (PEER_USER, r); } @@ -145,9 +149,9 @@ peer_id_t next_token_chat (void) { int l; char *s = next_token (&l); if (!s) { return PEER_NOT_FOUND; } - + if (l >= 6 && !memcmp (s, "chat#", 5)) { - s += 5; + s += 5; l -= 5; int r = atoi (s); if (r >= 0) { return set_peer_id (PEER_CHAT, r); } @@ -185,16 +189,16 @@ peer_id_t next_token_peer (void) { int l; char *s = next_token (&l); if (!s) { return PEER_NOT_FOUND; } - + if (l >= 6 && !memcmp (s, "user#", 5)) { - s += 5; + s += 5; l -= 5; int r = atoi (s); if (r >= 0) { return set_peer_id (PEER_USER, r); } else { return PEER_NOT_FOUND; } } if (l >= 6 && !memcmp (s, "chat#", 5)) { - s += 5; + s += 5; l -= 5; int r = atoi (s); if (r >= 0) { return set_peer_id (PEER_CHAT, r); } @@ -239,7 +243,7 @@ char *get_default_prompt (void) { } l += tsnprintf (buf + l, 999 - l, "]" COLOR_NORMAL); return buf; - } + } l += tsnprintf (buf + l, 999 - l, "%s", default_prompt); return buf; } @@ -391,7 +395,7 @@ int get_complete_mode (void) { if (*r == '[' && !r[l]) { return 6; } - + if (!*line_ptr) { return 0; } char **command = commands; int n = 0; @@ -482,7 +486,7 @@ int complete_string_list (char **list, int index, const char *text, int len, cha return -1; } } -char *command_generator (const char *text, int state) { +char *command_generator (const char *text, int state) { static int len, index, mode; if (in_chat_mode) { @@ -490,12 +494,12 @@ char *command_generator (const char *text, int state) { index = complete_string_list (in_chat_commands, index, text, rl_point, &R); return R; } - + char c = 0; if (!state) { len = strlen (text); index = -1; - + c = rl_line_buffer[rl_point]; rl_line_buffer[rl_point] = 0; mode = get_complete_mode (); @@ -503,9 +507,9 @@ char *command_generator (const char *text, int state) { if (index == -1) { return 0; } } - if (mode == -1) { + if (mode == -1) { if (c) { rl_line_buffer[rl_point] = c; } - return 0; + return 0; } char *R = 0; @@ -515,7 +519,7 @@ char *command_generator (const char *text, int state) { if (c) { rl_line_buffer[rl_point] = c; } return R; case 1: - index = complete_user_list (index, text, len, &R); + index = complete_user_list (index, text, len, &R); if (c) { rl_line_buffer[rl_point] = c; } return R; case 2: @@ -597,9 +601,9 @@ void interpreter (char *line UU) { line_ptr = line; offline_mode = 0; count = 1; - if (!line) { + if (!line) { in_readline = 0; - return; + return; } if (line && *line) { add_history (line); @@ -626,7 +630,7 @@ void interpreter (char *line UU) { l = ll; command = cs; #define IS_WORD(s) is_same_word (command, l, (s)) -#define RET in_readline = 0; return; +#define RET in_readline = 0; return; peer_id_t id; #define GET_PEER \ @@ -634,25 +638,25 @@ void interpreter (char *line UU) { if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ printf ("Bad user/chat id\n"); \ RET; \ - } + } #define GET_PEER_USER \ id = next_token_user (); \ if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ printf ("Bad user id\n"); \ RET; \ - } + } #define GET_PEER_CHAT \ id = next_token_chat (); \ if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ printf ("Bad chat id\n"); \ RET; \ - } + } #define GET_PEER_ENCR_CHAT \ id = next_token_encr_chat (); \ if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ printf ("Bad encr_chat id\n"); \ RET; \ - } + } if (IS_WORD ("contact_list")) { do_update_contact_list (); @@ -725,7 +729,7 @@ void interpreter (char *line UU) { if (M && !M->service && M->media.type == CODE_message_media_photo) { do_load_photo (&M->media.photo, 1); } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_photo) { - do_load_encr_video (&M->media.encr_video, 1); // this is not a bug. + do_load_encr_video (&M->media.encr_video, 1); // this is not a bug. } else { printf ("Bad msg id\n"); RET; @@ -740,7 +744,7 @@ void interpreter (char *line UU) { if (M && !M->service && M->media.type == CODE_message_media_photo) { do_load_photo (&M->media.photo, 2); } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_photo) { - do_load_encr_video (&M->media.encr_video, 2); // this is not a bug. + do_load_encr_video (&M->media.encr_video, 2); // this is not a bug. } else { printf ("Bad msg id\n"); RET; @@ -812,12 +816,12 @@ void interpreter (char *line UU) { int limit = next_token_int (); do_get_history (id, limit > 0 ? limit : 40); } else if (IS_WORD ("chat_add_user")) { - GET_PEER_CHAT; + GET_PEER_CHAT; peer_id_t chat_id = id; GET_PEER_USER; do_add_user_to_chat (chat_id, id, 100); } else if (IS_WORD ("chat_del_user")) { - GET_PEER_CHAT; + GET_PEER_CHAT; peer_id_t chat_id = id; GET_PEER_USER; do_del_user_from_chat (chat_id, id); @@ -907,7 +911,7 @@ void interpreter (char *line UU) { ); pop_color (); } else if (IS_WORD ("show_license")) { - char *b = + char *b = #include "LICENSE.h" ; printf ("%s", b); @@ -941,7 +945,7 @@ void interpreter (char *line UU) { GET_PEER_ENCR_CHAT; do_visualize_key (id); } else if (IS_WORD ("create_secret_chat")) { - GET_PEER; + GET_PEER; do_create_secret_chat (id); } else if (IS_WORD ("create_group_chat")) { GET_PEER; @@ -950,8 +954,8 @@ void interpreter (char *line UU) { if (!s) { printf ("Empty chat topic\n"); RET; - } - do_create_group_chat (id, s); + } + do_create_group_chat (id, s); } else if (IS_WORD ("suggested_contacts")) { do_get_suggested (); } else if (IS_WORD ("status_online")) { @@ -1169,7 +1173,7 @@ void print_end (void) { #if READLINE_GNU rl_replace_line(saved_line, 0); #else - memcpy (rl_line_buffer, saved_line, rl_end + 1); // not safe, but I hope this would work. + memcpy (rl_line_buffer, saved_line, rl_end + 1); // not safe, but I hope this would work. #endif rl_point = saved_point; rl_redisplay(); @@ -1183,7 +1187,7 @@ void hexdump (int *in_ptr, int *in_end) { int *ptr = in_ptr; while (ptr < in_end) { printf (" %08x", *(ptr ++)); } printf ("\n"); - print_end (); + print_end (); } void logprintf (const char *format, ...) { @@ -1311,7 +1315,7 @@ void print_user_name (peer_id_t id, peer_t *U) { } else if (!U->user.last_name || !strlen (U->user.last_name)) { printf ("%s", U->user.first_name); } else { - printf ("%s %s", U->user.first_name, U->user.last_name); + printf ("%s %s", U->user.first_name, U->user.last_name); } if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { pop_color (); @@ -1374,7 +1378,7 @@ void print_service_message (struct message *M) { assert (M); print_start (); push_color (COLOR_GREY); - + push_color (COLOR_MAGENTA); if (msg_num_mode) { printf ("%lld ", M->id); @@ -1390,7 +1394,7 @@ void print_service_message (struct message *M) { } printf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); - + switch (M->action.type) { case CODE_message_action_empty: printf ("\n"); @@ -1405,7 +1409,7 @@ void print_service_message (struct message *M) { printf (" created chat %s. %d users\n", M->action.title, M->action.user_num); break; case CODE_message_action_chat_edit_title: - printf (" changed title to %s\n", + printf (" changed title to %s\n", M->action.new_title); break; case CODE_message_action_chat_edit_photo: diff --git a/libtg.h b/libtg.h deleted file mode 100755 index 13b1fb5..0000000 --- a/libtg.h +++ /dev/null @@ -1 +0,0 @@ -int runtg (int argc, char **argv); diff --git a/main.c b/main.c index 7f6f32a..9d858df 100644 --- a/main.c +++ b/main.c @@ -300,7 +300,7 @@ void parse_config (void) { strcpy (buf + l, "test"); config_lookup_bool (&conf, buf, &test_dc); - strcpy (buf + l, "log_level"); + strcpy (buf + l, "log_lev el"); long long t = log_level; config_lookup_int (&conf, buf, (void *)&t); log_level = t; @@ -476,23 +476,16 @@ void sig_abrt_handler (int signum __attribute__ ((unused))) { exit (EXIT_FAILURE); } -int runtg (int argc, char **argv) { +int main (int argc, char **argv) { signal (SIGSEGV, sig_segv_handler); signal (SIGABRT, sig_abrt_handler); log_level = 10; args_parse (argc, argv); - printf ( - "Telegram-client version " TG_VERSION ", Copyright (C) 2013 Vitaly Valtman\n" - "Telegram-client comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.\n" - "This is free software, and you are welcome to redistribute it\n" - "under certain conditions; type `show_license' for details.\n" - ); running_for_first_time (); parse_config (); - get_terminal_attributes (); #ifdef USE_LUA @@ -505,3 +498,11 @@ int runtg (int argc, char **argv) { return 0; } + + +/** + * Log into Telegram with the given login credentials. + */ +int tg_login () { + return main(0, NULL); +} diff --git a/mtproto-client.c b/mtproto-client.c index d19a26f..cb598d3 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -131,7 +131,7 @@ int Response_len; * */ -#define TG_SERVER_PUBKEY_FILENAME "tg-server.pub" +#define TG_SERVER_PUBKEY_FILENAME "/etc/telegram/server.pub" char *rsa_public_key_name; // = TG_SERVER_PUBKEY_FILENAME; RSA *pubKey; long long pk_fingerprint; @@ -249,7 +249,7 @@ int send_req_pq_packet (struct connection *c) { clear_packet (); out_int (CODE_req_pq); out_ints ((int *)nonce, 4); - rpc_send_packet (c); + rpc_send_packet (c); c_state = st_reqpq_sent; return 1; } @@ -333,7 +333,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { if (p1 > p2) { unsigned t = p1; p1 = p2; p2 = t; } - + if (verbosity) { logprintf ( "p1 = %d, p2 = %d, %d iterations\n", p1, p2, it); @@ -370,7 +370,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { clen = 3; } else { clen = 4; - } + } p1 = __builtin_bswap32 (p1); out_cstring ((char *)&p1 + 4 - clen, clen); p1 = __builtin_bswap32 (p1); @@ -387,7 +387,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { p2 = __builtin_bswap32 (p2); out_cstring ((char *)&p2 + 4 - clen, clen); p2 = __builtin_bswap32 (p2); - + //out_int (0x0301); // p=3 //out_int (0x0501); // q=5 out_ints ((int *) nonce, 4); @@ -397,7 +397,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); int l = encrypt_packet_buffer (); - + clear_packet (); out_int (CODE_req_DH_params); out_ints ((int *) nonce, 4); @@ -412,7 +412,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { clen = 3; } else { clen = 4; - } + } p1 = __builtin_bswap32 (p1); out_cstring ((char *)&p1 + 4 - clen, clen); p1 = __builtin_bswap32 (p1); @@ -428,12 +428,12 @@ int process_respq_answer (struct connection *c, char *packet, int len) { p2 = __builtin_bswap32 (p2); out_cstring ((char *)&p2 + 4 - clen, clen); p2 = __builtin_bswap32 (p2); - + out_long (pk_fingerprint); out_cstring ((char *) encrypt_buffer, l); c_state = st_reqdh_sent; - + return rpc_send_packet (c); } @@ -497,7 +497,7 @@ int check_g (unsigned char p[256], BIGNUM *g) { int ok = 0; int i; for (i = 0; i < 64; i++) { - if (s[i]) { + if (s[i]) { ok = 1; break; } @@ -505,7 +505,7 @@ int check_g (unsigned char p[256], BIGNUM *g) { if (!ok) { return -1; } ok = 0; for (i = 0; i < 64; i++) { - if (s[255 - i]) { + if (s[255 - i]) { ok = 1; break; } @@ -513,7 +513,7 @@ int check_g (unsigned char p[256], BIGNUM *g) { if (!ok) { return -1; } ok = 0; for (i = 0; i < 64; i++) { - if (s[i] < p[i]) { + if (s[i] < p[i]) { ok = 1; break; } else if (s[i] > p[i]) { @@ -587,7 +587,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { out_ints ((int *) nonce, 4); out_ints ((int *) server_nonce, 4); out_long (0LL); - + BN_init (&dh_g); ensure (BN_set_word (&dh_g, g)); @@ -614,7 +614,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { BN_free (&dh_prime); //hexdump (auth_key, auth_key + 256); - + sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); //hexdump ((char *)packet_buffer, (char *)packet_ptr); @@ -656,7 +656,7 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { sha1 (tmp, 41, sha1_buffer); assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; - + if (verbosity >= 3) { logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); } @@ -673,7 +673,7 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { auth_success ++; GET_DC(c)->flags |= 1; write_auth_file (); - + return 1; } @@ -765,7 +765,7 @@ long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, in //hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24); assert (l > 0); rpc_send_message (c, &enc_msg, l + UNENCSZ); - + return client_last_msg_id; } @@ -850,9 +850,9 @@ void work_update_binlog (void) { struct user *U = &UC->user; if (U->first_name) { tfree_str (U->first_name); } if (U->last_name) { tfree_str (U->last_name); } - if (U->print_name) { + if (U->print_name) { peer_delete_name (UC); - tfree_str (U->print_name); + tfree_str (U->print_name); } U->first_name = fetch_str_dup (); U->last_name = fetch_str_dup (); @@ -871,7 +871,7 @@ void work_update_binlog (void) { fetch_date (); if (UC) { struct user *U = &UC->user; - + unsigned y = fetch_int (); if (y == CODE_user_profile_photo_empty) { U->photo_id = 0; @@ -1058,7 +1058,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_file_location (&big); } bl_do_set_user_profile_photo (U, photo_id, &big, &small); - + print_start (); push_color (COLOR_YELLOW); print_date (time (0)); @@ -1129,7 +1129,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { users[i].inviter_id = fetch_int (); users[i].date = fetch_int (); } - int version = fetch_int (); + int version = fetch_int (); bl_do_set_chat_participants (&C->chat, version, n, users); } } else { @@ -1339,8 +1339,8 @@ 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 ()); - int version = fetch_int (); - + 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)); @@ -1365,7 +1365,7 @@ 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 ()); 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)); @@ -1430,7 +1430,7 @@ void work_updates (struct connection *c, long long msg_id) { void work_update_short_message (struct connection *c UU, long long msg_id UU) { assert (fetch_int () == (int)CODE_update_short_message); - struct message *M = fetch_alloc_message_short (); + struct message *M = fetch_alloc_message_short (); unread_messages ++; print_message (M); update_prompt (); @@ -1441,7 +1441,7 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) { void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) { assert (fetch_int () == CODE_update_short_chat_message); - struct message *M = fetch_alloc_message_short_chat (); + struct message *M = fetch_alloc_message_short_chat (); unread_messages ++; print_message (M); update_prompt (); @@ -1458,8 +1458,8 @@ void work_container (struct connection *c, long long msg_id UU) { int n = fetch_int (); int i; for (i = 0; i < n; i++) { - long long id = fetch_long (); - //int seqno = fetch_int (); + long long id = fetch_long (); + //int seqno = fetch_int (); fetch_int (); // seq_no if (id & 1) { insert_msg_id (c->session, id); @@ -1482,7 +1482,7 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { //DC->session_id = fetch_long (); fetch_long (); // unique_id GET_DC(c)->server_salt = fetch_long (); - + } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { @@ -1523,7 +1523,7 @@ void work_packed (struct connection *c, long long msg_id) { static int buf[MAX_PACKED_SIZE >> 2]; assert (!in_gzip); in_gzip = 1; - + int l = prefetch_strlen (); char *s = fetch_str (l); @@ -1650,7 +1650,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); if (verbosity) { - logprintf ( "process_rpc_message(), len=%d\n", len); + logprintf ( "process_rpc_message(), len=%d\n", len); } assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); struct dc *DC = GET_DC(c); @@ -1669,7 +1669,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, DC->server_salt = enc->server_salt; write_auth_file (); } - + int this_server_time = enc->msg_id >> 32LL; if (!DC->server_time_delta) { DC->server_time_delta = this_server_time - get_utime (CLOCK_REALTIME); @@ -1697,10 +1697,10 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (l >= (MINSZ - UNENCSZ) + 8); //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); ++good_messages; - + in_ptr = enc->message; in_end = in_ptr + (enc->msg_len / 4); - + if (enc->msg_id & 1) { insert_msg_id (c->session, enc->msg_id); } @@ -1774,7 +1774,7 @@ int rpc_execute (struct connection *c, int op, int len) { logprintf ( "fatal: cannot receive answer in state %d\n", c_state); exit (2); } - + return 0; } @@ -1793,7 +1793,7 @@ int tc_becomes_ready (struct connection *c) { char byte = 0xef; assert (write_out (c, &byte, 1) == 1); flush_out (c); - + #if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif diff --git a/purple-plugin/Makefile b/purple-plugin/Makefile index cf6ec88..5edef35 100755 --- a/purple-plugin/Makefile +++ b/purple-plugin/Makefile @@ -56,9 +56,11 @@ debug: $(LIBNAME) PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple) +# TODO: Find a better place for server.pub .PHONY: install install: $(LIBNAME) install -D $(LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(LIBNAME) + install -D ../tg-server.pub /etc/telegram/server.pub install -D telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png install -D telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png install -D telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png @@ -66,6 +68,7 @@ install: $(LIBNAME) .PHONY: uninstall uninstall: $(LIBNAME) rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(LIBNAME) + rm -f /etc/telegram/server.pub rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png @@ -77,4 +80,4 @@ clean: .PHONY: run run: all install - pidgin -d | grep -i 'plugins\|telegram' + pidgin -d diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 287ad80..ad49259 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -16,7 +16,7 @@ #include -// TODO: check if we really need all those includes... +// Libpurple Plugin Includes #include "notify.h" #include "plugin.h" // NEEDED? #include "version.h" @@ -34,23 +34,12 @@ #include "util.h" #include "prpl.h" -#include +// Telegram Includes +#include -#define PLUGIN_ID "prpl-telegram" +// telegram-purple includes +#include "telegram-purple.h" -#define TELEGRAM_APP_API_ID 16944 -#define TELEGRAM_APP_API_HASH "457b5a190c750ed0a772bc48bbdf75dc" -#define TELEGRAM_TEST_SERVER "173.240.5.253" -#define TELEGRAM_PRODUCTION_SERVER "173.240.5.1" -#define TELEGRAM_DEFAULT_PORT 443 -#define TELEGRAM_PUBLIC_KEY "-----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daSan9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTwEfzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3nSlv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB-----END RSA PUBLIC KEY-----" - - -typedef struct { - PurpleAccount *account; - PurpleConnection *gc; - PurpleSslConnection *gsc; -} telegram_conn; static PurplePlugin *_telegram_protocol = NULL; @@ -94,7 +83,7 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); purple_debug_info(PLUGIN_ID, "calling runtg()\n"); - runtg(0, NULL); + tg_login(); purple_debug_info(PLUGIN_ID, "returned from runtg()\n"); /* @@ -498,19 +487,35 @@ static PurplePluginProtocolInfo prpl_info = { NULL /* add_buddies_with_invite */ }; -static void init_plugin(PurplePlugin *plugin) +static void tgprpl_init(PurplePlugin *plugin) { - PurpleAccountOption *option; + PurpleAccountOption *option; + PurpleAccountUserSplit *split; + GList *verification_values = NULL; - prpl_info.user_splits = NULL; + // Required Verification-Key + split = purple_account_user_split_new("Verification key", "-", '@'); + purple_account_user_split_set_reverse(split, FALSE); + prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); + + // Extra Options + #define ADD_VALUE(list, desc, v) { \ + PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ + kvp->key = g_strdup((desc)); \ + kvp->value = g_strdup((v)); \ + list = g_list_prepend(list, kvp); \ + } + ADD_VALUE(verification_values, "Phone", "phone"); + ADD_VALUE(verification_values, "SMS", "sms"); + option = purple_account_option_list_new("Verification type", "verification_type", verification_values); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + // TODO: Path to public key (When you can change the server hostname, you should also be able to change the public key) - option = purple_account_option_string_new("SMS-Key", "sms_key", "0000"); + option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); _telegram_protocol = plugin; @@ -559,4 +564,4 @@ static PurplePluginInfo info = { NULL // reserved }; -PURPLE_INIT_PLUGIN(telegram, init_plugin, info) +PURPLE_INIT_PLUGIN(telegram, tgprpl_init, info) diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h new file mode 100644 index 0000000..72f7c32 --- /dev/null +++ b/purple-plugin/telegram-purple.h @@ -0,0 +1,38 @@ +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include + +#include "notify.h" +#include "plugin.h" +#include "version.h" +#include "account.h" +#include "connection.h" + +#define PLUGIN_ID "prpl-telegram" + +#define TELEGRAM_APP_API_ID 16944 +#define TELEGRAM_APP_API_HASH "457b5a190c750ed0a772bc48bbdf75dc" +#define TELEGRAM_TEST_SERVER "173.240.5.253" +#define TELEGRAM_PRODUCTION_SERVER "173.240.5.1" +#define TELEGRAM_DEFAULT_PORT 443 +#define TELEGRAM_PUBLIC_KEY "-----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daSan9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTwEfzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3nSlv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB-----END RSA PUBLIC KEY-----" + +typedef struct { + PurpleAccount *account; + PurpleConnection *gc; + PurpleSslConnection *gsc; +} telegram_conn; diff --git a/tg-cli.h b/tg-cli.h new file mode 100755 index 0000000..b51fbf4 --- /dev/null +++ b/tg-cli.h @@ -0,0 +1,3 @@ +// Export functions for plugins + +int tg_login (); From 70682ef8b5ffeecc550c8e7034e7f3b1725b942f Mon Sep 17 00:00:00 2001 From: Christopher Althaus Date: Fri, 23 May 2014 09:49:00 +0200 Subject: [PATCH 310/465] =?UTF-8?q?Git=20Kommandos=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 2550852..d8541bb 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,15 @@ Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpu purple_debug_info(PLUGIN_ID, "Debugnachricht"); + +## GIT +git pull -> Stand aktualisieren +git add -A -> Files hinzufügen +git push -> Stand hochladen +git commit -> Commiten + + + ## Troubleshooting Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden From 8b4a1c8d10135993bbff455bb8e04b198a83b1ee Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 23 May 2014 11:36:54 +0200 Subject: [PATCH 311/465] Use input values from account settings to authentication to data center --- loop.c | 154 ++++++++++++++++---------------- loop.h | 1 + main.c | 19 +++- purple-plugin/telegram-purple.c | 50 ++++++----- purple-plugin/telegram-purple.h | 3 + tg-cli.h | 4 + 6 files changed, 132 insertions(+), 99 deletions(-) diff --git a/loop.c b/loop.c index 1ed78e5..644593d 100644 --- a/loop.c +++ b/loop.c @@ -53,6 +53,12 @@ #include "binlog.h" #include "lua-tg.h" +// + +#include "purple-plugin/telegram-purple.h" +// + + extern char *default_username; extern char *auth_token; extern int test_dc; @@ -92,7 +98,7 @@ void net_loop (int flags, int (*is_end)(void)) { if (flags & 1) { rl_callback_read_char (); } else { - char *line = 0; + char *line = 0; size_t len = 0; assert (getline (&line, &len, stdin) >= 0); got_it (line, strlen (line)); @@ -110,7 +116,7 @@ void net_loop (int flags, int (*is_end)(void)) { if (unknown_user_list_pos) { do_get_user_list_info_silent (unknown_user_list_pos, unknown_user_list); unknown_user_list_pos = 0; - } + } } } @@ -122,7 +128,7 @@ void got_it (char *line, int len) { assert (len > 0); line[-- len] = 0; // delete end of line *_s = line; - *_l = len; + *_l = len; got_it_ok = 1; } @@ -170,7 +176,7 @@ void write_dc (int auth_file_fd, struct dc *DC) { } else { assert (write (auth_file_fd, zero, 256 + 8) == 256 + 8); } - + assert (write (auth_file_fd, &DC->server_salt, 8) == 8); assert (write (auth_file_fd, &DC->has_auth, 4) == 4); } @@ -214,6 +220,9 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (read (auth_file_fd, &DC->auth_key, 256) == 256); assert (read (auth_file_fd, &DC->server_salt, 8) == 8); + printf("auth_key_id: %lli \n", DC->auth_key_id); + printf("auth_key_id: ?"); + printf("server_salt: %lli \n", DC->server_salt); if (DC->auth_key_id) { DC->flags |= 1; } @@ -287,14 +296,14 @@ void read_state_file (void) { assert (version >= 0); int x[4]; if (read (state_file_fd, x, 16) < 16) { - close (state_file_fd); + close (state_file_fd); return; } pts = x[0]; qts = x[1]; seq = x[2]; last_date = x[3]; - close (state_file_fd); + close (state_file_fd); } void write_state_file (void) { @@ -316,7 +325,7 @@ void write_state_file (void) { x[4] = seq; x[5] = last_date; assert (write (state_file_fd, x, 24) == 24); - close (state_file_fd); + close (state_file_fd); wseq = seq; wpts = pts; wqts = qts; wdate = last_date; } @@ -412,7 +421,7 @@ void write_secret_chat_file (void) { t = strlen (Peers[i]->print_name); assert (write (fd, &t, 4) == 4); assert (write (fd, Peers[i]->print_name, t) == t); - + assert (write (fd, &Peers[i]->encr_chat.state, 4) == 4); assert (write (fd, &Peers[i]->encr_chat.user_id, 4) == 4); @@ -426,7 +435,7 @@ void write_secret_chat_file (void) { assert (write (fd, Peers[i]->encr_chat.nonce, 256) == 256); } assert (write (fd, Peers[i]->encr_chat.key, 256) == 256); - assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8); + assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8); } } assert (write (fd, &encr_root, 4) == 4); @@ -454,7 +463,7 @@ int readline_active; int new_dc_num; int wait_dialog_list; -int loop (void) { +void init_loop (void) { on_start (); if (binlog_enabled) { double t = get_double_time (); @@ -480,7 +489,7 @@ int loop (void) { auth_state = 100; write_auth_file (); } - + if (verbosity) { logprintf ("Requesting info about DC...\n"); } @@ -495,61 +504,42 @@ int loop (void) { assert (DC_list[i]->auth_key_id); write_auth_file (); } +} +int start_loop (char* code, char* auth_mode) { if (auth_state == 100 || !(DC_working->has_auth)) { - if (!default_username) { - size_t size = 0; - char *user = 0; - - if (!user) { - printf ("Telephone number (with '+' sign): "); - if (net_getline (&user, &size) == -1) { - perror ("getline()"); - exit (EXIT_FAILURE); - } - set_default_username (user); - } - } int res = do_auth_check_phone (default_username); assert (res >= 0); logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); if (res > 0 && !register_mode) { - do_send_code (default_username); - char *code = 0; - size_t size = 0; - printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); - while (1) { - if (net_getline (&code, &size) == -1) { - perror ("getline()"); - exit (EXIT_FAILURE); - } - if (!strcmp (code, "call")) { - printf ("You typed \"call\", switching to phone system.\n"); - do_phone_call (default_username); - printf ("Calling you! Code: "); - continue; - } + // Register Mode 1 + if (code) { if (do_send_code_result (code) >= 0) { - break; + printf ("Authentication successfull, state = 300\n"); + auth_state = 300; } - printf ("Invalid code. Try again: "); - tfree_str (code); + } else { + // Send Code + if (strcmp(TELEGRAM_AUTH_MODE_SMS, auth_mode)) { + do_send_code (default_username); + printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); + } else { + printf ("You typed \"call\", switching to phone system.\n"); + do_phone_call (default_username); + printf ("Calling you!"); + } } - auth_state = 300; } else { printf ("User is not registered. Do you want to register? [Y/n] "); - char *code; + printf ("ERROR THIS IS NOT POSSIBLE!\n"); + return 1; + // Register Mode 2 + // TODO: Requires first and last name, decide how to handle this. + // - We need some sort of switch between registration modes + // - When this mode is selected First and Last name should be added to the form + // Currently Requires Manuel Entry in Terminal. + /* size_t size; - if (net_getline (&code, &size) == -1) { - perror ("getline()"); - exit (EXIT_FAILURE); - } - if (!*code || *code == 'y' || *code == 'Y') { - printf ("Ok, starting registartion.\n"); - } else { - printf ("Then try again\n"); - exit (EXIT_SUCCESS); - } char *first_name; printf ("First name: "); if (net_getline (&first_name, &size) == -1) { @@ -567,30 +557,26 @@ int loop (void) { 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 (if you did not receive an SMS and want to be called, type \"call\"): "); - while (1) { - if (net_getline (&code, &size) == -1) { - perror ("getline()"); - exit (EXIT_FAILURE); - } - if (!strcmp (code, "call")) { - printf ("You typed \"call\", switching to phone system.\n"); - do_phone_call (default_username); - printf ("Calling you! Code: "); - continue; - } - if (do_send_code_result_auth (code, first_name, last_name) >= 0) { - break; - } - printf ("Invalid code. Try again: "); - tfree_str (code); + + if (*code) { + if (do_send_code_result_auth (code, first_name, last_name) >= 0) { + auth_state = 300; + } + } else { + if (strcmp(TELEGRAM_AUTH_MODE_SMS, auth_mode)) { + do_send_code (default_username); + printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); + } else { + printf ("You typed \"call\", switching to phone system.\n"); + do_phone_call (default_username); + printf ("Calling you! Code: "); + } } - auth_state = 300; + */ } } + 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); @@ -614,13 +600,29 @@ int loop (void) { #endif send_all_unsent (); - do_get_dialog_list (); if (wait_dialog_list) { dialog_list_got = 0; net_loop (0, dlgot); } - return main_loop (); + return 0; //main_loop (); } +/** + * Do what loop does, but use input from arguments instead of prompting + * the user + * + * When authentication is not yet done, request authenticatino code and exit + * with 0. In all other cases exit with 1. + */ +int loop_auto(char *username, char *code, char* auth_mode) { + init_loop(); + set_default_username (username); + return start_loop(code, auth_mode); +} + +int loop (void) { + init_loop(); + return start_loop(NULL, NULL); +} diff --git a/loop.h b/loop.h index 6f7c7e4..b586133 100644 --- a/loop.h +++ b/loop.h @@ -19,6 +19,7 @@ #ifndef __LOOP_H__ #define __LOOP_H__ int loop (void); +int loop_auto(char *username, char *code, char *auth_mode); void net_loop (int flags, int (*end)(void)); void write_auth_file (void); void write_state_file (void); diff --git a/main.c b/main.c index 9d858df..a8aa8e8 100644 --- a/main.c +++ b/main.c @@ -476,7 +476,7 @@ void sig_abrt_handler (int signum __attribute__ ((unused))) { exit (EXIT_FAILURE); } -int main (int argc, char **argv) { +int tgmain (int argc, char **argv) { signal (SIGSEGV, sig_segv_handler); signal (SIGABRT, sig_abrt_handler); @@ -503,6 +503,19 @@ int main (int argc, char **argv) { /** * Log into Telegram with the given login credentials. */ -int tg_login () { - return main(0, NULL); +int tg_login (char *username, char *code, char *auth_mode) { + log_level = 10; + running_for_first_time (); + parse_config (); + + get_terminal_attributes (); + + #ifdef USE_LUA + if (lua_file) { + lua_init (lua_file); + } + #endif + + loop_auto(username, code, auth_mode); + return 0; } diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index ad49259..31f5db6 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -15,6 +15,7 @@ */ #include +#include // Libpurple Plugin Includes #include "notify.h" @@ -82,18 +83,34 @@ static void tgprpl_login(PurpleAccount * acct) { purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); - purple_debug_info(PLUGIN_ID, "calling runtg()\n"); - tg_login(); - purple_debug_info(PLUGIN_ID, "returned from runtg()\n"); - - /* - PurpleConnection *gc = purple_account_get_connection(acct); - const char *username = purple_account_get_username(acct); - const char *sms_key = purple_account_get_string(acct, "sms_key", ""); + const char *code = purple_account_get_string(acct, "sms_key", NULL); const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); + printf("username: %s\n", username); + printf("code: %s\n", code); + printf("hostname: %s\n", hostname); + + // TODO: Do proper input validation + if (code && strcmp(code, "")) { + code = NULL; + } +// You should receive a SMS with a code soon, please copy that code into the account option 'Verification Key'. + if (!code) { + purple_notify_message( + _telegram_protocol, + PURPLE_NOTIFY_MSG_INFO, + "Telegram Verification", + "Telegram needs to verify this phone number. ", + NULL, + NULL, + NULL + ); + } + tg_login(username, code, TELEGRAM_AUTH_MODE_SMS); + /* + PurpleConnection *gc = purple_account_get_connection(acct); purple_debug_info(PLUGIN_ID, "logging in %s\n", username); if (strcmp(sms_key[0], "")) { @@ -494,7 +511,7 @@ static void tgprpl_init(PurplePlugin *plugin) GList *verification_values = NULL; // Required Verification-Key - split = purple_account_user_split_new("Verification key", "-", '@'); + split = purple_account_user_split_new("Verification key", NULL, '@'); purple_account_user_split_set_reverse(split, FALSE); prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); @@ -505,15 +522,16 @@ static void tgprpl_init(PurplePlugin *plugin) kvp->value = g_strdup((v)); \ list = g_list_prepend(list, kvp); \ } - ADD_VALUE(verification_values, "Phone", "phone"); - ADD_VALUE(verification_values, "SMS", "sms"); + ADD_VALUE(verification_values, "Phone", TELEGRAM_AUTH_MODE_PHONE); + ADD_VALUE(verification_values, "SMS", TELEGRAM_AUTH_MODE_SMS); option = purple_account_option_list_new("Verification type", "verification_type", verification_values); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - // TODO: Path to public key (When you can change the server hostname, you should also be able to change the public key) + // TODO: Path to public key (When you can change the server hostname, + // you should also be able to change the public key) option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); @@ -521,14 +539,6 @@ static void tgprpl_init(PurplePlugin *plugin) _telegram_protocol = plugin; } -/* -static gboolean plugin_load(PurplePlugin *plugin) { - purple_notify_message(plugin, PURPLE_NOTIFY_MSG_INFO, "Hallo Telegram", - "Das ist nur ein Test des Build-Systems, bitte einfach weiter gehen.", NULL, NULL, NULL); - return TRUE; -} -*/ - static GList *tgprpl_actions(PurplePlugin * plugin, gpointer context) { // return possible actions (See Libpurple doc) diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 72f7c32..3c0d48a 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -31,6 +31,9 @@ #define TELEGRAM_DEFAULT_PORT 443 #define TELEGRAM_PUBLIC_KEY "-----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daSan9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTwEfzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3nSlv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB-----END RSA PUBLIC KEY-----" +#define TELEGRAM_AUTH_MODE_PHONE "phone" +#define TELEGRAM_AUTH_MODE_SMS "sms" + typedef struct { PurpleAccount *account; PurpleConnection *gc; diff --git a/tg-cli.h b/tg-cli.h index b51fbf4..95b1156 100755 --- a/tg-cli.h +++ b/tg-cli.h @@ -1,3 +1,7 @@ // Export functions for plugins int tg_login (); + +// Settings +#define AUTH_MODE_SMS "sms" +#define AUTH_MODE_PHONE "phone" From 855c461f35f620cc1bbcb5df12ff83f68d9a67cf Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 23 May 2014 13:42:05 +0200 Subject: [PATCH 312/465] Debugging changes --- loop.c | 21 ++++++++++++++++++++- main.c | 7 ++++++- purple-plugin/Makefile | 5 ++++- purple-plugin/telegram-purple.c | 26 ++++++++++++++------------ 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/loop.c b/loop.c index 644593d..9954b3d 100644 --- a/loop.c +++ b/loop.c @@ -477,7 +477,9 @@ void init_loop (void) { } else { read_auth_file (); } + printf("update prompt()\n"); update_prompt (); + printf("update prompt() done... \n"); assert (DC_list[dc_working_num]); if (!DC_working || !DC_working->auth_key_id) { @@ -494,7 +496,9 @@ void init_loop (void) { logprintf ("Requesting info about DC...\n"); } do_help_get_config (); + printf("net_loop\n"); net_loop (0, mcs); + printf("net_loop done...\n"); if (verbosity) { logprintf ("DC_info: %d new DC got\n", new_dc_num); } @@ -507,27 +511,41 @@ void init_loop (void) { } int start_loop (char* code, char* auth_mode) { + printf("Calling start_loop()\n"); + printf("auth_state %i\n", auth_state); if (auth_state == 100 || !(DC_working->has_auth)) { + printf("auth_state == 100 || !(DC_working->has_auth)"); int res = do_auth_check_phone (default_username); assert (res >= 0); logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); if (res > 0 && !register_mode) { // Register Mode 1 + printf ("Register Mode 1\n"); if (code) { if (do_send_code_result (code) >= 0) { printf ("Authentication successfull, state = 300\n"); auth_state = 300; } } else { + printf("No code given, attempting to register\n"); // Send Code - if (strcmp(TELEGRAM_AUTH_MODE_SMS, auth_mode)) { + printf ("auth mode %s\n", auth_mode); + /* + if (strcmp(TELEGRAM_AUTH_MODE_SMS"sms", auth_mode)) { + */ do_send_code (default_username); printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); + printf("storing current state in auth file...\n"); + write_auth_file (); + printf("exitting...\n"); + return 0; + /* } else { printf ("You typed \"call\", switching to phone system.\n"); do_phone_call (default_username); printf ("Calling you!"); } + */ } } else { printf ("User is not registered. Do you want to register? [Y/n] "); @@ -575,6 +593,7 @@ int start_loop (char* code, char* auth_mode) { */ } } + printf("Authentication done\n"); int i; for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->has_auth) { diff --git a/main.c b/main.c index a8aa8e8..cc73045 100644 --- a/main.c +++ b/main.c @@ -57,6 +57,10 @@ # include "lua-tg.h" #endif +// TODO: Delete this shit +#include +#define BREAK raise(SIGINT); + #define PROGNAME "telegram-client" #define VERSION "0.01" @@ -515,7 +519,8 @@ int tg_login (char *username, char *code, char *auth_mode) { lua_init (lua_file); } #endif - + + BREAK loop_auto(username, code, auth_mode); return 0; } diff --git a/purple-plugin/Makefile b/purple-plugin/Makefile index 5edef35..a450ff2 100755 --- a/purple-plugin/Makefile +++ b/purple-plugin/Makefile @@ -43,15 +43,18 @@ LDFLAGS = $(ARCHFLAGS) -shared $(CC) -c $(INCLUDE) $(CFLAGS) -o $@ $< $(LIBNAME): $(C_OBJS) + cd ..; make objects; cd ./purple-plugin; $(LD) $(LDFLAGS) $(INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $^ $(OBJECTSTG) .PHONY: strip strip: $(LIBNAME) $(STRIP) --strip-unneeded $(LIBNAME) -.PHONY: debug +.PHONY: debug install debug: CFLAGS += -g -DDEBUG debug: $(LIBNAME) + gdb -tui pidgin + PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 31f5db6..fb5157f 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -90,25 +90,27 @@ static void tgprpl_login(PurpleAccount * acct) printf("username: %s\n", username); printf("code: %s\n", code); printf("hostname: %s\n", hostname); - + // TODO: Do proper input validation + /* if (code && strcmp(code, "")) { code = NULL; } - -// You should receive a SMS with a code soon, please copy that code into the account option 'Verification Key'. + */ if (!code) { - purple_notify_message( - _telegram_protocol, - PURPLE_NOTIFY_MSG_INFO, - "Telegram Verification", - "Telegram needs to verify this phone number. ", - NULL, - NULL, - NULL - ); + purple_notify_message( + _telegram_protocol, + PURPLE_NOTIFY_MSG_INFO, + "Telegram Verification", + "Telegram needs to verify this phone number. You should receive a SMS with a code soon, please copy that code into the account option 'Verification Key'.", + NULL, + NULL, + NULL + ); } tg_login(username, code, TELEGRAM_AUTH_MODE_SMS); + printf("Returned from tg_login...\n"); + /* PurpleConnection *gc = purple_account_get_connection(acct); purple_debug_info(PLUGIN_ID, "logging in %s\n", username); From 58244abb2dad2e57d4dab8465994d9a91b7e868a Mon Sep 17 00:00:00 2001 From: Christopher Althaus Date: Fri, 30 May 2014 10:05:48 +0200 Subject: [PATCH 313/465] changed login --- README.md | 5 +++++ purple-plugin/telegram-purple.c | 31 +++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d8541bb..88a3b65 100644 --- a/README.md +++ b/README.md @@ -107,4 +107,9 @@ git commit -> Commiten ## Troubleshooting +Zum löschen der angelegten Accounts +rm /home/USER/.purple/accounts.xml + Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden + + diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index fb5157f..f1ab3c5 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -83,14 +83,28 @@ static void tgprpl_login(PurpleAccount * acct) { purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); - const char *username = purple_account_get_username(acct); - const char *code = purple_account_get_string(acct, "sms_key", NULL); - const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); + const char *username = purple_account_get_username(acct); + const char *code = purple_account_get_string(acct, "verification_key", NULL); + const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); + const char *verificationType = purple_account_get_string(acct, "verification_type", TELEGRAM_AUTH_MODE_SMS); int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); + printf("username: %s\n", username); printf("code: %s\n", code); printf("hostname: %s\n", hostname); + purple_debug_info(PLUGIN_ID, "running_for_first_time()\n"); + running_for_first_time(); + purple_debug_info(PLUGIN_ID, "parse_config()\n"); + parse_config (); + purple_debug_info(PLUGIN_ID, "init_loop()\n"); + init_loop(); + purple_debug_info(PLUGIN_ID, "set_default_username()\n"); + set_default_username (username); + purple_debug_info(PLUGIN_ID, "start_loop() -> Authentication\n"); + start_loop (code, verificationType); + + // TODO: Do proper input validation /* if (code && strcmp(code, "")) { @@ -108,7 +122,7 @@ static void tgprpl_login(PurpleAccount * acct) NULL ); } - tg_login(username, code, TELEGRAM_AUTH_MODE_SMS); + // tg_login(username, code, TELEGRAM_AUTH_MODE_SMS); printf("Returned from tg_login...\n"); /* @@ -508,14 +522,14 @@ static PurplePluginProtocolInfo prpl_info = { static void tgprpl_init(PurplePlugin *plugin) { - PurpleAccountOption *option; + PurpleAccountOption *option; PurpleAccountUserSplit *split; GList *verification_values = NULL; // Required Verification-Key - split = purple_account_user_split_new("Verification key", NULL, '@'); - purple_account_user_split_set_reverse(split, FALSE); - prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); +// split = purple_account_user_split_new("Verification key", NULL, '@'); +// purple_account_user_split_set_reverse(split, FALSE); +// prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); // Extra Options #define ADD_VALUE(list, desc, v) { \ @@ -530,6 +544,7 @@ static void tgprpl_init(PurplePlugin *plugin) prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); + option = purple_account_option_string_new("Verification key", "verification_key", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); // TODO: Path to public key (When you can change the server hostname, From 93f4bd25ae888d044eba5063dceff0aa88e15635 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 9 Jun 2014 14:22:06 +0200 Subject: [PATCH 314/465] Add an externally controllable message-log and redirect tg-cli logging to the libpurple logging mechanism --- Makefile.in | 4 +- interface.c | 11 ++++-- msglog.c | 67 +++++++++++++++++++++++++++++++++ msglog.h | 17 +++++++++ purple-plugin/Makefile | 2 +- purple-plugin/telegram-purple.c | 25 ++++++++++-- 6 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 msglog.c create mode 100644 msglog.h diff --git a/Makefile.in b/Makefile.in index e710bd7..eb4650f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -13,10 +13,10 @@ EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h ${srcdir}/msglog.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o msglog.o .SUFFIXES: diff --git a/interface.c b/interface.c index cd7635e..6af4dc0 100644 --- a/interface.c +++ b/interface.c @@ -49,6 +49,7 @@ // libpurple debugging-messages #include "debug.h" #include "purple-plugin/telegram-purple.h" +#include "msglog.h" #define ALLOW_MULT 1 char *default_prompt = "> "; @@ -1191,20 +1192,22 @@ void hexdump (int *in_ptr, int *in_end) { } void logprintf (const char *format, ...) { + va_list ap; + va_start (ap, format); + log_message(format, ap); + va_end (ap); + /* int x = 0; if (!prompt_was) { x = 1; print_start (); } printf (COLOR_GREY " *** "); - va_list ap; - va_start (ap, format); - vfprintf (stdout, format, ap); - va_end (ap); printf (COLOR_NORMAL); if (x) { print_end (); } + */ } int color_stack_pos; diff --git a/msglog.c b/msglog.c new file mode 100644 index 0000000..cbe1828 --- /dev/null +++ b/msglog.c @@ -0,0 +1,67 @@ +#include +#include + +#define COLOR_RED "\033[0;31m" +#define COLOR_REDB "\033[1;31m" +#define COLOR_NORMAL "\033[0m" +#define COLOR_GREEN "\033[32;1m" +#define COLOR_GREY "\033[37;1m" +#define COLOR_YELLOW "\033[33;1m" +#define COLOR_BLUE "\033[34;1m" +#define COLOR_MAGENTA "\033[35;1m" +#define COLOR_CYAN "\033[36;1m" +#define COLOR_LCYAN "\033[0;36m" + +#define COLOR_INVERSE "\033[7m" + +void log_printf(const char *format, ...) +{ + printf (COLOR_GREY " *** "); + va_list ap; + va_start (ap, format); + vfprintf (stdout, format, ap); + va_end (ap); + printf (COLOR_NORMAL); +} + +/** + * The callback that will log the given msg to the used target + */ +void (*log_cb)(const char*, ...) = log_printf; + +/** + * Set a custom logging callback to use instead of the regular + * printf to stdout + */ +void set_log_cb(void (*cb)(const char*, ...)) +{ + log_cb = cb; +} + +/** + * Log a message to the current message log + */ +void log_message(const char *format, ...) +{ + va_list ap; + va_start (ap, format); + log_cb(format, ap); + va_end (ap); +} + +/* +TODO: implement different log levels + +void log_debug(const char* format, ...) +{ +} + +void log_warning(const char* format, ...) +{ +} + +void log_error(const char* format, ...) +{ +} +*/ + diff --git a/msglog.h b/msglog.h new file mode 100644 index 0000000..07d74dc --- /dev/null +++ b/msglog.h @@ -0,0 +1,17 @@ +/** + * Set a custom logging callback to use instead of regular printing + * to stdout + */ +void set_log_cb(void (*cb)(const char*, ...)); + +/** + * Log a message to the current message log + */ +void log_message(const char *format, ...); + +/* +void log_debug(const char* format, ...); +void log_warning(const char* format, ...); +void log_error(const char* format, ...); +*/ + diff --git a/purple-plugin/Makefile b/purple-plugin/Makefile index a450ff2..87b5aca 100755 --- a/purple-plugin/Makefile +++ b/purple-plugin/Makefile @@ -4,7 +4,7 @@ EXTRA_LIBS = -lcrypto -lz -lm -lreadline LDFLAGSTG = -L/usr/local/lib CPPFLAGSTG = -I/usr/local/include -OBJECTSTG = ../main.o ../loop.o ../interface.o ../net.o ../mtproto-common.o ../mtproto-client.o ../queries.o ../structures.o ../binlog.o ../tools.o ../lua-tg.o +OBJECTSTG = ../main.o ../loop.o ../interface.o ../net.o ../mtproto-common.o ../mtproto-client.o ../queries.o ../structures.o ../binlog.o ../tools.o ../lua-tg.o ../msglog.o INCLUDE = -I. -I.. # diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f1ab3c5..4d73b4b 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -16,10 +16,13 @@ #include #include +#include + +// test // Libpurple Plugin Includes #include "notify.h" -#include "plugin.h" // NEEDED? +#include "plugin.h" #include "version.h" #include "account.h" #include "accountopt.h" @@ -37,13 +40,26 @@ // Telegram Includes #include +#include "msglog.h" // telegram-purple includes +#include "loop.h" #include "telegram-purple.h" - static PurplePlugin *_telegram_protocol = NULL; +/** + * Redirect the msglog of the telegram-cli application to the libpurple + * logger + */ +void tg_cli_log_cb(const char* format, ...) +{ + va_list ap; + va_start (ap, format); + purple_debug_info(PLUGIN_ID, format, ap); + va_end (ap); +} + /** * Returns the base icon name for the given buddy and account. * If buddy is NULL and the account is non-NULL, it will return the @@ -522,10 +538,13 @@ static PurplePluginProtocolInfo prpl_info = { static void tgprpl_init(PurplePlugin *plugin) { - PurpleAccountOption *option; + PurpleAccountOption *option; PurpleAccountUserSplit *split; GList *verification_values = NULL; + // intialise logging + set_log_cb(&tg_cli_log_cb); + // Required Verification-Key // split = purple_account_user_split_new("Verification key", NULL, '@'); // purple_account_user_split_set_reverse(split, FALSE); From 90f7b39e11ede386c155c29700744b5f5793b53a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 15 Jun 2014 03:22:39 +0200 Subject: [PATCH 315/465] Fix log format arguments Remove the misuse of va_list and emulate behavior of purple debugging functions in our own code, since a va_list cannot be passed to purple_debug_info, --- interface.c | 24 ++++++++++++------------ msglog.c | 17 +++++++++-------- msglog.h | 6 ++++-- purple-plugin/telegram-purple.c | 17 ++++++++++++----- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/interface.c b/interface.c index 6af4dc0..6f77bac 100644 --- a/interface.c +++ b/interface.c @@ -1191,24 +1191,24 @@ void hexdump (int *in_ptr, int *in_end) { print_end (); } +/* void logprintf (const char *format, ...) { va_list ap; va_start (ap, format); log_message(format, ap); va_end (ap); - /* - int x = 0; - if (!prompt_was) { - x = 1; - print_start (); - } - printf (COLOR_GREY " *** "); - printf (COLOR_NORMAL); - if (x) { - print_end (); - } - */ + //int x = 0; + //if (!prompt_was) { + // x = 1; + // print_start (); + //} + //printf (COLOR_GREY " *** "); + //printf (COLOR_NORMAL); + //if (x) { + // print_end (); + //} } +*/ int color_stack_pos; const char *color_stack[10]; diff --git a/msglog.c b/msglog.c index cbe1828..0799b79 100644 --- a/msglog.c +++ b/msglog.c @@ -14,26 +14,27 @@ #define COLOR_INVERSE "\033[7m" -void log_printf(const char *format, ...) +/** + * Log a message to the telegram-cli message log, by + * just writing it to STDOUT and appending '***' + */ +void log_printf(const char *format, va_list ap) { printf (COLOR_GREY " *** "); - va_list ap; - va_start (ap, format); - vfprintf (stdout, format, ap); - va_end (ap); + vprintf (format, ap); printf (COLOR_NORMAL); } /** * The callback that will log the given msg to the used target */ -void (*log_cb)(const char*, ...) = log_printf; +void (*log_cb)(const char* format, va_list ap) = log_printf; /** * Set a custom logging callback to use instead of the regular * printf to stdout */ -void set_log_cb(void (*cb)(const char*, ...)) +void set_log_cb(void (*cb)(const char*, va_list ap)) { log_cb = cb; } @@ -41,7 +42,7 @@ void set_log_cb(void (*cb)(const char*, ...)) /** * Log a message to the current message log */ -void log_message(const char *format, ...) +void logprintf(const char *format, ...) { va_list ap; va_start (ap, format); diff --git a/msglog.h b/msglog.h index 07d74dc..e574ba2 100644 --- a/msglog.h +++ b/msglog.h @@ -1,13 +1,15 @@ +#include + /** * Set a custom logging callback to use instead of regular printing * to stdout */ -void set_log_cb(void (*cb)(const char*, ...)); +void set_log_cb(void (*cb)(const char*, va_list ap)); /** * Log a message to the current message log */ -void log_message(const char *format, ...); +void logprintf(const char *format, ...); /* void log_debug(const char* format, ...); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 4d73b4b..2e417c2 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include // test @@ -37,6 +40,8 @@ #include "status.h" #include "util.h" #include "prpl.h" +#include "prefs.h" +#include "util.h" // Telegram Includes #include @@ -52,12 +57,14 @@ static PurplePlugin *_telegram_protocol = NULL; * Redirect the msglog of the telegram-cli application to the libpurple * logger */ -void tg_cli_log_cb(const char* format, ...) +void tg_cli_log_cb(const char* format, va_list ap) { - va_list ap; - va_start (ap, format); - purple_debug_info(PLUGIN_ID, format, ap); - va_end (ap); + // emulate libpurple logging function, because we cant pass va_list + // directly + time_t mtime = time(NULL); + const char *mdate = purple_utf8_strftime("%H:%M:%S", localtime(&mtime)); + printf("(%s) prpl-telegram: ", mdate); + vprintf(format, ap); } /** From 62090b3ca0e418121f1140fd5f8030d94d876443 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 15 Jun 2014 13:38:38 +0200 Subject: [PATCH 316/465] Implement login and authentication mechanism and fix the logging mechanism Use purple debugging functions by formatting the string beforehand and then passing the readily formatted string, instead of doing it with va_list. Log into the telegram network using the provided SMS code and hash or request a new one, in case one of those isn't provided. Store and load the state using the file config/auth, to be able to restore previous logins. --- loop.c | 139 +++++++++++++++++++++++++------- mtproto-client.c | 2 + net.c | 1 + purple-plugin/Makefile | 4 +- purple-plugin/telegram-purple.c | 127 +++++++++++++++-------------- queries.c | 125 ++++++++++++++-------------- queries.h | 4 +- tg-cli.h | 33 ++++++++ 8 files changed, 280 insertions(+), 155 deletions(-) diff --git a/loop.c b/loop.c index 9954b3d..61b0a5b 100644 --- a/loop.c +++ b/loop.c @@ -75,6 +75,7 @@ extern int queries_num; int unread_messages; void got_it (char *line, int len); void net_loop (int flags, int (*is_end)(void)) { + logprintf("starting net_loop()\n"); while (!is_end ()) { struct pollfd fds[101]; int cc = 0; @@ -84,11 +85,13 @@ void net_loop (int flags, int (*is_end)(void)) { cc ++; } + logprintf("writing_state_file()\n"); write_state_file (); int x = connections_make_poll_array (fds + cc, 101 - cc) + cc; double timer = next_timer_in (); if (timer > 1000) { timer = 1000; } if (poll (fds, x, timer) < 0) { + logprintf("poll returned -1, wait a little bit.\n"); work_timers (); continue; } @@ -109,7 +112,7 @@ void net_loop (int flags, int (*is_end)(void)) { lua_do_all (); #endif if (safe_quit && !queries_num) { - printf ("All done. Exit\n"); + logprintf ("All done. Exit\n"); rl_callback_handler_remove (); exit (0); } @@ -182,6 +185,11 @@ void write_dc (int auth_file_fd, struct dc *DC) { } int our_id; + +void store_config () { + write_auth_file(); +} + void write_auth_file (void) { if (binlog_enabled) { return; } int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); @@ -220,9 +228,9 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (read (auth_file_fd, &DC->auth_key, 256) == 256); assert (read (auth_file_fd, &DC->server_salt, 8) == 8); - printf("auth_key_id: %lli \n", DC->auth_key_id); - printf("auth_key_id: ?"); - printf("server_salt: %lli \n", DC->server_salt); + logprintf("auth_key_id: %lli \n", DC->auth_key_id); + logprintf("auth_key_id: ?"); + logprintf("server_salt: %lli \n", DC->server_salt); if (DC->auth_key_id) { DC->flags |= 1; } @@ -248,7 +256,10 @@ void read_auth_file (void) { empty_auth_file (); } assert (auth_file_fd >= 0); + + // amount of data centers unsigned x; + // magic number of file unsigned m; if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) { close (auth_file_fd); @@ -463,7 +474,11 @@ int readline_active; int new_dc_num; int wait_dialog_list; -void init_loop (void) { +/** + * Discover the network and authorise with all data centers + */ +void network_connect (void) { + verbosity = 0; on_start (); if (binlog_enabled) { double t = get_double_time (); @@ -477,79 +492,141 @@ void init_loop (void) { } else { read_auth_file (); } - printf("update prompt()\n"); + logprintf("update prompt()\n"); update_prompt (); - printf("update prompt() done... \n"); + logprintf("update prompt() done... \n"); assert (DC_list[dc_working_num]); if (!DC_working || !DC_working->auth_key_id) { // if (auth_state == 0) { + logprintf("No working DC or not start_loopd.\n"); DC_working = DC_list[dc_working_num]; assert (!DC_working->auth_key_id); dc_authorize (DC_working); assert (DC_working->auth_key_id); auth_state = 100; write_auth_file (); + logprintf("Authorized DataCentre: auth_key_id: %lld \n", DC_working->auth_key_id); } if (verbosity) { logprintf ("Requesting info about DC...\n"); } do_help_get_config (); - printf("net_loop\n"); + logprintf("net_loop\n"); net_loop (0, mcs); - printf("net_loop done...\n"); + logprintf("net_loop done...\n"); if (verbosity) { logprintf ("DC_info: %d new DC got\n", new_dc_num); } int i; for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->auth_key_id) { + logprintf("DataCentre %d not start_loopd, authorizing...\n", i); dc_authorize (DC_list[i]); assert (DC_list[i]->auth_key_id); write_auth_file (); + logprintf("DataCentre start_loopd, key id: %lld\n", DC_list[i]->auth_key_id); } } +/** + * Return if the given phone is registered + */ +int network_phone_is_registered() { + int res = do_auth_check_phone (default_username); + assert(res >= 0); + return res; +} + + +/** + * Return if the current client is registered. + */ +int network_client_is_registered() { + return !(auth_state == 100 || !(DC_working->has_auth)); +} + +/** + * Request a verification for the given client, by sending + * a code to the current phone number + */ +char* network_request_registration () +{ + return do_send_code (default_username); +} + +/** + * Verify the phone, by providing the code and the real name + * + * NOTE: This should be called when the phone number was previously + * unknown to the telegram network. + */ +int network_verify_phone_registration(char* code, char *firstname, char *lastname) +{ + if (do_send_code_result_auth (code, firstname, lastname) >= 0) { + auth_state = 300; + return 1; + } + return 0; +} + +/** + * Verify the current client by providing the given code + */ +int network_verify_registration(const char *code, const char *sms_hash) +{ + logprintf("telegram: pointer - code: %p, hash: %p\n", code, sms_hash); + logprintf("telegram: string - code: %s, hash: %s\n", code, sms_hash); + if (do_send_code_result (code, sms_hash) >= 0) { + logprintf ("Authentication successfull, state = 300\n"); + auth_state = 300; + return 1; + } + return 0; +} + int start_loop (char* code, char* auth_mode) { - printf("Calling start_loop()\n"); - printf("auth_state %i\n", auth_state); + logprintf("Calling start_loop()\n"); + logprintf("auth_state %i\n", auth_state); if (auth_state == 100 || !(DC_working->has_auth)) { - printf("auth_state == 100 || !(DC_working->has_auth)"); + logprintf("auth_state == 100 || !(DC_working->has_auth)"); int res = do_auth_check_phone (default_username); assert (res >= 0); logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); if (res > 0 && !register_mode) { // Register Mode 1 - printf ("Register Mode 1\n"); + logprintf ("Register Mode 1\n"); if (code) { + /* if (do_send_code_result (code) >= 0) { - printf ("Authentication successfull, state = 300\n"); + logprintf ("Authentication successfull, state = 300\n"); auth_state = 300; } + */ } else { - printf("No code given, attempting to register\n"); + logprintf("No code given, attempting to register\n"); // Send Code - printf ("auth mode %s\n", auth_mode); + logprintf ("auth mode %s\n", auth_mode); /* if (strcmp(TELEGRAM_AUTH_MODE_SMS"sms", auth_mode)) { */ do_send_code (default_username); - printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); - printf("storing current state in auth file...\n"); + logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); + logprintf("storing current state in auth file...\n"); write_auth_file (); - printf("exitting...\n"); + logprintf("exitting...\n"); return 0; /* } else { - printf ("You typed \"call\", switching to phone system.\n"); + logprintf ("You typed \"call\", switching to phone system.\n"); do_phone_call (default_username); - printf ("Calling you!"); + logprintf ("Calling you!"); } */ } } else { - printf ("User is not registered. Do you want to register? [Y/n] "); - printf ("ERROR THIS IS NOT POSSIBLE!\n"); + logprintf ("User is not registered. Do you want to register? [Y/n] "); + logprintf ("ERROR THIS IS NOT POSSIBLE!\n"); return 1; // Register Mode 2 // TODO: Requires first and last name, decide how to handle this. @@ -559,13 +636,13 @@ int start_loop (char* code, char* auth_mode) { /* size_t size; char *first_name; - printf ("First name: "); + logprintf ("First name: "); if (net_getline (&first_name, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); } char *last_name; - printf ("Last name: "); + logprintf ("Last name: "); if (net_getline (&last_name, &size) == -1) { perror ("getline()"); exit (EXIT_FAILURE); @@ -583,17 +660,17 @@ int start_loop (char* code, char* auth_mode) { } else { if (strcmp(TELEGRAM_AUTH_MODE_SMS, auth_mode)) { do_send_code (default_username); - printf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); + logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); } else { - printf ("You typed \"call\", switching to phone system.\n"); + logprintf ("You typed \"call\", switching to phone system.\n"); do_phone_call (default_username); - printf ("Calling you! Code: "); + logprintf ("Calling you! Code: "); } } */ } } - printf("Authentication done\n"); + logprintf("Authentication done\n"); int i; for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->has_auth) { @@ -636,12 +713,12 @@ int start_loop (char* code, char* auth_mode) { * with 0. In all other cases exit with 1. */ int loop_auto(char *username, char *code, char* auth_mode) { - init_loop(); + network_connect(); set_default_username (username); return start_loop(code, auth_mode); } int loop (void) { - init_loop(); + network_connect(); return start_loop(NULL, NULL); } diff --git a/mtproto-client.c b/mtproto-client.c index cb598d3..442e4c2 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -225,6 +225,7 @@ int rpc_send_packet (struct connection *c) { } int rpc_send_message (struct connection *c, void *data, int len) { + logprintf("rpc_send_message(...)\n"); assert (len > 0 && !(len & 0xfc000003)); int total_len = len >> 2; if (total_len < 0x7f) { @@ -743,6 +744,7 @@ int aes_encrypt_message (struct dc *DC, struct encrypted_message *enc) { } long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful) { + logprintf("encrypt_send_message(...)\n"); struct dc *DC = GET_DC(c); struct session *S = c->session; assert (S); diff --git a/net.c b/net.c index 881f670..db2b474 100644 --- a/net.c +++ b/net.c @@ -634,6 +634,7 @@ struct dc *alloc_dc (int id, char *ip, int port UU) { } void dc_create_session (struct dc *DC) { + logprintf("dc_create_session(...)\n"); struct session *S = talloc0 (sizeof (*S)); assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); S->dc = DC; diff --git a/purple-plugin/Makefile b/purple-plugin/Makefile index 87b5aca..0651517 100755 --- a/purple-plugin/Makefile +++ b/purple-plugin/Makefile @@ -16,7 +16,7 @@ ifeq ($(ARCH),i686) else ifeq ($(ARCH),x86_64) ARCHFLAGS = -m64 else - ARCHFLAGS = + ARCHFLAGS = endif .PHONY: all @@ -83,4 +83,4 @@ clean: .PHONY: run run: all install - pidgin -d + pidgin -d | grep telegram diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 2e417c2..ffab3d8 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -59,12 +59,9 @@ static PurplePlugin *_telegram_protocol = NULL; */ void tg_cli_log_cb(const char* format, va_list ap) { - // emulate libpurple logging function, because we cant pass va_list - // directly - time_t mtime = time(NULL); - const char *mdate = purple_utf8_strftime("%H:%M:%S", localtime(&mtime)); - printf("(%s) prpl-telegram: ", mdate); - vprintf(format, ap); + char buffer[256]; + vsnprintf(buffer, sizeof(buffer), format, ap); + purple_debug_info(PLUGIN_ID, "%s", buffer); } /** @@ -105,73 +102,79 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info static void tgprpl_login(PurpleAccount * acct) { purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); + PurpleConnection *gc = purple_account_get_connection(acct); - const char *username = purple_account_get_username(acct); - const char *code = purple_account_get_string(acct, "verification_key", NULL); - const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); - const char *verificationType = purple_account_get_string(acct, "verification_type", TELEGRAM_AUTH_MODE_SMS); - int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); + const char *username = purple_account_get_username(acct); + const char *code = purple_account_get_string(acct, "verification_key", NULL); + const char *hash = purple_account_get_string(acct, "verification_hash", NULL); + const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); + // const char *verificationType = purple_account_get_string(acct, "verification_type", TELEGRAM_AUTH_MODE_SMS); + // int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); - printf("username: %s\n", username); - printf("code: %s\n", code); - printf("hostname: %s\n", hostname); + purple_debug_info(PLUGIN_ID, "username: %s\n", username); + purple_debug_info(PLUGIN_ID, "code: %s\n", code); + purple_debug_info(PLUGIN_ID, "verification_hash: %s\n", hash); + purple_debug_info(PLUGIN_ID, "hostname: %s\n", hostname); + // ensure config-file exists an purple_debug_info(PLUGIN_ID, "running_for_first_time()\n"); running_for_first_time(); + + // load all settings: the known network topology, log and configuration file paths purple_debug_info(PLUGIN_ID, "parse_config()\n"); parse_config (); - purple_debug_info(PLUGIN_ID, "init_loop()\n"); - init_loop(); purple_debug_info(PLUGIN_ID, "set_default_username()\n"); set_default_username (username); - purple_debug_info(PLUGIN_ID, "start_loop() -> Authentication\n"); - start_loop (code, verificationType); - - - // TODO: Do proper input validation - /* - if (code && strcmp(code, "")) { - code = NULL; - } - */ - if (!code) { - purple_notify_message( - _telegram_protocol, - PURPLE_NOTIFY_MSG_INFO, - "Telegram Verification", - "Telegram needs to verify this phone number. You should receive a SMS with a code soon, please copy that code into the account option 'Verification Key'.", - NULL, - NULL, - NULL - ); - } - // tg_login(username, code, TELEGRAM_AUTH_MODE_SMS); - printf("Returned from tg_login...\n"); - /* - PurpleConnection *gc = purple_account_get_connection(acct); - purple_debug_info(PLUGIN_ID, "logging in %s\n", username); + // Connect to the network + purple_debug_info(PLUGIN_ID, "Connecting to the Telegram network...\n"); + network_connect(); - if (strcmp(sms_key[0], "")) { - purple_debug_info(PLUGIN_ID, "no sms key -> send sms key request\n"); - } + // Login + if (!network_phone_is_registered()) { + purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); + } - purple_debug_info(PLUGIN_ID, "Connect\n"); - purple_connection_update_progress(gc, "Connecting", 0, 4); - telegram_conn *conn; - conn = g_new0(telegram_conn, 1); - conn->gc = gc; + if (!network_client_is_registered()) { + purple_debug_info(PLUGIN_ID, "Client is not registered\n"); + + if (code && hash) { + purple_debug_info(PLUGIN_ID, "SMS code provided, trying to verify \n"); + purple_debug_info(PLUGIN_ID, "pointer - code:%p hash:%p\n", code, hash); + purple_debug_info(PLUGIN_ID, "string - code%s hash:%s\n", code, hash); + int verified = network_verify_registration(code, hash); + if (verified) { + store_config(); + } else { + purple_connection_set_state(gc, PURPLE_DISCONNECTED); + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", + "Please make sure you entered the correct verification code.", NULL, NULL, NULL); + return; + } + } else { + // TODO: we should find a way to request the key + // only once. + purple_debug_info(PLUGIN_ID, "Device not registered, requesting new authentication code.\n"); + char *new_hash = network_request_registration(); + purple_debug_info(PLUGIN_ID, "Saving verification_hash: '%s'", new_hash); + purple_account_set_string(acct, "verification_hash", new_hash); + } + } + + // Our protocol data, that will be delivered to us + // through purple connection + telegram_conn *conn = g_new0(telegram_conn, 1); + conn->gc = gc; conn->account = acct; + purple_connection_set_protocol_data(gc, conn); - gc->proto_data = conn; - purple_connection_set_state(gc, PURPLE_CONNECTED); - - purple_debug_info(PLUGIN_ID, "Connected\n"); - */ + + // TODO: probably needs to be in callback after connection + purple_connection_set_state(gc, PURPLE_CONNECTED); + purple_debug_info(PLUGIN_ID, "Logged in...\n"); } - /** * This must be implemented. */ @@ -192,6 +195,7 @@ static void tgprpl_close(PurpleConnection * gc) static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) { purple_debug_info(PLUGIN_ID, "tgprpl_send_im()\n"); + return -1; } @@ -241,7 +245,6 @@ static void tgprpl_add_buddies(PurpleConnection * gc, GList * buddies, GList * g static void tgprpl_remove_buddy(PurpleConnection * gc, PurpleBuddy * buddy, PurpleGroup * group) { purple_debug_info(PLUGIN_ID, "tgprpl_remove_buddy()\n"); - } static void tgprpl_remove_buddies(PurpleConnection * gc, GList * buddies, GList * groups) @@ -569,8 +572,13 @@ static void tgprpl_init(PurplePlugin *plugin) option = purple_account_option_list_new("Verification type", "verification_type", verification_values); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); - option = purple_account_option_string_new("Verification key", "verification_key", NULL); + // option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); + // prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_string_new("Verification key", "verification_key", NULL); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_string_new("Verification hash", "verification_hash", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); // TODO: Path to public key (When you can change the server hostname, @@ -617,4 +625,5 @@ static PurplePluginInfo info = { NULL // reserved }; + PURPLE_INIT_PLUGIN(telegram, tgprpl_init, info) diff --git a/queries.c b/queries.c index 5087531..181f766 100644 --- a/queries.c +++ b/queries.c @@ -126,11 +126,13 @@ void query_restart (long long id) { } struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { + logprintf("send_query(...)\n"); assert (DC); assert (DC->auth_key_id); if (!DC->sessions[0]) { dc_create_session (DC); } + logprintf("telegram: verbosity: %d\n", verbosity); if (verbosity) { logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } @@ -397,6 +399,7 @@ int send_code_on_answer (struct query *q UU) { tfree_str (phone_code_hash); } phone_code_hash = tstrndup (s, l); + logprintf("telegram: phone_code_hash: %s\n", phone_code_hash); fetch_int (); fetch_bool (); want_dc_num = -1; @@ -434,7 +437,7 @@ int config_got (void) { char *suser; extern int dc_working_num; -void do_send_code (const char *user) { +char* do_send_code (const char *user) { logprintf ("sending code\n"); suser = tstrdup (user); want_dc_num = 0; @@ -450,7 +453,7 @@ void do_send_code (const char *user) { logprintf ("send_code: dc_num = %d\n", dc_working_num); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); - if (want_dc_num == -1) { return; } + if (want_dc_num == -1) { return phone_code_hash; } DC_working = DC_list[want_dc_num]; if (!DC_working->sessions[0]) { @@ -474,6 +477,8 @@ void do_send_code (const char *user) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); assert (want_dc_num == -1); + + return phone_code_hash; } @@ -626,12 +631,11 @@ int sign_in_on_answer (struct query *q UU) { fetch_user (&User); if (!our_id) { our_id = get_peer_id (User.id); - bl_do_set_our_id (our_id); } sign_in_ok = 1; 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 ())); + logprintf ( "telegram: 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; @@ -643,7 +647,6 @@ int sign_in_on_answer (struct query *q UU) { 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; } @@ -652,11 +655,11 @@ struct query_methods sign_in_methods = { .on_error = sign_in_on_error }; -int do_send_code_result (const char *code) { +int do_send_code_result (const char *code, const char *sms_hash) { clear_packet (); out_int (CODE_auth_sign_in); out_string (suser); - out_string (phone_code_hash); + out_string(sms_hash); out_string (code); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, 0); sign_in_ok = 0; @@ -698,27 +701,27 @@ int get_contacts_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user (); print_start (); push_color (COLOR_YELLOW); - printf ("User #%d: ", get_peer_id (U->id)); + logprintf ("User #%d: ", get_peer_id (U->id)); print_user_name (U->id, (peer_t *)U); push_color (COLOR_GREEN); - printf (" ("); - printf ("%s", U->print_name); + logprintf (" ("); + logprintf ("%s", U->print_name); if (U->phone) { - printf (" "); - printf ("%s", U->phone); + logprintf (" "); + logprintf ("%s", U->phone); } - printf (") "); + logprintf (") "); pop_color (); if (U->status.online > 0) { - printf ("online\n"); + logprintf ("online\n"); } else { if (U->status.online < 0) { - printf ("offline. Was online "); + logprintf ("offline. Was online "); print_date_full (U->status.when); } else { - printf ("offline permanent"); + logprintf ("offline permanent"); } - printf ("\n"); + logprintf ("\n"); } pop_color (); print_end (); @@ -872,9 +875,9 @@ int msg_send_on_answer (struct query *q UU) { } print_start (); push_color (COLOR_YELLOW); - printf ("Link with user "); + logprintf ("Link with user "); print_user_name (U->id, (void *)U); - printf (" changed\n"); + logprintf (" changed\n"); pop_color (); print_end (); } @@ -1175,15 +1178,15 @@ int get_dialogs_on_answer (struct query *q UU) { switch (get_peer_type (plist[i])) { case PEER_USER: UC = user_chat_get (plist[i]); - printf ("User "); + logprintf ("User "); print_user_name (plist[i], UC); - printf (": %d unread\n", dlist[2 * i + 1]); + logprintf (": %d unread\n", dlist[2 * i + 1]); break; case PEER_CHAT: UC = user_chat_get (plist[i]); - printf ("Chat "); + logprintf ("Chat "); print_chat_name (plist[i], UC); - printf (": %d unread\n", dlist[2 * i + 1]); + logprintf (": %d unread\n", dlist[2 * i + 1]); break; } } @@ -1646,21 +1649,21 @@ void print_chat_info (struct chat *C) { peer_t *U = (void *)C; print_start (); push_color (COLOR_YELLOW); - printf ("Chat "); + logprintf ("Chat "); print_chat_name (U->id, U); - printf (" members:\n"); + logprintf (" members:\n"); int i; for (i = 0; i < C->user_list_size; i++) { - printf ("\t\t"); + logprintf ("\t\t"); 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 "); + logprintf (" invited by "); print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (MK_USER (C->user_list[i].inviter_id))); - printf (" at "); + logprintf (" at "); print_date_full (C->user_list[i].date); if (C->user_list[i].user_id == C->admin_id) { - printf (" admin"); + logprintf (" admin"); } - printf ("\n"); + logprintf ("\n"); } pop_color (); print_end (); @@ -1700,17 +1703,17 @@ void print_user_info (struct user *U) { peer_t *C = (void *)U; print_start (); push_color (COLOR_YELLOW); - printf ("User "); + logprintf ("User "); print_user_name (U->id, C); - printf (":\n"); - printf ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); - printf ("\tphone: %s\n", U->phone); + logprintf (":\n"); + logprintf ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); + logprintf ("\tphone: %s\n", U->phone); if (U->status.online > 0) { - printf ("\tonline\n"); + logprintf ("\tonline\n"); } else { - printf ("\toffline (was online "); + logprintf ("\toffline (was online "); print_date_full (U->status.when); - printf (")\n"); + logprintf (")\n"); } pop_color (); print_end (); @@ -2127,27 +2130,27 @@ int add_contact_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user (); print_start (); push_color (COLOR_YELLOW); - printf ("User #%d: ", get_peer_id (U->id)); + logprintf ("User #%d: ", get_peer_id (U->id)); print_user_name (U->id, (peer_t *)U); push_color (COLOR_GREEN); - printf (" ("); - printf ("%s", U->print_name); + logprintf (" ("); + logprintf ("%s", U->print_name); if (U->phone) { - printf (" "); - printf ("%s", U->phone); + logprintf (" "); + logprintf ("%s", U->phone); } - printf (") "); + logprintf (") "); pop_color (); if (U->status.online > 0) { - printf ("online\n"); + logprintf ("online\n"); } else { if (U->status.online < 0) { - printf ("offline. Was online "); + logprintf ("offline. Was online "); print_date_full (U->status.when); } else { - printf ("offline permanent"); + logprintf ("offline permanent"); } - printf ("\n"); + logprintf ("\n"); } pop_color (); print_end (); @@ -2223,11 +2226,11 @@ int contacts_search_on_answer (struct query *q UU) { push_color (COLOR_YELLOW); for (i = 0; i < n; i++) { struct user *U = fetch_alloc_user (); - printf ("User "); + logprintf ("User "); push_color (COLOR_RED); - printf ("%s %s", U->first_name, U->last_name); + logprintf ("%s %s", U->first_name, U->last_name); pop_color (); - printf (". Phone %s\n", U->phone); + logprintf (". Phone %s\n", U->phone); } pop_color (); print_end (); @@ -2254,17 +2257,17 @@ int send_encr_accept_on_answer (struct query *q UU) { if (E->state == sc_ok) { print_start (); push_color (COLOR_YELLOW); - printf ("Encrypted connection with "); + logprintf ("Encrypted connection with "); print_encr_chat_name (E->id, (void *)E); - printf (" established\n"); + logprintf (" established\n"); pop_color (); print_end (); } else { print_start (); push_color (COLOR_YELLOW); - printf ("Encrypted connection with "); + logprintf ("Encrypted connection with "); print_encr_chat_name (E->id, (void *)E); - printf (" failed\n"); + logprintf (" failed\n"); pop_color (); print_end (); } @@ -2276,17 +2279,17 @@ int send_encr_request_on_answer (struct query *q UU) { if (E->state == sc_deleted) { print_start (); push_color (COLOR_YELLOW); - printf ("Encrypted connection with "); + logprintf ("Encrypted connection with "); print_encr_chat_name (E->id, (void *)E); - printf (" can not be established\n"); + logprintf (" can not be established\n"); pop_color (); print_end (); } else { print_start (); push_color (COLOR_YELLOW); - printf ("Establishing connection with "); + logprintf ("Establishing connection with "); print_encr_chat_name (E->id, (void *)E); - printf ("\n"); + logprintf ("\n"); pop_color (); print_end (); @@ -2679,12 +2682,12 @@ void do_visualize_key (peer_id_t id) { for (j = 0; j < 4; j ++) { push_color (colors[x & 3]); push_color (COLOR_INVERSE); - printf (" "); + logprintf (" "); pop_color (); pop_color (); x = x >> 2; } - if (i & 1) { printf ("\n"); } + if (i & 1) { logprintf ("\n"); } } print_end (); } @@ -2713,7 +2716,7 @@ int get_suggested_on_answer (struct query *q UU) { peer_t *U = (void *)fetch_alloc_user (); assert (get_peer_id (U->id) == l[2 * i]); print_user_name (U->id, U); - printf (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); + logprintf (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); } pop_color (); print_end (); diff --git a/queries.h b/queries.h index afcc64e..189f89d 100644 --- a/queries.h +++ b/queries.h @@ -63,9 +63,9 @@ void work_timers (void); extern struct query_methods help_get_config_methods; -void do_send_code (const char *user); +char* do_send_code (const char *user); void do_phone_call (const char *user); -int do_send_code_result (const char *code); +int do_send_code_result (const char *code, const char *sms_hash); double get_double_time (void); void do_update_contact_list (void); diff --git a/tg-cli.h b/tg-cli.h index 95b1156..128e69c 100755 --- a/tg-cli.h +++ b/tg-cli.h @@ -2,6 +2,39 @@ int tg_login (); +void running_for_first_time (); + +void parse_config (); +void store_config (); + +void read_auth_file (); + +/** + * Connect to the telegram network with the given configuration + */ +void network_connect (); + +/** + * Request a registration code + */ +char* network_request_registration(); + +/** + * Verify the registration with the given registration code + */ +int network_verify_registration(const char *code, const char *sms_hash); + +/** + * Retur if the current phone is registered in the given network. + */ +int network_phone_is_registered(); + +/** + * Return if the current client is registered. + */ +int network_client_is_registered(); + +void set_default_username (); // Settings #define AUTH_MODE_SMS "sms" #define AUTH_MODE_PHONE "phone" From a005c015cdb58bb991ded99d1e40dc5e5ae2729b Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 15 Jun 2014 19:58:49 +0200 Subject: [PATCH 317/465] Implement phone number registration When the current phone number is not registered with the telegram network, ask for first and last name and proceed with the regular sms-code authentication scheme. --- loop.c | 26 ++++++++--- purple-plugin/telegram-purple.c | 81 +++++++++++++++++++++++++++------ queries.c | 14 +++++- queries.h | 4 +- tg-cli.h | 6 +++ 5 files changed, 108 insertions(+), 23 deletions(-) diff --git a/loop.c b/loop.c index 61b0a5b..566bf2e 100644 --- a/loop.c +++ b/loop.c @@ -556,14 +556,28 @@ char* network_request_registration () } /** - * Verify the phone, by providing the code and the real name + * Request a verification for the given client, by sending + * a code to the current phone number + */ +char* network_request_phone_registration () +{ + return do_send_code (default_username); +} + + +/** + * Verify the phone number by providing the sms_code and the real name * * NOTE: This should be called when the phone number was previously * unknown to the telegram network. */ -int network_verify_phone_registration(char* code, char *firstname, char *lastname) +int network_verify_phone_registration(const char* code, const char *sms_hash, + const char *first ,const char *last) { - if (do_send_code_result_auth (code, firstname, lastname) >= 0) { + logprintf("Registering with code:%s, hash:%s, first:%s, last:%s\n", code, sms_hash, + first, last); + if (do_send_code_result_auth (code, sms_hash, first, last) >= 0) { + logprintf ("Authentication successfull, state = 300\n"); auth_state = 300; return 1; } @@ -575,9 +589,9 @@ int network_verify_phone_registration(char* code, char *firstname, char *lastnam */ int network_verify_registration(const char *code, const char *sms_hash) { - logprintf("telegram: pointer - code: %p, hash: %p\n", code, sms_hash); - logprintf("telegram: string - code: %s, hash: %s\n", code, sms_hash); - if (do_send_code_result (code, sms_hash) >= 0) { + logprintf("Verifying with hash:%s, code:%s\n", code, sms_hash); + int state; + if ((state = do_send_code_result (code, sms_hash)) >= 0) { logprintf ("Authentication successfull, state = 300\n"); auth_state = 300; return 1; diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index ffab3d8..20ac264 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -49,6 +49,7 @@ // telegram-purple includes #include "loop.h" +#include "queries.h" #include "telegram-purple.h" static PurplePlugin *_telegram_protocol = NULL; @@ -96,6 +97,36 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); } +/** + * Request a verification key, save the returned verification_hash in the account settings + * for later usage and inform the user. + */ +static void login_request_verification(PurpleAccount *acct) +{ + // TODO: we should find a way to request the key + // only once. + purple_debug_info(PLUGIN_ID, "No code provided, requesting new authentication code.\n"); + char *new_hash = network_request_registration(); + purple_debug_info(PLUGIN_ID, "Saving verification_hash: '%s'", new_hash); + purple_account_set_string(acct, "verification_hash", new_hash); + + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Please Verify", + "You need to verify this device, please enter the code Telegram has sent to you by SMS.", + NULL, NULL, NULL); +} + +/** + * Handle a failed verification, by removing the invalid sms code and + * notifying the user + */ +static void login_verification_fail(PurpleAccount *acct) +{ + // remove invalid sms code, so we won't try to register again + purple_account_set_string(acct, "verification_key", ""); + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", + "Please make sure you entered the correct verification code.", NULL, NULL, NULL); +} + /** * This must be implemented. */ @@ -120,7 +151,7 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "running_for_first_time()\n"); running_for_first_time(); - // load all settings: the known network topology, log and configuration file paths + // load all settings: the known network topology, secret keys, logs and configuration file paths purple_debug_info(PLUGIN_ID, "parse_config()\n"); parse_config (); purple_debug_info(PLUGIN_ID, "set_default_username()\n"); @@ -130,34 +161,50 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "Connecting to the Telegram network...\n"); network_connect(); - // Login + // Assure phone number registration if (!network_phone_is_registered()) { purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); + const char *first_name = purple_account_get_string(acct, "first_name", NULL); + const char *last_name = purple_account_get_string(acct, "last_name", NULL); + if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", + "Enter your first and last name to register this phone number with the telegram network.", + NULL, NULL, NULL); + return; + } + if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { + int registered = network_verify_phone_registration(code, hash, first_name, last_name); + if (registered) { + store_config(); + } else { + login_verification_fail(acct); + return; + } + } else { + login_request_verification(acct); + return; + } } + // Assure client registration if (!network_client_is_registered()) { purple_debug_info(PLUGIN_ID, "Client is not registered\n"); - if (code && hash) { + if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { purple_debug_info(PLUGIN_ID, "SMS code provided, trying to verify \n"); - purple_debug_info(PLUGIN_ID, "pointer - code:%p hash:%p\n", code, hash); - purple_debug_info(PLUGIN_ID, "string - code%s hash:%s\n", code, hash); + purple_debug_info(PLUGIN_ID, "strlen - code: %lu hash: %lu\n", strlen(code), strlen(hash)); + purple_debug_info(PLUGIN_ID, "pointer - code: %p hash: %p\n", code, hash); + purple_debug_info(PLUGIN_ID, "string - code: %s hash: %s\n", code, hash); int verified = network_verify_registration(code, hash); if (verified) { store_config(); } else { - purple_connection_set_state(gc, PURPLE_DISCONNECTED); - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", - "Please make sure you entered the correct verification code.", NULL, NULL, NULL); + login_verification_fail(acct); return; } } else { - // TODO: we should find a way to request the key - // only once. - purple_debug_info(PLUGIN_ID, "Device not registered, requesting new authentication code.\n"); - char *new_hash = network_request_registration(); - purple_debug_info(PLUGIN_ID, "Saving verification_hash: '%s'", new_hash); - purple_account_set_string(acct, "verification_hash", new_hash); + login_request_verification(acct); + return; } } @@ -581,6 +628,12 @@ static void tgprpl_init(PurplePlugin *plugin) option = purple_account_option_string_new("Verification hash", "verification_hash", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_string_new("First Name", "first_name", NULL); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_string_new("Last Name", "last_name", NULL); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + // TODO: Path to public key (When you can change the server hostname, // you should also be able to change the public key) diff --git a/queries.c b/queries.c index 181f766..10b450d 100644 --- a/queries.c +++ b/queries.c @@ -644,8 +644,18 @@ int sign_in_on_answer (struct query *q UU) { return 0; } +char lasterror[75]; +const char *get_last_err() +{ + return lasterror; +} + 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); + if (sizeof(lasterror) >= strlen(error)) { + int dest = memcmp(lasterror, error, strlen(error)); + logprintf("memcpy-state: %d", dest); + } sign_in_ok = -1; return 0; } @@ -667,11 +677,11 @@ int do_send_code_result (const char *code, const char *sms_hash) { return sign_in_ok; } -int do_send_code_result_auth (const char *code, const char *first_name, const char *last_name) { +int do_send_code_result_auth (const char *code, const char *sms_hash, 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 (sms_hash); out_string (code); out_string (first_name); out_string (last_name); diff --git a/queries.h b/queries.h index 189f89d..8456600 100644 --- a/queries.h +++ b/queries.h @@ -98,7 +98,7 @@ void do_load_document_thumb (struct document *video, 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); +int do_send_code_result_auth (const char *code, const char *sms_hash, const char *first_name, const char *last_name); void do_import_auth (int num); void do_export_auth (int num); void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); @@ -121,3 +121,5 @@ void do_restore_msg (long long id); int get_dh_config_on_answer (struct query *q); void fetch_dc_option (void); #endif + +const char *get_last_err(); diff --git a/tg-cli.h b/tg-cli.h index 128e69c..1989dfd 100755 --- a/tg-cli.h +++ b/tg-cli.h @@ -24,6 +24,12 @@ char* network_request_registration(); */ int network_verify_registration(const char *code, const char *sms_hash); +/** + * Verify the registration with the given registration code + */ +int network_verify_phone_registration(const char *code, const char *sms_hash, + const char *first, const char *last); + /** * Retur if the current phone is registered in the given network. */ From 75e1abe520a1893076b8f02142414e2d9afd4679 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 21 Jun 2014 01:51:26 +0200 Subject: [PATCH 318/465] Remove useless functions --- loop.c | 43 +++++++++++++++++++++++++++---------------- loop.h | 3 +-- main.c | 23 +---------------------- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/loop.c b/loop.c index 566bf2e..30fa263 100644 --- a/loop.c +++ b/loop.c @@ -87,15 +87,22 @@ void net_loop (int flags, int (*is_end)(void)) { logprintf("writing_state_file()\n"); write_state_file (); + // Ensure that all connections are active? int x = connections_make_poll_array (fds + cc, 101 - cc) + cc; double timer = next_timer_in (); + + // Wait until file descriptors are ready if (timer > 1000) { timer = 1000; } if (poll (fds, x, timer) < 0) { logprintf("poll returned -1, wait a little bit.\n"); work_timers (); continue; } + + // Execute all timers that are currently due work_timers (); + + // ? if ((flags & 3) && (fds[0].revents & POLLIN)) { unread_messages = 0; if (flags & 1) { @@ -107,6 +114,8 @@ void net_loop (int flags, int (*is_end)(void)) { got_it (line, strlen (line)); } } + + // connections_poll_result (fds + cc, x - cc); #ifdef USE_LUA lua_do_all (); @@ -599,6 +608,23 @@ int network_verify_registration(const char *code, const char *sms_hash) return 0; } +/** + * Export current authentication state to all known data centers. + */ +void network_export_registration() +{ + 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); + bl_do_dc_signed (i); + write_auth_file (); + } + write_auth_file (); + fflush (stdout); + fflush (stderr); +} + int start_loop (char* code, char* auth_mode) { logprintf("Calling start_loop()\n"); logprintf("auth_state %i\n", auth_state); @@ -647,7 +673,6 @@ int start_loop (char* code, char* auth_mode) { // - We need some sort of switch between registration modes // - When this mode is selected First and Last name should be added to the form // Currently Requires Manuel Entry in Terminal. - /* size_t size; char *first_name; logprintf ("First name: "); @@ -668,7 +693,7 @@ int start_loop (char* code, char* auth_mode) { DC_working = DC_list[dc_working_num]; if (*code) { - if (do_send_code_result_auth (code, first_name, last_name) >= 0) { + if (do_send_code_result_auth (code, "-", first_name, last_name) >= 0) { auth_state = 300; } } else { @@ -681,7 +706,6 @@ int start_loop (char* code, char* auth_mode) { logprintf ("Calling you! Code: "); } } - */ } } logprintf("Authentication done\n"); @@ -719,19 +743,6 @@ int start_loop (char* code, char* auth_mode) { return 0; //main_loop (); } -/** - * Do what loop does, but use input from arguments instead of prompting - * the user - * - * When authentication is not yet done, request authenticatino code and exit - * with 0. In all other cases exit with 1. - */ -int loop_auto(char *username, char *code, char* auth_mode) { - network_connect(); - set_default_username (username); - return start_loop(code, auth_mode); -} - int loop (void) { network_connect(); return start_loop(NULL, NULL); diff --git a/loop.h b/loop.h index b586133..d09ef02 100644 --- a/loop.h +++ b/loop.h @@ -18,8 +18,7 @@ */ #ifndef __LOOP_H__ #define __LOOP_H__ -int loop (void); -int loop_auto(char *username, char *code, char *auth_mode); +int loop(); void net_loop (int flags, int (*end)(void)); void write_auth_file (void); void write_state_file (void); diff --git a/main.c b/main.c index cc73045..d657316 100644 --- a/main.c +++ b/main.c @@ -386,6 +386,7 @@ int wait_dialog_list; char *lua_file; void args_parse (int argc, char **argv) { + verbosity = 2; int opt = 0; while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:RfBL:Es:wW")) != -1) { switch (opt) { @@ -502,25 +503,3 @@ int tgmain (int argc, char **argv) { return 0; } - - -/** - * Log into Telegram with the given login credentials. - */ -int tg_login (char *username, char *code, char *auth_mode) { - log_level = 10; - running_for_first_time (); - parse_config (); - - get_terminal_attributes (); - - #ifdef USE_LUA - if (lua_file) { - lua_init (lua_file); - } - #endif - - BREAK - loop_auto(username, code, auth_mode); - return 0; -} From dbf509d59e09c8f6e4a8104cd750e0eebe54726d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 22 Jun 2014 23:33:57 +0200 Subject: [PATCH 319/465] Log some terminal messages to libpurple log --- interface.c | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/interface.c b/interface.c index 6f77bac..6560f9c 100644 --- a/interface.c +++ b/interface.c @@ -1467,32 +1467,32 @@ void print_message (struct message *M) { if (M->out) { push_color (COLOR_GREEN); if (msg_num_mode) { - printf ("%lld ", M->id); + logprintf ("%lld ", M->id); } print_date (M->date); pop_color (); - printf (" "); + logprintf (" "); print_user_name (M->to_id, user_chat_get (M->to_id)); push_color (COLOR_GREEN); if (M->unread) { - printf (" <<< "); + logprintf (" <<< "); } else { - printf (" ««« "); + logprintf (" ««« "); } } else { push_color (COLOR_BLUE); if (msg_num_mode) { - printf ("%lld ", M->id); + logprintf ("%lld ", M->id); } print_date (M->date); pop_color (); - printf (" "); + logprintf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); push_color (COLOR_BLUE); if (M->unread) { - printf (" >>> "); + logprintf (" >>> "); } else { - printf (" »»» "); + logprintf (" »»» "); } if (alert_sound) { play_sound(); @@ -1504,31 +1504,31 @@ void print_message (struct message *M) { if (M->out) { push_color (COLOR_GREEN); if (msg_num_mode) { - printf ("%lld ", M->id); + logprintf ("%lld ", M->id); } print_date (M->date); - printf (" "); + logprintf (" "); push_color (COLOR_CYAN); - printf (" %s", P->print_name); + logprintf (" %s", P->print_name); pop_color (); if (M->unread) { - printf (" <<< "); + logprintf (" <<< "); } else { - printf (" ««« "); + logprintf (" ««« "); } } else { push_color (COLOR_BLUE); if (msg_num_mode) { - printf ("%lld ", M->id); + logprintf ("%lld ", M->id); } print_date (M->date); push_color (COLOR_CYAN); - printf (" %s", P->print_name); + logprintf (" %s", P->print_name); pop_color (); if (M->unread) { - printf (" >>> "); + logprintf (" >>> "); } else { - printf (" »»» "); + logprintf (" »»» "); } if (alert_sound) { play_sound(); @@ -1538,13 +1538,13 @@ void print_message (struct message *M) { assert (get_peer_type (M->to_id) == PEER_CHAT); push_color (COLOR_MAGENTA); if (msg_num_mode) { - printf ("%lld ", M->id); + logprintf ("%lld ", M->id); } print_date (M->date); pop_color (); - printf (" "); + logprintf (" "); print_chat_name (M->to_id, user_chat_get (M->to_id)); - printf (" "); + logprintf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); if ((get_peer_type (M->from_id) == PEER_USER) && (get_peer_id (M->from_id) == our_id)) { push_color (COLOR_GREEN); @@ -1552,25 +1552,25 @@ void print_message (struct message *M) { push_color (COLOR_BLUE); } if (M->unread) { - printf (" >>> "); + logprintf (" >>> "); } else { - printf (" »»» "); + logprintf (" »»» "); } } if (get_peer_type (M->fwd_from_id) == PEER_USER) { - printf ("[fwd from "); + logprintf ("[fwd from "); print_user_name (M->fwd_from_id, user_chat_get (M->fwd_from_id)); - printf ("] "); + logprintf ("] "); } if (M->message && strlen (M->message)) { - printf ("%s", M->message); + logprintf ("%s", M->message); } if (M->media.type != CODE_message_media_empty) { print_media (&M->media); } pop_color (); assert (!color_stack_pos); - printf ("\n"); + logprintf ("\n"); print_end(); } From d712b7e17fa101bff59efc5bcbd76b550f82c8e0 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 22 Jun 2014 23:36:52 +0200 Subject: [PATCH 320/465] Add possibillity to listen to created users, chats and groups with event handlers and add some ability to exchange output functions with own callbacks --- loop.c | 27 +++++++++++++++++- mtproto-client.c | 12 ++++++-- net.c | 54 +++++++++++++++++++++++++++++++++-- queries.c | 17 +++++++++-- structures.c | 27 ++++++++++++++++++ structures.h | 3 ++ tg-cli.h | 73 ++++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 202 insertions(+), 11 deletions(-) diff --git a/loop.c b/loop.c index 30fa263..b51a71d 100644 --- a/loop.c +++ b/loop.c @@ -536,6 +536,10 @@ void network_connect (void) { write_auth_file (); logprintf("DataCentre start_loopd, key id: %lld\n", DC_list[i]->auth_key_id); } + + // read saved connection state + read_state_file (); + read_secret_chat_file (); } /** @@ -625,6 +629,25 @@ void network_export_registration() fflush (stderr); } +/** + * Fetch all unknown messages of the current session + */ +void session_get_difference() +{ + do_get_difference(); + net_loop (0, dgot); +} + +extern int contacts_got; +int cupdate_got() { + return contacts_got; +} +void session_update_contact_list() +{ + do_update_contact_list(); + net_loop(0, cupdate_got); +} + int start_loop (char* code, char* auth_mode) { logprintf("Calling start_loop()\n"); logprintf("auth_state %i\n", auth_state); @@ -722,9 +745,11 @@ int start_loop (char* code, char* auth_mode) { fflush (stdout); fflush (stderr); + // read saved connection state read_state_file (); read_secret_chat_file (); - + + // callbacks for interface functions set_interface_callbacks (); do_get_difference (); diff --git a/mtproto-client.c b/mtproto-client.c index 442e4c2..675cb5b 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -66,6 +66,8 @@ #include "mtproto-common.h" +#include "tg-cli.h" + #define MAX_NET_RES (1L << 16) extern int log_level; @@ -906,6 +908,7 @@ void work_update_binlog (void) { void work_update (struct connection *c UU, long long msg_id UU) { unsigned op = fetch_int (); + logprintf("work_update(): OP:%d\n", op); switch (op) { case CODE_update_new_message: { @@ -913,7 +916,8 @@ void work_update (struct connection *c UU, long long msg_id UU) { assert (M); fetch_pts (); unread_messages ++; - print_message (M); + event_update_new_message(M); + //print_message (M); update_prompt (); break; }; @@ -1717,10 +1721,12 @@ int rpc_execute (struct connection *c, int op, int len) { if (verbosity) { logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); } -/* if (op < 0) { + /* + if (op < 0) { assert (read_in (c, Response, Response_len) == Response_len); return 0; - }*/ + } + */ if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); diff --git a/net.c b/net.c index db2b474..fe88e11 100644 --- a/net.c +++ b/net.c @@ -59,6 +59,43 @@ extern FILE *log_net_f; void fail_connection (struct connection *c); +/* + * Delegate the read-oprations to external function + */ +ssize_t (*netread)(int fd, void *buff, size_t size) = read; +void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)) { + netread = cb; +} + +/* + * Delegate the write operations to external function + */ +ssize_t (*netwrite)(int fd, const void *buff, size_t size) = write; +void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)) { + netwrite = cb; +} + +/* + * Delegate the session creation to an external callback + * + * TODO: use dc_ensure_session instead of dc_create_session to create sessions, + * to make this actually work + */ +void dc_create_session (struct dc *DC); +void dc_ensure_session_local (struct dc *DC, void (*on_session_ready)(void)) { + dc_create_session(DC); + on_session_ready(); +} +void (*dc_ensure_session)(struct dc *DC, void (*on_session_ready)(void)); +void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))) +{ + dc_ensure_session = dc_ens_sess; +} + +/* + * + */ + #define PING_TIMEOUT 10 void start_ping_timer (struct connection *c); @@ -386,22 +423,29 @@ void try_write (struct connection *c) { } int x = 0; while (c->out_head) { - int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + + // Log all written packages if (r > 0 && log_net_f) { fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { + fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); } fprintf (log_net_f, "\n"); fflush (log_net_f); } + if (r >= 0) { x += r; c->out_head->rptr += r; if (c->out_head->rptr != c->out_head->wptr) { + // Inhalt des Buffers nicht komplett abgeschickt, + // es geht nichts mehr in den Socket break; } + // buffer ausgelesen, alten buffer löschen struct connection_buffer *b = c->out_head; c->out_head = b->next; if (!c->out_head) { @@ -497,11 +541,12 @@ void try_read (struct connection *c) { } int x = 0; while (1) { - int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); + int r = netread (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); if (r > 0 && log_net_f) { fprintf (log_net_f, "%.02lf %d IN %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { + // print all writte bits fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i)); } fprintf (log_net_f, "\n"); @@ -509,13 +554,17 @@ void try_read (struct connection *c) { } if (r > 0) { c->last_receive_time = get_double_time (); + // reset ping timer stop_ping_timer (c); start_ping_timer (c); } if (r >= 0) { + // write pointer nach vorne setzen c->in_tail->wptr += r; x += r; + if (c->in_tail->wptr != c->in_tail->end) { + // Paket nicht komplett beschrieben, keine neuen Daten liegen an. break; } struct connection_buffer *b = new_connection_buffer (1 << 20); @@ -646,3 +695,4 @@ void dc_create_session (struct dc *DC) { assert (!DC->sessions[0]); DC->sessions[0] = S; } + diff --git a/queries.c b/queries.c index 10b450d..5a4129b 100644 --- a/queries.c +++ b/queries.c @@ -53,6 +53,7 @@ #include "no-preview.h" #include "binlog.h" +#include "tg-cli.h" #define sha1 SHA1 @@ -132,7 +133,6 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth if (!DC->sessions[0]) { dc_create_session (DC); } - logprintf("telegram: verbosity: %d\n", verbosity); if (verbosity) { logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } @@ -695,6 +695,7 @@ int do_send_code_result_auth (const char *code, const char *sms_hash, const char /* {{{ Get contacts */ extern char *user_list[]; +int contacts_got = 0; int get_contacts_on_answer (struct query *q UU) { int i; assert (fetch_int () == (int)CODE_contacts_contacts); @@ -708,7 +709,8 @@ int get_contacts_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); n = fetch_int (); for (i = 0; i < n; i++) { - struct user *U = fetch_alloc_user (); + fetch_alloc_user (); + /* print_start (); push_color (COLOR_YELLOW); logprintf ("User #%d: ", get_peer_id (U->id)); @@ -735,7 +737,9 @@ int get_contacts_on_answer (struct query *q UU) { } pop_color (); print_end (); + */ } + contacts_got = 1; return 0; } @@ -745,11 +749,14 @@ struct query_methods get_contacts_methods = { void do_update_contact_list (void) { + contacts_got = 0; clear_packet (); out_int (CODE_contacts_get_contacts); out_string (""); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, 0); } + + /* }}} */ /* {{{ Encrypt decrypted */ @@ -2565,6 +2572,7 @@ int unread_messages; int difference_got; int seq, pts, qts, last_date; int get_state_on_answer (struct query *q UU) { + logprintf("get_state_on_answer()\n"); assert (fetch_int () == (int)CODE_updates_state); bl_do_set_pts (fetch_int ()); bl_do_set_qts (fetch_int ()); @@ -2578,6 +2586,7 @@ int get_state_on_answer (struct query *q UU) { int get_difference_active; int get_difference_on_answer (struct query *q UU) { + logprintf("get_difference_on_answer()\n"); get_difference_active = 0; unsigned x = fetch_int (); if (x == CODE_updates_difference_empty) { @@ -2629,7 +2638,8 @@ int get_difference_on_answer (struct query *q UU) { unread_messages = fetch_int (); write_state_file (); for (i = 0; i < ml_pos; i++) { - print_message (ML[i]); + event_update_new_message(ML[i]); + //print_message (ML[i]); } if (x == CODE_updates_difference_slice) { do_get_difference (); @@ -2651,6 +2661,7 @@ struct query_methods get_difference_methods = { }; void do_get_difference (void) { + logprintf("do_get_difference()\n"); get_difference_active = 1; difference_got = 0; clear_packet (); diff --git a/structures.c b/structures.c index 687155e..d8a5887 100644 --- a/structures.c +++ b/structures.c @@ -33,6 +33,8 @@ #include "queries.h" #include "binlog.h" +#include "tg-cli.h" + #define sha1 SHA1 static int id_cmp (struct message *M1, struct message *M2); @@ -204,6 +206,21 @@ long long fetch_user_photo (struct user *U) { return 0; } +int user_get_printname(peer_t *user, char *buffer, int maxlen) +{ + char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; + char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; + if (strlen(first_name) && strlen(last_name)) { + return snprintf(buffer, maxlen, "%s %s", first_name, last_name); + } else if (strlen(first_name)) { + return snprintf(buffer, maxlen, "%s", first_name); + } else if (strlen(last_name)) { + return snprintf(buffer, maxlen, "%s", last_name); + } else { + return snprintf(buffer, maxlen, "%d", get_peer_id(user->id)); + } +} + int fetch_user (struct user *U) { unsigned x = fetch_int (); code_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); @@ -1512,10 +1529,12 @@ static int id_cmp (struct message *M1, struct message *M2) { } struct user *fetch_alloc_user (void) { + int send_event = 0; int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); if (!U) { + send_event = 1; users_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_USER (data[1]); @@ -1524,6 +1543,9 @@ struct user *fetch_alloc_user (void) { Peers[peer_num ++] = U; } fetch_user (&U->user); + if (send_event) { + event_user_allocated(U); + } return &U->user; } @@ -1871,10 +1893,12 @@ struct message *fetch_alloc_message_short_chat (void) { } struct chat *fetch_alloc_chat (void) { + int send_event = 0; int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_CHAT (data[1])); if (!U) { + send_event = 1; chats_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[1]); @@ -1883,6 +1907,9 @@ struct chat *fetch_alloc_chat (void) { Peers[peer_num ++] = U; } fetch_chat (&U->chat); + if (send_event) { + event_chat_allocated(U); + } return &U->chat; } diff --git a/structures.h b/structures.h index ad4360f..686e4ee 100644 --- a/structures.h +++ b/structures.h @@ -156,6 +156,7 @@ struct user { char *real_last_name; }; + struct chat_user { int user_id; int inviter_id; @@ -380,6 +381,8 @@ void peer_insert_name (peer_t *P); void peer_delete_name (peer_t *P); peer_t *peer_lookup_name (const char *s); +int user_get_printname(peer_t *user, char *buffer, int maxlen); + #define PEER_USER 1 #define PEER_CHAT 2 #define PEER_GEO_CHAT 3 diff --git a/tg-cli.h b/tg-cli.h index 1989dfd..bb2ddf8 100755 --- a/tg-cli.h +++ b/tg-cli.h @@ -1,12 +1,15 @@ +#include +#include "net.h" +#include "mtproto-common.h" +#include "structures.h" + // Export functions for plugins int tg_login (); void running_for_first_time (); - void parse_config (); void store_config (); - void read_auth_file (); /** @@ -40,6 +43,72 @@ int network_phone_is_registered(); */ int network_client_is_registered(); +/** + * Export the current registration to all available data centers + */ +void network_export_registration(); + +/** + * Fetch all unknown messages of the current session + */ +void session_get_difference(); + +/** + * Fetch all known contacts + */ +void session_update_contact_list(); + +/* + * Events + */ +void on_update_new_message(void (*on_msg)(struct message *M)); +void event_update_new_message(struct message *M); + +void on_update_user_typing(); +void on_update_chat_user_typing(); +void on_update_user_status(); +void on_update_user_name(); +void on_update_user_photo(); +void on_update_chat_participants(); + +/* + * Load known users and chats on connect + */ +void on_user_allocated(); + +void on_user_allocated(void (*handler)(peer_t *user)); +void event_user_allocated(peer_t *user); + +void on_chat_allocated(void (*handler)(peer_t *chat)); +void event_chat_allocated(peer_t *chat); + +// template +//void on_blarg(void (*on_msg)(struct message *M)); +//void event_blarg(struct message *M); + +void on_chat_allocated(); + +/** + * Set a function to use as a handle to read from a network resource + * instead of the regular socket read function + */ +void set_net_read_cb(int (*cb)(int fd, void *buff, size_t size)); + +/** + * Set a function to use as handle to write to a newtork resource + * instead of the regular socket write function + */ +void set_net_write_cb(int (*cb)(int fd, const void *buff, size_t size)); + +/** + * Set a function to use as handle to create new connections instead of the regular + * socket write function + */ +void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))); + +/** + * ? + */ void set_default_username (); // Settings #define AUTH_MODE_SMS "sms" From 0945a3ca113baf69c02136f28acd1f5a2acc0f53 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 22 Jun 2014 23:37:40 +0200 Subject: [PATCH 321/465] Add event handler functionality to tg-cli --- purple-plugin/Makefile | 7 ++--- tg-cli.c | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) create mode 100755 tg-cli.c diff --git a/purple-plugin/Makefile b/purple-plugin/Makefile index 0651517..41aff3e 100755 --- a/purple-plugin/Makefile +++ b/purple-plugin/Makefile @@ -4,7 +4,7 @@ EXTRA_LIBS = -lcrypto -lz -lm -lreadline LDFLAGSTG = -L/usr/local/lib CPPFLAGSTG = -I/usr/local/include -OBJECTSTG = ../main.o ../loop.o ../interface.o ../net.o ../mtproto-common.o ../mtproto-client.o ../queries.o ../structures.o ../binlog.o ../tools.o ../lua-tg.o ../msglog.o +OBJECTSTG = ../main.o ../loop.o ../interface.o ../net.o ../mtproto-common.o ../mtproto-client.o ../queries.o ../structures.o ../binlog.o ../tools.o ../lua-tg.o ../msglog.o ../tg-cli.o INCLUDE = -I. -I.. # @@ -34,6 +34,7 @@ CFLAGS = \ -fPIC \ -DPURPLE_PLUGINS \ -DPIC \ + -g \ $(CFLAGS_PURPLE) LIBS_PURPLE = $(shell pkg-config --libs purple) @@ -53,7 +54,7 @@ strip: $(LIBNAME) .PHONY: debug install debug: CFLAGS += -g -DDEBUG debug: $(LIBNAME) - gdb -tui pidgin + gdb -tui -ex 'break telegram-purple.c:tgprpl_login' pidgin PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) @@ -83,4 +84,4 @@ clean: .PHONY: run run: all install - pidgin -d | grep telegram + pidgin -d diff --git a/tg-cli.c b/tg-cli.c new file mode 100755 index 0000000..b73eff8 --- /dev/null +++ b/tg-cli.c @@ -0,0 +1,59 @@ +#include +#include "mtproto-common.h" +#include "tg-cli.h" +#include "msglog.h" + +/* + * Events + */ + +/* + * New message received + */ +void (*on_msg_handler)(struct message *M); +void on_update_new_message(void (*on_msg)(struct message *M)) { + on_msg_handler = on_msg; +} +void event_update_new_message(struct message *M) { + if (on_msg_handler) { + on_msg_handler(M); + } +} + +/* + * User allocated + */ +void (*on_user_allocated_handler)(peer_t *user); +void on_user_allocated(void (*handler)(peer_t *user)) { + on_user_allocated_handler = handler; +} +void event_user_allocated(peer_t *user) { + if (on_user_allocated_handler) { + on_user_allocated_handler(user); + } +} + +/* + * Chat allocated + */ +void (*on_chat_allocated_handler)(peer_t *chat); +void on_chat_allocated(void (*handler)(peer_t *chat)) { + on_chat_allocated_handler = handler; +} +void event_chat_allocated(peer_t *chat) { + if (on_chat_allocated_handler) { + on_chat_allocated_handler(chat); + } +} + +// template +//void (*on_blarg_handler)(type); +//void on_blarg(void (*handler)(type)) { +// on_blarg_handler = handler; +//} +//void event_blarg(type) { +// if (on_blarg_handler) { +// on_blarg_handler(type); +// } +//} + From 6325bd108db8e3d01a4aee4c1cb32a180442cb92 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 22 Jun 2014 23:39:05 +0200 Subject: [PATCH 322/465] Listen to changed users and add new chats to the current sessions --- purple-plugin/telegram-purple.c | 88 ++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 17 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 20ac264..534e4cc 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -46,14 +46,25 @@ // Telegram Includes #include #include "msglog.h" +#include "mtproto-client.h" +#include "mtproto-common.h" // telegram-purple includes #include "loop.h" #include "queries.h" #include "telegram-purple.h" +#include "request.h" + +#define BUDDYNAME_MAX_LENGTH 128 static PurplePlugin *_telegram_protocol = NULL; +// TODO: Use PurpleConnection from PurpleAccount callback +PurpleConnection *_gc; +// TODO: Use PurpleAccount from PurpleAccount callback +PurpleAccount *_pa; +PurpleGroup *tggroup; + /** * Redirect the msglog of the telegram-cli application to the libpurple * logger @@ -65,6 +76,10 @@ void tg_cli_log_cb(const char* format, va_list ap) purple_debug_info(PLUGIN_ID, "%s", buffer); } +void on_new_message(struct message *M); +void user_allocated_handler(peer_t *user); +void chat_allocated_handler(peer_t *chat); + /** * Returns the base icon name for the given buddy and account. * If buddy is NULL and the account is non-NULL, it will return the @@ -79,16 +94,6 @@ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) return "telegram"; } -/** - * Gets a short string representing this buddy's status. This will - * be shown on the buddy list. - */ -static char *tgprpl_status_text(PurpleBuddy * buddy) -{ - purple_debug_info(PLUGIN_ID, "tgprpl_status_text()\n"); - return "status text"; -} - /** * Allows the prpl to add text to a buddy's tooltip. */ @@ -125,6 +130,7 @@ static void login_verification_fail(PurpleAccount *acct) purple_account_set_string(acct, "verification_key", ""); purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", "Please make sure you entered the correct verification code.", NULL, NULL, NULL); + } /** @@ -134,6 +140,8 @@ static void tgprpl_login(PurpleAccount * acct) { purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); + _gc = gc; + _pa = acct; const char *username = purple_account_get_username(acct); const char *code = purple_account_get_string(acct, "verification_key", NULL); @@ -199,14 +207,37 @@ static void tgprpl_login(PurpleAccount * acct) if (verified) { store_config(); } else { - login_verification_fail(acct); - return; + login_verification_fail(acct); + return; } } else { login_request_verification(acct); return; } } + purple_debug_info(PLUGIN_ID, "Logged in...\n"); + purple_connection_set_display_name(gc, username); + purple_connection_set_state(gc, PURPLE_CONNECTED); + purple_blist_add_account(acct); + + tggroup = purple_find_group("Telegram"); + if (tggroup == NULL) { + purple_debug_info(PLUGIN_ID, "PurpleGroup = NULL, creating"); + tggroup = purple_group_new("Telegram"); + purple_blist_add_group(tggroup, NULL); + } + + purple_debug_info(PLUGIN_ID, "Fetching Network Info\n"); + on_update_new_message(on_new_message); + on_user_allocated(user_allocated_handler); + on_chat_allocated(chat_allocated_handler); + + // get all current contacts + purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); + session_update_contact_list(); + + // get new messages + session_get_difference(); // Our protocol data, that will be delivered to us // through purple connection @@ -216,10 +247,33 @@ static void tgprpl_login(PurpleAccount * acct) purple_connection_set_protocol_data(gc, conn); gc->proto_data = conn; - - // TODO: probably needs to be in callback after connection - purple_connection_set_state(gc, PURPLE_CONNECTED); - purple_debug_info(PLUGIN_ID, "Logged in...\n"); +} + +void on_new_message(struct message *M) +{ + purple_debug_info(PLUGIN_ID, "New Message: %s\n", M->message); +} + +void user_allocated_handler(peer_t *user) +{ + char* name = malloc(BUDDYNAME_MAX_LENGTH); + if (user_get_printname(user, name, BUDDYNAME_MAX_LENGTH) < 0) { + purple_debug_info(PLUGIN_ID, "Buddy name of (%d) too long, not adding to buddy list.\n", + get_peer_id(user->id)); + return; + } + PurpleBuddy *buddy = purple_find_buddy(_pa, name); + if (!buddy) { + purple_debug_info(PLUGIN_ID, "User Allocated: %s\n", name); + PurpleBuddy *buddy = purple_buddy_new(_pa, name, name); + purple_blist_add_buddy(buddy, NULL, tggroup, NULL); + purple_blist_alias_buddy(buddy, name); + } +} + +void chat_allocated_handler(peer_t *chat) +{ + purple_debug_info(PLUGIN_ID, "Chat Allocated: %s\n", chat->print_name); } /** @@ -523,7 +577,7 @@ static PurplePluginProtocolInfo prpl_info = { }, tgprpl_list_icon, NULL, - tgprpl_status_text, + NULL, tgprpl_tooltip_text, tgprpl_status_types, NULL, /* blist_node_menu */ From f28d89c9c624fe514348f97339779bb8f8001480 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 27 Jun 2014 09:35:47 +0200 Subject: [PATCH 323/465] Replace tabs with 4 spaces --- purple-plugin/telegram-purple.c | 433 ++++++++++++++++---------------- 1 file changed, 221 insertions(+), 212 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 534e4cc..6502299 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -67,13 +67,13 @@ PurpleGroup *tggroup; /** * Redirect the msglog of the telegram-cli application to the libpurple - * logger + * logger */ void tg_cli_log_cb(const char* format, va_list ap) { char buffer[256]; vsnprintf(buffer, sizeof(buffer), format, ap); - purple_debug_info(PLUGIN_ID, "%s", buffer); + purple_debug_info(PLUGIN_ID, "%s", buffer); } void on_new_message(struct message *M); @@ -91,7 +91,7 @@ void chat_allocated_handler(peer_t *chat); static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) { purple_debug_info(PLUGIN_ID, "tgrpl_list_icon()\n"); - return "telegram"; + return "telegram"; } /** @@ -99,7 +99,7 @@ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) */ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { - purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); + purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); } /** @@ -108,29 +108,29 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info */ static void login_request_verification(PurpleAccount *acct) { - // TODO: we should find a way to request the key - // only once. - purple_debug_info(PLUGIN_ID, "No code provided, requesting new authentication code.\n"); - char *new_hash = network_request_registration(); - purple_debug_info(PLUGIN_ID, "Saving verification_hash: '%s'", new_hash); - purple_account_set_string(acct, "verification_hash", new_hash); + // TODO: we should find a way to request the key + // only once. + purple_debug_info(PLUGIN_ID, "No code provided, requesting new authentication code.\n"); + char *new_hash = network_request_registration(); + purple_debug_info(PLUGIN_ID, "Saving verification_hash: '%s'", new_hash); + purple_account_set_string(acct, "verification_hash", new_hash); - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Please Verify", - "You need to verify this device, please enter the code Telegram has sent to you by SMS.", - NULL, NULL, NULL); + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Please Verify", + "You need to verify this device, please enter the code Telegram has sent to you by SMS.", + NULL, NULL, NULL); } /** * Handle a failed verification, by removing the invalid sms code and - * notifying the user + * notifying the user */ static void login_verification_fail(PurpleAccount *acct) { - // remove invalid sms code, so we won't try to register again - purple_account_set_string(acct, "verification_key", ""); - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", - "Please make sure you entered the correct verification code.", NULL, NULL, NULL); - + // remove invalid sms code, so we won't try to register again + purple_account_set_string(acct, "verification_key", ""); + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", + "Please make sure you entered the correct verification code.", NULL, NULL, NULL); + } /** @@ -140,12 +140,12 @@ static void tgprpl_login(PurpleAccount * acct) { purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); - _gc = gc; - _pa = acct; + _gc = gc; + _pa = acct; const char *username = purple_account_get_username(acct); const char *code = purple_account_get_string(acct, "verification_key", NULL); - const char *hash = purple_account_get_string(acct, "verification_hash", NULL); + const char *hash = purple_account_get_string(acct, "verification_hash", NULL); const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); // const char *verificationType = purple_account_get_string(acct, "verification_type", TELEGRAM_AUTH_MODE_SMS); // int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); @@ -155,94 +155,94 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "verification_hash: %s\n", hash); purple_debug_info(PLUGIN_ID, "hostname: %s\n", hostname); - // ensure config-file exists an + // ensure config-file exists an purple_debug_info(PLUGIN_ID, "running_for_first_time()\n"); running_for_first_time(); - // load all settings: the known network topology, secret keys, logs and configuration file paths + // load all settings: the known network topology, secret keys, logs and configuration file paths purple_debug_info(PLUGIN_ID, "parse_config()\n"); parse_config (); purple_debug_info(PLUGIN_ID, "set_default_username()\n"); set_default_username (username); - // Connect to the network + // Connect to the network purple_debug_info(PLUGIN_ID, "Connecting to the Telegram network...\n"); network_connect(); - // Assure phone number registration - if (!network_phone_is_registered()) { - purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); - const char *first_name = purple_account_get_string(acct, "first_name", NULL); - const char *last_name = purple_account_get_string(acct, "last_name", NULL); - if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", - "Enter your first and last name to register this phone number with the telegram network.", - NULL, NULL, NULL); - return; - } - if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { - int registered = network_verify_phone_registration(code, hash, first_name, last_name); - if (registered) { - store_config(); - } else { - login_verification_fail(acct); - return; - } - } else { - login_request_verification(acct); - return; - } - } + // Assure phone number registration + if (!network_phone_is_registered()) { + purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); + const char *first_name = purple_account_get_string(acct, "first_name", NULL); + const char *last_name = purple_account_get_string(acct, "last_name", NULL); + if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", + "Enter your first and last name to register this phone number with the telegram network.", + NULL, NULL, NULL); + return; + } + if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { + int registered = network_verify_phone_registration(code, hash, first_name, last_name); + if (registered) { + store_config(); + } else { + login_verification_fail(acct); + return; + } + } else { + login_request_verification(acct); + return; + } + } - // Assure client registration - if (!network_client_is_registered()) { - purple_debug_info(PLUGIN_ID, "Client is not registered\n"); - - if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { - purple_debug_info(PLUGIN_ID, "SMS code provided, trying to verify \n"); - purple_debug_info(PLUGIN_ID, "strlen - code: %lu hash: %lu\n", strlen(code), strlen(hash)); - purple_debug_info(PLUGIN_ID, "pointer - code: %p hash: %p\n", code, hash); - purple_debug_info(PLUGIN_ID, "string - code: %s hash: %s\n", code, hash); - int verified = network_verify_registration(code, hash); - if (verified) { - store_config(); - } else { - login_verification_fail(acct); - return; - } - } else { - login_request_verification(acct); - return; - } - } + // Assure client registration + if (!network_client_is_registered()) { + purple_debug_info(PLUGIN_ID, "Client is not registered\n"); + + if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { + purple_debug_info(PLUGIN_ID, "SMS code provided, trying to verify \n"); + purple_debug_info(PLUGIN_ID, "strlen - code: %lu hash: %lu\n", strlen(code), strlen(hash)); + purple_debug_info(PLUGIN_ID, "pointer - code: %p hash: %p\n", code, hash); + purple_debug_info(PLUGIN_ID, "string - code: %s hash: %s\n", code, hash); + int verified = network_verify_registration(code, hash); + if (verified) { + store_config(); + } else { + login_verification_fail(acct); + return; + } + } else { + login_request_verification(acct); + return; + } + } purple_debug_info(PLUGIN_ID, "Logged in...\n"); - purple_connection_set_display_name(gc, username); - purple_connection_set_state(gc, PURPLE_CONNECTED); - purple_blist_add_account(acct); + purple_connection_set_display_name(gc, username); + purple_connection_set_state(gc, PURPLE_CONNECTED); + purple_blist_add_account(acct); - tggroup = purple_find_group("Telegram"); - if (tggroup == NULL) { - purple_debug_info(PLUGIN_ID, "PurpleGroup = NULL, creating"); - tggroup = purple_group_new("Telegram"); - purple_blist_add_group(tggroup, NULL); - } + tggroup = purple_find_group("Telegram"); + if (tggroup == NULL) { + purple_debug_info(PLUGIN_ID, "PurpleGroup = NULL, creating"); + tggroup = purple_group_new("Telegram"); + purple_blist_add_group(tggroup, NULL); + } purple_debug_info(PLUGIN_ID, "Fetching Network Info\n"); - on_update_new_message(on_new_message); - on_user_allocated(user_allocated_handler); - on_chat_allocated(chat_allocated_handler); + on_update_new_message(on_new_message); + on_user_allocated(user_allocated_handler); + on_chat_allocated(chat_allocated_handler); - // get all current contacts - purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); - session_update_contact_list(); + // get all current contacts + purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); + session_update_contact_list(); - // get new messages - session_get_difference(); + // get new messages + session_get_difference(); - // Our protocol data, that will be delivered to us - // through purple connection + // Our protocol data, that will be delivered to us + // through purple connection telegram_conn *conn = g_new0(telegram_conn, 1); - conn->gc = gc; + conn->gc = gc; conn->account = acct; purple_connection_set_protocol_data(gc, conn); @@ -252,28 +252,36 @@ static void tgprpl_login(PurpleAccount * acct) void on_new_message(struct message *M) { purple_debug_info(PLUGIN_ID, "New Message: %s\n", M->message); + // TODO: this should probably be freed again somwhere + char *who = g_strdup_printf("%d", get_peer_id(M->from_id)); + serv_got_im(_gc, who, M->message, PURPLE_MESSAGE_RECV, time(NULL)); + g_free(who); } void user_allocated_handler(peer_t *user) { - char* name = malloc(BUDDYNAME_MAX_LENGTH); - if (user_get_printname(user, name, BUDDYNAME_MAX_LENGTH) < 0) { - purple_debug_info(PLUGIN_ID, "Buddy name of (%d) too long, not adding to buddy list.\n", - get_peer_id(user->id)); - return; - } - PurpleBuddy *buddy = purple_find_buddy(_pa, name); - if (!buddy) { - purple_debug_info(PLUGIN_ID, "User Allocated: %s\n", name); - PurpleBuddy *buddy = purple_buddy_new(_pa, name, name); - purple_blist_add_buddy(buddy, NULL, tggroup, NULL); - purple_blist_alias_buddy(buddy, name); - } + gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); + // TODO: this should probably be freed again somwhere + char *alias = malloc(BUDDYNAME_MAX_LENGTH); + + if (user_get_alias(user, alias, BUDDYNAME_MAX_LENGTH) < 0) { + purple_debug_info(PLUGIN_ID, "Buddyalias of (%d) too long, not adding to buddy list.\n", + get_peer_id(user->id)); + return; + } + PurpleBuddy *buddy = purple_find_buddy(_pa, name); + if (!buddy) { + purple_debug_info(PLUGIN_ID, "Adding %s to buddy list ", name); + buddy = purple_buddy_new(_pa, name, alias); + purple_blist_add_buddy(buddy, NULL, tggroup, NULL); + } + purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); + g_free(name); } void chat_allocated_handler(peer_t *chat) { - purple_debug_info(PLUGIN_ID, "Chat Allocated: %s\n", chat->print_name); + purple_debug_info(PLUGIN_ID, "Chat Allocated: %s\n", chat->print_name); } /** @@ -313,7 +321,7 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me * @param message The message to send to the chat. * @param flags A bitwise OR of #PurpleMessageFlags representing * message flags. - * @return A positive number or 0 in case of success, + * @return A positive number or 0 in case of success, * a negative error number in case of failure. */ static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) @@ -427,10 +435,12 @@ static GList *tgprpl_status_types(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "tgprpl_status_types()\n"); GList *types = NULL; PurpleStatusType *type; - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, "available", NULL, TRUE, TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, "available", NULL, + TRUE, TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); types = g_list_prepend(types, type); - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, "unavailable", NULL, TRUE, TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, "unavailable", NULL, TRUE, + TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); types = g_list_prepend(types, type); type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE); @@ -562,145 +572,144 @@ static void tgprpl_send_file(PurpleConnection * gc, const char *who, const char // SEE prpl.h static PurplePluginProtocolInfo prpl_info = { - OPT_PROTO_NO_PASSWORD, /* options */ - NULL, /* user_splits, initialized in tgprpl_init() */ - NULL, /* protocol_options, initialized in tgprpl_init() */ - - { /* icon_spec, a PurpleBuddyIconSpec */ - "png", /* format */ - 1, /* min_width */ - 1, /* min_height */ - 512, /* max_width */ - 512, /* max_height */ - 64000, /* max_filesize */ - PURPLE_ICON_SCALE_SEND, /* scale_rules */ - }, - tgprpl_list_icon, - NULL, - NULL, - tgprpl_tooltip_text, - tgprpl_status_types, - NULL, /* blist_node_menu */ + OPT_PROTO_NO_PASSWORD, /* options */ + NULL, /* user_splits, initialized in tgprpl_init() */ + NULL, /* protocol_options, initialized in tgprpl_init() */ + { /* icon_spec, a PurpleBuddyIconSpec */ + "png", /* format */ + 1, /* min_width */ + 1, /* min_height */ + 512, /* max_width */ + 512, /* max_height */ + 64000, /* max_filesize */ + PURPLE_ICON_SCALE_SEND, /* scale_rules */ + }, + tgprpl_list_icon, + NULL, + NULL, + tgprpl_tooltip_text, + tgprpl_status_types, + NULL, /* blist_node_menu */ tgprpl_chat_join_info, - tgprpl_chat_info_defaults, /* chat_info_defaults */ - tgprpl_login, /* login */ - tgprpl_close, /* close */ - tgprpl_send_im, /* send_im */ - NULL, /* set_info */ - tgprpl_send_typing, /* send_typing */ - tgprpl_get_info, /* get_info */ - tgprpl_set_status, /* set_status */ - NULL, /* set_idle */ - NULL, /* change_passwd */ - tgprpl_add_buddy, /* add_buddy */ - tgprpl_add_buddies, /* add_buddies */ - tgprpl_remove_buddy, /* remove_buddy */ - tgprpl_remove_buddies, /* remove_buddies */ - NULL, /* add_permit */ - tgprpl_add_deny, /* add_deny */ - NULL, /* rem_permit */ - tgprpl_rem_deny, /* rem_deny */ - NULL, /* set_permit_deny */ - tgprpl_chat_join, /* join_chat */ - NULL, /* reject_chat */ - tgprpl_get_chat_name, /* get_chat_name */ - tgprpl_chat_invite, /* chat_invite */ - NULL, /* chat_leave */ - NULL, /* chat_whisper */ - tgprpl_send_chat, /* chat_send */ - NULL, /* keepalive */ - NULL, /* register_user */ - NULL, /* get_cb_info */ - NULL, /* get_cb_away */ - NULL, /* alias_buddy */ - tgprpl_group_buddy, /* group_buddy */ - tgprpl_rename_group, /* rename_group */ - NULL, /* buddy_free */ - tgprpl_convo_closed, /* convo_closed */ - purple_normalize_nocase, /* normalize */ - tgprpl_set_buddy_icon, /* set_buddy_icon */ - NULL, /* remove_group */ - NULL, /* get_cb_real_name */ - NULL, /* set_chat_topic */ - NULL, /* find_blist_chat */ - NULL, /* roomlist_get_list */ - NULL, /* roomlist_cancel */ - NULL, /* roomlist_expand_category */ - tgprpl_can_receive_file, /* can_receive_file */ - tgprpl_send_file, /* send_file */ - tgprpl_new_xfer, /* new_xfer */ - tgprpl_offline_message, /* offline_message */ - NULL, /* whiteboard_prpl_ops */ - NULL, /* send_raw */ - NULL, /* roomlist_room_serialize */ - NULL, /* unregister_user */ - NULL, /* send_attention */ - NULL, /* get_attention_types */ - sizeof(PurplePluginProtocolInfo), /* struct_size */ - NULL, /* get_account_text_table */ - NULL, /* initiate_media */ - NULL, /* get_media_caps */ - NULL, /* get_moods */ - NULL, /* set_public_alias */ - NULL, /* get_public_alias */ - NULL, /* add_buddy_with_invite */ - NULL /* add_buddies_with_invite */ + tgprpl_chat_info_defaults, /* chat_info_defaults */ + tgprpl_login, /* login */ + tgprpl_close, /* close */ + tgprpl_send_im, /* send_im */ + NULL, /* set_info */ + tgprpl_send_typing, /* send_typing */ + tgprpl_get_info, /* get_info */ + tgprpl_set_status, /* set_status */ + NULL, /* set_idle */ + NULL, /* change_passwd */ + tgprpl_add_buddy, /* add_buddy */ + tgprpl_add_buddies, /* add_buddies */ + tgprpl_remove_buddy, /* remove_buddy */ + tgprpl_remove_buddies, /* remove_buddies */ + NULL, /* add_permit */ + tgprpl_add_deny, /* add_deny */ + NULL, /* rem_permit */ + tgprpl_rem_deny, /* rem_deny */ + NULL, /* set_permit_deny */ + tgprpl_chat_join, /* join_chat */ + NULL, /* reject_chat */ + tgprpl_get_chat_name, /* get_chat_name */ + tgprpl_chat_invite, /* chat_invite */ + NULL, /* chat_leave */ + NULL, /* chat_whisper */ + tgprpl_send_chat, /* chat_send */ + NULL, /* keepalive */ + NULL, /* register_user */ + NULL, /* get_cb_info */ + NULL, /* get_cb_away */ + NULL, /* alias_buddy */ + tgprpl_group_buddy, /* group_buddy */ + tgprpl_rename_group, /* rename_group */ + NULL, /* buddy_free */ + tgprpl_convo_closed, /* convo_closed */ + purple_normalize_nocase, /* normalize */ + tgprpl_set_buddy_icon, /* set_buddy_icon */ + NULL, /* remove_group */ + NULL, /* get_cb_real_name */ + NULL, /* set_chat_topic */ + NULL, /* find_blist_chat */ + NULL, /* roomlist_get_list */ + NULL, /* roomlist_cancel */ + NULL, /* roomlist_expand_category */ + tgprpl_can_receive_file, /* can_receive_file */ + tgprpl_send_file, /* send_file */ + tgprpl_new_xfer, /* new_xfer */ + tgprpl_offline_message, /* offline_message */ + NULL, /* whiteboard_prpl_ops */ + NULL, /* send_raw */ + NULL, /* roomlist_room_serialize */ + NULL, /* unregister_user */ + NULL, /* send_attention */ + NULL, /* get_attention_types */ + sizeof(PurplePluginProtocolInfo), /* struct_size */ + NULL, /* get_account_text_table */ + NULL, /* initiate_media */ + NULL, /* get_media_caps */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static void tgprpl_init(PurplePlugin *plugin) { PurpleAccountOption *option; - PurpleAccountUserSplit *split; - GList *verification_values = NULL; + PurpleAccountUserSplit *split; + GList *verification_values = NULL; - // intialise logging + // intialise logging set_log_cb(&tg_cli_log_cb); - // Required Verification-Key -// split = purple_account_user_split_new("Verification key", NULL, '@'); -// purple_account_user_split_set_reverse(split, FALSE); -// prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); + // Required Verification-Key +// split = purple_account_user_split_new("Verification key", NULL, '@'); +// purple_account_user_split_set_reverse(split, FALSE); +// prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); - // Extra Options + // Extra Options #define ADD_VALUE(list, desc, v) { \ PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ kvp->key = g_strdup((desc)); \ kvp->value = g_strdup((v)); \ list = g_list_prepend(list, kvp); \ } - ADD_VALUE(verification_values, "Phone", TELEGRAM_AUTH_MODE_PHONE); - ADD_VALUE(verification_values, "SMS", TELEGRAM_AUTH_MODE_SMS); - option = purple_account_option_list_new("Verification type", "verification_type", verification_values); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + ADD_VALUE(verification_values, "Phone", TELEGRAM_AUTH_MODE_PHONE); + ADD_VALUE(verification_values, "SMS", TELEGRAM_AUTH_MODE_SMS); + option = purple_account_option_list_new("Verification type", "verification_type", verification_values); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - // option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); - // prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + // option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); + // prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new("Verification key", "verification_key", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new("Verification hash", "verification_hash", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new("First Name", "first_name", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new("Last Name", "last_name", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - // TODO: Path to public key (When you can change the server hostname, + // TODO: Path to public key (When you can change the server hostname, // you should also be able to change the public key) - option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - _telegram_protocol = plugin; + _telegram_protocol = plugin; } static GList *tgprpl_actions(PurplePlugin * plugin, gpointer context) { // return possible actions (See Libpurple doc) - return (GList *)NULL; + return (GList *)NULL; } static PurplePluginInfo info = { From 2099d9fbc3701a4d131d0df41bb155c90ef26cba Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 27 Jun 2014 09:37:35 +0200 Subject: [PATCH 324/465] Rename printname to alias --- structures.c | 2 +- structures.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/structures.c b/structures.c index d8a5887..d7465bf 100644 --- a/structures.c +++ b/structures.c @@ -206,7 +206,7 @@ long long fetch_user_photo (struct user *U) { return 0; } -int user_get_printname(peer_t *user, char *buffer, int maxlen) +int user_get_alias(peer_t *user, char *buffer, int maxlen) { char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; diff --git a/structures.h b/structures.h index 686e4ee..63610b4 100644 --- a/structures.h +++ b/structures.h @@ -381,7 +381,7 @@ void peer_insert_name (peer_t *P); void peer_delete_name (peer_t *P); peer_t *peer_lookup_name (const char *s); -int user_get_printname(peer_t *user, char *buffer, int maxlen); +int user_get_alias(peer_t *user, char *buffer, int maxlen); #define PEER_USER 1 #define PEER_CHAT 2 From 6a439a5d55cf2eaa14d28be5ce9602219a096ca9 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 8 Jul 2014 21:17:50 +0200 Subject: [PATCH 325/465] Move everything into one Makefile Avoid having to execute two different make commands to properly build the plugin, when there are changes in the telegram-cli files. --- Makefile.in | 94 ++++++++++++++++++++++++++++++++++++++---- purple-plugin/Makefile | 87 -------------------------------------- 2 files changed, 85 insertions(+), 96 deletions(-) delete mode 100755 purple-plugin/Makefile diff --git a/Makefile.in b/Makefile.in index eb4650f..f2abddb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,3 +1,7 @@ +# +# Telegram Flags +# + srcdir=@srcdir@ CFLAGS=@CFLAGS@ @@ -6,9 +10,6 @@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -# include libpurple headers for debugging purposes -CFLAGS_PURPLE = $(shell pkg-config --cflags purple) - EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} @@ -16,23 +17,98 @@ LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h ${srcdir}/msglog.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o msglog.o +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o msglog.o tg-cli.o .SUFFIXES: .SUFFIXES: .c .h .o -all: telegram + +# +# Plugin Flags +# + +LIBS_PURPLE = $(shell pkg-config --libs purple) +CFLAGS_PURPLE = $(shell pkg-config --cflags purple) +PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) +DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple) + +ARCH = "" +ifeq ($(ARCH),i686) + ARCHFLAGS = -m32 +else ifeq ($(ARCH),x86_64) + ARCHFLAGS = -m64 +else + ARCHFLAGS = +endif + +LD = $(CC) +PRPL_C_SRCS = purple-plugin/telegram-purple.c +PRPL_C_OBJS = $(PRPL_C_SRCS:.c=.o) +PRPL_LIBNAME = telegram-purple.so +PRPL_INCLUDE = -I. -I./purple-plugin +PRPL_LDFLAGS = $(ARCHFLAGS) -shared +STRIP = strip +PRPL_CFLAGS = \ + $(ARCHFLAGS) \ + -fPIC \ + -DPURPLE_PLUGINS \ + -DPIC \ + -g \ + $(CFLAGS_PURPLE) + +# +# Telegram Objects +# + +.c.o : + ${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ ${OBJECTS}: ${HEADERS} telegram: ${OBJECTS} ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ -.c.o : - ${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ +# +# Plugin Objects +# -objects: ${OBJECTS} +$(PRPL_C_OBJS): $(PRPL_C_SRCS) + $(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $< + +$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) + $(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $(PRPL_C_OBJS) $(OBJECTS) + +plugin: $(PRPL_LIBNAME) + +.PHONY: strip +strip: $(PRPL_LIBNAME) + $(STRIP) --strip-unneeded $(PRPL_LIBNAME) + +debug: PRPL_CFLAGS += -g -DDEBUG +debug: $(PRPL_LIBNAME) + gdb -tui -ex 'break telegram-purple.c:tgprpl_login' pidgin + +# TODO: Find a better place for server.pub +install: $(PRPL_LIBNAME) + install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) + install -D tg-server.pub /etc/telegram/server.pub + install -D purple-plugin/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png + install -D purple-plugin/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png + install -D purple-plugin/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png + +.PHONY: uninstall +uninstall: $(PRPL_LIBNAME) + rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) + rm -f /etc/telegram/server.pub + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png + +.PHONY: run +run: install + pidgin -d | grep 'telegram\|plugin' clean: - rm -rf *.a *.o telegram config.log config.status > /dev/null || echo "all clean" + rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean" + diff --git a/purple-plugin/Makefile b/purple-plugin/Makefile deleted file mode 100755 index 41aff3e..0000000 --- a/purple-plugin/Makefile +++ /dev/null @@ -1,87 +0,0 @@ -# Include libs from tg (--disable-liblua --disable-lib) - -# TODO: These flags should depend on the used configuration flags -EXTRA_LIBS = -lcrypto -lz -lm -lreadline -LDFLAGSTG = -L/usr/local/lib -CPPFLAGSTG = -I/usr/local/include -OBJECTSTG = ../main.o ../loop.o ../interface.o ../net.o ../mtproto-common.o ../mtproto-client.o ../queries.o ../structures.o ../binlog.o ../tools.o ../lua-tg.o ../msglog.o ../tg-cli.o -INCLUDE = -I. -I.. -# - -LIBNAME = telegram-purple.so -ARCH = "" - -ifeq ($(ARCH),i686) - ARCHFLAGS = -m32 -else ifeq ($(ARCH),x86_64) - ARCHFLAGS = -m64 -else - ARCHFLAGS = -endif - -.PHONY: all -all: $(LIBNAME) - -C_SRCS = telegram-purple.c -C_OBJS = $(C_SRCS:.c=.o) - -STRIP = strip -CC = gcc -LD = $(CC) -CFLAGS_PURPLE = $(shell pkg-config --cflags purple) -CFLAGS = \ - $(ARCHFLAGS) \ - -fPIC \ - -DPURPLE_PLUGINS \ - -DPIC \ - -g \ - $(CFLAGS_PURPLE) - -LIBS_PURPLE = $(shell pkg-config --libs purple) -LDFLAGS = $(ARCHFLAGS) -shared - -%.o: %.c - $(CC) -c $(INCLUDE) $(CFLAGS) -o $@ $< - -$(LIBNAME): $(C_OBJS) - cd ..; make objects; cd ./purple-plugin; - $(LD) $(LDFLAGS) $(INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $^ $(OBJECTSTG) - -.PHONY: strip -strip: $(LIBNAME) - $(STRIP) --strip-unneeded $(LIBNAME) - -.PHONY: debug install -debug: CFLAGS += -g -DDEBUG -debug: $(LIBNAME) - gdb -tui -ex 'break telegram-purple.c:tgprpl_login' pidgin - - -PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) -DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple) - -# TODO: Find a better place for server.pub -.PHONY: install -install: $(LIBNAME) - install -D $(LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(LIBNAME) - install -D ../tg-server.pub /etc/telegram/server.pub - install -D telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png - install -D telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png - install -D telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png - -.PHONY: uninstall -uninstall: $(LIBNAME) - rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(LIBNAME) - rm -f /etc/telegram/server.pub - rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png - rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png - rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png - -.PHONY: clean -clean: - -rm -f *.o *.a - -rm -f $(LIBNAME) - -.PHONY: run -run: all install - pidgin -d From 44e9163b669a8c7fb06903305894d7a9a20575df Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 11 Jul 2014 01:06:37 +0200 Subject: [PATCH 326/465] Remove useless comments --- main.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/main.c b/main.c index d657316..10b0018 100644 --- a/main.c +++ b/main.c @@ -236,18 +236,6 @@ void running_for_first_time (void) { exit (EXIT_FAILURE); } close (config_file_fd); - /*int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); - int x = -1; - assert (write (auth_file_fd, &x, 4) == 4); - close (auth_file_fd); - - printf ("[%s] created\n", config_filename);*/ - - /* create downloads directory */ - /*if (mkdir (downloads_directory, 0755) !=0) { - perror ("creating download directory"); - exit (EXIT_FAILURE); - }*/ } } From 43a5a80c48475ba6c7b5e3d0f942cd25c574acd6 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 11 Jul 2014 01:13:01 +0200 Subject: [PATCH 327/465] Set up stub for telegram library --- Makefile.in | 5 +- purple-plugin/telegram-purple.c | 13 ++- structures.c | 2 - tg-cli.c => telegram.c | 30 +++-- telegram.h | 199 +++++++++++++++++++++++++++++--- tg-cli.h | 115 ------------------ 6 files changed, 215 insertions(+), 149 deletions(-) rename tg-cli.c => telegram.c (59%) delete mode 100755 tg-cli.h diff --git a/Makefile.in b/Makefile.in index f2abddb..6e37204 100644 --- a/Makefile.in +++ b/Makefile.in @@ -17,8 +17,7 @@ LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h ${srcdir}/msglog.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o msglog.o tg-cli.o - +OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o msglog.o telegram.o .SUFFIXES: .SUFFIXES: .c .h .o @@ -107,7 +106,7 @@ uninstall: $(PRPL_LIBNAME) .PHONY: run run: install - pidgin -d | grep 'telegram\|plugin' + pidgin -d | grep 'telegram\|plugin\|proxy' clean: rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean" diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 6502299..f4f9ac3 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -44,7 +44,7 @@ #include "util.h" // Telegram Includes -#include +#include "telegram.h" #include "msglog.h" #include "mtproto-client.h" #include "mtproto-common.h" @@ -90,7 +90,7 @@ void chat_allocated_handler(peer_t *chat); */ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) { - purple_debug_info(PLUGIN_ID, "tgrpl_list_icon()\n"); + //purple_debug_info(PLUGIN_ID, "tgrpl_list_icon()\n"); return "telegram"; } @@ -145,7 +145,7 @@ static void tgprpl_login(PurpleAccount * acct) const char *username = purple_account_get_username(acct); const char *code = purple_account_get_string(acct, "verification_key", NULL); - const char *hash = purple_account_get_string(acct, "verification_hash", NULL); + const char *hash = purple_account_get_string(acct, "verification_hash", NULL); const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); // const char *verificationType = purple_account_get_string(acct, "verification_type", TELEGRAM_AUTH_MODE_SMS); // int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); @@ -304,8 +304,11 @@ static void tgprpl_close(PurpleConnection * gc) static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) { purple_debug_info(PLUGIN_ID, "tgprpl_send_im()\n"); - - return -1; + PurpleBuddy *b = purple_find_buddy(_pa, who); + peer_id_t *peer = purple_buddy_get_protocol_data(b); + do_send_message(*peer, message, strlen(message)); + // TODO: error handling + return 1; } /** diff --git a/structures.c b/structures.c index d7465bf..78b75e8 100644 --- a/structures.c +++ b/structures.c @@ -33,8 +33,6 @@ #include "queries.h" #include "binlog.h" -#include "tg-cli.h" - #define sha1 SHA1 static int id_cmp (struct message *M1, struct message *M2); diff --git a/tg-cli.c b/telegram.c similarity index 59% rename from tg-cli.c rename to telegram.c index b73eff8..0fdb88d 100755 --- a/tg-cli.c +++ b/telegram.c @@ -1,6 +1,6 @@ #include #include "mtproto-common.h" -#include "tg-cli.h" +#include "telegram.h" #include "msglog.h" /* @@ -37,23 +37,39 @@ void event_user_allocated(peer_t *user) { * Chat allocated */ void (*on_chat_allocated_handler)(peer_t *chat); -void on_chat_allocated(void (*handler)(peer_t *chat)) { +void on_chat_allocated(void (*handler)(peer_t *chat)) +{ on_chat_allocated_handler = handler; } -void event_chat_allocated(peer_t *chat) { +void event_chat_allocated(peer_t *chat) +{ if (on_chat_allocated_handler) { on_chat_allocated_handler(chat); } } +/* + * Callback to create proxy connections + */ +void (*proxy_connection_source)(const char *host, int port, void (*on_connection_created)(int fd)) = NULL; +void *proxy_connection_data = NULL; +void set_proxy_connection_source (void (*connection_source)(const char *host, int port, + void (*on_connection_created)(int fd)), void* data) +{ + proxy_connection_source = connection_source; + proxy_connection_data = data; +} + // template //void (*on_blarg_handler)(type); -//void on_blarg(void (*handler)(type)) { +//void on_blarg(void (*handler)(type)) +//{ // on_blarg_handler = handler; //} -//void event_blarg(type) { -// if (on_blarg_handler) { +//void event_blarg(type) +//{ +// if (on_blarg_handler) +// { // on_blarg_handler(type); // } //} - diff --git a/telegram.h b/telegram.h index d72da12..69882c4 100644 --- a/telegram.h +++ b/telegram.h @@ -1,24 +1,189 @@ -/* - This file is part of telegram-client. +/* + * libtelegram + * =========== + * + * Telegram library based on the telegram cli application by vysheng (see https://github.com/vysheng/tg) + */ - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ #define MAX_DC_NUM 9 #define MAX_PEER_NUM 100000 #ifndef PROG_NAME #define PROG_NAME "telegram" #endif + +#include +#include "net.h" +#include "mtproto-common.h" +#include "structures.h" + + +/** + * A telegram session + * + * Contains all globals from the telegram-cli application and should + * be passed to + */ +struct telegram { + + /* + * Read and save the configuration files into this directory + * + * Every distinct account needs its own configuration directory, that + * will be used to store encryption data and the protocol state for this + * specific user + */ + char *config_dir; + + /* + * Reserved for custom protocol data + */ + void *protocol_data; + + /* + * Events and Callbacks + */ + // TODO: Insert definitions for all function pointers for event and logging + + /* + * Internal protocol state + */ + // TODO: Insert *all* global variables from the telegram-implementation + +}; + +/* + * Constructor + */ +void telegram_create( /* struct telegram, struct configuration config */ ); + // TODO: Initiate a new telegram instance + +/* + * Destructor + */ +void telegram_destroy(struct telegram instance); + // TODO: Write clean-up functions to free all allocated resources of this session + +// Export functions for plugins + +int tg_login (); + +void running_for_first_time (); +void parse_config (); +void store_config (); +void read_auth_file (); + +/** + * Connect to the telegram network with the given configuration + */ +void network_connect(); + +/** + * Request a registration code + */ +char* network_request_registration(); + +/** + * Verify the registration with the given registration code + */ +int network_verify_registration(const char *code, const char *sms_hash); + +/** + * Verify the registration with the given registration code + */ +int network_verify_phone_registration(const char *code, const char *sms_hash, + const char *first, const char *last); + +/** + * Retur if the current phone is registered in the given network. + */ +int network_phone_is_registered(); + +/** + * Return if the current client is registered. + */ +int network_client_is_registered(); + +/** + * Export the current registration to all available data centers + */ +void network_export_registration(); + +/** + * Fetch all unknown messages of the current session + */ +void session_get_difference(); + +/** + * Fetch all known contacts + */ +void session_update_contact_list(); + +/* + * Events + */ +void on_update_new_message(void (*on_msg)(struct message *M)); +void event_update_new_message(struct message *M); + +void on_update_user_typing(); +void on_update_chat_user_typing(); +void on_update_user_status(); +void on_update_user_name(); +void on_update_user_photo(); +void on_update_chat_participants(); + +/* + * Load known users and chats on connect + */ +void on_user_allocated(); + +void on_user_allocated(void (*handler)(peer_t *user)); +void event_user_allocated(peer_t *user); + +void on_chat_allocated(void (*handler)(peer_t *chat)); +void event_chat_allocated(peer_t *chat); + +// template +//void on_blarg(void (*on_msg)(struct message *M)); +//void event_blarg(struct message *M); + +void on_chat_allocated(); + +/** + * Set a function to use as a handle to read from a network resource + * instead of the regular socket read function + */ +void set_net_read_cb(int (*cb)(int fd, void *buff, size_t size)); + +/** + * Set a function to use as handle to write to a newtork resource + * instead of the regular socket write function + */ +void set_net_write_cb(int (*cb)(int fd, const void *buff, size_t size)); + +/** + * The current proxy connection source. + */ +extern void (*proxy_connection_source)(const char *host, int port, void (*on_connection_created)(int fd)); + +/** + * The connection data passed to the connection source. + */ +extern void *proxy_connection_data; + +/** + * Set an alternative connection_source which is used to create open connections instead of the + * regular function. + * + * @param connection_source Called when a new connection is needed. A connection source must accept + * host and port and pass a valid file descriptor to an open TCP-Socket to the + * callback function on_connection_created + * @param data Additional connection data, that will be passed to the callback and may be + * needed for establishing the connection. + */ +void set_proxy_connection_source (void (*connection_source)(const char *host, int port, void (*on_connection_created)(int fd)), void* data); + +/** + * ? + */ +void set_default_username (); diff --git a/tg-cli.h b/tg-cli.h deleted file mode 100755 index bb2ddf8..0000000 --- a/tg-cli.h +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include "net.h" -#include "mtproto-common.h" -#include "structures.h" - -// Export functions for plugins - -int tg_login (); - -void running_for_first_time (); -void parse_config (); -void store_config (); -void read_auth_file (); - -/** - * Connect to the telegram network with the given configuration - */ -void network_connect (); - -/** - * Request a registration code - */ -char* network_request_registration(); - -/** - * Verify the registration with the given registration code - */ -int network_verify_registration(const char *code, const char *sms_hash); - -/** - * Verify the registration with the given registration code - */ -int network_verify_phone_registration(const char *code, const char *sms_hash, - const char *first, const char *last); - -/** - * Retur if the current phone is registered in the given network. - */ -int network_phone_is_registered(); - -/** - * Return if the current client is registered. - */ -int network_client_is_registered(); - -/** - * Export the current registration to all available data centers - */ -void network_export_registration(); - -/** - * Fetch all unknown messages of the current session - */ -void session_get_difference(); - -/** - * Fetch all known contacts - */ -void session_update_contact_list(); - -/* - * Events - */ -void on_update_new_message(void (*on_msg)(struct message *M)); -void event_update_new_message(struct message *M); - -void on_update_user_typing(); -void on_update_chat_user_typing(); -void on_update_user_status(); -void on_update_user_name(); -void on_update_user_photo(); -void on_update_chat_participants(); - -/* - * Load known users and chats on connect - */ -void on_user_allocated(); - -void on_user_allocated(void (*handler)(peer_t *user)); -void event_user_allocated(peer_t *user); - -void on_chat_allocated(void (*handler)(peer_t *chat)); -void event_chat_allocated(peer_t *chat); - -// template -//void on_blarg(void (*on_msg)(struct message *M)); -//void event_blarg(struct message *M); - -void on_chat_allocated(); - -/** - * Set a function to use as a handle to read from a network resource - * instead of the regular socket read function - */ -void set_net_read_cb(int (*cb)(int fd, void *buff, size_t size)); - -/** - * Set a function to use as handle to write to a newtork resource - * instead of the regular socket write function - */ -void set_net_write_cb(int (*cb)(int fd, const void *buff, size_t size)); - -/** - * Set a function to use as handle to create new connections instead of the regular - * socket write function - */ -void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))); - -/** - * ? - */ -void set_default_username (); -// Settings -#define AUTH_MODE_SMS "sms" -#define AUTH_MODE_PHONE "phone" From f78adc8b96bbc493e5b2c59c693cdc8d2d2acda1 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 11 Jul 2014 02:19:05 +0200 Subject: [PATCH 328/465] Support sending messages --- mtproto-client.c | 1 - purple-plugin/telegram-purple.c | 2 +- queries.c | 22 ++++++++++++++++++++-- telegram.h | 7 ++++++- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 675cb5b..827a50c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -66,7 +66,6 @@ #include "mtproto-common.h" -#include "tg-cli.h" #define MAX_NET_RES (1L << 16) extern int log_level; diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f4f9ac3..8a7fd98 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -307,7 +307,7 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me PurpleBuddy *b = purple_find_buddy(_pa, who); peer_id_t *peer = purple_buddy_get_protocol_data(b); do_send_message(*peer, message, strlen(message)); - // TODO: error handling + flush_queries(); return 1; } diff --git a/queries.c b/queries.c index 5a4129b..7d561e2 100644 --- a/queries.c +++ b/queries.c @@ -53,7 +53,6 @@ #include "no-preview.h" #include "binlog.h" -#include "tg-cli.h" #define sha1 SHA1 @@ -75,7 +74,22 @@ long long cur_downloaded_bytes; extern int binlog_enabled; extern int sync_from_start; -int queries_num; +int queries_num = 0; + +int all_queries_done() +{ + if (queries_num > 0) { + logprintf("all_queries_done() == false\n"); + return 0; + } else { + logprintf("all_queries_done() == true\n"); + return 1; + } +} + +void flush_queries () { + net_loop(0, all_queries_done); +} void out_peer_id (peer_id_t id); #define QUERY_TIMEOUT 6.0 @@ -162,6 +176,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth q->extra = extra; queries_num ++; + logprintf("queries_num: %d\n", queries_num); return q; } @@ -201,6 +216,7 @@ void query_error (long long id) { tfree (q, sizeof (*q)); } queries_num --; + logprintf("queries_num: %d\n", queries_num); } #define MAX_PACKED_SIZE (1 << 24) @@ -255,6 +271,7 @@ void query_result (long long id UU) { in_end = eend; } queries_num --; + logprintf("queries_num: %d\n", queries_num); } #define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) @@ -2907,3 +2924,4 @@ void do_update_status (int online UU) { out_int (online ? CODE_bool_false : CODE_bool_true); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &update_status_methods, 0); } + diff --git a/telegram.h b/telegram.h index 69882c4..a63ac99 100644 --- a/telegram.h +++ b/telegram.h @@ -73,6 +73,11 @@ void parse_config (); void store_config (); void read_auth_file (); +/** + * Read and write until all queries received a response or errored + */ +void flush_queries (); + /** * Connect to the telegram network with the given configuration */ @@ -184,6 +189,6 @@ extern void *proxy_connection_data; void set_proxy_connection_source (void (*connection_source)(const char *host, int port, void (*on_connection_created)(int fd)), void* data); /** - * ? + * */ void set_default_username (); From 7fad1403ec722153e63731c7e55a2a6289bb7c3d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 11 Jul 2014 19:57:32 +0200 Subject: [PATCH 329/465] Fetch chats and refactor libtelegram api --- loop.c | 19 ----- purple-plugin/telegram-purple.c | 140 ++++++++++++++++++++++++++------ queries.c | 2 + structures.c | 17 ++-- telegram.c | 29 ++----- telegram.h | 12 +-- 6 files changed, 136 insertions(+), 83 deletions(-) diff --git a/loop.c b/loop.c index b51a71d..dae5586 100644 --- a/loop.c +++ b/loop.c @@ -629,25 +629,6 @@ void network_export_registration() fflush (stderr); } -/** - * Fetch all unknown messages of the current session - */ -void session_get_difference() -{ - do_get_difference(); - net_loop (0, dgot); -} - -extern int contacts_got; -int cupdate_got() { - return contacts_got; -} -void session_update_contact_list() -{ - do_update_contact_list(); - net_loop(0, cupdate_got); -} - int start_loop (char* code, char* auth_mode) { logprintf("Calling start_loop()\n"); logprintf("auth_state %i\n", auth_state); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 8a7fd98..ea99879 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -48,6 +48,7 @@ #include "msglog.h" #include "mtproto-client.h" #include "mtproto-common.h" +#include "structures.h" // telegram-purple includes #include "loop.h" @@ -77,8 +78,7 @@ void tg_cli_log_cb(const char* format, va_list ap) } void on_new_message(struct message *M); -void user_allocated_handler(peer_t *user); -void chat_allocated_handler(peer_t *chat); +void peer_allocated_handler(peer_t *user); /** * Returns the base icon name for the given buddy and account. @@ -227,22 +227,25 @@ static void tgprpl_login(PurpleAccount * acct) purple_blist_add_group(tggroup, NULL); } - purple_debug_info(PLUGIN_ID, "Fetching Network Info\n"); on_update_new_message(on_new_message); - on_user_allocated(user_allocated_handler); - on_chat_allocated(chat_allocated_handler); + on_peer_allocated(peer_allocated_handler); // get all current contacts purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); - session_update_contact_list(); + do_update_contact_list(); + + purple_debug_info(PLUGIN_ID, "Fetching all current chats...\n"); + do_get_dialog_list(); // get new messages - session_get_difference(); + purple_debug_info(PLUGIN_ID, "Fetching new messages...\n"); + do_get_difference(); + flush_queries(); // Our protocol data, that will be delivered to us // through purple connection telegram_conn *conn = g_new0(telegram_conn, 1); - conn->gc = gc; + conn->gc = gc; conn->account = acct; purple_connection_set_protocol_data(gc, conn); @@ -258,30 +261,113 @@ void on_new_message(struct message *M) g_free(who); } -void user_allocated_handler(peer_t *user) -{ - gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); - // TODO: this should probably be freed again somwhere - char *alias = malloc(BUDDYNAME_MAX_LENGTH); - if (user_get_alias(user, alias, BUDDYNAME_MAX_LENGTH) < 0) { - purple_debug_info(PLUGIN_ID, "Buddyalias of (%d) too long, not adding to buddy list.\n", - get_peer_id(user->id)); - return; +/* + * Search chats in hash table + * + * TODO: There has to be an easier way to do this + */ +static PurpleChat *blist_find_chat_by_hasht_cond(PurpleConnection *gc, int (*fn)(GHashTable *hasht, void *data), void *data) +{ + PurpleAccount *account = purple_connection_get_account(gc); + PurpleBlistNode *node = purple_blist_get_root(); + GHashTable *hasht; + while (node) { + if (PURPLE_BLIST_NODE_IS_CHAT(node)) { + PurpleChat *ch = PURPLE_CHAT(node); + if (purple_chat_get_account(ch) == account) { + hasht = purple_chat_get_components(ch); + if (fn(hasht, data)) + return ch; + } + } + node = purple_blist_node_next(node, FALSE); } - PurpleBuddy *buddy = purple_find_buddy(_pa, name); - if (!buddy) { - purple_debug_info(PLUGIN_ID, "Adding %s to buddy list ", name); - buddy = purple_buddy_new(_pa, name, alias); - purple_blist_add_buddy(buddy, NULL, tggroup, NULL); - } - purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); - g_free(name); + return NULL; +} +static int hasht_cmp_id(GHashTable *hasht, void *data) +{ + return !strcmp(g_hash_table_lookup(hasht, "id"), *((char **)data)); +} +static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id) +{ + return blist_find_chat_by_hasht_cond(gc, hasht_cmp_id, &id); } -void chat_allocated_handler(peer_t *chat) + +void peer_allocated_handler(peer_t *user) { - purple_debug_info(PLUGIN_ID, "Chat Allocated: %s\n", chat->print_name); + gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); + logprintf("Allocated peer: %s\n", name); + + switch (user->id.type) { + case PEER_USER: { + logprintf("Peer type: user.\n"); + // TODO: this should probably be freed again somwhere + char *alias = malloc(BUDDYNAME_MAX_LENGTH); + if (user_get_alias(user, alias, BUDDYNAME_MAX_LENGTH) < 0) { + purple_debug_info(PLUGIN_ID, "Buddyalias of (%d) too long, not adding to buddy list.\n", + get_peer_id(user->id)); + return; + } + PurpleBuddy *buddy = purple_find_buddy(_pa, name); + if (!buddy) { + purple_debug_info(PLUGIN_ID, "Adding %s to buddy list\n", name); + buddy = purple_buddy_new(_pa, name, alias); + purple_blist_add_buddy(buddy, NULL, tggroup, NULL); + } + purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); + g_free(name); + } + break; + case PEER_CHAT: { + logprintf("Peer type: chat.\n"); + PurpleChat *ch = blist_find_chat_by_id(_gc, name); + if (!ch) { + gchar *admin = g_strdup_printf("%d", user->chat.admin_id); + GHashTable *htable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert(htable, g_strdup("subject"), user->chat.title); + g_hash_table_insert(htable, g_strdup("id"), name); + g_hash_table_insert(htable, g_strdup("owner"), admin); + logprintf("Adding chat to blist: %s (%s, %s)\n", user->chat.title, name, admin); + ch = purple_chat_new(_pa, user->chat.title, htable); + purple_blist_add_chat(ch, NULL, NULL); + } + + GHashTable *gh = purple_chat_get_components(ch); + //char const *id = g_hash_table_lookup(gh, "id"); + char const *owner = g_hash_table_lookup(gh, "owner"); + + PurpleConversation *conv = purple_find_chat(_gc, atoi(name)); + + purple_conv_chat_clear_users(purple_conversation_get_chat_data(conv)); + if (conv) { + struct chat_user *usr = user->chat.user_list; + int size = user->chat.user_list_size; + int i; + for (i = 0; i < size; i++) { + struct chat_user *cu = (usr + i); + // TODO: Inviter ID + // peer_id_t u = MK_USER (cu->user_id); + // peer_t *uchat = user_chat_get(u); + const char *cuname = g_strdup_printf("%d", cu->user_id); + logprintf("Adding user %s to chat %s\n", cuname, name); + purple_conv_chat_add_user(purple_conversation_get_chat_data(conv), cuname, "", + PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), FALSE); + } + } + } + break; + case PEER_GEO_CHAT: + logprintf("Peer type: geo-chat.\n"); + break; + case PEER_ENCR_CHAT: + logprintf("Peer type: encrypted chat.\n"); + break; + case PEER_UNKNOWN: + logprintf("Peer type: unknown.\n"); + break; + } } /** diff --git a/queries.c b/queries.c index 7d561e2..0197f8d 100644 --- a/queries.c +++ b/queries.c @@ -2639,11 +2639,13 @@ int get_difference_on_answer (struct query *q UU) { } assert (fetch_int () == CODE_vector); n = fetch_int (); + logprintf("Found %d chats\n", n); for (i = 0; i < n; i++) { fetch_alloc_chat (); } assert (fetch_int () == CODE_vector); n = fetch_int (); + logprintf("Found %d users\n", n); for (i = 0; i < n; i++) { fetch_alloc_user (); } diff --git a/structures.c b/structures.c index 78b75e8..a06290b 100644 --- a/structures.c +++ b/structures.c @@ -1527,6 +1527,7 @@ static int id_cmp (struct message *M1, struct message *M2) { } struct user *fetch_alloc_user (void) { + logprintf("fetch_alloc_user()\n"); int send_event = 0; int data[2]; prefetch_data (data, 8); @@ -1542,12 +1543,13 @@ struct user *fetch_alloc_user (void) { } fetch_user (&U->user); if (send_event) { - event_user_allocated(U); + event_peer_allocated(U); } return &U->user; } struct secret_chat *fetch_alloc_encrypted_chat (void) { + logprintf("fetch_alloc_encrypted_chat()\n"); int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); @@ -1560,6 +1562,7 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) { Peers[peer_num ++] = U; } fetch_encrypted_chat (&U->encr_chat); + event_peer_allocated(U); return &U->encr_chat; } @@ -1806,6 +1809,7 @@ void message_del_peer (struct message *M) { } struct message *fetch_alloc_message (void) { + logprintf("fetch_alloc_message()\n"); int data[2]; prefetch_data (data, 8); struct message *M = message_get (data[1]); @@ -1821,6 +1825,7 @@ struct message *fetch_alloc_message (void) { } struct message *fetch_alloc_geo_message (void) { + logprintf("fetch_alloc_geo_message()\n"); struct message *M = talloc (sizeof (*M)); fetch_geo_message (M); struct message *M1 = tree_lookup_message (message_tree, M); @@ -1844,6 +1849,7 @@ struct message *fetch_alloc_geo_message (void) { } struct message *fetch_alloc_encrypted_message (void) { + logprintf("fetch_alloc_encrypted_message()\n"); int data[3]; prefetch_data (data, 12); struct message *M = message_get (*(long long *)(data + 1)); @@ -1891,12 +1897,13 @@ struct message *fetch_alloc_message_short_chat (void) { } struct chat *fetch_alloc_chat (void) { - int send_event = 0; + logprintf("fetch_alloc_chat()\n"); int data[2]; prefetch_data (data, 8); peer_t *U = user_chat_get (MK_CHAT (data[1])); + logprintf("id %d\n", U->id.id); + logprintf("type %d\n", U->id.type); if (!U) { - send_event = 1; chats_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[1]); @@ -1905,9 +1912,7 @@ struct chat *fetch_alloc_chat (void) { Peers[peer_num ++] = U; } fetch_chat (&U->chat); - if (send_event) { - event_chat_allocated(U); - } + event_peer_allocated(U); return &U->chat; } diff --git a/telegram.c b/telegram.c index 0fdb88d..071dc63 100755 --- a/telegram.c +++ b/telegram.c @@ -21,30 +21,15 @@ void event_update_new_message(struct message *M) { } /* - * User allocated + * Peer allocated */ -void (*on_user_allocated_handler)(peer_t *user); -void on_user_allocated(void (*handler)(peer_t *user)) { - on_user_allocated_handler = handler; +void (*on_peer_allocated_handler)(peer_t *peer); +void on_peer_allocated(void (*handler)(peer_t *peer)) { + on_peer_allocated_handler = handler; } -void event_user_allocated(peer_t *user) { - if (on_user_allocated_handler) { - on_user_allocated_handler(user); - } -} - -/* - * Chat allocated - */ -void (*on_chat_allocated_handler)(peer_t *chat); -void on_chat_allocated(void (*handler)(peer_t *chat)) -{ - on_chat_allocated_handler = handler; -} -void event_chat_allocated(peer_t *chat) -{ - if (on_chat_allocated_handler) { - on_chat_allocated_handler(chat); +void event_peer_allocated(peer_t *peer) { + if (on_peer_allocated_handler) { + on_peer_allocated_handler(peer); } } diff --git a/telegram.h b/telegram.h index a63ac99..597014d 100644 --- a/telegram.h +++ b/telegram.h @@ -2,7 +2,7 @@ * libtelegram * =========== * - * Telegram library based on the telegram cli application by vysheng (see https://github.com/vysheng/tg) + * Telegram library based on the telegram cli application, that was originally made by vysheng (see https://github.com/vysheng/tg) */ #define MAX_DC_NUM 9 @@ -140,20 +140,14 @@ void on_update_chat_participants(); /* * Load known users and chats on connect */ -void on_user_allocated(); -void on_user_allocated(void (*handler)(peer_t *user)); -void event_user_allocated(peer_t *user); - -void on_chat_allocated(void (*handler)(peer_t *chat)); -void event_chat_allocated(peer_t *chat); +void on_peer_allocated(void (*handler)(peer_t *peer)); +void event_peer_allocated(peer_t *peer); // template //void on_blarg(void (*on_msg)(struct message *M)); //void event_blarg(struct message *M); -void on_chat_allocated(); - /** * Set a function to use as a handle to read from a network resource * instead of the regular socket read function From 9b7f273579da2fe48f486bc5890507824cf0753b Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Sat, 26 Jul 2014 09:11:47 +0000 Subject: [PATCH 330/465] README.md edited online with Bitbucket --- README.md | 226 +++++++++++++++++++++++++++--------------------------- 1 file changed, 111 insertions(+), 115 deletions(-) diff --git a/README.md b/README.md index 88a3b65..296ee48 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,111 @@ -telegram-purple -=============== - - -# Installieren - -1. Sicherstellen dass Pidgin installiert ist. -2. Dieses Git-Repository klonen. - - - git clone https://bitbucket.org/telegrampurple/telegram-purple - - -3. Im Ordner von **telegram-purple** make ausführen: - - - cd telgram-purple - ./configure --disable-liblua --disable-libconfig - make objects - cd purple-plugin - make install - - -Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. - - -# Testen und Debuggen - -Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: - - - sudo chmod 777 -R `pkg-config --variable=plugindir purple` - sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol - - -## Testen - - -Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: - - - make run - - -Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: - - - sudo killall pidgin - - - -### Filtern der Lognachrichten - -Wenn Pidgin einfach mit **make run** ausgeführt wird, werden alle Debugnachrichten des gesamten Programms ausgegegeben. Libpurple verwendet interne Loggingfunktionen die den Lognachrichten automatisch einen Prefix hinzufügen, z.B. "plugins:" für Nachrichten des Pluginsloaders und "prpl-telegram:" für Nachrichten dieses Plugins. - -Wenn man nur Ausgaben des Plugin-Loaders und von telegram-purple haben möchte kann man unnötige Nachrichten mit **grep** herausfiltern. - - - make run | grep -i 'prpl-telegram:\|plugins:' - - -# Deinstallieren - -Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: - - - sudo make uninstall - - - -# Coding-Guidelines - -## Coding Style - -Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. - - unsigned int some_function(int a, int b) - { - if (true) { - // ... - } else { - // ... - } - } - - -## Logging - -Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). - - - #include "debug.h" - #define PLUGIN_ID "prpl-telegram" - - // ... - - purple_debug_info(PLUGIN_ID, "Debugnachricht"); - - -## GIT -git pull -> Stand aktualisieren -git add -A -> Files hinzufügen -git push -> Stand hochladen -git commit -> Commiten - - - -## Troubleshooting - -Zum löschen der angelegten Accounts -rm /home/USER/.purple/accounts.xml - -Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden - - +telegram-purple +=============== + + +# Installieren + +1. Sicherstellen dass Pidgin installiert ist. +2. Dieses Git-Repository klonen. + + + git clone https://bitbucket.org/telegrampurple/telegram-purple + + +3. Im Ordner von **telegram-purple** make ausführen: + + + cd telgram-purple + ./configure --disable-liblua --disable-libconfig + make install + + +Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. + + +# Testen und Debuggen + +Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: + + + sudo chmod 777 -R `pkg-config --variable=plugindir purple` + sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol + + +## Testen + + +Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: + + + make run + + +Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: + + + sudo killall pidgin + + + +### Filtern der Lognachrichten + +Wenn Pidgin einfach mit **make run** ausgeführt wird, werden alle Debugnachrichten des gesamten Programms ausgegegeben. Libpurple verwendet interne Loggingfunktionen die den Lognachrichten automatisch einen Prefix hinzufügen, z.B. "plugins:" für Nachrichten des Pluginsloaders und "prpl-telegram:" für Nachrichten dieses Plugins. + +Wenn man nur Ausgaben des Plugin-Loaders und von telegram-purple haben möchte kann man unnötige Nachrichten mit **grep** herausfiltern. + + + make run | grep -i 'prpl-telegram:\|plugins:' + + +# Deinstallieren + +Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: + + + sudo make uninstall + + + +# Coding-Guidelines + +## Coding Style + +Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. + + unsigned int some_function(int a, int b) + { + if (true) { + // ... + } else { + // ... + } + } + + +## Logging + +Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). + + + #include "debug.h" + #define PLUGIN_ID "prpl-telegram" + + // ... + + purple_debug_info(PLUGIN_ID, "Debugnachricht"); + + +## GIT +git pull -> Stand aktualisieren +git add -A -> Files hinzufügen +git push -> Stand hochladen +git commit -> Commiten + + + +## Troubleshooting + +Zum löschen der angelegten Accounts +rm /home/USER/.purple/accounts.xml + +Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden \ No newline at end of file From 67c5a5e7124122b1da4d62fed61a37586a86d1d3 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 29 Jul 2014 15:31:37 +0200 Subject: [PATCH 331/465] Ignore ycm-autocompletion files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e35cfab..d8a3631 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ config.status nbproject/ tags .DS_Store +.ycm_extra_conf.py +*.pyc From ed7aa7de5b9b4d63e7b89ef9f0cd20fdb131eb61 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 26 Jul 2014 11:55:45 +0200 Subject: [PATCH 332/465] Refactor Intermediate State 1 --- App configuration.html | 177 +++++++++ Makefile.in | 6 +- README.es | 142 ------- README.md | 363 +++++++++++------ binlog.c | 126 ++---- binlog.h | 5 +- interface.c | 10 +- loop.c | 477 +++++++++++----------- loop.h | 31 +- lua-tg.c | 3 +- lua-tg.h | 2 + main.c | 2 +- msglog.c | 6 + msglog.h | 2 + mtproto-client.c | 490 ++++++++++++----------- mtproto-client.h | 9 + mtproto-common.c | 1 - mtproto-common.h | 3 +- net.c | 127 ++---- net.h | 23 +- purple-plugin/telegram-purple.c | 258 ++++++++---- purple-plugin/telegram-purple.h | 5 +- queries.c | 679 +++++++++++++++++++------------- queries.h | 98 ++--- structures.c | 35 +- structures.h | 11 +- telegram.c | 225 +++++++++-- telegram.h | 221 +++++++---- 28 files changed, 2050 insertions(+), 1487 deletions(-) create mode 100644 App configuration.html delete mode 100644 README.es diff --git a/App configuration.html b/App configuration.html new file mode 100644 index 0000000..e416b66 --- /dev/null +++ b/App configuration.html @@ -0,0 +1,177 @@ + + + + + App configuration + + + + + + + + + + +

+
+ +
+
+
+
+

App configuration

+
+ +
+ 16154 +
+
+
+ +
+ +
+ 99428c722d0ed59b9cd844e4577cb4bb +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +

alphanumeric, 5-32 characters

+
+
+ +
+

PUSH-notifications settings

+ +
+ + +
+
+ +
+

+ APNS certificates + +  Update +  Delete + +

+ + + + +
+ +

Available MTProto servers

+ +
+ +
+ 173.240.5.253:443 +

First DC

+
+
+
+ +
+ 173.240.5.1:443 +

First DC

+
+
+ +
+ +
+
-----BEGIN RSA PUBLIC KEY-----
+MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
+lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
+an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
+Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
+8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
+Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
+-----END RSA PUBLIC KEY-----
+
+
+ + +
+ + Cancel +
+
+
+ +
+
+
+ + + + + + + \ No newline at end of file diff --git a/Makefile.in b/Makefile.in index 6e37204..865eb7f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -8,16 +8,16 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h ${srcdir}/msglog.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h INCLUDE=-I. -I${srcdir} CC=@CC@ -OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o lua-tg.o msglog.o telegram.o +OBJECTS=loop.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o msglog.o telegram.o .SUFFIXES: .SUFFIXES: .c .h .o diff --git a/README.es b/README.es deleted file mode 100644 index ede5809..0000000 --- a/README.es +++ /dev/null @@ -1,142 +0,0 @@ -## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) - -Interfaz de línea de comandos para: [Telegram](http://telegram.org). Usa interfaz readline. - -### Documentación del API y el protocolo - -La documentación del APi de Telegram está disponible aquí: http://core.telegram.org/api - -La documentación del protocolo MTproto está disponible aquí: http://core.telegram.org/mtproto - -### Instalación - -Clona el Repositorio GitHub - - $ git clone https://github.com/vysheng/tg.git && cd tg - -o descarga y descomprime el zip - - $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip - $ unzip tg-master.zip && cd tg-master - -#### Linux - -Librerías requeridas: readline openssl y (si desea usar config) libconfig y liblua. -Si no deseas usarlo, pasa las siguientes opciones --disable-libconfig y --disable-liblua respectivamente. - -En Ubuntu usa: - - $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev - -En gentoo: - - $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua - -En Fedora: - - $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel - -Por defecto Makefile utiliza liblua5.2 de ubuntu. Si utilizas una versión diferente de liblua o linux, tienes que ejecutar el script ./configure o recibirás un error de compilación extraño. - -Entonces - - $ ./configure - $ make - - -#### Mac OS X - -El cliente depende de [librería readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) y [libconfig](http://www.hyperrealm.com/libconfig/), las cuales no están incluídas en OS X por defecto. Debes instalar estas librerías de forma manual, usando por ejemplo [Homebrew](http://brew.sh/). - - $ brew install libconfig - $ brew install readline - $ brew install lua - $ export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" - $ export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" - $ ./configure && make - -Gracias a [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) por esta solución. - -#### FreeBSD - -Instalar estos puertos: - -* devel/libconfig -* devel/libexecinfo - -Entonces construir: - - $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure - $ make - -#### Otros UNIX - -Si logras ejecutarlo en otros UNIX, por favor házmelo saber. - - -### Uso - - ./telegram -k - - -Por defecto la clave pública se almacena en la misma carpeta con el nombre tg-server.pub o en /etc/telegram/server.pub, si no lo es, indica dónde encontrarlo: - - ./telegram -k tg-server.pub - -El Cliente soporta completamiento con TAB e historial de comandos. - -Peer se refiere al nombre del contacto o de diálogo y se puede acceder por completamiento con Tab. -Para los contactos de usuario el peer es el Nombre Apellido con todos los espacios cambiados a guiones bajos. -Para los chats es su título con todos los espacios cambiados a guiones bajos. -Para los chats encriptados es Nombre Apellido con todos los espacios cambiados a guiones bajos. - -Si dos o más peers tienen el mismo nombre, una almohadilla y un número es añadido al nombre. (por ejemplo A_B,A_B#1,A_B#2 y así sucesivamente). - -### Comandos soportados - -#### Mensajería - - -* **msg** \ texto - envía el mensaje a este usuario. -* **fwd** \ \ - reenviar un mensaje al usuario. Puedes ver los número de mensajes iniciando el Cliente con -N. -* **chat_with_peer** \ - inicia un chat con este usuario. /exit o /quit para salir de este modo. -* **add_contact** \ \ \ - intenta añadir este contacto a la lista de contactos. -* **rename_contact** \ \ \ - intenta renombrar el contacto. Si tienes otro dispositivo será una pelea. -* **mark_read** \ - marca todos los mensajes como recibidos de ese usuario. - -#### Multimedia - -* **send_photo** \ \ - manda una foto al usuario. -* **send_video** \ \ - envia un video al usuario. -* **send_text** \ \ - envia un archivo de texto como un mensaje en plano. -* **load_photo**/load_video/load_video_thumb \ - carga foto/video indicado del directorio de descarga. -* **view_photo**/view_video/view_video_thumb \ - carga foto/video indicado del directorio de descarga y lo abre con el visor por defecto del sistema. - - -#### Opciones de chat de grupo - -* **chat_info** \ - imprime información del chat. -* **chat_add_user** \ \ - agrega un usuario al chat. -* **chat_del_user** \ \ - elimina un usuario del chat. -* **rename_chat** \ \ - cambia el nombre al chat. - -#### Search - -* **search** \ patrón - busca el patrón indicado en los mensajes con ese usuario. -* **global_search** patrón - busca el patrón indicado en todos los mensajes. - -#### Chat secreto - -* **create_secret_chat** \ - crea un chat secreto con el usuario indicado. -* **visualize_key** \ - Muestra la clave de cifrado. Debes compararla con la del otro usuario. - -#### Estadísticas e información varia. - -* **user_info** \ - muestra información sobre el usuario. -* **history** \ [limit] - muestra el historial (y la marca como leído). Limite por defecto = 40. -* **dialog_list** - muestra información acerca del dialogo -* **contact_list** - muestra información acerca de tu lista de contactos. -* **suggested_contacts** - muestra información sobre sus contactos, tiene un máximo de amigos comunes. -* **stats** - solo para depuración. -* **show_license** - muestra la licencia GPLv2. -* **help** - imprime esta ayuda. diff --git a/README.md b/README.md index 296ee48..3abf83a 100644 --- a/README.md +++ b/README.md @@ -1,111 +1,252 @@ -telegram-purple -=============== - - -# Installieren - -1. Sicherstellen dass Pidgin installiert ist. -2. Dieses Git-Repository klonen. - - - git clone https://bitbucket.org/telegrampurple/telegram-purple - - -3. Im Ordner von **telegram-purple** make ausführen: - - - cd telgram-purple - ./configure --disable-liblua --disable-libconfig - make install - - -Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. - - -# Testen und Debuggen - -Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: - - - sudo chmod 777 -R `pkg-config --variable=plugindir purple` - sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol - - -## Testen - - -Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: - - - make run - - -Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: - - - sudo killall pidgin - - - -### Filtern der Lognachrichten - -Wenn Pidgin einfach mit **make run** ausgeführt wird, werden alle Debugnachrichten des gesamten Programms ausgegegeben. Libpurple verwendet interne Loggingfunktionen die den Lognachrichten automatisch einen Prefix hinzufügen, z.B. "plugins:" für Nachrichten des Pluginsloaders und "prpl-telegram:" für Nachrichten dieses Plugins. - -Wenn man nur Ausgaben des Plugin-Loaders und von telegram-purple haben möchte kann man unnötige Nachrichten mit **grep** herausfiltern. - - - make run | grep -i 'prpl-telegram:\|plugins:' - - -# Deinstallieren - -Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: - - - sudo make uninstall - - - -# Coding-Guidelines - -## Coding Style - -Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. - - unsigned int some_function(int a, int b) - { - if (true) { - // ... - } else { - // ... - } - } - - -## Logging - -Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). - - - #include "debug.h" - #define PLUGIN_ID "prpl-telegram" - - // ... - - purple_debug_info(PLUGIN_ID, "Debugnachricht"); - - -## GIT -git pull -> Stand aktualisieren -git add -A -> Files hinzufügen -git push -> Stand hochladen -git commit -> Commiten - - - -## Troubleshooting - -Zum löschen der angelegten Accounts -rm /home/USER/.purple/accounts.xml - -Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden \ No newline at end of file +telegram-purple +=============== + + +# Installieren + +1. Sicherstellen dass Pidgin installiert ist. +2. Dieses Git-Repository klonen. + + + git clone https://bitbucket.org/telegrampurple/telegram-purple + + +3. Im Ordner von **telegram-purple** make ausführen: + + + cd telgram-purple + ./configure --disable-liblua --disable-libconfig + make install + + +Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. + + +# Testen und Debuggen + +Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: + + + sudo chmod 777 -R `pkg-config --variable=plugindir purple` + sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol + + +## Testen + + +Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: + + + make run + + +Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: + + + sudo killall pidgin + + + +### Filtern der Lognachrichten + +Wenn Pidgin einfach mit **make run** ausgeführt wird, werden alle Debugnachrichten des gesamten Programms ausgegegeben. Libpurple verwendet interne Loggingfunktionen die den Lognachrichten automatisch einen Prefix hinzufügen, z.B. "plugins:" für Nachrichten des Pluginsloaders und "prpl-telegram:" für Nachrichten dieses Plugins. + +Wenn man nur Ausgaben des Plugin-Loaders und von telegram-purple haben möchte kann man unnötige Nachrichten mit **grep** herausfiltern. + + + make run | grep -i 'prpl-telegram:\|plugins:' + + +# Deinstallieren + +Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: + + + sudo make uninstall + + + +# Coding-Guidelines + +## Coding Style + +Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. + + unsigned int some_function(int a, int b) + { + if (true) { + // ... + } else { + // ... + } + } + + +## Logging + +Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). + + + #include "debug.h" + #define PLUGIN_ID "prpl-telegram" + + // ... + + purple_debug_info(PLUGIN_ID, "Debugnachricht"); + + +## GIT +git pull -> Stand aktualisieren +git add -A -> Files hinzufügen +git push -> Stand hochladen +git commit -> Commiten + + + +## Troubleshooting + +Zum löschen der angelegten Accounts +rm /home/USER/.purple/accounts.xml + +Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden +======= +telegram-purple +=============== + + +# Installieren + +1. Sicherstellen dass Pidgin installiert ist. +2. Dieses Git-Repository klonen. + + + git clone https://bitbucket.org/telegrampurple/telegram-purple + + +3. Im Ordner von **telegram-purple** make ausführen: + + + cd telgram-purple + ./configure --disable-liblua --disable-libconfig + make install + + +Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. + + +# Testen und Debuggen + +Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: + + + sudo chmod 777 -R `pkg-config --variable=plugindir purple` + sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol + + +## Testen + + +Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: + + + make run + + +Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: + + + sudo killall pidgin + + + +# Deinstallieren + +Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: + + + sudo make uninstall + + + +# Coding-Guidelines + +## Speicherverwaltung + +Glib verwendet eigene Datentypen und eigene Funktionen zu Speicherverwaltung. Wenn diese mit den regulären Funktionen von c vermischt werden, z.B. malloc und g\_free auf dem selben Pointer, kann die Anwendung abstürzen. + + + char *str = malloc(10); + g_free(str); // APPLICATION ERROR + + +Beim Purple-Plugin müssen wir die Typen und Verwaltungsfunktionen von glib verwenden, deshalb werden im Unterordner ./purple-plugin ausschließlich g\_alloc g\_new und g\_free zum allozieren und löschen von Objekten verwendet. Siehe ([https://developer.gnome.org/glib/2.30/glib-Memory-Allocation.html]) + +In Telegram-Cli werden keine glib-Funktionen verwendet, deshalb müssen wie hier ausschließlich die regulären C-Funktionen malloc und free verwenden. + +### Aufrufe von Telegram-CLI + +Wir rufen Telegram-CLI vom Purple-Plugin aus auf. Um die verschiedenen Sorten der Speicherverwaltung nicht zu vermischen, muss Telegram-CLI seinen gesamten Speicher selbst verwalten. Wenn strings oder Structs vom Plugin aus an die Bibliothek übergeben werden müssen die Objekte deshalb kopiert werden. + + + void *telegram_do_something(Telegram tg, const char* string) + { + char *dup = malloc(strlen(login) * sizeof(char)); + dup = memcpy(dup, string); + global->login = dup; + } + + +Jede Komponente der Anwendung muss deshalb den Speicher den sie alloziert auch selbst verwalten, da andere Komponenten diese niemals löschen werden. Wenn der String im Plugin mit einer allozierenden Funktion wie g\_strdup erstellt wurde, muss diese deshalb auch wieder mit g\_free gelöscht werden, da sonst ein Memory Leak entsteht. + + + gchar *str = g_strdup(string); + // ... + telegram_do_something(telegram, str); + // ... + g\_gree(str); + + + +## Coding Style + +Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. + + unsigned int some_function(int a, int b) + { + if (true) { + // ... + } else { + // ... + } + } + + +## Logging + +Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). + + + #include "debug.h" + #define PLUGIN_ID "prpl-telegram" + + // ... + + purple_debug_info(PLUGIN_ID, "Debugnachricht"); + + +## GIT +git pull -> Stand aktualisieren +git add -A -> Files hinzufügen +git push -> Stand hochladen +git commit -> Commiten + + + +## Troubleshooting + +Zum löschen der angelegten Accounts +rm /home/USER/.purple/accounts.xml + +Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden + + diff --git a/binlog.c b/binlog.c index b544876..13dd663 100644 --- a/binlog.c +++ b/binlog.c @@ -21,9 +21,6 @@ #include "config.h" #endif -#ifdef USE_LUA -# include "lua-tg.h" -#endif #include #include #include @@ -41,6 +38,7 @@ #include "net.h" #include "include.h" #include "mtproto-client.h" +#include "telegram.h" #include @@ -48,6 +46,7 @@ int binlog_buffer[BINLOG_BUFFER_SIZE]; int *rptr; int *wptr; +int test_dc = 0; extern int test_dc; extern int pts; @@ -58,11 +57,11 @@ extern int seq; #define MAX_LOG_EVENT_SIZE (1 << 17) char *get_binlog_file_name (void); -extern struct dc *DC_list[]; -extern struct dc *DC_working; -extern int dc_working_num; +//extern struct dc *DC_list[]; +//extern int dc_working_num; extern int our_id; extern int binlog_enabled; +int binlog_enabled = 0; extern int encr_root; extern unsigned char *encr_prime; extern int encr_param_version; @@ -76,7 +75,8 @@ void *alloc_log_event (int l UU) { long long binlog_pos; -void replay_log_event (void) { +void replay_log_event (struct telegram *instance) { + int *start = rptr; in_replay_log = 1; assert (rptr < wptr); @@ -104,7 +104,7 @@ void replay_log_event (void) { if (verbosity) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } - alloc_dc (id, tstrndup (ip, l2), port); + alloc_dc (instance->auth.DC_list, id, tstrndup (ip, l2), port); } rptr = in_ptr; break; @@ -113,12 +113,12 @@ void replay_log_event (void) { { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); - assert (DC_list[num]); - DC_list[num]->auth_key_id = *(long long *)rptr; + assert (instance->auth.DC_list[num]); + instance->auth.DC_list[num]->auth_key_id = *(long long *)rptr; rptr += 2; - memcpy (DC_list[num]->auth_key, rptr, 256); + memcpy (instance->auth.DC_list[num]->auth_key, rptr, 256); rptr += 64; - DC_list[num]->flags |= 1; + instance->auth.DC_list[num]->flags |= 1; }; break; case LOG_DEFAULT_DC: @@ -126,17 +126,13 @@ void replay_log_event (void) { { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); - DC_working = DC_list[num]; - dc_working_num = num; + instance->auth.dc_working_num = num; } break; case LOG_OUR_ID: rptr ++; { our_id = *(rptr ++); - #ifdef USE_LUA - lua_our_id (our_id); - #endif } break; case LOG_DC_SIGNED: @@ -144,8 +140,8 @@ void replay_log_event (void) { { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); - assert (DC_list[num]); - DC_list[num]->has_auth = 1; + assert (instance->auth.DC_list[num]); + instance->auth.DC_list[num]->has_auth = 1; } break; case LOG_DC_SALT: @@ -153,20 +149,20 @@ void replay_log_event (void) { { int num = *(rptr ++); assert (num >= 0 && num <= MAX_DC_ID); - assert (DC_list[num]); - DC_list[num]->server_salt = *(long long *)rptr; + assert (instance->auth.DC_list[num]); + instance->auth.DC_list[num]->server_salt = *(long long *)rptr; rptr += 2; }; break; -/* case CODE_user_empty: - case CODE_user_self: - case CODE_user_contact: - case CODE_user_request: - case CODE_user_foreign: +// case CODE_user_empty: +// case CODE_user_self: +// case CODE_user_contact: +// case CODE_user_request: +// case CODE_user_foreign: case CODE_user_deleted: fetch_alloc_user (); rptr = in_ptr; - break;*/ + break; case LOG_DH_CONFIG: get_dh_config_on_answer (0); rptr = in_ptr; @@ -293,9 +289,6 @@ void replay_log_event (void) { struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->state = sc_ok; - #ifdef USE_LUA - lua_secret_chat_created (U); - #endif } break; case CODE_binlog_new_user: @@ -325,10 +318,6 @@ void replay_log_event (void) { if (fetch_int ()) { U->flags |= FLAG_USER_CONTACT; } - - #ifdef USE_LUA - lua_user_update (U); - #endif } rptr = in_ptr; break; @@ -359,10 +348,6 @@ void replay_log_event (void) { assert (U); if (U->user.phone) { tfree_str (U->user.phone); } U->user.phone = fetch_str_dup (); - - #ifdef USE_LUA - lua_user_update (&U->user); - #endif } rptr = in_ptr; break; @@ -409,10 +394,6 @@ void replay_log_event (void) { if (U->user.real_last_name) { tfree_str (U->user.real_last_name); } U->user.real_first_name = fetch_str_dup (); U->user.real_last_name = fetch_str_dup (); - - #ifdef USE_LUA - lua_user_update (&U->user); - #endif } rptr = in_ptr; break; @@ -613,10 +594,6 @@ void replay_log_event (void) { C->version = fetch_int (); fetch_data (&C->photo_big, sizeof (struct file_location)); fetch_data (&C->photo_small, sizeof (struct file_location)); - - #ifdef USE_LUA - lua_chat_update (C); - #endif }; rptr = in_ptr; break; @@ -643,9 +620,6 @@ void replay_log_event (void) { } C->print_title = create_print_name (C->id, C->title, 0, 0, 0); peer_insert_name ((void *)C); - #ifdef USE_LUA - lua_chat_update (C); - #endif }; rptr = in_ptr; break; @@ -665,9 +639,6 @@ void replay_log_event (void) { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.date = *(rptr ++); - #ifdef USE_LUA - lua_chat_update (&C->chat); - #endif }; break; case CODE_binlog_set_chat_version: @@ -677,9 +648,6 @@ void replay_log_event (void) { assert (C && (C->flags & FLAG_CREATED)); C->chat.version = *(rptr ++); C->chat.users_num = *(rptr ++); - #ifdef USE_LUA - lua_chat_update (&C->chat); - #endif }; break; case CODE_binlog_set_chat_admin: @@ -688,9 +656,6 @@ void replay_log_event (void) { peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.admin_id = *(rptr ++); - #ifdef USE_LUA - lua_chat_update (&C->chat); - #endif }; break; case CODE_binlog_set_chat_participants: @@ -704,9 +669,6 @@ void replay_log_event (void) { C->chat.user_list = talloc (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; - #ifdef USE_LUA - lua_chat_update (&C->chat); - #endif }; break; case CODE_binlog_chat_full_photo: @@ -746,9 +708,6 @@ void replay_log_event (void) { 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; - #ifdef USE_LUA - lua_chat_update (C); - #endif } break; case CODE_binlog_del_chat_participant: @@ -776,9 +735,6 @@ void replay_log_event (void) { C->user_list_size --; C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); C->user_list_version = version; - #ifdef USE_LUA - lua_chat_update (C); - #endif } break; case CODE_binlog_create_message_text: @@ -828,10 +784,6 @@ void replay_log_event (void) { message_insert_unsent (M); M->flags |= FLAG_PENDING; } - - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -867,9 +819,6 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -903,9 +852,6 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -941,9 +887,6 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -979,9 +922,6 @@ void replay_log_event (void) { M->out = get_peer_id (M->from_id) == our_id; message_insert (M); - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -1010,9 +950,6 @@ void replay_log_event (void) { M->service = 1; message_insert (M); - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -1042,9 +979,6 @@ void replay_log_event (void) { M->service = 1; message_insert (M); - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -1074,9 +1008,6 @@ void replay_log_event (void) { M->service = 1; message_insert (M); - #ifdef USE_LUA - lua_new_msg (M); - #endif } rptr = in_ptr; break; @@ -1176,7 +1107,7 @@ void create_new_binlog (void) { } -void replay_log (void) { +void replay_log (struct telegram *instance) { if (access (get_binlog_file_name (), F_OK) < 0) { printf ("No binlog found. Creating new one\n"); create_new_binlog (); @@ -1210,7 +1141,7 @@ void replay_log (void) { wptr += (k / 4); } if (wptr == rptr) { break; } - replay_log_event (); + replay_log_event (instance); } close (fd); } @@ -1240,7 +1171,8 @@ void add_log_event (const int *data, int len) { wptr = rptr + (len / 4); int *in = in_ptr; int *end = in_end; - replay_log_event (); + // TODO: + //replay_log_event (); if (rptr != wptr) { logprintf ("Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len); assert (rptr == wptr); @@ -1381,8 +1313,8 @@ void bl_do_set_user_friend (struct user *U, int friend) { add_log_event (ev, 12); } -void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port) { - struct dc *DC = DC_list[id]; +void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance) { + struct dc *DC = instance->auth.DC_list[id]; if (DC) { return; } clear_packet (); diff --git a/binlog.h b/binlog.h index d0d2d9b..c72699a 100644 --- a/binlog.h +++ b/binlog.h @@ -20,6 +20,7 @@ #define __BINLOG_H__ #include "structures.h" +#include "telegram.h" #define LOG_START 0x8948329a #define LOG_AUTH_KEY 0x984932aa @@ -84,12 +85,12 @@ #define CODE_binlog_delete_msg 0xa1d6ab6d void *alloc_log_event (int l); -void replay_log (void); +void replay_log (struct telegram *instance); void add_log_event (const int *data, int l); void write_binlog (void); void bl_do_set_auth_key_id (int num, unsigned char *buf); -void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port); +void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); void bl_do_set_our_id (int id); void bl_do_new_user (int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); diff --git a/interface.c b/interface.c index 6560f9c..1cf7d34 100644 --- a/interface.c +++ b/interface.c @@ -40,7 +40,6 @@ #include "include.h" #include "queries.h" -#include "interface.h" #include "telegram.h" #include "structures.h" @@ -63,7 +62,7 @@ int safe_quit; int in_readline; int readline_active; -int log_level; +int log_level = 1; long long cur_uploading_bytes; long long cur_uploaded_bytes; @@ -1183,13 +1182,6 @@ void print_end (void) { prompt_was = 0; } -void hexdump (int *in_ptr, int *in_end) { - print_start (); - int *ptr = in_ptr; - while (ptr < in_end) { printf (" %08x", *(ptr ++)); } - printf ("\n"); - print_end (); -} /* void logprintf (const char *format, ...) { diff --git a/loop.c b/loop.c index dae5586..fd29ca3 100644 --- a/loop.c +++ b/loop.c @@ -43,7 +43,6 @@ #include #include -#include "interface.h" #include "net.h" #include "mtproto-client.h" #include "mtproto-common.h" @@ -59,10 +58,9 @@ // -extern char *default_username; + extern char *auth_token; extern int test_dc; -void set_default_username (const char *s); int default_dc_num; extern int binlog_enabled; @@ -74,6 +72,7 @@ extern int queries_num; int unread_messages; void got_it (char *line, int len); +/* void net_loop (int flags, int (*is_end)(void)) { logprintf("starting net_loop()\n"); while (!is_end ()) { @@ -131,6 +130,7 @@ void net_loop (int flags, int (*is_end)(void)) { } } } +*/ char **_s; size_t *_l; @@ -167,13 +167,12 @@ int main_loop (void) { } -struct dc *DC_list[MAX_DC_ID + 1]; -struct dc *DC_working; -int dc_working_num; -int auth_state; +//struct dc *DC_list[MAX_DC_ID + 1]; +//struct dc *DC_working; +//int dc_working_num; +//int auth_state; char *get_auth_key_filename (void); char *get_state_filename (void); -char *get_secret_chat_filename (void); int zero[512]; @@ -195,36 +194,32 @@ void write_dc (int auth_file_fd, struct dc *DC) { int our_id; -void store_config () { - write_auth_file(); -} - -void write_auth_file (void) { +void write_auth_file (struct authorization_state state, const char *filename) { if (binlog_enabled) { return; } - int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); + int auth_file_fd = open (filename /*get_auth_key_filename ()*/, O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); 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); - assert (write (auth_file_fd, &dc_working_num, 4) == 4); - assert (write (auth_file_fd, &auth_state, 4) == 4); + assert (write (auth_file_fd, &state.dc_working_num, 4) == 4); + assert (write (auth_file_fd, &state.auth_state, 4) == 4); int i; for (i = 0; i <= MAX_DC_ID; i++) { - if (DC_list[i]) { + if (state.DC_list[i]) { x = 1; assert (write (auth_file_fd, &x, 4) == 4); - write_dc (auth_file_fd, DC_list[i]); + write_dc (auth_file_fd, state.DC_list[i]); } else { x = 0; assert (write (auth_file_fd, &x, 4) == 4); } } - assert (write (auth_file_fd, &our_id, 4) == 4); + assert (write (auth_file_fd, &state.our_id, 4) == 4); close (auth_file_fd); } -void read_dc (int auth_file_fd, int id, unsigned ver) { +void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) { int port = 0; assert (read (auth_file_fd, &port, 4) == 4); int l = 0; @@ -233,7 +228,7 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { char *ip = talloc (l + 1); assert (read (auth_file_fd, ip, l) == l); ip[l] = 0; - struct dc *DC = alloc_dc (id, ip, port); + struct dc *DC = alloc_dc (DC_list, id, ip, port); assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (read (auth_file_fd, &DC->auth_key, 256) == 256); assert (read (auth_file_fd, &DC->server_salt, 8) == 8); @@ -250,19 +245,24 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { } } -void empty_auth_file (void) { - alloc_dc (1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); - dc_working_num = 1; - auth_state = 0; - write_auth_file (); + +void empty_auth_file (struct authorization_state *state, const char *filename) { + alloc_dc (state->DC_list, 1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); + state->dc_working_num = 1; + state->auth_state = 0; + write_auth_file (*state, filename); } -int need_dc_list_update; -void read_auth_file (void) { - if (binlog_enabled) { return; } - int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); +struct authorization_state read_auth_file (const char *filename) { + struct authorization_state state; + state.dc_working_num = 0; + state.auth_state = 0; + state.our_id = 0; + + if (binlog_enabled) { return state; } + int auth_file_fd = open (filename /*get_auth_key_filename ()*/, O_CREAT | O_RDWR, 0600); if (auth_file_fd < 0) { - empty_auth_file (); + empty_auth_file (&state, filename); } assert (auth_file_fd >= 0); @@ -272,81 +272,91 @@ void read_auth_file (void) { 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; + empty_auth_file (&state, filename); + return state; } assert (read (auth_file_fd, &x, 4) == 4); assert (x <= MAX_DC_ID); - assert (read (auth_file_fd, &dc_working_num, 4) == 4); - assert (read (auth_file_fd, &auth_state, 4) == 4); + assert (read (auth_file_fd, &state.dc_working_num, 4) == 4); + assert (read (auth_file_fd, &state.auth_state, 4) == 4); if (m == DC_SERIALIZED_MAGIC) { - auth_state = 700; + state.auth_state = 700; } int 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, m); + read_dc (auth_file_fd, i, m, state.DC_list); } } - int l = read (auth_file_fd, &our_id, 4); + int l = read (auth_file_fd, &state.our_id, 4); if (l < 4) { assert (!l); } close (auth_file_fd); - DC_working = DC_list[dc_working_num]; + struct dc *DC_working = state.DC_list[state.dc_working_num]; if (m == DC_SERIALIZED_MAGIC) { DC_working->has_auth = 1; } + return state; } int pts, qts, seq, last_date; -void read_state_file (void) { - if (binlog_enabled) { return; } - int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600); +struct protocol_state read_state_file (const char *filename) { + struct protocol_state state; + state.last_date = 0; + state.qts = 0; + state.pts = 0; + state.seq = 0; + + if (binlog_enabled) { return state; } + int state_file_fd = open (filename/*get_state_filename ()*/, O_CREAT | O_RDWR, 0600); if (state_file_fd < 0) { - return; + return state; } int version, magic; - if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; } - if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; } - if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return; } + if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return state; } + if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return state; } + if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return state; } assert (version >= 0); int x[4]; if (read (state_file_fd, x, 16) < 16) { close (state_file_fd); - return; + return state; } - pts = x[0]; - qts = x[1]; - seq = x[2]; - last_date = x[3]; + state.pts = x[0]; + state.qts = x[1]; + state.seq = x[2]; + state.last_date = x[3]; close (state_file_fd); + return state; } -void write_state_file (void) { +void write_state_file (struct protocol_state state, const char* filename) { if (binlog_enabled) { return; } + /* static int wseq; static int wpts; static int wqts; static int wdate; if (wseq >= seq && wpts >= pts && wqts >= qts && wdate >= last_date) { return; } - int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600); + */ + int state_file_fd = open (filename /*get_state_filename ()*/, O_CREAT | O_RDWR, 0600); if (state_file_fd < 0) { return; } int x[6]; x[0] = STATE_FILE_MAGIC; x[1] = 0; - x[2] = pts; - x[3] = qts; - x[4] = seq; - x[5] = last_date; + x[2] = state.pts; + x[3] = state.qts; + x[4] = state.seq; + x[5] = state.last_date; assert (write (state_file_fd, x, 24) == 24); close (state_file_fd); - wseq = seq; wpts = pts; wqts = qts; wdate = last_date; + //wseq = seq; wpts = pts; wqts = qts; wdate = last_date; } extern peer_t *Peers[]; @@ -357,9 +367,11 @@ extern unsigned char *encr_prime; extern int encr_param_version; extern int dialog_list_got; -void read_secret_chat_file (void) { +// TODO: Refactor +void read_secret_chat_file (const char *file) { + if (binlog_enabled) { return; } - int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); + int fd = open (file, O_CREAT | O_RDWR, 0600); if (fd < 0) { return; } @@ -414,9 +426,10 @@ void read_secret_chat_file (void) { close (fd); } -void write_secret_chat_file (void) { +// TODO: Refactor +void write_secret_chat_file (const char *filename) { if (binlog_enabled) { return; } - int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); + int fd = open (filename, O_CREAT | O_RDWR, 0600); if (fd < 0) { return; } @@ -483,39 +496,31 @@ int readline_active; int new_dc_num; int wait_dialog_list; + /** * Discover the network and authorise with all data centers - */ -void network_connect (void) { +void network_connect (struct telegram *instance) { verbosity = 0; on_start (); - if (binlog_enabled) { - double t = get_double_time (); - logprintf ("replay log start\n"); - replay_log (); - logprintf ("replay log end in %lf seconds\n", get_double_time () - t); - write_binlog (); - #ifdef USE_LUA - lua_binlog_end (); - #endif - } else { - read_auth_file (); - } - logprintf("update prompt()\n"); - update_prompt (); - logprintf("update prompt() done... \n"); + // will return empty default values on empty files + instance->auth = read_auth_file ("/home/dev-jessie/.telegram/auth_file"); + instance->proto = read_state_file ("/home/dev-jessie/.telegram/auth_file"); + + struct dc *DC_list = (struct dc*)instance->auth.DC_list; + struct dc *DC_working = NULL; assert (DC_list[dc_working_num]); if (!DC_working || !DC_working->auth_key_id) { // if (auth_state == 0) { logprintf("No working DC or not start_loopd.\n"); - DC_working = DC_list[dc_working_num]; + DC_working = &DC_list[instance->auth.dc_working_num]; assert (!DC_working->auth_key_id); dc_authorize (DC_working); assert (DC_working->auth_key_id); auth_state = 100; - write_auth_file (); + write_auth_file (instance->auth); logprintf("Authorized DataCentre: auth_key_id: %lld \n", DC_working->auth_key_id); + } else { } if (verbosity) { @@ -528,62 +533,37 @@ void network_connect (void) { if (verbosity) { logprintf ("DC_info: %d new DC got\n", new_dc_num); } - int i; - for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->auth_key_id) { - logprintf("DataCentre %d not start_loopd, authorizing...\n", i); - dc_authorize (DC_list[i]); - assert (DC_list[i]->auth_key_id); - write_auth_file (); - logprintf("DataCentre start_loopd, key id: %lld\n", DC_list[i]->auth_key_id); - } - // read saved connection state - read_state_file (); + //read_state_file (); read_secret_chat_file (); } + */ /** * Return if the given phone is registered */ + /* int network_phone_is_registered() { int res = do_auth_check_phone (default_username); assert(res >= 0); return res; } - +*/ /** - * Return if the current client is registered. + * Return whether the current client is registered. */ -int network_client_is_registered() { - return !(auth_state == 100 || !(DC_working->has_auth)); +int network_client_is_registered(struct telegram *tg) { + return !(tg->auth.auth_state == 100 || !(telegram_get_working_dc(tg)->has_auth)); } -/** - * Request a verification for the given client, by sending - * a code to the current phone number - */ -char* network_request_registration () -{ - return do_send_code (default_username); -} - -/** - * Request a verification for the given client, by sending - * a code to the current phone number - */ -char* network_request_phone_registration () -{ - return do_send_code (default_username); -} - - /** * Verify the phone number by providing the sms_code and the real name * * NOTE: This should be called when the phone number was previously * unknown to the telegram network. */ + /* int network_verify_phone_registration(const char* code, const char *sms_hash, const char *first ,const char *last) { @@ -596,10 +576,12 @@ int network_verify_phone_registration(const char* code, const char *sms_hash, } return 0; } +*/ /** * Verify the current client by providing the given code */ + /* int network_verify_registration(const char *code, const char *sms_hash) { logprintf("Verifying with hash:%s, code:%s\n", code, sms_hash); @@ -611,145 +593,148 @@ int network_verify_registration(const char *code, const char *sms_hash) } return 0; } +*/ /** * Export current authentication state to all known data centers. */ -void network_export_registration() -{ - 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); - bl_do_dc_signed (i); - write_auth_file (); - } - write_auth_file (); - fflush (stdout); - fflush (stderr); -} +//void network_export_registration() +//{ +// 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); +// bl_do_dc_signed (i); +// write_auth_file (); +// } +// write_auth_file (); +// fflush (stdout); +// fflush (stderr); +//} -int start_loop (char* code, char* auth_mode) { - logprintf("Calling start_loop()\n"); - logprintf("auth_state %i\n", auth_state); - if (auth_state == 100 || !(DC_working->has_auth)) { - logprintf("auth_state == 100 || !(DC_working->has_auth)"); - int res = do_auth_check_phone (default_username); - assert (res >= 0); - logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); - if (res > 0 && !register_mode) { - // Register Mode 1 - logprintf ("Register Mode 1\n"); - if (code) { - /* - if (do_send_code_result (code) >= 0) { - logprintf ("Authentication successfull, state = 300\n"); - auth_state = 300; - } - */ - } else { - logprintf("No code given, attempting to register\n"); - // Send Code - logprintf ("auth mode %s\n", auth_mode); - /* - if (strcmp(TELEGRAM_AUTH_MODE_SMS"sms", auth_mode)) { - */ - do_send_code (default_username); - logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); - logprintf("storing current state in auth file...\n"); - write_auth_file (); - logprintf("exitting...\n"); - return 0; - /* - } else { - logprintf ("You typed \"call\", switching to phone system.\n"); - do_phone_call (default_username); - logprintf ("Calling you!"); - } - */ - } - } else { - logprintf ("User is not registered. Do you want to register? [Y/n] "); - logprintf ("ERROR THIS IS NOT POSSIBLE!\n"); - return 1; - // Register Mode 2 - // TODO: Requires first and last name, decide how to handle this. - // - We need some sort of switch between registration modes - // - When this mode is selected First and Last name should be added to the form - // Currently Requires Manuel Entry in Terminal. - size_t size; - char *first_name; - logprintf ("First name: "); - if (net_getline (&first_name, &size) == -1) { - perror ("getline()"); - exit (EXIT_FAILURE); - } - char *last_name; - logprintf ("Last 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]; - - if (*code) { - if (do_send_code_result_auth (code, "-", first_name, last_name) >= 0) { - auth_state = 300; - } - } else { - if (strcmp(TELEGRAM_AUTH_MODE_SMS, auth_mode)) { - do_send_code (default_username); - logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); - } else { - logprintf ("You typed \"call\", switching to phone system.\n"); - do_phone_call (default_username); - logprintf ("Calling you! Code: "); - } - } - } - } - logprintf("Authentication done\n"); - - 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); - bl_do_dc_signed (i); - write_auth_file (); - } - write_auth_file (); - - fflush (stdout); - fflush (stderr); - - // read saved connection state - read_state_file (); - read_secret_chat_file (); - - // callbacks for interface functions - set_interface_callbacks (); - - do_get_difference (); - net_loop (0, dgot); - #ifdef USE_LUA - lua_diff_end (); - #endif - send_all_unsent (); - - do_get_dialog_list (); - if (wait_dialog_list) { - dialog_list_got = 0; - net_loop (0, dlgot); - } - - return 0; //main_loop (); -} +//int start_loop (char* code, char* auth_mode) { +// logprintf("Calling start_loop()\n"); +// logprintf("auth_state %i\n", auth_state); +// if (auth_state == 100 || !(DC_working->has_auth)) { +// logprintf("auth_state == 100 || !(DC_working->has_auth)"); +// int res = do_auth_check_phone (default_username); +// assert (res >= 0); +// logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); +// if (res > 0 && !register_mode) { +// // Register Mode 1 +// logprintf ("Register Mode 1\n"); +// if (code) { +// /* +// if (do_send_code_result (code) >= 0) { +// logprintf ("Authentication successfull, state = 300\n"); +// auth_state = 300; +// } +// */ +// } else { +// logprintf("No code given, attempting to register\n"); +// // Send Code +// logprintf ("auth mode %s\n", auth_mode); +// /* +// if (strcmp(TELEGRAM_AUTH_MODE_SMS"sms", auth_mode)) { +// */ +// do_send_code (default_username); +// logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); +// logprintf("storing current state in auth file...\n"); +// write_auth_file (); +// logprintf("exitting...\n"); +// return 0; +// /* +// } else { +// logprintf ("You typed \"call\", switching to phone system.\n"); +// do_phone_call (default_username); +// logprintf ("Calling you!"); +// } +// */ +// } +// } else { +// logprintf ("User is not registered. Do you want to register? [Y/n] "); +// logprintf ("ERROR THIS IS NOT POSSIBLE!\n"); +// return 1; +// // Register Mode 2 +// // TODO: Requires first and last name, decide how to handle this. +// // - We need some sort of switch between registration modes +// // - When this mode is selected First and Last name should be added to the form +// // Currently Requires Manuel Entry in Terminal. +// size_t size; +// char *first_name; +// logprintf ("First name: "); +// if (net_getline (&first_name, &size) == -1) { +// perror ("getline()"); +// exit (EXIT_FAILURE); +// } +// char *last_name; +// logprintf ("Last 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]; +// +// if (*code) { +// if (do_send_code_result_auth (code, "-", first_name, last_name) >= 0) { +// auth_state = 300; +// } +// } else { +// if (strcmp(TELEGRAM_AUTH_MODE_SMS, auth_mode)) { +// do_send_code (default_username); +// logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); +// } else { +// logprintf ("You typed \"call\", switching to phone system.\n"); +// do_phone_call (default_username); +// logprintf ("Calling you! Code: "); +// } +// } +// } +// } +// logprintf("Authentication done\n"); +// +// 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); +// bl_do_dc_signed (i); +// write_auth_file (); +// } +// write_auth_file (); +// +// fflush (stdout); +// fflush (stderr); +// +// // read saved connection state +// read_state_file (); +// read_secret_chat_file (); +// +// // callbacks for interface functions +// set_interface_callbacks (); +// +// do_get_difference (); +// net_loop (0, dgot); +// #ifdef USE_LUA +// lua_diff_end (); +// #endif +// send_all_unsent (); +// +// do_get_dialog_list (); +// if (wait_dialog_list) { +// dialog_list_got = 0; +// net_loop (0, dlgot); +// } +// +// return 0; //main_loop (); +//} +/* int loop (void) { network_connect(); return start_loop(NULL, NULL); } +*/ diff --git a/loop.h b/loop.h index d09ef02..467b454 100644 --- a/loop.h +++ b/loop.h @@ -16,11 +16,36 @@ Copyright Vitaly Valtman 2013 */ + +#pragma once + +#include "net.h" + #ifndef __LOOP_H__ #define __LOOP_H__ int loop(); void net_loop (int flags, int (*end)(void)); -void write_auth_file (void); -void write_state_file (void); -void write_secret_chat_file (void); +void write_secret_chat_file (const char *filename); #endif + +struct protocol_state { + int pts; + int qts; + int seq; + int last_date; +}; + +struct authorization_state { + int dc_working_num; + int auth_state; + struct dc *DC_list[11]; + int our_id; +}; + +void write_auth_file (struct authorization_state state, const char *filename); +struct authorization_state read_auth_file (const char *filename); + +void write_state_file (struct protocol_state state, const char *filename); +struct protocol_state read_state_file (const char *filename); + +void on_start(); diff --git a/lua-tg.c b/lua-tg.c index 1d7b6e9..6ff996b 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -3,6 +3,7 @@ #endif #ifdef USE_LUA +/* #include "lua-tg.h" #include "include.h" @@ -16,7 +17,6 @@ lua_State *luaState; #include "structures.h" -#include "interface.h" #include "constants.h" #include "tools.h" #include "queries.h" @@ -545,5 +545,6 @@ void lua_init (const char *file) { exit (1); } } +*/ #endif diff --git a/lua-tg.h b/lua-tg.h index 35f3b09..6ea8faa 100644 --- a/lua-tg.h +++ b/lua-tg.h @@ -4,6 +4,7 @@ #include #include "structures.h" +/* void lua_init (const char *file); void lua_new_msg (struct message *M); void lua_our_id (int id); @@ -13,4 +14,5 @@ void lua_chat_update (struct chat *C); void lua_binlog_end (void); void lua_diff_end (void); void lua_do_all (void); +*/ #endif diff --git a/main.c b/main.c index 10b0018..ff68e14 100644 --- a/main.c +++ b/main.c @@ -50,7 +50,6 @@ #include "telegram.h" #include "loop.h" #include "mtproto-client.h" -#include "interface.h" #include "tools.h" #ifdef USE_LUA @@ -92,6 +91,7 @@ char *config_directory; char *binlog_file_name; int binlog_enabled; extern int log_level; +int log_level = 1; int sync_from_start; int allow_weak_random; diff --git a/msglog.c b/msglog.c index 0799b79..cbbbcc2 100644 --- a/msglog.c +++ b/msglog.c @@ -50,6 +50,12 @@ void logprintf(const char *format, ...) va_end (ap); } +void hexdump (int *in_ptr, int *in_end) { + int *ptr = in_ptr; + while (ptr < in_end) { printf (" %08x", *(ptr ++)); } + printf ("\n"); +} + /* TODO: implement different log levels diff --git a/msglog.h b/msglog.h index e574ba2..9d52637 100644 --- a/msglog.h +++ b/msglog.h @@ -11,6 +11,8 @@ void set_log_cb(void (*cb)(const char*, va_list ap)); */ void logprintf(const char *format, ...); +void hexdump (int *in_ptr, int *in_end); + /* void log_debug(const char* format, ...); void log_warning(const char* format, ...); diff --git a/mtproto-client.c b/mtproto-client.c index 827a50c..bda8bf7 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -50,7 +50,6 @@ #include "include.h" #include "queries.h" #include "loop.h" -#include "interface.h" #include "structures.h" #include "binlog.h" @@ -69,6 +68,7 @@ #define MAX_NET_RES (1L << 16) extern int log_level; +int log_level = 1; int verbosity; int auth_success; @@ -78,12 +78,14 @@ char new_nonce[256]; char server_nonce[256]; extern int binlog_enabled; extern int disable_auto_accept; +int disable_auto_accept = 0; extern int allow_weak_random; +int allow_weak_random = 0; int total_packets_sent; long long total_data_sent; - +/* int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); int rpc_close (struct connection *c); @@ -93,6 +95,7 @@ struct connection_methods auth_methods = { .ready = rpc_becomes_ready, .close = rpc_close }; +*/ long long precise_time; @@ -218,7 +221,7 @@ int rpc_send_packet (struct connection *c) { } write_out (c, &unenc_msg_header, 20); write_out (c, packet_buffer, len); - flush_out (c); + //flush_out (c); total_packets_sent ++; total_data_sent += total_len; @@ -674,7 +677,6 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { } auth_success ++; GET_DC(c)->flags |= 1; - write_auth_file (); return 1; } @@ -778,7 +780,7 @@ int auth_work_start (struct connection *c UU) { return 1; } -void rpc_execute_answer (struct connection *c, long long msg_id UU); +void rpc_execute_answer (struct telegram *instance, long long msg_id UU); int unread_messages; int our_id; @@ -905,19 +907,19 @@ void work_update_binlog (void) { } } -void work_update (struct connection *c UU, long long msg_id UU) { +void work_update (struct connection *c UU, long long msg_id UU, struct telegram *instance) { unsigned op = fetch_int (); logprintf("work_update(): OP:%d\n", op); switch (op) { case CODE_update_new_message: { - struct message *M = fetch_alloc_message (); + struct message *M = fetch_alloc_message (instance); assert (M); fetch_pts (); unread_messages ++; event_update_new_message(M); - //print_message (M); - update_prompt (); + ////print_message (M); + //update_prompt (); break; }; case CODE_update_message_i_d: @@ -944,12 +946,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { } fetch_pts (); if (log_level >= 1) { - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" %d messages marked as read\n", n); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } } break; @@ -958,14 +960,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_id_t id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (id); if (log_level >= 2) { - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" User "); - print_user_name (id, U); + //print_user_name (id, U); printf (" is typing....\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } } break; @@ -976,16 +978,16 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_t *C = user_chat_get (chat_id); peer_t *U = user_chat_get (id); if (log_level >= 2) { - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" User "); - print_user_name (id, U); + //print_user_name (id, U); printf (" is typing in chat "); - print_chat_name (chat_id, C); + //print_chat_name (chat_id, C); printf ("....\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } } break; @@ -996,15 +998,15 @@ void work_update (struct connection *c UU, long long msg_id UU) { if (U) { fetch_user_status (&U->user.status); if (log_level >= 3) { - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" User "); - print_user_name (user_id, U); + //print_user_name (user_id, U); printf (" is now "); printf ("%s\n", (U->user.status.online > 0) ? "online" : "offline"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } } else { struct user_status t; @@ -1023,16 +1025,16 @@ void work_update (struct connection *c UU, long long msg_id UU) { char *l = fetch_str (l2); struct user *U = &UC->user; bl_do_set_user_real_name (U, f, l1, l, l2); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" User "); - print_user_name (user_id, UC); + //print_user_name (user_id, UC); printf (" changed name to "); - print_user_name (user_id, UC); + //print_user_name (user_id, UC); printf ("\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } else { fetch_skip_str (); fetch_skip_str (); @@ -1064,14 +1066,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { } bl_do_set_user_profile_photo (U, photo_id, &big, &small); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" User "); - print_user_name (user_id, UC); + //print_user_name (user_id, UC); printf (" updated profile photo\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } else { struct file_location t; unsigned y = fetch_int (); @@ -1090,12 +1092,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { { assert (fetch_int () == CODE_vector); int n = fetch_int (); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" Restored %d messages\n", n); - pop_color (); - print_end (); + //pop_color (); + //print_end (); fetch_skip (n); fetch_pts (); } @@ -1104,12 +1106,12 @@ void work_update (struct connection *c UU, long long msg_id UU) { { assert (fetch_int () == CODE_vector); int n = fetch_int (); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" Deleted %d messages\n", n); - pop_color (); - print_end (); + //pop_color (); + //print_end (); fetch_skip (n); fetch_pts (); } @@ -1146,18 +1148,18 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_int (); // version } } - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" Chat "); - print_chat_name (chat_id, C); + //print_chat_name (chat_id, C); if (x == CODE_chat_participants) { printf (" changed list: now %d members\n", n); } else { printf (" changed list, but we are forbidden to know about it (Why this update even was sent to us?\n"); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); } break; case CODE_update_contact_registered: @@ -1165,28 +1167,28 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_id_t user_id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (user_id); fetch_int (); // date - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" User "); - print_user_name (user_id, U); + //print_user_name (user_id, U); printf (" registered\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } break; case CODE_update_contact_link: { peer_id_t user_id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (user_id); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" Updated link with user "); - print_user_name (user_id, U); + //print_user_name (user_id, U); printf ("\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); unsigned t = fetch_int (); assert (t == CODE_contacts_my_link_empty || t == CODE_contacts_my_link_requested || t == CODE_contacts_my_link_contact); if (t == CODE_contacts_my_link_requested) { @@ -1203,14 +1205,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { { peer_id_t user_id = MK_USER (fetch_int ()); peer_t *U = user_chat_get (user_id); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" User "); - print_user_name (user_id, U); + //print_user_name (user_id, U); printf (" activated\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } break; case CODE_update_new_authorization: @@ -1219,31 +1221,31 @@ void work_update (struct connection *c UU, long long msg_id UU) { fetch_int (); // date char *s = fetch_str_dup (); char *location = fetch_str_dup (); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" New autorization: device='%s' location='%s'\n", s, location); - pop_color (); - print_end (); + //pop_color (); + //print_end (); tfree_str (s); tfree_str (location); } break; case CODE_update_new_geo_chat_message: { - struct message *M = fetch_alloc_geo_message (); + struct message *M = fetch_alloc_geo_message (instance); unread_messages ++; - print_message (M); - update_prompt (); + //print_message (M); + //update_prompt (); } break; case CODE_update_new_encrypted_message: { - struct message *M = fetch_alloc_encrypted_message (); + struct message *M = fetch_alloc_encrypted_message (instance); unread_messages ++; - print_message (M); - update_prompt (); + //print_message (M); + //update_prompt (); fetch_qts (); } break; @@ -1253,37 +1255,37 @@ void work_update (struct connection *c UU, long long msg_id UU) { if (verbosity >= 2) { logprintf ("Secret chat state = %d\n", E->state); } - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); switch (E->state) { case sc_none: break; case sc_waiting: printf (" Encrypted chat "); - print_encr_chat_name (E->id, (void *)E); + //print_encr_chat_name (E->id, (void *)E); printf (" is now in wait state\n"); break; case sc_request: printf (" Encrypted chat "); - print_encr_chat_name (E->id, (void *)E); + //print_encr_chat_name (E->id, (void *)E); printf (" is now in request state. Sending request ok\n"); break; case sc_ok: printf (" Encrypted chat "); - print_encr_chat_name (E->id, (void *)E); + //print_encr_chat_name (E->id, (void *)E); printf (" is now in ok state\n"); break; case sc_deleted: printf (" Encrypted chat "); - print_encr_chat_name (E->id, (void *)E); + //print_encr_chat_name (E->id, (void *)E); printf (" is now in deleted state\n"); break; } - pop_color (); - print_end (); + //pop_color (); + //print_end (); if (E->state == sc_request && !disable_auto_accept) { - do_accept_encr_chat_request (E); + do_accept_encr_chat_request (instance, E); } fetch_int (); // date } @@ -1292,21 +1294,21 @@ void work_update (struct connection *c UU, long long msg_id UU) { { peer_id_t id = MK_ENCR_CHAT (fetch_int ()); peer_t *P = user_chat_get (id); - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); if (P) { printf (" User "); peer_id_t user_id = MK_USER (P->encr_chat.user_id); - print_user_name (user_id, user_chat_get (user_id)); + //print_user_name (user_id, user_chat_get (user_id)); printf (" typing in secret chat "); - print_encr_chat_name (id, P); + //print_encr_chat_name (id, P); printf ("\n"); } else { printf (" Some user is typing in unknown secret chat\n"); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); } break; case CODE_update_encrypted_messages_read: @@ -1328,14 +1330,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { } } if (log_level >= 1) { - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" Encrypted chat "); - print_encr_chat_name_full (id, user_chat_get (id)); + //print_encr_chat_name_full (id, user_chat_get (id)); printf (": %d messages marked read \n", x); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } } break; @@ -1351,18 +1353,18 @@ void work_update (struct connection *c UU, long long msg_id UU) { 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); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" Chat "); - print_chat_name (chat_id, user_chat_get (chat_id)); + //print_chat_name (chat_id, user_chat_get (chat_id)); printf (": user "); - print_user_name (user_id, user_chat_get (user_id)); + //print_user_name (user_id, user_chat_get (user_id)); printf (" added by user "); - print_user_name (inviter_id, user_chat_get (inviter_id)); + //print_user_name (inviter_id, user_chat_get (inviter_id)); printf ("\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } break; case CODE_update_chat_participant_delete: @@ -1376,16 +1378,16 @@ void work_update (struct connection *c UU, long long msg_id UU) { bl_do_chat_del_user (&C->chat, version, get_peer_id (user_id)); } - print_start (); - push_color (COLOR_YELLOW); - print_date (time (0)); + //print_start (); + //push_color (COLOR_YELLOW); + //print_date (time (0)); printf (" Chat "); - print_chat_name (chat_id, user_chat_get (chat_id)); + //print_chat_name (chat_id, user_chat_get (chat_id)); printf (": user "); - print_user_name (user_id, user_chat_get (user_id)); + //print_user_name (user_id, user_chat_get (user_id)); printf (" deleted\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } break; case CODE_update_dc_options: @@ -1395,7 +1397,7 @@ void work_update (struct connection *c UU, long long msg_id UU) { assert (n >= 0); int i; for (i = 0; i < n; i++) { - fetch_dc_option (); + fetch_dc_option (instance); } } break; @@ -1405,19 +1407,21 @@ void work_update (struct connection *c UU, long long msg_id UU) { } } -void work_update_short (struct connection *c, long long msg_id) { +void work_update_short (struct telegram *instance, long long msg_id) { + struct connection *c = telegram_get_connection(instance); assert (fetch_int () == CODE_update_short); - work_update (c, msg_id); + work_update (c, msg_id, instance); fetch_date (); } -void work_updates (struct connection *c, long long msg_id) { +void work_updates (struct telegram *instance, long long msg_id) { + struct connection *c = telegram_get_connection(instance); assert (fetch_int () == CODE_updates); assert (fetch_int () == CODE_vector); int n = fetch_int (); int i; for (i = 0; i < n; i++) { - work_update (c, msg_id); + work_update (c, msg_id, instance); } assert (fetch_int () == CODE_vector); n = fetch_int (); @@ -1433,29 +1437,30 @@ void work_updates (struct connection *c, long long msg_id) { bl_do_set_seq (fetch_int ()); } -void work_update_short_message (struct connection *c UU, long long msg_id UU) { +void work_update_short_message (struct connection *c UU, long long msg_id UU, struct telegram *instance) { assert (fetch_int () == (int)CODE_update_short_message); - struct message *M = fetch_alloc_message_short (); + struct message *M = fetch_alloc_message_short (instance); unread_messages ++; - print_message (M); - update_prompt (); + //print_message (M); + //update_prompt (); if (M->date > last_date) { last_date = M->date; } } -void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) { +void work_update_short_chat_message (struct connection *c UU, long long msg_id UU, struct telegram *instance) { assert (fetch_int () == CODE_update_short_chat_message); - struct message *M = fetch_alloc_message_short_chat (); + struct message *M = fetch_alloc_message_short_chat (instance); unread_messages ++; - print_message (M); - update_prompt (); + //print_message (M); + //update_prompt (); if (M->date > last_date) { last_date = M->date; } } -void work_container (struct connection *c, long long msg_id UU) { +void work_container (struct telegram *instance, long long msg_id UU) { + struct connection *c = telegram_get_connection(instance); if (verbosity) { logprintf ( "work_container: msg_id = %lld\n", msg_id); } @@ -1472,7 +1477,7 @@ void work_container (struct connection *c, long long msg_id UU) { int bytes = fetch_int (); int *t = in_end; in_end = in_ptr + (bytes / 4); - rpc_execute_answer (c, id); + rpc_execute_answer (instance, id); assert (in_ptr == in_end); in_end = t; } @@ -1487,7 +1492,6 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { //DC->session_id = fetch_long (); fetch_long (); // unique_id GET_DC(c)->server_salt = fetch_long (); - } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { @@ -1522,7 +1526,7 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { } #define MAX_PACKED_SIZE (1 << 24) -void work_packed (struct connection *c, long long msg_id) { +void work_packed (struct telegram *instance, long long msg_id) { assert (fetch_int () == CODE_gzip_packed); static int in_gzip; static int buf[MAX_PACKED_SIZE >> 2]; @@ -1542,7 +1546,7 @@ void work_packed (struct connection *c, long long msg_id) { logprintf ( "Unzipped data: "); hexdump_in (); } - rpc_execute_answer (c, msg_id); + rpc_execute_answer (instance, msg_id); in_ptr = end; in_end = eend; in_gzip = 0; @@ -1579,10 +1583,10 @@ void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { fetch_int (); // status } -void work_updates_to_long (struct connection *c UU, long long msg_id UU) { +void work_updates_to_long (struct telegram *instance, struct connection *c UU, long long msg_id UU) { assert (fetch_int () == (int)CODE_updates_too_long); logprintf ("updates to long... Getting difference\n"); - do_get_difference (); + do_get_difference (instance); } void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { @@ -1593,7 +1597,8 @@ void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { logprintf ("bad_msg_notification: msg_id = %lld, seq = %d, error = %d\n", m1, s, e); } -void rpc_execute_answer (struct connection *c, long long msg_id UU) { +void rpc_execute_answer (struct telegram *instance, long long msg_id UU) { + struct connection *c = telegram_get_connection(instance); if (verbosity >= 5) { logprintf ("rpc_execute_answer: fd=%d\n", c->fd); hexdump_in (); @@ -1601,7 +1606,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { int op = prefetch_int (); switch (op) { case CODE_msg_container: - work_container (c, msg_id); + work_container (instance, msg_id); return; case CODE_new_session_created: work_new_session_created (c, msg_id); @@ -1613,19 +1618,19 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { work_rpc_result (c, msg_id); return; case CODE_update_short: - work_update_short (c, msg_id); + work_update_short (instance, msg_id); return; case CODE_updates: - work_updates (c, msg_id); + work_updates (instance, msg_id); return; case CODE_update_short_message: - work_update_short_message (c, msg_id); + work_update_short_message (c, msg_id, instance); return; case CODE_update_short_chat_message: - work_update_short_chat_message (c, msg_id); + work_update_short_chat_message (c, msg_id, instance); return; case CODE_gzip_packed: - work_packed (c, msg_id); + work_packed (instance, msg_id); return; case CODE_bad_server_salt: work_bad_server_salt (c, msg_id); @@ -1640,7 +1645,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { work_new_detailed_info (c, msg_id); return; case CODE_updates_too_long: - work_updates_to_long (c, msg_id); + work_updates_to_long (instance, c, msg_id); return; case CODE_bad_msg_notification: work_bad_msg_notification (c, msg_id); @@ -1651,7 +1656,9 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { in_ptr = in_end; // Will not fail due to assertion in_ptr == in_end } -int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { +int process_rpc_message (struct telegram *instance, struct encrypted_message *enc, int len) { + struct connection *c UU = telegram_get_connection(instance); + const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); if (verbosity) { @@ -1672,7 +1679,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, //assert (enc->server_salt == server_salt); //in fact server salt can change if (DC->server_salt != enc->server_salt) { DC->server_salt = enc->server_salt; - write_auth_file (); + //write_auth_file (); } int this_server_time = enc->msg_id >> 32LL; @@ -1710,81 +1717,121 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, insert_msg_id (c->session, enc->msg_id); } assert (c->session->session_id == enc->session_id); - rpc_execute_answer (c, enc->msg_id); + rpc_execute_answer (instance, enc->msg_id); assert (in_ptr == in_end); return 0; } -int rpc_execute (struct connection *c, int op, int len) { - if (verbosity) { - logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); - } - /* - if (op < 0) { - assert (read_in (c, Response, Response_len) == Response_len); - return 0; - } - */ +//int rpc_execute (struct connection *c, int op, int len) { +// if (verbosity) { +// logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); +// } +// if (op < 0) { +// assert (read_in (c, Response, Response_len) == Response_len); +// return 0; +// } +// +// if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { +// logprintf ( "answer too long (%d bytes), skipping\n", len); +// return 0; +// } +// +// int Response_len = len; +// +// if (verbosity >= 2) { +// logprintf ("Response_len = %d\n", Response_len); +// } +// assert (read_in (c, Response, Response_len) == Response_len); +// Response[Response_len] = 0; +// if (verbosity >= 2) { +// logprintf ( "have %d Response bytes\n", Response_len); +// } +// +// int o = c_state; +// if (GET_DC(c)->flags & 1) { o = st_authorized;} +// switch (o) { +// case st_reqpq_sent: +// process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); +// return 0; +// case st_reqdh_sent: +// process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); +// return 0; +// case st_client_dh_sent: +// process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); +// return 0; +// case st_authorized: +// if (op < 0 && op >= -999) { +// logprintf ("Server error %d\n", op); +// } else { +// process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); +// } +// return 0; +// default: +// logprintf ( "fatal: cannot receive answer in state %d\n", c_state); +// exit (2); +// } +// +// return 0; +//} +int rpc_execute_req_pq (struct telegram *instance, int len) { + struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); return 0; } - int Response_len = len; - - if (verbosity >= 2) { - logprintf ("Response_len = %d\n", Response_len); - } assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; - if (verbosity >= 2) { - logprintf ( "have %d Response bytes\n", Response_len); - } - -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) - setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); -#endif - int o = c_state; - if (GET_DC(c)->flags & 1) { o = st_authorized;} - switch (o) { - case st_reqpq_sent: - process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) - setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); -#endif - return 0; - case st_reqdh_sent: - process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) - setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); -#endif - return 0; - case st_client_dh_sent: - process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) - setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); -#endif - return 0; - case st_authorized: - if (op < 0 && op >= -999) { - logprintf ("Server error %d\n", op); - } else { - process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); - } -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) - setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); -#endif - return 0; - default: - logprintf ( "fatal: cannot receive answer in state %d\n", c_state); - exit (2); - } - + process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); return 0; } +int rpc_execute_rq_dh (struct telegram *instance, int len) { + struct connection *c = telegram_get_connection(instance); + if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { + logprintf ( "answer too long (%d bytes), skipping\n", len); + return 0; + } + int Response_len = len; + assert (read_in (c, Response, Response_len) == Response_len); + Response[Response_len] = 0; + process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); + return 0; +} + +int rpc_execute_cdh_sent (struct telegram *instance, int len) { + struct connection *c = telegram_get_connection(instance); + if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { + logprintf ( "answer too long (%d bytes), skipping\n", len); + return 0; + } + int Response_len = len; + assert (read_in (c, Response, Response_len) == Response_len); + Response[Response_len] = 0; + process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); + return 0; +} + +int rpc_execute_authorized (struct telegram *instance, int op, int len) { + struct connection *c = telegram_get_connection(instance); + if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { + logprintf ( "answer too long (%d bytes), skipping\n", len); + return 0; + } + int Response_len = len; + assert (read_in (c, Response, Response_len) == Response_len); + Response[Response_len] = 0; + if (op < 0 && op >= -999) { + logprintf ("Server error %d\n", op); + } else { + process_rpc_message (instance, (void *)(Response/* + 8*/), Response_len/* - 12*/); + } + return 0; +} + + int tc_close (struct connection *c, int who) { if (verbosity) { @@ -1799,11 +1846,7 @@ int tc_becomes_ready (struct connection *c) { } char byte = 0xef; assert (write_out (c, &byte, 1) == 1); - flush_out (c); -#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) - setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); -#endif int o = c_state; if (GET_DC(c)->flags & 1) { o = st_authorized; } switch (o) { @@ -1860,9 +1903,6 @@ int auth_ok (void) { void dc_authorize (struct dc *DC) { c_state = 0; auth_success = 0; - if (!DC->sessions[0]) { - dc_create_session (DC); - } if (verbosity) { logprintf ( "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); } diff --git a/mtproto-client.h b/mtproto-client.h index 0782b7b..49f8891 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -30,4 +30,13 @@ int check_g (unsigned char p[256], BIGNUM *g); int check_g_bn (BIGNUM *p, BIGNUM *g); int check_DH_params (BIGNUM *p, int g); void secure_random (void *s, int l); + + +int send_req_pq_packet (struct telegram *instance); + +int rpc_execute_req_pq (struct telegram *instance, int len); +int rpc_execute_rq_dh (struct telegram *instance, int len); +int rpc_execute_cdh_sent (struct telegram *instance, int len); +int rpc_execute_authorized (struct telegram *instance, int op, int len); + #endif diff --git a/mtproto-common.c b/mtproto-common.c index 65c95eb..28027c4 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -39,7 +39,6 @@ #include #include "mtproto-common.h" -#include "interface.h" #include "include.h" #ifdef __MACH__ diff --git a/mtproto-common.h b/mtproto-common.h index 619be74..0dbf71d 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -26,9 +26,10 @@ #include #include -#include "interface.h" #include "tools.h" #include "constants.h" +#include "msglog.h" + /* DH key exchange protocol data structures */ #define CODE_req_pq 0x60469778 #define CODE_resPQ 0x05162463 diff --git a/net.c b/net.c index fe88e11..0570d65 100644 --- a/net.c +++ b/net.c @@ -1,12 +1,12 @@ /* This file is part of telegram-client. - Telegram-client is free software: you can redistribute it and/or modify + struct telegram-client is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - Telegram-client is distributed in the hope that it will be useful, + struct telegram-client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -43,7 +43,7 @@ #include "mtproto-client.h" #include "mtproto-common.h" #include "tree.h" -#include "interface.h" +#include "telegram.h" #ifndef POLLRDHUP #define POLLRDHUP 0 @@ -55,7 +55,8 @@ double get_utime (int clock_id); int verbosity; extern struct connection_methods auth_methods; -extern FILE *log_net_f; +extern FILE *log_net_f ; +FILE *log_net_f = NULL; void fail_connection (struct connection *c); @@ -75,27 +76,6 @@ void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)) { netwrite = cb; } -/* - * Delegate the session creation to an external callback - * - * TODO: use dc_ensure_session instead of dc_create_session to create sessions, - * to make this actually work - */ -void dc_create_session (struct dc *DC); -void dc_ensure_session_local (struct dc *DC, void (*on_session_ready)(void)) { - dc_create_session(DC); - on_session_ready(); -} -void (*dc_ensure_session)(struct dc *DC, void (*on_session_ready)(void)); -void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))) -{ - dc_ensure_session = dc_ens_sess; -} - -/* - * - */ - #define PING_TIMEOUT 10 void start_ping_timer (struct connection *c); @@ -254,8 +234,8 @@ void flush_out (struct connection *c UU) { } #define MAX_CONNECTIONS 100 -struct connection *Connections[MAX_CONNECTIONS]; -int max_connection_fd; +//struct connection *Connections[MAX_CONNECTIONS]; +//int max_connection_fd; void rotate_port (struct connection *c) { switch (c->port) { @@ -271,76 +251,23 @@ void rotate_port (struct connection *c) { } } -struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods) { +struct connection *create_connection (const char *host, int port, int fd) { struct connection *c = talloc0 (sizeof (*c)); - int fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd == -1) { - logprintf ("Can not create socket: %m\n"); - exit (1); - } - assert (fd >= 0 && fd < MAX_CONNECTIONS); - if (fd > max_connection_fd) { - max_connection_fd = fd; - } - int flags = -1; - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); - setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)); - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags)); - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons (port); - addr.sin_addr.s_addr = inet_addr (host); - - - fcntl (fd, F_SETFL, O_NONBLOCK); - - if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { - if (errno != EINPROGRESS) { - logprintf ( "Can not connect to %s:%d %m\n", host, port); - close (fd); - tfree (c, sizeof (*c)); - return 0; - } - } - - struct pollfd s; - s.fd = fd; - s.events = POLLOUT | POLLERR | POLLRDHUP | POLLHUP; - errno = 0; - - while (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { - if (errno == EINTR) { continue; } - if (errno) { - logprintf ("Problems in poll: %m\n"); - exit (1); - } - logprintf ("Connect with %s:%d timeout\n", host, port); - close (fd); - tfree (c, sizeof (*c)); - return 0; - } - - c->session = session; c->fd = fd; c->ip = tstrdup (host); c->flags = 0; c->state = conn_ready; - c->methods = methods; c->port = port; - assert (!Connections[fd]); - Connections[fd] = c; if (verbosity) { logprintf ( "connect to %s:%d successful\n", host, port); } - if (c->methods->ready) { - c->methods->ready (c); - } c->last_receive_time = get_double_time (); - start_ping_timer (c); + // Don't ping TODO: Really? Timeout callback functions of libpurple + //start_ping_timer (c); return c; } +/* void restart_connection (struct connection *c) { if (c->last_connect_time == time (0)) { start_fail_timer (c); @@ -415,9 +342,11 @@ void fail_connection (struct connection *c) { logprintf ("Lost connection to server... %s:%d\n", c->ip, c->port); restart_connection (c); } +*/ extern FILE *log_net_f; -void try_write (struct connection *c) { +void try_write (struct telegram *instance) { + struct connection *c = telegram_get_connection(instance); if (verbosity) { logprintf ( "try write: fd = %d\n", c->fd); } @@ -494,7 +423,9 @@ void hexdump_buf (struct connection_buffer *b) { } -void try_rpc_read (struct connection *c) { +void try_rpc_read (struct telegram *instance) { + struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; + assert (c->in_head); if (verbosity >= 3) { hexdump_buf (c->in_head); @@ -528,11 +459,15 @@ void try_rpc_read (struct connection *c) { len *= 4; int op; assert (read_in_lookup (c, &op, 4) == 4); - c->methods->execute (c, op, len); + // read + //c->methods->execute (c, op, len); + try_rpc_interpret(instance, op, len); } } -void try_read (struct connection *c) { +void try_read (struct telegram *instance) { + struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; + if (verbosity) { logprintf ( "try read: fd = %d\n", c->fd); } @@ -587,10 +522,11 @@ void try_read (struct connection *c) { } c->in_bytes += x; if (x) { - try_rpc_read (c); + try_rpc_read (instance); } } +/* int connections_make_poll_array (struct pollfd *fds, int max) { int _max = max; int i; @@ -615,7 +551,9 @@ int connections_make_poll_array (struct pollfd *fds, int max) { } return _max - max; } +*/ +/* void connections_poll_result (struct pollfd *fds, int max) { if (verbosity >= 10) { logprintf ( "connections_poll_result: max = %d\n", max); @@ -643,6 +581,7 @@ void connections_poll_result (struct pollfd *fds, int max) { } } } +*/ int send_all_acks (struct session *S) { clear_packet (); @@ -672,7 +611,7 @@ void insert_msg_id (struct session *S, long long id) { extern struct dc *DC_list[]; -struct dc *alloc_dc (int id, char *ip, int port UU) { +struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { assert (!DC_list[id]); struct dc *DC = talloc0 (sizeof (*DC)); DC->id = id; @@ -682,16 +621,12 @@ struct dc *alloc_dc (int id, char *ip, int port UU) { return DC; } -void dc_create_session (struct dc *DC) { +void dc_create_session (struct dc *DC, struct connection *c) { logprintf("dc_create_session(...)\n"); struct session *S = talloc0 (sizeof (*S)); assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); S->dc = DC; - S->c = create_connection (DC->ip, DC->port, S, &auth_methods); - if (!S->c) { - logprintf ("Can not create connection to DC. Is network down?\n"); - exit (1); - } + S->c = c; assert (!DC->sessions[0]); DC->sessions[0] = S; } diff --git a/net.h b/net.h index d89029f..10ec628 100644 --- a/net.h +++ b/net.h @@ -1,12 +1,12 @@ /* This file is part of telegram-client. - Telegram-client is free software: you can redistribute it and/or modify + struct telegram-client is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - Telegram-client is distributed in the hope that it will be useful, + struct telegram-client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -19,9 +19,11 @@ #ifndef __NET_H__ #define __NET_H__ +#define MAX_DC_ID 10 #include struct dc; #include "queries.h" +#include "telegram.h" #define TG_SERVER "173.240.5.1" #define TG_SERVER_TEST "173.240.5.253" #define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" @@ -31,7 +33,6 @@ struct dc; #define TG_VERSION "0.01-beta" #define ACK_TIMEOUT 1 -#define MAX_DC_ID 10 enum dc_state { st_init, @@ -40,7 +41,7 @@ enum dc_state { st_client_dh_sent, st_authorized, st_error -} ; +}; struct connection; struct connection_methods { @@ -125,7 +126,6 @@ struct connection { int out_packet_num; int last_connect_time; int in_fail_timer; - struct connection_methods *methods; struct session *session; void *extra; struct event_timer ev; @@ -140,12 +140,19 @@ int read_in (struct connection *c, void *data, int len); void create_all_outbound_connections (void); -struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods); +struct connection *create_connection (const char *host, int port, int fd); int connections_make_poll_array (struct pollfd *fds, int max); void connections_poll_result (struct pollfd *fds, int max); -void dc_create_session (struct dc *DC); void insert_msg_id (struct session *S, long long id); -struct dc *alloc_dc (int id, char *ip, int port); +struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port); + +void dc_create_session (struct dc *DC, struct connection *c); + +void try_read (struct telegram *instance); +void try_rpc_read (struct telegram *instance); + +void try_write (struct telegram *instance); #define GET_DC(c) (c->session->dc) #endif + diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index ea99879..4cf58c9 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -43,7 +43,7 @@ #include "prefs.h" #include "util.h" -// Telegram Includes +// struct telegram Includes #include "telegram.h" #include "msglog.h" #include "mtproto-client.h" @@ -60,15 +60,15 @@ static PurplePlugin *_telegram_protocol = NULL; -// TODO: Use PurpleConnection from PurpleAccount callback PurpleConnection *_gc; -// TODO: Use PurpleAccount from PurpleAccount callback PurpleAccount *_pa; PurpleGroup *tggroup; +void tgprpl_login_on_connected(); + /** - * Redirect the msglog of the telegram-cli application to the libpurple - * logger + * Formats the given format string with the given arguments and writes + * it to the libpurple log */ void tg_cli_log_cb(const char* format, va_list ap) { @@ -116,7 +116,7 @@ static void login_request_verification(PurpleAccount *acct) purple_account_set_string(acct, "verification_hash", new_hash); purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Please Verify", - "You need to verify this device, please enter the code Telegram has sent to you by SMS.", + "You need to verify this device, please enter the code struct telegram has sent to you by SMS.", NULL, NULL, NULL); } @@ -130,7 +130,116 @@ static void login_verification_fail(PurpleAccount *acct) purple_account_set_string(acct, "verification_key", ""); purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", "Please make sure you entered the correct verification code.", NULL, NULL, NULL); - +} + +static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + logprintf("tgprpl_output_cb()\n"); + PurpleConnection *c = data; + telegram_conn *conn = purple_connection_get_protocol_data(c); + telegram_write_output(conn->tg); +} + +static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + logprintf("tgprpl_input_cb()\n"); + PurpleConnection *c = data; + telegram_conn *conn = purple_connection_get_protocol_data(c); + telegram_read_input(conn->tg); +} + +/* +static void tgprpl_on_input(struct telegram *tg) +{ + PurpleConnection *c = data; +} +*/ + +static void tgprpl_on_state_change(struct telegram *instance, int state, void *data) +{ + telegram_conn *conn = instance->extra; + switch (state) { + case STATE_PHONE_NOT_REGISTERED: + // TODO: Request first and last name + // TODO: Fetch PurpleAccount and don't use global + purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); + const char *first_name = purple_account_get_string(conn->pa, "first_name", NULL); + const char *last_name = purple_account_get_string(conn->pa, "last_name", NULL); + const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); + const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); + purple_debug_info(PLUGIN_ID, "code: %s\n", code); + purple_debug_info(PLUGIN_ID, "verification_hash: %s\n", hash); + if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", + "Enter your first and last name to register this phone number with the telegram network.", + NULL, NULL, NULL); + return; + } + network_verify_phone_registration(code, hash, first_name, last_name); + break; + + case STATE_PHONE_CODE_NOT_ENTERED: + purple_connection_set_state(_gc, PURPLE_CONNECTED); + // TODO: Request SMS code + break; + + case STATE_CLIENT_NOT_REGISTERED: + // ask for registration type + break; + + case STATE_CLIENT_CODE_NOT_ENTERED: { + const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); + const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); + network_verify_registration(code, hash); + // enter SMS code + } + break; + + case STATE_READY: + // ready + purple_debug_info(PLUGIN_ID, "Logged in...\n"); + purple_connection_set_state(conn->gc, PURPLE_CONNECTED); + char const *username = purple_account_get_username(conn->pa); + purple_connection_set_display_name(conn->gc, username); + purple_blist_add_account(conn->pa); + + tggroup = purple_find_group("struct telegram"); + if (tggroup == NULL) { + purple_debug_info(PLUGIN_ID, "PurpleGroup = NULL, creating"); + tggroup = purple_group_new("struct telegram"); + purple_blist_add_group(tggroup, NULL); + } + + on_update_new_message(on_new_message); + on_peer_allocated(peer_allocated_handler); + + // get all current contacts + purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); + do_update_contact_list(instance); + + purple_debug_info(PLUGIN_ID, "Fetching all current chats...\n"); + do_get_dialog_list(instance); + + // get new messages + purple_debug_info(PLUGIN_ID, "Fetching new messages...\n"); + do_get_difference(instance); + telegram_flush_queries(instance); + break; + + case STATE_ERROR: { + const char* err = data; + logprintf("Connection errored: %s\n", err); + + } + break; + } +} + +static void init_dc_settings(PurpleAccount *acc, struct dc *DC) +{ + DC->port = purple_account_get_int(acc, "port", TELEGRAM_DEFAULT_PORT); + DC->ip = g_strdup(purple_account_get_string(acc, "server", TELEGRAM_TEST_SERVER)); + DC->id = 0; } /** @@ -140,46 +249,58 @@ static void tgprpl_login(PurpleAccount * acct) { purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); + char const *username = purple_account_get_username(acct); _gc = gc; _pa = acct; - const char *username = purple_account_get_username(acct); - const char *code = purple_account_get_string(acct, "verification_key", NULL); - const char *hash = purple_account_get_string(acct, "verification_hash", NULL); - const char *hostname = purple_account_get_string(acct, "server", TELEGRAM_TEST_SERVER); - // const char *verificationType = purple_account_get_string(acct, "verification_type", TELEGRAM_AUTH_MODE_SMS); - // int port = purple_account_get_int(acct, "port", TELEGRAM_DEFAULT_PORT); + struct dc DC; + init_dc_settings(acct, &DC); + // TODO: fetch current home directory + // use this as root + struct telegram *tg = telegram_new(&DC, username, "/home/dev-jessie/.telegram"); + telegram_add_state_change_listener(tg, tgprpl_on_state_change); + telegram_restore_session(tg); + telegram_conn *conn = g_new0(telegram_conn, 1); + conn->tg = tg; + conn->gc = gc; + conn->pa = acct; + purple_connection_set_protocol_data(gc, conn); + tg->extra = conn; + + purple_connection_set_state(gc, PURPLE_CONNECTING); + purple_proxy_connect(gc, acct, DC.ip, DC.port, tgprpl_login_on_connected, tg); purple_debug_info(PLUGIN_ID, "username: %s\n", username); - purple_debug_info(PLUGIN_ID, "code: %s\n", code); - purple_debug_info(PLUGIN_ID, "verification_hash: %s\n", hash); - purple_debug_info(PLUGIN_ID, "hostname: %s\n", hostname); + purple_debug_info(PLUGIN_ID, "hostname: %s\n", DC.ip); +} - // ensure config-file exists an - purple_debug_info(PLUGIN_ID, "running_for_first_time()\n"); - running_for_first_time(); +void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); + struct telegram *tg = (struct telegram*) data; + //running_for_first_time(); - // load all settings: the known network topology, secret keys, logs and configuration file paths - purple_debug_info(PLUGIN_ID, "parse_config()\n"); - parse_config (); - purple_debug_info(PLUGIN_ID, "set_default_username()\n"); - set_default_username (username); + if (fd == -1) { + logprintf("purple_proxy_connect failed: %s\n", error_message); + telegram_free(tg); + return; + } + + purple_debug_info(PLUGIN_ID, "Connecting to the struct telegram network...\n"); + purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, telegram_get_connection(tg)); + purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, telegram_get_connection(tg)); + telegram_network_connect(tg, fd); + + // // load all settings: the known network topology, secret keys, logs and configuration file paths + // purple_debug_info(PLUGIN_ID, "parse_config()\n"); + // parse_config (); + // purple_debug_info(PLUGIN_ID, "set_default_username()\n"); + //set_default_username (username); // Connect to the network - purple_debug_info(PLUGIN_ID, "Connecting to the Telegram network...\n"); - network_connect(); - // Assure phone number registration + /* if (!network_phone_is_registered()) { - purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); - const char *first_name = purple_account_get_string(acct, "first_name", NULL); - const char *last_name = purple_account_get_string(acct, "last_name", NULL); - if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", - "Enter your first and last name to register this phone number with the telegram network.", - NULL, NULL, NULL); - return; - } if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { int registered = network_verify_phone_registration(code, hash, first_name, last_name); if (registered) { @@ -193,8 +314,10 @@ static void tgprpl_login(PurpleAccount * acct) return; } } + */ // Assure client registration + /* if (!network_client_is_registered()) { purple_debug_info(PLUGIN_ID, "Client is not registered\n"); @@ -203,7 +326,6 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "strlen - code: %lu hash: %lu\n", strlen(code), strlen(hash)); purple_debug_info(PLUGIN_ID, "pointer - code: %p hash: %p\n", code, hash); purple_debug_info(PLUGIN_ID, "string - code: %s hash: %s\n", code, hash); - int verified = network_verify_registration(code, hash); if (verified) { store_config(); } else { @@ -215,41 +337,7 @@ static void tgprpl_login(PurpleAccount * acct) return; } } - purple_debug_info(PLUGIN_ID, "Logged in...\n"); - purple_connection_set_display_name(gc, username); - purple_connection_set_state(gc, PURPLE_CONNECTED); - purple_blist_add_account(acct); - - tggroup = purple_find_group("Telegram"); - if (tggroup == NULL) { - purple_debug_info(PLUGIN_ID, "PurpleGroup = NULL, creating"); - tggroup = purple_group_new("Telegram"); - purple_blist_add_group(tggroup, NULL); - } - - on_update_new_message(on_new_message); - on_peer_allocated(peer_allocated_handler); - - // get all current contacts - purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); - do_update_contact_list(); - - purple_debug_info(PLUGIN_ID, "Fetching all current chats...\n"); - do_get_dialog_list(); - - // get new messages - purple_debug_info(PLUGIN_ID, "Fetching new messages...\n"); - do_get_difference(); - flush_queries(); - - // Our protocol data, that will be delivered to us - // through purple connection - telegram_conn *conn = g_new0(telegram_conn, 1); - conn->gc = gc; - conn->account = acct; - - purple_connection_set_protocol_data(gc, conn); - gc->proto_data = conn; + */ } void on_new_message(struct message *M) @@ -389,11 +477,11 @@ static void tgprpl_close(PurpleConnection * gc) */ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) { + telegram_conn *conn = purple_connection_get_protocol_data(gc); purple_debug_info(PLUGIN_ID, "tgprpl_send_im()\n"); PurpleBuddy *b = purple_find_buddy(_pa, who); peer_id_t *peer = purple_buddy_get_protocol_data(b); - do_send_message(*peer, message, strlen(message)); - flush_queries(); + do_send_message(conn->tg, *peer, message, strlen(message)); return 1; } @@ -751,14 +839,9 @@ static void tgprpl_init(PurplePlugin *plugin) PurpleAccountUserSplit *split; GList *verification_values = NULL; - // intialise logging + // Redirect the msglog of the telegram-cli application to the libpurple logger set_log_cb(&tg_cli_log_cb); - // Required Verification-Key -// split = purple_account_user_split_new("Verification key", NULL, '@'); -// purple_account_user_split_set_reverse(split, FALSE); -// prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); - // Extra Options #define ADD_VALUE(list, desc, v) { \ PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ @@ -768,12 +851,10 @@ static void tgprpl_init(PurplePlugin *plugin) } ADD_VALUE(verification_values, "Phone", TELEGRAM_AUTH_MODE_PHONE); ADD_VALUE(verification_values, "SMS", TELEGRAM_AUTH_MODE_SMS); + option = purple_account_option_list_new("Verification type", "verification_type", verification_values); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - // option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); - // prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_string_new("Verification key", "verification_key", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); @@ -786,9 +867,13 @@ static void tgprpl_init(PurplePlugin *plugin) option = purple_account_option_string_new("Last Name", "last_name", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + // TODO: Path to public key (When you can change the server hostname, // you should also be able to change the public key) + option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); @@ -811,10 +896,10 @@ static PurplePluginInfo info = { NULL, PURPLE_PRIORITY_DEFAULT, PLUGIN_ID, - "Telegram", + "struct telegram", "0.1", - "Telegram integration.", - "Includes support for the Telegram protocol into libpurple.", + "struct telegram integration.", + "Adds support for the struct telegram protocol to libpurple.", "Christopher Althaus , Markus Endres , Matthias Jentsch ", "https://bitbucket.org/telegrampurple/telegram-purple", NULL, // on load @@ -832,3 +917,4 @@ static PurplePluginInfo info = { PURPLE_INIT_PLUGIN(telegram, tgprpl_init, info) + diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 3c0d48a..433e7f3 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -21,6 +21,7 @@ #include "version.h" #include "account.h" #include "connection.h" +#include "telegram.h" #define PLUGIN_ID "prpl-telegram" @@ -35,7 +36,7 @@ #define TELEGRAM_AUTH_MODE_SMS "sms" typedef struct { - PurpleAccount *account; + struct telegram *tg; + PurpleAccount *pa; PurpleConnection *gc; - PurpleSslConnection *gsc; } telegram_conn; diff --git a/queries.c b/queries.c index 0197f8d..3f07807 100644 --- a/queries.c +++ b/queries.c @@ -1,12 +1,12 @@ /* This file is part of telegram-client. - Telegram-client is free software: you can redistribute it and/or modify + struct telegram-client is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - Telegram-client is distributed in the hope that it will be useful, + struct telegram-client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -40,10 +40,8 @@ #include "queries.h" #include "tree.h" #include "mtproto-common.h" -#include "telegram.h" #include "loop.h" #include "structures.h" -#include "interface.h" #include "net.h" #include #include @@ -53,6 +51,8 @@ #include "no-preview.h" #include "binlog.h" +#include "telegram.h" +#include "msglog.h" #define sha1 SHA1 @@ -65,6 +65,7 @@ char *get_downloads_directory (void); int verbosity; extern int offline_mode; +int offline_mode = 0; long long cur_uploading_bytes; long long cur_uploaded_bytes; @@ -73,6 +74,7 @@ long long cur_downloaded_bytes; extern int binlog_enabled; extern int sync_from_start; +int sync_from_start = 0; int queries_num = 0; @@ -87,8 +89,8 @@ int all_queries_done() } } -void flush_queries () { - net_loop(0, all_queries_done); +void telegram_flush_queries (struct telegram *instance) { + instance->on_output(instance); } void out_peer_id (peer_id_t id); @@ -142,11 +144,11 @@ void query_restart (long long id) { struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { logprintf("send_query(...)\n"); - assert (DC); - assert (DC->auth_key_id); + /* if (!DC->sessions[0]) { dc_create_session (DC); } + */ if (verbosity) { logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } @@ -316,8 +318,8 @@ int max_chat_size; int max_bcast_size; int want_dc_num; int new_dc_num; -extern struct dc *DC_list[]; -extern struct dc *DC_working; +//extern struct dc *DC_list[]; +//extern struct dc *DC_working; void out_random (int n) { assert (n <= 32); @@ -350,7 +352,7 @@ void do_insert_header (void) { /* {{{ Get config */ -void fetch_dc_option (void) { +void fetch_dc_option (struct telegram *instance) { assert (fetch_int () == CODE_dc_option); int id = fetch_int (); int l1 = prefetch_strlen (); @@ -362,10 +364,12 @@ void fetch_dc_option (void) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } - bl_do_dc_option (id, l1, name, l2, ip, port); + bl_do_dc_option (id, l1, name, l2, ip, port, instance); } int help_get_config_on_answer (struct query *q UU) { + struct telegram *instance = q->extra; + unsigned op = fetch_int (); assert (op == CODE_config || op == CODE_config_old); fetch_int (); @@ -382,7 +386,7 @@ int help_get_config_on_answer (struct query *q UU) { assert (n <= 10); int i; for (i = 0; i < n; i++) { - fetch_dc_option (); + fetch_dc_option (instance); } max_chat_size = fetch_int (); if (op == CODE_config) { @@ -391,6 +395,7 @@ int help_get_config_on_answer (struct query *q UU) { if (verbosity >= 2) { logprintf ( "chat_size = %d\n", max_chat_size); } + telegram_change_state(instance, STATE_CONNECTED, 0); return 0; } @@ -398,16 +403,19 @@ struct query_methods help_get_config_methods = { .on_answer = help_get_config_on_answer }; -void do_help_get_config (void) { +void do_help_get_config (struct telegram *instance) { clear_packet (); out_int (CODE_help_get_config); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0); + struct dc *DC_working = telegram_get_working_dc(instance); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, instance); } /* }}} */ /* {{{ Send code */ char *phone_code_hash; int send_code_on_answer (struct query *q UU) { + struct telegram *instance = q->extra; + assert (fetch_int () == (int)CODE_auth_sent_code); fetch_bool (); int l = prefetch_strlen (); @@ -420,18 +428,30 @@ int send_code_on_answer (struct query *q UU) { fetch_int (); fetch_bool (); want_dc_num = -1; + if (instance->session_state == STATE_PHONE_CODE_REQUESTED) { + telegram_change_state(instance, STATE_PHONE_CODE_NOT_ENTERED, phone_code_hash); + } else if (instance->session_state == STATE_CLIENT_CODE_REQUESTED) { + telegram_change_state(instance, STATE_CLIENT_CODE_NOT_ENTERED, phone_code_hash); + } else { + logprintf("send_code_on_answer(): Invalid State %d ", instance->session_state); + telegram_change_state(instance, STATE_ERROR, NULL); + } return 0; } int send_code_on_error (struct query *q UU, int error_code, int l, char *error) { + struct telegram *tg = q->extra; + int s = strlen ("PHONE_MIGRATE_"); int s2 = strlen ("NETWORK_MIGRATE_"); if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { - int i = error[s] - '0'; - want_dc_num = i; + int want_dc_num = error[s] - '0'; + tg->auth.dc_working_num = want_dc_num; + telegram_change_state(tg, STATE_ERROR, error); } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { - int i = error[s2] - '0'; - want_dc_num = i; + int want_dc_num = error[s2] - '0'; + tg->auth.dc_working_num = want_dc_num; + telegram_change_state(tg, STATE_ERROR, error); } else { logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); assert (0); @@ -448,13 +468,8 @@ int code_is_sent (void) { return want_dc_num; } -int config_got (void) { - return DC_list[want_dc_num] != 0; -} - char *suser; -extern int dc_working_num; -char* do_send_code (const char *user) { +void do_send_code (struct telegram *instance, const char *user) { logprintf ("sending code\n"); suser = tstrdup (user); want_dc_num = 0; @@ -467,17 +482,21 @@ char* do_send_code (const char *user) { out_string (TG_APP_HASH); out_string ("en"); - logprintf ("send_code: dc_num = %d\n", dc_working_num); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); - net_loop (0, code_is_sent); - if (want_dc_num == -1) { return phone_code_hash; } - - DC_working = DC_list[want_dc_num]; - if (!DC_working->sessions[0]) { - dc_create_session (DC_working); + logprintf ("send_code: dc_num = %d\n", instance->auth.dc_working_num); + send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &send_code_methods, instance); + if (instance->session_state == STATE_PHONE_NOT_REGISTERED) { + telegram_change_state(instance, STATE_PHONE_CODE_REQUESTED, NULL); + } else if (instance->session_state == STATE_CLIENT_NOT_REGISTERED) { + telegram_change_state(instance, STATE_CLIENT_CODE_REQUESTED, NULL); + } else { + logprintf("do_send_code() Invalid State %d, erroring\n", instance->session_state); + telegram_change_state(instance, STATE_ERROR, NULL); } - dc_working_num = want_dc_num; + // TODO: Phone Code Hash + /* + net_loop (0, code_is_sent); + if (want_dc_num == -1) { return phone_code_hash; } bl_do_set_working_dc (dc_working_num); logprintf ("send_code: dc_num = %d\n", dc_working_num); @@ -491,11 +510,12 @@ char* do_send_code (const char *user) { out_string (TG_APP_HASH); out_string ("en"); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); + send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); net_loop (0, code_is_sent); assert (want_dc_num == -1); return phone_code_hash; + */ } @@ -515,7 +535,7 @@ struct query_methods phone_call_methods = { .on_error = phone_call_on_error }; -void do_phone_call (const char *user) { +void do_phone_call (struct telegram *instance, const char *user) { logprintf ("calling user\n"); suser = tstrdup (user); want_dc_num = 0; @@ -525,8 +545,8 @@ void do_phone_call (const char *user) { out_string (user); out_string (phone_code_hash); - logprintf ("do_phone_call: dc_num = %d\n", dc_working_num); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &phone_call_methods, 0); + logprintf ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); + send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &phone_call_methods, 0); } /* }}} */ @@ -546,31 +566,26 @@ int check_phone_on_answer (struct query *q UU) { 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_"); + struct telegram* instance = q->extra; + if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { + // update used data centre int i = error[s] - '0'; - assert (DC_list[i]); + instance->auth.dc_working_num = i; - dc_working_num = i; - DC_working = DC_list[i]; - write_auth_file (); - - bl_do_set_working_dc (i); - - check_phone_result = 1; + //bl_do_set_working_dc (i); + //check_phone_result = 1; } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { + // update used data centre int i = error[s2] - '0'; - assert (DC_list[i]); - dc_working_num = i; + instance->auth.dc_working_num = i; + //bl_do_set_working_dc (i); - bl_do_set_working_dc (i); - - DC_working = DC_list[i]; - write_auth_file (); - check_phone_result = 1; + //check_phone_result = 1; } else { logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); - assert (0); } + telegram_change_state(instance, STATE_ERROR, error); return 0; } @@ -579,17 +594,20 @@ struct query_methods check_phone_methods = { .on_error = check_phone_on_error }; -int do_auth_check_phone (const char *user) { +int do_auth_check_phone (struct telegram *instance, const char *user) { suser = tstrdup (user); clear_packet (); out_int (CODE_auth_check_phone); out_string (user); check_phone_result = -1; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, 0); + struct dc *DC_working = telegram_get_working_dc(instance); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, instance); + /* net_loop (0, cr_f); check_phone_result = -1; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, instance); net_loop (0, cr_f); + */ return check_phone_result; } /* }}} */ @@ -623,7 +641,8 @@ struct query_methods nearest_dc_methods = { .on_error = fail_on_error }; -int do_get_nearest_dc (void) { +int do_get_nearest_dc (struct telegram *instance) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_help_get_nearest_dc); nearest_dc_num = -1; @@ -643,6 +662,7 @@ int sign_in_is_ok (void) { struct user User; int sign_in_on_answer (struct query *q UU) { + struct dc *DC_working = telegram_get_working_dc(q->extra); assert (fetch_int () == (int)CODE_auth_authorization); int expires = fetch_int (); fetch_user (&User); @@ -682,19 +702,21 @@ struct query_methods sign_in_methods = { .on_error = sign_in_on_error }; -int do_send_code_result (const char *code, const char *sms_hash) { +int do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_auth_sign_in); out_string (suser); out_string(sms_hash); out_string (code); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, instance); sign_in_ok = 0; net_loop (0, sign_in_is_ok); return sign_in_ok; } -int do_send_code_result_auth (const char *code, const char *sms_hash, const char *first_name, const char *last_name) { +int do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_auth_sign_up); out_string (suser); @@ -702,7 +724,7 @@ int do_send_code_result_auth (const char *code, const char *sms_hash, const char 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); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, instance); sign_in_ok = 0; net_loop (0, sign_in_is_ok); return sign_in_ok; @@ -728,11 +750,11 @@ int get_contacts_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); /* - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("User #%d: ", get_peer_id (U->id)); - print_user_name (U->id, (peer_t *)U); - push_color (COLOR_GREEN); + //print_user_name (U->id, (peer_t *)U); + //push_color (COLOR_GREEN); logprintf (" ("); logprintf ("%s", U->print_name); if (U->phone) { @@ -740,20 +762,20 @@ int get_contacts_on_answer (struct query *q UU) { logprintf ("%s", U->phone); } logprintf (") "); - pop_color (); + //pop_color (); if (U->status.online > 0) { logprintf ("online\n"); } else { if (U->status.online < 0) { logprintf ("offline. Was online "); - print_date_full (U->status.when); + //print_date_full (U->status.when); } else { logprintf ("offline permanent"); } logprintf ("\n"); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); */ } contacts_got = 1; @@ -765,7 +787,8 @@ struct query_methods get_contacts_methods = { }; -void do_update_contact_list (void) { +void do_update_contact_list (struct telegram *instance) { + struct dc *DC_working = telegram_get_working_dc(instance); contacts_got = 0; clear_packet (); out_int (CODE_contacts_get_contacts); @@ -860,7 +883,7 @@ void encr_finish (struct secret_chat *E) { /* {{{ Seng msg (plain text) */ int msg_send_encr_on_answer (struct query *q UU) { assert (fetch_int () == CODE_messages_sent_encrypted_message); - rprintf ("Sent\n"); + logprintf ("Sent\n"); struct message *M = q->extra; //M->date = fetch_int (); fetch_int (); @@ -907,16 +930,16 @@ int msg_send_on_answer (struct query *q UU) { if (b == CODE_contacts_foreign_link_requested) { U->flags |= FLAG_USER_OUT_CONTACT; } - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("Link with user "); - print_user_name (U->id, (void *)U); + //print_user_name (U->id, (void *)U); logprintf (" changed\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } } - rprintf ("Sent: id = %d\n", id); + logprintf ("Sent: id = %d\n", id); bl_do_set_message_sent (M); return 0; } @@ -940,7 +963,8 @@ struct query_methods msg_send_encr_methods = { int out_message_num; int our_id; -void do_send_encr_msg (struct message *M) { +void do_send_encr_msg (struct telegram *instance, struct message *M) { + struct dc *DC_working = telegram_get_working_dc(instance); peer_t *P = user_chat_get (M->to_id); if (!P || P->encr_chat.state != sc_ok) { return; } @@ -963,9 +987,10 @@ void do_send_encr_msg (struct message *M) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M); } -void do_send_msg (struct message *M) { +void do_send_msg (struct telegram *instance, struct message *M) { + struct dc *DC_working = telegram_get_working_dc(instance); if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { - do_send_encr_msg (M); + do_send_encr_msg (instance ,M); return; } clear_packet (); @@ -976,7 +1001,7 @@ void do_send_msg (struct message *M) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M); } -void do_send_message (peer_id_t id, const char *msg, int len) { +void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len) { if (get_peer_type (id) == PEER_ENCR_CHAT) { peer_t *P = user_chat_get (id); if (!P) { @@ -994,16 +1019,16 @@ void do_send_message (peer_id_t id, const char *msg, int len) { bl_do_send_message_text (t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); struct message *M = message_get (t); assert (M); - do_send_msg (M); - print_message (M); + do_send_msg (instance, M); + //print_message (M); } /* }}} */ /* {{{ Send text file */ -void do_send_text (peer_id_t id, char *file_name) { +void do_send_text (struct telegram *instance, peer_id_t id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { - rprintf ("No such file '%s'\n", file_name); + logprintf ("No such file '%s'\n", file_name); tfree_str (file_name); return; } @@ -1011,12 +1036,12 @@ void do_send_text (peer_id_t id, char *file_name) { int x = read (fd, buf, (1 << 20) + 1); assert (x >= 0); if (x == (1 << 20) + 1) { - rprintf ("Too big file '%s'\n", file_name); + logprintf ("Too big file '%s'\n", file_name); tfree_str (file_name); close (fd); } else { buf[x] = 0; - do_send_message (id, buf, x); + do_send_message (instance, id, buf, x); tfree_str (file_name); close (fd); } @@ -1045,7 +1070,8 @@ struct query_methods mark_read_encr_methods = { .on_answer = mark_read_encr_on_receive }; -void do_messages_mark_read (peer_id_t id, int max_id) { +void do_messages_mark_read (struct telegram *instance, peer_id_t id, int max_id) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_read_history); out_peer_id (id); @@ -1054,7 +1080,8 @@ void do_messages_mark_read (peer_id_t id, int max_id) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, 0); } -void do_messages_mark_read_encr (peer_id_t id, long long access_hash, int last_time) { +void do_messages_mark_read_encr (struct telegram *instance, peer_id_t id, long long access_hash, int last_time) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_read_encrypted_history); out_int (CODE_input_encrypted_chat); @@ -1064,45 +1091,54 @@ void do_messages_mark_read_encr (peer_id_t id, long long access_hash, int last_t send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, 0); } -void do_mark_read (peer_id_t id) { +void do_mark_read (struct telegram *instance, peer_id_t id) { peer_t *P = user_chat_get (id); if (!P) { - rprintf ("Unknown peer\n"); + logprintf ("Unknown peer\n"); return; } if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) { if (!P->last) { - rprintf ("Unknown last peer message\n"); + logprintf ("Unknown last peer message\n"); return; } - do_messages_mark_read (id, P->last->id); + do_messages_mark_read (instance, id, P->last->id); return; } assert (get_peer_type (id) == PEER_ENCR_CHAT); if (P->last) { - do_messages_mark_read_encr (id, P->encr_chat.access_hash, P->last->date); + do_messages_mark_read_encr (instance, id, P->encr_chat.access_hash, P->last->date); } else { - do_messages_mark_read_encr (id, P->encr_chat.access_hash, time (0) - 10); + do_messages_mark_read_encr (instance, id, P->encr_chat.access_hash, time (0) - 10); } } /* }}} */ +struct get_hist_extra { + struct telegram *instance; + peer_id_t peer_id; +}; + /* {{{ Get history */ int get_history_on_answer (struct query *q UU) { + struct get_hist_extra *extra = q->extra; + struct telegram *instance = extra->instance; + peer_id_t peer_id = extra->peer_id; + static struct message *ML[10000]; int i; int x = fetch_int (); if (x == (int)CODE_messages_messages_slice) { fetch_int (); - rprintf ("...\n"); + logprintf ("...\n"); } else { assert (x == (int)CODE_messages_messages); } assert (fetch_int () == CODE_vector); int n = fetch_int (); for (i = 0; i < n; i++) { - struct message *M = fetch_alloc_message (); + struct message *M = fetch_alloc_message (instance); if (i <= 9999) { ML[i] = M; } @@ -1110,7 +1146,7 @@ int get_history_on_answer (struct query *q UU) { if (n > 10000) { n = 10000; } int sn = n; for (i = n - 1; i >= 0; i--) { - print_message (ML[i]); + //print_message (ML[i]); } assert (fetch_int () == CODE_vector); n = fetch_int (); @@ -1122,9 +1158,11 @@ int get_history_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } + if (sn > 0 && q->extra) { - do_messages_mark_read (*(peer_id_t *)&(q->extra), ML[0]->id); + do_messages_mark_read (instance, peer_id, ML[0]->id); } + free(extra); return 0; } @@ -1143,15 +1181,16 @@ void do_get_local_history (peer_id_t id, int limit) { count ++; } while (M) { - print_message (M); + //print_message (M); M = M->prev; } } -void do_get_history (peer_id_t id, int limit) { +void do_get_history (struct telegram *instance, peer_id_t id, int limit) { + struct dc *DC_working = telegram_get_working_dc(instance); if (get_peer_type (id) == PEER_ENCR_CHAT || offline_mode) { do_get_local_history (id, limit); - do_mark_read (id); + do_mark_read (instance, id); return; } clear_packet (); @@ -1160,13 +1199,19 @@ void do_get_history (peer_id_t id, int limit) { out_int (0); out_int (0); out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, (void *)*(long *)&id); + + struct get_hist_extra *extra = malloc(sizeof(struct get_hist_extra)); + extra->instance = instance; + extra->peer_id = id; + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, extra); } /* }}} */ /* {{{ Get dialogs */ int dialog_list_got; int get_dialogs_on_answer (struct query *q UU) { + struct telegram *instance = q->extra; unsigned x = fetch_int (); assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); if (x == CODE_messages_dialogs_slice) { @@ -1193,7 +1238,7 @@ int get_dialogs_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); n = fetch_int (); for (i = 0; i < n; i++) { - fetch_alloc_message (); + fetch_alloc_message (instance); } assert (fetch_int () == CODE_vector); n = fetch_int (); @@ -1205,27 +1250,27 @@ int get_dialogs_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (); } - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); for (i = dl_size - 1; i >= 0; i--) { peer_t *UC; switch (get_peer_type (plist[i])) { case PEER_USER: UC = user_chat_get (plist[i]); logprintf ("User "); - print_user_name (plist[i], UC); + //print_user_name (plist[i], UC); logprintf (": %d unread\n", dlist[2 * i + 1]); break; case PEER_CHAT: UC = user_chat_get (plist[i]); logprintf ("Chat "); - print_chat_name (plist[i], UC); + //print_chat_name (plist[i], UC); logprintf (": %d unread\n", dlist[2 * i + 1]); break; } } - pop_color (); - print_end (); + //pop_color (); + //print_end (); dialog_list_got = 1; return 0; @@ -1236,13 +1281,14 @@ struct query_methods get_dialogs_methods = { }; -void do_get_dialog_list (void) { +void do_get_dialog_list (struct telegram *instance) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_get_dialogs); out_int (0); out_int (0); out_int (1000); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, instance); } /* }}} */ @@ -1289,16 +1335,23 @@ void out_peer_id (peer_id_t id) { } } -void send_part (struct send_file *f); +struct send_file_extra { + struct telegram *instance; + struct send_file *file; +}; + +void send_part (struct telegram *instance, struct send_file *f); int send_file_part_on_answer (struct query *q) { + struct send_file_extra *extra = q->extra; assert (fetch_int () == (int)CODE_bool_true); - send_part (q->extra); + send_part (extra->instance, extra->file); return 0; } int send_file_on_answer (struct query *q UU) { + struct telegram *instance = q->extra; assert (fetch_int () == (int)CODE_messages_stated_message); - struct message *M = fetch_alloc_message (); + struct message *M = fetch_alloc_message (instance); assert (fetch_int () == CODE_vector); int n, i; n = fetch_int (); @@ -1312,7 +1365,7 @@ int send_file_on_answer (struct query *q UU) { } fetch_pts (); fetch_seq (); - print_message (M); + //print_message (M); return 0; } @@ -1330,7 +1383,7 @@ int send_encr_file_on_answer (struct query *q UU) { fetch_int (); M->media.encr_photo.dc_id = fetch_int (); assert (fetch_int () == M->media.encr_photo.key_fingerprint); - print_message (M); + //print_message (M); message_insert (M); return 0; } @@ -1347,7 +1400,9 @@ struct query_methods send_encr_file_methods = { .on_answer = send_encr_file_on_answer }; -void send_part (struct send_file *f) { +void send_part (struct telegram *instance, struct send_file *f) { + + struct dc *DC_working = telegram_get_working_dc(instance); if (f->fd >= 0) { if (!f->part_num) { cur_uploading_bytes += f->size; @@ -1391,12 +1446,16 @@ void send_part (struct send_file *f) { } else { assert (f->part_size == x); } - update_prompt (); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); + //update_prompt (); + + struct send_file_extra *extra = malloc(sizeof(struct send_file_extra)); + extra->instance = instance; + extra->file = f; + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, extra); } else { cur_uploaded_bytes -= f->size; cur_uploading_bytes -= f->size; - update_prompt (); + //update_prompt (); clear_packet (); assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_audio || f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document); if (!f->encr) { @@ -1437,7 +1496,7 @@ void send_part (struct send_file *f) { } out_long (-lrand48 () * (1ll << 32) - lrand48 ()); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, instance); } else { struct message *M = talloc0 (sizeof (*M)); @@ -1527,14 +1586,14 @@ void send_part (struct send_file *f) { M->date = time (0); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M); - } tfree_str (f->file_name); tfree (f, sizeof (*f)); } } -void send_file_thumb (struct send_file *f) { +void send_file_thumb (struct telegram *instance, struct send_file *f) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); f->thumb_id = lrand48 () * (1ll << 32) + lrand48 (); out_int (CODE_upload_save_file_part); @@ -1544,10 +1603,10 @@ void send_file_thumb (struct send_file *f) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); } -void do_send_photo (int type, peer_id_t to_id, char *file_name) { +void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { - rprintf ("No such file '%s'\n", file_name); + logprintf ("No such file '%s'\n", file_name); tfree_str (file_name); return; } @@ -1555,7 +1614,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { fstat (fd, &buf); long long size = buf.st_size; if (size <= 0) { - rprintf ("File has zero length\n"); + logprintf ("File has zero length\n"); tfree_str (file_name); close (fd); return; @@ -1573,7 +1632,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { if (f->part_size > (512 << 10)) { close (fd); - rprintf ("Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000); + logprintf ("Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000); tfree (f, sizeof (*f)); tfree_str (file_name); return; @@ -1594,20 +1653,21 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { } if (f->media_type == CODE_input_media_uploaded_video && !f->encr) { f->media_type = CODE_input_media_uploaded_thumb_video; - send_file_thumb (f); + send_file_thumb (instance, f); } else if (f->media_type == CODE_input_media_uploaded_document && !f->encr) { f->media_type = CODE_input_media_uploaded_thumb_document; - send_file_thumb (f); + send_file_thumb (instance, f); } else { - send_part (f); + send_part (instance, f); } } /* }}} */ /* {{{ Forward */ int fwd_msg_on_answer (struct query *q UU) { + struct telegram *instance = q->extra; assert (fetch_int () == (int)CODE_messages_stated_message); - struct message *M = fetch_alloc_message (); + struct message *M = fetch_alloc_message (instance); assert (fetch_int () == CODE_vector); int n, i; n = fetch_int (); @@ -1621,7 +1681,7 @@ int fwd_msg_on_answer (struct query *q UU) { } fetch_pts (); fetch_seq (); - print_message (M); + //print_message (M); return 0; } @@ -1629,9 +1689,10 @@ struct query_methods fwd_msg_methods = { .on_answer = fwd_msg_on_answer }; -void do_forward_message (peer_id_t id, int n) { +void do_forward_message (struct telegram *instance, peer_id_t id, int n) { + struct dc *DC_working = telegram_get_working_dc(instance); if (get_peer_type (id) == PEER_ENCR_CHAT) { - rprintf ("Can not forward messages from secret chat\n"); + logprintf ("Can not forward messages from secret chat\n"); return; } clear_packet (); @@ -1639,14 +1700,16 @@ void do_forward_message (peer_id_t id, int n) { out_peer_id (id); out_int (n); out_long (lrand48 () * (1ll << 32) + lrand48 ()); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, instance); } /* }}} */ /* {{{ Rename chat */ int rename_chat_on_answer (struct query *q UU) { + struct telegram *instance = q->extra; + assert (fetch_int () == (int)CODE_messages_stated_message); - struct message *M = fetch_alloc_message (); + struct message *M = fetch_alloc_message (instance); assert (fetch_int () == CODE_vector); int n, i; n = fetch_int (); @@ -1660,7 +1723,7 @@ int rename_chat_on_answer (struct query *q UU) { } fetch_pts (); fetch_seq (); - print_message (M); + //print_message (M); return 0; } @@ -1668,44 +1731,45 @@ struct query_methods rename_chat_methods = { .on_answer = rename_chat_on_answer }; -void do_rename_chat (peer_id_t id, char *name UU) { +void do_rename_chat (struct telegram *instance, peer_id_t id, char *name UU) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_edit_chat_title); assert (get_peer_type (id) == PEER_CHAT); out_int (get_peer_id (id)); out_string (name); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, instance); } /* }}} */ /* {{{ Chat info */ void print_chat_info (struct chat *C) { peer_t *U = (void *)C; - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("Chat "); - print_chat_name (U->id, U); + //print_chat_name (U->id, U); logprintf (" members:\n"); int i; for (i = 0; i < C->user_list_size; i++) { logprintf ("\t\t"); - print_user_name (MK_USER (C->user_list[i].user_id), user_chat_get (MK_USER (C->user_list[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))); logprintf (" invited by "); - print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (MK_USER (C->user_list[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))); logprintf (" at "); - print_date_full (C->user_list[i].date); + //print_date_full (C->user_list[i].date); if (C->user_list[i].user_id == C->admin_id) { logprintf (" admin"); } logprintf ("\n"); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); } int chat_info_on_answer (struct query *q UU) { struct chat *C = fetch_alloc_chat_full (); - print_chat_info (C); + //print_chat_info (C); return 0; } @@ -1713,13 +1777,14 @@ struct query_methods chat_info_methods = { .on_answer = chat_info_on_answer }; -void do_get_chat_info (peer_id_t id) { +void do_get_chat_info (struct telegram *instance, peer_id_t id) { + struct dc *DC_working = telegram_get_working_dc(instance); if (offline_mode) { peer_t *C = user_chat_get (id); if (!C) { - rprintf ("No such chat\n"); + logprintf ("No such chat\n"); } else { - print_chat_info (&C->chat); + //print_chat_info (&C->chat); } return; } @@ -1735,10 +1800,10 @@ void do_get_chat_info (peer_id_t id) { void print_user_info (struct user *U) { peer_t *C = (void *)U; - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("User "); - print_user_name (U->id, C); + //print_user_name (U->id, C); logprintf (":\n"); logprintf ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); logprintf ("\tphone: %s\n", U->phone); @@ -1746,16 +1811,16 @@ void print_user_info (struct user *U) { logprintf ("\tonline\n"); } else { logprintf ("\toffline (was online "); - print_date_full (U->status.when); + //print_date_full (U->status.when); logprintf (")\n"); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); } int user_info_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user_full (); - print_user_info (U); + //print_user_info (U); return 0; } @@ -1763,13 +1828,14 @@ struct query_methods user_info_methods = { .on_answer = user_info_on_answer }; -void do_get_user_info (peer_id_t id) { +void do_get_user_info (struct telegram *instance, peer_id_t id) { + struct dc *DC_working = telegram_get_working_dc(instance); if (offline_mode) { peer_t *C = user_chat_get (id); if (!C) { - rprintf ("No such user\n"); + logprintf ("No such user\n"); } else { - print_user_info (&C->user); + //print_user_info (&C->user); } return; } @@ -1804,7 +1870,8 @@ struct query_methods user_list_info_silent_methods = { .on_answer = user_list_info_silent_on_answer }; -void do_get_user_list_info_silent (int num, int *list) { +void do_get_user_list_info_silent (struct telegram *instance, int num, int *list) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_users_get_users); out_int (CODE_vector); @@ -1841,7 +1908,7 @@ struct download { void end_load (struct download *D) { cur_downloading_bytes -= D->size; cur_downloaded_bytes -= D->size; - update_prompt (); + //update_prompt (); close (D->fd); if (D->next == 1) { logprintf ("Done: %s\n", D->name); @@ -1864,12 +1931,21 @@ void end_load (struct download *D) { tfree (D, sizeof (*D)); } -void load_next_part (struct download *D); +struct download_extra { + struct telegram *instance; + struct download *dl; +}; + +void load_next_part (struct telegram *instance, struct download *D); int download_on_answer (struct query *q) { + struct download_extra *extra = q->extra; + struct telegram *instance = extra->instance; + struct download *D = extra->dl; + free(extra); + assert (fetch_int () == (int)CODE_upload_file); unsigned x = fetch_int (); assert (x); - struct download *D = q->extra; if (D->fd == -1) { D->fd = open (D->name, O_CREAT | O_WRONLY, 0640); } @@ -1877,7 +1953,7 @@ int download_on_answer (struct query *q) { int len = prefetch_strlen (); assert (len >= 0); cur_downloaded_bytes += len; - update_prompt (); + //update_prompt (); if (D->iv) { unsigned char *ptr = (void *)fetch_str (len); assert (!(len & 15)); @@ -1894,7 +1970,7 @@ int download_on_answer (struct query *q) { } D->offset += len; if (D->offset < D->size) { - load_next_part (D); + load_next_part (instance, D); return 0; } else { end_load (D); @@ -1906,7 +1982,7 @@ struct query_methods download_methods = { .on_answer = download_on_answer }; -void load_next_part (struct download *D) { +void load_next_part (struct telegram *instance, struct download *D) { if (!D->offset) { static char buf[PATH_MAX]; int l; @@ -1926,7 +2002,7 @@ void load_next_part (struct download *D) { if (D->offset >= D->size) { cur_downloading_bytes += D->size; cur_downloaded_bytes += D->offset; - rprintf ("Already downloaded\n"); + logprintf ("Already downloaded\n"); end_load (D); return; } @@ -1934,7 +2010,7 @@ void load_next_part (struct download *D) { cur_downloading_bytes += D->size; cur_downloaded_bytes += D->offset; - update_prompt (); + //update_prompt (); } clear_packet (); out_int (CODE_upload_get_file); @@ -1954,13 +2030,18 @@ void load_next_part (struct download *D) { } out_int (D->offset); out_int (1 << 14); - send_query (DC_list[D->dc], packet_ptr - packet_buffer, packet_buffer, &download_methods, D); + + struct download_extra *extra = malloc(sizeof(struct download_extra)); + extra->instance = instance; + extra->dl = D; + + send_query (instance->auth.DC_list[D->dc], packet_ptr - packet_buffer, packet_buffer, &download_methods, extra); //send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); } -void do_load_photo_size (struct photo_size *P, int next) { +void do_load_photo_size (struct telegram *instance, struct photo_size *P, int next) { if (!P->loc.dc) { - rprintf ("Bad video thumb\n"); + logprintf ("Bad video thumb\n"); return; } @@ -1977,10 +2058,10 @@ void do_load_photo_size (struct photo_size *P, int next) { D->next = next; D->name = 0; D->fd = -1; - load_next_part (D); + load_next_part (instance, D); } -void do_load_photo (struct photo *photo, int next) { +void do_load_photo (struct telegram *instance, struct photo *photo, int next) { if (!photo->sizes_num) { return; } int max = -1; int maxi = 0; @@ -1991,18 +2072,18 @@ void do_load_photo (struct photo *photo, int next) { maxi = i; } } - do_load_photo_size (&photo->sizes[maxi], next); + do_load_photo_size (instance, &photo->sizes[maxi], next); } -void do_load_video_thumb (struct video *video, int next) { - do_load_photo_size (&video->thumb, next); +void do_load_video_thumb (struct telegram *instance, struct video *video, int next) { + do_load_photo_size (instance, &video->thumb, next); } -void do_load_document_thumb (struct document *video, int next) { - do_load_photo_size (&video->thumb, next); +void do_load_document_thumb (struct telegram *instance, struct document *video, int next) { + do_load_photo_size (instance, &video->thumb, next); } -void do_load_video (struct video *V, int next) { +void do_load_video (struct telegram *instance, struct video *V, int next) { assert (V); assert (next); struct download *D = talloc0 (sizeof (*D)); @@ -2015,10 +2096,10 @@ void do_load_video (struct video *V, int next) { D->name = 0; D->fd = -1; D->type = CODE_input_video_file_location; - load_next_part (D); + load_next_part (instance, D); } -void do_load_audio (struct video *V, int next) { +void do_load_audio (struct telegram *instance, struct video *V, int next) { assert (V); assert (next); struct download *D = talloc0 (sizeof (*D)); @@ -2031,10 +2112,10 @@ void do_load_audio (struct video *V, int next) { D->name = 0; D->fd = -1; D->type = CODE_input_audio_file_location; - load_next_part (D); + load_next_part (instance, D); } -void do_load_document (struct document *V, int next) { +void do_load_document (struct telegram *instance, struct document *V, int next) { assert (V); assert (next); struct download *D = talloc0 (sizeof (*D)); @@ -2047,10 +2128,10 @@ void do_load_document (struct document *V, int next) { D->name = 0; D->fd = -1; D->type = CODE_input_document_file_location; - load_next_part (D); + load_next_part (instance, D); } -void do_load_encr_video (struct encr_video *V, int next) { +void do_load_encr_video (struct telegram *instance, struct encr_video *V, int next) { assert (V); assert (next); struct download *D = talloc0 (sizeof (*D)); @@ -2065,7 +2146,7 @@ void do_load_encr_video (struct encr_video *V, int next) { D->key = V->key; D->iv = talloc (32); memcpy (D->iv, V->iv, 32); - load_next_part (D); + load_next_part (instance, D); unsigned char md5[16]; unsigned char str[64]; @@ -2107,7 +2188,8 @@ struct query_methods export_auth_methods = { .on_error = fail_on_error }; -void do_export_auth (int num) { +void do_export_auth (struct telegram *instance, int num) { + struct dc *DC_working = telegram_get_working_dc(instance); export_auth_str = 0; clear_packet (); out_int (CODE_auth_export_authorization); @@ -2132,12 +2214,12 @@ struct query_methods import_auth_methods = { .on_error = fail_on_error }; -void do_import_auth (int num) { +void do_import_auth (struct telegram *instance, 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); + send_query (instance->auth.DC_list[num], packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, 0); net_loop (0, isn_export_auth_str); } /* }}} */ @@ -2162,11 +2244,11 @@ int add_contact_on_answer (struct query *q UU) { n = fetch_int (); for (i = 0; i < n ; i++) { struct user *U = fetch_alloc_user (); - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("User #%d: ", get_peer_id (U->id)); - print_user_name (U->id, (peer_t *)U); - push_color (COLOR_GREEN); + //print_user_name (U->id, (peer_t *)U); + //push_color (COLOR_GREEN); logprintf (" ("); logprintf ("%s", U->print_name); if (U->phone) { @@ -2174,20 +2256,20 @@ int add_contact_on_answer (struct query *q UU) { logprintf ("%s", U->phone); } logprintf (") "); - pop_color (); + //pop_color (); if (U->status.online > 0) { logprintf ("online\n"); } else { if (U->status.online < 0) { logprintf ("offline. Was online "); - print_date_full (U->status.when); + //print_date_full (U->status.when); } else { logprintf ("offline permanent"); } logprintf ("\n"); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); } return 0; @@ -2197,7 +2279,8 @@ struct query_methods add_contact_methods = { .on_answer = add_contact_on_answer, }; -void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force) { +void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_contacts_import_contacts); out_int (CODE_vector); @@ -2221,9 +2304,10 @@ struct query_methods msg_search_methods = { .on_answer = msg_search_on_answer }; -void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) { +void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s) { + struct dc *DC_working = telegram_get_working_dc(instance); if (get_peer_type (id) == PEER_ENCR_CHAT) { - rprintf ("Can not search in secure chat\n"); + logprintf ("Can not search in secure chat\n"); return; } clear_packet (); @@ -2256,18 +2340,18 @@ int contacts_search_on_answer (struct query *q UU) { } assert (fetch_int () == CODE_vector); n = fetch_int (); - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); for (i = 0; i < n; i++) { struct user *U = fetch_alloc_user (); logprintf ("User "); - push_color (COLOR_RED); + //push_color (COLOR_RED); logprintf ("%s %s", U->first_name, U->last_name); - pop_color (); + //pop_color (); logprintf (". Phone %s\n", U->phone); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); return 0; } @@ -2275,7 +2359,8 @@ struct query_methods contacts_search_methods = { .on_answer = contacts_search_on_answer }; -void do_contacts_search (int limit, const char *s) { +void do_contacts_search (struct telegram *instance, int limit, const char *s) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_contacts_search); out_string (s); @@ -2289,21 +2374,21 @@ int send_encr_accept_on_answer (struct query *q UU) { struct secret_chat *E = fetch_alloc_encrypted_chat (); if (E->state == sc_ok) { - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("Encrypted connection with "); - print_encr_chat_name (E->id, (void *)E); + ////print_encr_chat_name (E->id, (void *)E); logprintf (" established\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } else { - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("Encrypted connection with "); - print_encr_chat_name (E->id, (void *)E); + ////print_encr_chat_name (E->id, (void *)E); logprintf (" failed\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } return 0; } @@ -2311,21 +2396,21 @@ int send_encr_accept_on_answer (struct query *q UU) { int send_encr_request_on_answer (struct query *q UU) { struct secret_chat *E = fetch_alloc_encrypted_chat (); if (E->state == sc_deleted) { - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("Encrypted connection with "); - print_encr_chat_name (E->id, (void *)E); + //print_encr_chat_name (E->id, (void *)E); logprintf (" can not be established\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); } else { - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); logprintf ("Establishing connection with "); - print_encr_chat_name (E->id, (void *)E); + //print_encr_chat_name (E->id, (void *)E); logprintf ("\n"); - pop_color (); - print_end (); + //pop_color (); + //print_end (); assert (E->state == sc_waiting); } @@ -2345,7 +2430,8 @@ unsigned char *encr_prime; int encr_param_version; BN_CTX *ctx; -void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { +void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, unsigned char *random) { + struct dc *DC_working = telegram_get_working_dc(instance); int i; int ok = 0; for (i = 0; i < 64; i++) { @@ -2456,7 +2542,8 @@ void do_create_keys_end (struct secret_chat *U) { BN_clear_free (a); } -void do_send_create_encr_chat (void *x, unsigned char *random) { +void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char *random) { + struct dc *DC_working = telegram_get_working_dc(instance); int user_id = (long)x; int i; unsigned char random_here[256]; @@ -2514,7 +2601,8 @@ void do_send_create_encr_chat (void *x, unsigned char *random) { } out_int (get_peer_id (E->id)); out_cstring (g_a, 256); - write_secret_chat_file (); + // TODO: properly... + write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); BN_clear_free (g); BN_clear_free (p); @@ -2523,6 +2611,12 @@ void do_send_create_encr_chat (void *x, unsigned char *random) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E); } +struct create_encr_chat_extra { + void (*callback) (struct telegram *instance, struct secret_chat *E, unsigned char *random); + void *data; + struct telegram *instance; +}; + int get_dh_config_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); @@ -2545,9 +2639,13 @@ int get_dh_config_on_answer (struct query *q UU) { unsigned char *random = talloc (256); memcpy (random, fetch_str (256), 256); if (q->extra) { - void **x = q->extra; - ((void (*)(void *, void *))(*x))(x[1], random); - tfree (x, 2 * sizeof (void *)); + //((void (*)(void *, void *))(*x))(x[1], random); + + struct create_encr_chat_extra *extra = q->extra; + extra->callback(extra->instance, extra->data, random); + free(extra); + //tfree (x, 2 * sizeof (void *)); + tfree_secure (random, 256); } else { tfree_secure (random, 256); @@ -2559,28 +2657,34 @@ struct query_methods get_dh_config_methods = { .on_answer = get_dh_config_on_answer }; -void do_accept_encr_chat_request (struct secret_chat *E) { +void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E) { + struct dc *DC_working = telegram_get_working_dc(instance); assert (E->state == sc_request); clear_packet (); out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - void **x = talloc (2 * sizeof (void *)); - x[0] = do_send_accept_encr_chat; - x[1] = E; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); + + struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); + extra->callback = do_send_accept_encr_chat; + extra->instance = instance; + extra->data = (void*)E; + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, extra); } -void do_create_encr_chat_request (int user_id) { +void do_create_encr_chat_request (struct telegram *instance, int user_id) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_get_dh_config); out_int (encr_param_version); out_int (256); - void **x = talloc (2 * sizeof (void *)); - x[0] = do_send_create_encr_chat; - x[1] = (void *)(long)(user_id); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, x); + + struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); + extra->callback = do_send_accept_encr_chat; + extra->instance = instance; + extra->data = (void *)(long)user_id; + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, extra); } /* }}} */ @@ -2596,13 +2700,15 @@ int get_state_on_answer (struct query *q UU) { bl_do_set_date (fetch_int ()); bl_do_set_seq (fetch_int ()); unread_messages = fetch_int (); - write_state_file (); + //write_state_file (); difference_got = 1; return 0; } int get_difference_active; int get_difference_on_answer (struct query *q UU) { + struct telegram *instance = q->extra; + logprintf("get_difference_on_answer()\n"); get_difference_active = 0; unsigned x = fetch_int (); @@ -2618,18 +2724,18 @@ int get_difference_on_answer (struct query *q UU) { int ml_pos = 0; for (i = 0; i < n; i++) { if (ml_pos < 10000) { - ML[ml_pos ++] = fetch_alloc_message (); + ML[ml_pos ++] = fetch_alloc_message (instance); } else { - fetch_alloc_message (); + fetch_alloc_message (instance); } } assert (fetch_int () == CODE_vector); n = fetch_int (); for (i = 0; i < n; i++) { if (ml_pos < 10000) { - ML[ml_pos ++] = fetch_alloc_encrypted_message (); + ML[ml_pos ++] = fetch_alloc_encrypted_message (instance); } else { - fetch_alloc_encrypted_message (); + fetch_alloc_encrypted_message (instance); } } assert (fetch_int () == CODE_vector); @@ -2655,13 +2761,13 @@ int get_difference_on_answer (struct query *q UU) { bl_do_set_date (fetch_int ()); bl_do_set_seq (fetch_int ()); unread_messages = fetch_int (); - write_state_file (); + //write_state_file (); for (i = 0; i < ml_pos; i++) { event_update_new_message(ML[i]); - //print_message (ML[i]); + ////print_message (ML[i]); } if (x == CODE_updates_difference_slice) { - do_get_difference (); + do_get_difference (instance); } else { difference_got = 1; } @@ -2679,7 +2785,8 @@ struct query_methods get_difference_methods = { .on_answer = get_difference_on_answer }; -void do_get_difference (void) { +void do_get_difference (struct telegram *instance) { + struct dc *DC_working = telegram_get_working_dc(instance); logprintf("do_get_difference()\n"); get_difference_active = 1; difference_got = 0; @@ -2693,7 +2800,7 @@ void do_get_difference (void) { out_int (pts); out_int (last_date); out_int (qts); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_difference_methods, 0); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_difference_methods, instance); } else { out_int (CODE_updates_get_state); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0); @@ -2702,34 +2809,34 @@ void do_get_difference (void) { /* }}} */ /* {{{ Visualize key */ -char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN}; +//char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN}; void do_visualize_key (peer_id_t id) { assert (get_peer_type (id) == PEER_ENCR_CHAT); peer_t *P = user_chat_get (id); assert (P); if (P->encr_chat.state != sc_ok) { - rprintf ("Chat is not initialized yet\n"); + logprintf ("Chat is not initialized yet\n"); return; } unsigned char buf[20]; SHA1 ((void *)P->encr_chat.key, 256, buf); - print_start (); + //print_start (); int i; for (i = 0; i < 16; i++) { int x = buf[i]; int j; for (j = 0; j < 4; j ++) { - push_color (colors[x & 3]); - push_color (COLOR_INVERSE); - logprintf (" "); - pop_color (); - pop_color (); + ////push_color (colors[x & 3]); + ////push_color (COLOR_INVERSE); + //logprintf (" "); + ////pop_color (); + ////pop_color (); x = x >> 2; } if (i & 1) { logprintf ("\n"); } } - print_end (); + //print_end (); } /* }}} */ @@ -2750,16 +2857,16 @@ int get_suggested_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); int m = fetch_int (); assert (n == m); - print_start (); - push_color (COLOR_YELLOW); + //print_start (); + //push_color (COLOR_YELLOW); for (i = 0; i < m; i++) { peer_t *U = (void *)fetch_alloc_user (); assert (get_peer_id (U->id) == l[2 * i]); - print_user_name (U->id, U); + //print_user_name (U->id, U); logprintf (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); } - pop_color (); - print_end (); + //pop_color (); + //print_end (); return 0; } @@ -2767,7 +2874,8 @@ struct query_methods get_suggested_methods = { .on_answer = get_suggested_on_answer }; -void do_get_suggested (void) { +void do_get_suggested (struct telegram *instance) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_contacts_get_suggested); out_int (100); @@ -2781,7 +2889,8 @@ struct query_methods add_user_to_chat_methods = { .on_answer = fwd_msg_on_answer }; -void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit) { +void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_add_chat_user); out_int (get_peer_id (chat_id)); @@ -2800,7 +2909,8 @@ void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_user_to_chat_methods, 0); } -void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id) { +void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_delete_chat_user); out_int (get_peer_id (chat_id)); @@ -2822,15 +2932,15 @@ void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id) { /* {{{ Create secret chat */ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); -void do_create_secret_chat (peer_id_t id) { +void do_create_secret_chat (struct telegram *instance, peer_id_t id) { assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (id); if (!U) { - rprintf ("Can not create chat with unknown user\n"); + logprintf ("Can not create chat with unknown user\n"); return; } - do_create_encr_chat_request (get_peer_id (id)); + do_create_encr_chat_request (instance, get_peer_id (id)); } /* }}} */ @@ -2839,11 +2949,11 @@ struct query_methods create_group_chat_methods = { .on_answer = fwd_msg_on_answer }; -void do_create_group_chat (peer_id_t id, char *chat_topic) { +void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic) { assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (id); if (!U) { - rprintf ("Can not create chat with unknown user\n"); + logprintf ("Can not create chat with unknown user\n"); return; } clear_packet (); @@ -2859,7 +2969,7 @@ void do_create_group_chat (peer_id_t id, char *chat_topic) { out_int (get_peer_id (id)); } out_string (chat_topic); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &create_group_chat_methods, 0); + send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &create_group_chat_methods, 0); } /* }}} */ @@ -2878,7 +2988,8 @@ struct query_methods delete_msg_methods = { .on_answer = delete_msg_on_answer }; -void do_delete_msg (long long id) { +void do_delete_msg (struct telegram *instance, long long id) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_delete_messages); out_int (CODE_vector); @@ -2902,7 +3013,8 @@ struct query_methods restore_msg_methods = { .on_answer = restore_msg_on_answer }; -void do_restore_msg (long long id) { +void do_restore_msg (struct telegram *instance, long long id) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_messages_restore_messages); out_int (CODE_vector); @@ -2920,7 +3032,8 @@ struct query_methods update_status_methods = { .on_answer = update_status_on_answer }; -void do_update_status (int online UU) { +void do_update_status (struct telegram *instance, int online UU) { + struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_account_update_status); out_int (online ? CODE_bool_false : CODE_bool_true); diff --git a/queries.h b/queries.h index 8456600..dd6588e 100644 --- a/queries.h +++ b/queries.h @@ -1,12 +1,12 @@ /* This file is part of telegram-client. - Telegram-client is free software: you can redistribute it and/or modify + struct telegram-client is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - Telegram-client is distributed in the hope that it will be useful, + struct telegram-client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -17,10 +17,14 @@ Copyright Vitaly Valtman 2013 */ #include "net.h" +#include "telegram.h" #ifndef __QUERIES_H__ #define __QUERIES_H__ #include "structures.h" +// forward declare telegram +struct telegram; + #define QUERY_ACK_RECEIVED 1 struct query; @@ -63,63 +67,63 @@ void work_timers (void); extern struct query_methods help_get_config_methods; -char* do_send_code (const char *user); -void do_phone_call (const char *user); -int do_send_code_result (const char *code, const char *sms_hash); +void do_send_code (struct telegram *instance, const char *user); +void do_phone_call (struct telegram *instance, const char *user); +int do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash); double get_double_time (void); -void do_update_contact_list (void); +void do_update_contact_list (struct telegram *instance); union user_chat; -void do_send_message (peer_id_t id, const char *msg, int len); -void do_send_text (peer_id_t id, char *file); -void do_get_history (peer_id_t id, int limit); -void do_get_dialog_list (void); -void do_get_dialog_list_ex (void); -void do_send_photo (int type, peer_id_t to_id, char *file_name); -void do_get_chat_info (peer_id_t id); -void do_get_user_list_info_silent (int num, int *list); -void do_get_user_info (peer_id_t id); -void do_forward_message (peer_id_t id, int n); -void do_rename_chat (peer_id_t id, char *name); -void do_load_encr_video (struct encr_video *V, int next); -void do_create_encr_chat_request (int user_id); -void do_create_secret_chat (peer_id_t id); -void do_create_group_chat (peer_id_t id, char *chat_topic); -void do_get_suggested (void); +void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len); +void do_send_text (struct telegram *instance, peer_id_t id, char *file); +void do_get_history (struct telegram *instance, peer_id_t id, int limit); +void do_get_dialog_list (struct telegram*); +void do_get_dialog_list_ex (struct telegram*); +void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name); +void do_get_chat_info (struct telegram *instance, peer_id_t id); +void do_get_user_list_info_silent (struct telegram *instance, int num, int *list); +void do_get_user_info (struct telegram *instance, peer_id_t id); +void do_forward_message (struct telegram *instance, peer_id_t id, int n); +void do_rename_chat (struct telegram *instance, peer_id_t id, char *name); +void do_load_encr_video (struct telegram *instance, struct encr_video *V, int next); +void do_create_encr_chat_request (struct telegram *instance, int user_id); +void do_create_secret_chat (struct telegram *instance, peer_id_t id); +void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic); +void do_get_suggested (struct telegram*); struct photo; struct video; -void do_load_photo (struct photo *photo, int next); -void do_load_video_thumb (struct video *video, int next); -void do_load_audio (struct video *V, int next); -void do_load_video (struct video *V, int next); -void do_load_document (struct document *V, int next); -void do_load_document_thumb (struct document *video, 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 *sms_hash, const char *first_name, const char *last_name); -void do_import_auth (int num); -void do_export_auth (int num); -void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); -void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s); -void do_accept_encr_chat_request (struct secret_chat *E); -void do_get_difference (void); -void do_mark_read (peer_id_t id); +void do_load_photo (struct telegram *instance, struct photo *photo, int next); +void do_load_video_thumb (struct telegram *instance, struct video *video, int next); +void do_load_audio (struct telegram *instance, struct video *V, int next); +void do_load_video (struct telegram *instance, struct video *V, int next); +void do_load_document (struct telegram *instance, struct document *V, int next); +void do_load_document_thumb (struct telegram *instance, struct document *video, int next); +void do_help_get_config (struct telegram *instance); +int do_auth_check_phone (struct telegram *instance, const char *user); +int do_get_nearest_dc (struct telegram*); +int do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name); +void do_import_auth (struct telegram *instance, int num); +void do_export_auth (struct telegram *instance, int num); +void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); +void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s); +void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E); +void do_get_difference (struct telegram*); +void do_mark_read (struct telegram *instance, peer_id_t id); void do_visualize_key (peer_id_t id); void do_create_keys_end (struct secret_chat *U); -void do_add_user_to_chat (peer_id_t chat_id, peer_id_t id, int limit); -void do_del_user_from_chat (peer_id_t chat_id, peer_id_t id); -void do_update_status (int online); -void do_contacts_search (int limit, const char *s); -void do_send_msg (struct message *M); -void do_delete_msg (long long id); -void do_restore_msg (long long id); +void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit); +void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id); +void do_update_status (struct telegram *instance, int online); +void do_contacts_search (struct telegram *instance, int limit, const char *s); +void do_send_msg (struct telegram *instance, struct message *M); +void do_delete_msg (struct telegram *instance, long long id); +void do_restore_msg (struct telegram *instance, long long id); // For binlog int get_dh_config_on_answer (struct query *q); -void fetch_dc_option (void); +void fetch_dc_option (struct telegram *instance); #endif const char *get_last_err(); diff --git a/structures.c b/structures.c index a06290b..3d68143 100644 --- a/structures.c +++ b/structures.c @@ -231,7 +231,8 @@ int fetch_user (struct user *U) { assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { bl_do_set_our_id (get_peer_id (U->id)); - write_auth_file (); + // TODO: What to do here? + //write_auth_file (); } } @@ -323,7 +324,9 @@ void fetch_encrypted_chat (struct secret_chat *U) { return; } bl_do_encr_chat_delete (U); - write_secret_chat_file (); + + // TODO: properly + write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); return; } @@ -372,7 +375,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { } bl_do_encr_chat_requested (U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); - write_secret_chat_file (); + write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); } else { bl_do_set_encr_chat_access_hash (U, fetch_long ()); bl_do_set_encr_chat_date (U, fetch_int ()); @@ -386,7 +389,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { } if (x == CODE_encrypted_chat_waiting) { bl_do_set_encr_chat_state (U, sc_waiting); - write_secret_chat_file (); + write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); return; // We needed only access hash from here } @@ -418,7 +421,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { } bl_do_encr_chat_accepted (U, (void *)g_key, (void *)nonce, fetch_long ()); } - write_secret_chat_file (); + write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); } void fetch_notify_settings (void); @@ -1808,11 +1811,12 @@ void message_del_peer (struct message *M) { } } -struct message *fetch_alloc_message (void) { +struct message *fetch_alloc_message (struct telegram *instance) { logprintf("fetch_alloc_message()\n"); int data[2]; prefetch_data (data, 8); struct message *M = message_get (data[1]); + M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); @@ -1824,9 +1828,10 @@ struct message *fetch_alloc_message (void) { return M; } -struct message *fetch_alloc_geo_message (void) { +struct message *fetch_alloc_geo_message (struct telegram *instance) { logprintf("fetch_alloc_geo_message()\n"); struct message *M = talloc (sizeof (*M)); + M->instance = instance; fetch_geo_message (M); struct message *M1 = tree_lookup_message (message_tree, M); messages_allocated ++; @@ -1848,11 +1853,12 @@ struct message *fetch_alloc_geo_message (void) { } } -struct message *fetch_alloc_encrypted_message (void) { +struct message *fetch_alloc_encrypted_message (struct telegram *instance) { logprintf("fetch_alloc_encrypted_message()\n"); int data[3]; prefetch_data (data, 12); struct message *M = message_get (*(long long *)(data + 1)); + M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); @@ -1866,10 +1872,11 @@ struct message *fetch_alloc_encrypted_message (void) { return M; } -struct message *fetch_alloc_message_short (void) { +struct message *fetch_alloc_message_short (struct telegram *instance) { int data[1]; prefetch_data (data, 4); struct message *M = message_get (data[0]); + M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); @@ -1881,10 +1888,11 @@ struct message *fetch_alloc_message_short (void) { return M; } -struct message *fetch_alloc_message_short_chat (void) { +struct message *fetch_alloc_message_short_chat (struct telegram *instance) { int data[1]; prefetch_data (data, 4); struct message *M = message_get (data[0]); + M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); @@ -1998,9 +2006,10 @@ void message_remove_unsent (struct message *M) { void __send_msg (struct message *M) { logprintf ("Resending message...\n"); - print_message (M); - - do_send_msg (M); + //print_message (M); + + assert(M->instance); + do_send_msg (M->instance, M); } void send_all_unsent (void ) { diff --git a/structures.h b/structures.h index 63610b4..e9b9c59 100644 --- a/structures.h +++ b/structures.h @@ -318,6 +318,7 @@ struct message { int unread; int date; int service; + struct telegram *instance; union { struct message_action action; struct { @@ -336,11 +337,11 @@ struct user *fetch_alloc_user_full (void); struct chat *fetch_alloc_chat (void); struct chat *fetch_alloc_chat_full (void); struct secret_chat *fetch_alloc_encrypted_chat (void); -struct message *fetch_alloc_message (void); -struct message *fetch_alloc_geo_message (void); -struct message *fetch_alloc_message_short (void); -struct message *fetch_alloc_message_short_chat (void); -struct message *fetch_alloc_encrypted_message (void); +struct message *fetch_alloc_message (struct telegram *instance); +struct message *fetch_alloc_geo_message (struct telegram *instance); +struct message *fetch_alloc_message_short (struct telegram *instance); +struct message *fetch_alloc_message_short_chat (struct telegram *instance); +struct message *fetch_alloc_encrypted_message (struct telegram *instance); void fetch_encrypted_message_file (struct message_media *M); void fetch_skip_encrypted_message_file (void); void fetch_encrypted_message_file (struct message_media *M); diff --git a/telegram.c b/telegram.c index 071dc63..f712483 100755 --- a/telegram.c +++ b/telegram.c @@ -1,7 +1,15 @@ #include +#include +#include +#include +#include +#include + #include "mtproto-common.h" #include "telegram.h" #include "msglog.h" +#include "glib.h" +#include "mtproto-client.h" /* * Events @@ -11,50 +19,203 @@ * New message received */ void (*on_msg_handler)(struct message *M); -void on_update_new_message(void (*on_msg)(struct message *M)) { - on_msg_handler = on_msg; +void on_update_new_message(void (*on_msg)(struct message *M)) +{ + on_msg_handler = on_msg; } -void event_update_new_message(struct message *M) { - if (on_msg_handler) { - on_msg_handler(M); - } +void event_update_new_message(struct message *M) +{ + if (on_msg_handler) { + on_msg_handler(M); + } } /* * Peer allocated */ void (*on_peer_allocated_handler)(peer_t *peer); -void on_peer_allocated(void (*handler)(peer_t *peer)) { - on_peer_allocated_handler = handler; +void on_peer_allocated(void (*handler)(peer_t *peer)) +{ + on_peer_allocated_handler = handler; } -void event_peer_allocated(peer_t *peer) { - if (on_peer_allocated_handler) { - on_peer_allocated_handler(peer); - } +void event_peer_allocated(peer_t *peer) +{ + if (on_peer_allocated_handler) { + on_peer_allocated_handler(peer); + } } /* - * Callback to create proxy connections + * State changed */ -void (*proxy_connection_source)(const char *host, int port, void (*on_connection_created)(int fd)) = NULL; -void *proxy_connection_data = NULL; -void set_proxy_connection_source (void (*connection_source)(const char *host, int port, - void (*on_connection_created)(int fd)), void* data) +GList *change_listeners = NULL; +void telegram_add_state_change_listener(struct telegram *instance, state_listener_t listener) { - proxy_connection_source = connection_source; - proxy_connection_data = data; + instance->change_state_listeners = g_list_append(instance->change_state_listeners, listener); +} +void telegram_change_state(struct telegram *instance, int state, void *data) +{ + logprintf("Changing struct telegram state %d\n", state); + instance->session_state = state; + GList *curr = instance->change_state_listeners; + while ((curr = g_list_next(change_listeners)) != NULL) { + ((state_listener_t)curr->data)(instance, state, data); + } +} + +struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path) +{ + struct telegram *this = malloc(sizeof(struct telegram)); + this->protocol_data = NULL; + this->curr_dc = 0; + this->auth.DC_list[0] = DC; + this->change_state_listeners = NULL; + this->config_path = config_path; + strcpy(this->login, malloc(strlen(login) + 1)); + telegram_change_state(this, STATE_INITIALISED, NULL); + return this; +} + +void telegram_free(struct telegram *instance) +{ + g_list_free(instance->change_state_listeners); + free(instance->login); + free(instance); +} + +void assert_file_usable(const char *file) +{ + assert(access(file, W_OK | R_OK | F_OK) != -1); +} + +void assure_file_exists(const char *dir, const char *file) +{ + char f[256]; + g_mkdir_with_parents(dir, 0700); + sprintf(f, "%s/%s", dir, file); + close(open(f, O_RDWR | O_CREAT, S_IRUSR, S_IWUSR)); + assert_file_usable(f); +} + +struct connection *telegram_get_connection(struct telegram *instance) +{ + struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num]; + return DC->sessions[0]->c; +} + +struct dc *telegram_get_working_dc(struct telegram *instance) +{ + struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num]; + return DC; +} + +void telegram_restore_session(struct telegram *instance) +{ + char file[256]; + sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "auth"); + instance->auth = read_auth_file(file); + sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "state"); + instance->proto = read_state_file(file); +} + +void telegram_store_session(struct telegram *instance) +{ + char file[256]; + sprintf(file, "%s/%s", instance->config_path, instance->login); + assure_file_exists(file, "auth"); + assure_file_exists(file, "state"); + + sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "auth"); + write_auth_file(instance->auth, file); + + sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "state"); + write_state_file(instance->proto, file); +} + +void telegram_get_downloads_dir(struct telegram *instance) +{ + +} + +void telegram_network_connect(struct telegram *instance, int fd) +{ + on_start (); + struct dc *DC_working = telegram_get_working_dc(instance); + + // check whether authentication is needed + if (!DC_working->auth_key_id) { + logprintf("No working DC, authenticating.\n"); + + // init a new connection + struct connection *c = create_connection (DC_working->ip, DC_working->port, fd); + // init a new session with random session id + dc_create_session(DC_working, c); + + // Request PQ + char byte = 0xef; + assert (write_out (c, &byte, 1) == 1); + send_req_pq_packet (instance); + telegram_change_state(instance, STATE_PQ_REQUESTED, NULL); + } else { + logprintf("Already working session, setting state to connected.\n"); + telegram_change_state(instance, STATE_CONNECTED, NULL); + } +} + +void on_connected(struct telegram *instance) +{ + assert (telegram_get_working_dc(instance)->auth_key_id); + logprintf("Done...\n"); + telegram_store_session(instance); +} + +void on_state_change(struct telegram *instance, int state, void *data) +{ + switch (state) { + case STATE_CONNECTED: + on_connected(instance); + break; + case STATE_ERROR: { + const char* err = data; + logprintf("Telegram errored: %s \n", err); + break; + } + } +} + + +/** + * Read newest rpc response and update state + */ +void try_rpc_interpret(struct telegram *instance, int op, int len) +{ + switch (instance->session_state) { + case STATE_PQ_REQUESTED: + rpc_execute_req_pq(instance, len); + telegram_change_state(instance, STATE_DH_REQUESTED, NULL); + break; + case STATE_DH_REQUESTED: + rpc_execute_rq_dh(instance, len); + telegram_change_state(instance, STATE_CDH_REQUESTED, NULL); + break; + case STATE_CDH_REQUESTED: + rpc_execute_cdh_sent(instance, len); + telegram_change_state(instance, STATE_AUTH_DONE, NULL); + break; + case STATE_AUTH_DONE: + rpc_execute_authorized(instance, op, len); + telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); + do_help_get_config (instance); + break; + case STATE_CONFIG_REQUESTED: + // ? + telegram_store_session(instance); + break; + } +} + +void telegram_read_input (struct telegram *instance) +{ + try_read(instance); } -// template -//void (*on_blarg_handler)(type); -//void on_blarg(void (*handler)(type)) -//{ -// on_blarg_handler = handler; -//} -//void event_blarg(type) -//{ -// if (on_blarg_handler) -// { -// on_blarg_handler(type); -// } -//} diff --git a/telegram.h b/telegram.h index 597014d..77ac0c5 100644 --- a/telegram.h +++ b/telegram.h @@ -2,9 +2,10 @@ * libtelegram * =========== * - * Telegram library based on the telegram cli application, that was originally made by vysheng (see https://github.com/vysheng/tg) + * struct telegram library based on the telegram cli application, that was originally made by vysheng (see https://github.com/vysheng/tg) */ +#pragma once #define MAX_DC_NUM 9 #define MAX_PEER_NUM 100000 @@ -16,72 +17,175 @@ #include "net.h" #include "mtproto-common.h" #include "structures.h" +#include "glib.h" +#include "loop.h" +/* + * Libtelegram states + */ + +#define STATE_INITIALISED 0 +#define STATE_DISCONNECTED 1 + +// Error +#define STATE_ERROR 2 + +// Authentication +#define STATE_PQ_REQUESTED 3 +#define STATE_DH_REQUESTED 4 +#define STATE_CDH_REQUESTED 5 +#define STATE_AUTH_DONE 6 +#define STATE_CONFIG_REQUESTED 7 +#define STATE_EXPORTING_CONFIG 8 +#define STATE_DISCONNECTED_SWITCH_DC 9 + +// Login +#define STATE_CONNECTED 10 + +// - Phone Registration +#define STATE_PHONE_IS_REGISTERED_SENT 11 +#define STATE_PHONE_IS_REGISTERED_SENT_2 12 +#define STATE_PHONE_NOT_REGISTERED 13 +#define STATE_PHONE_CODE_REQUESTED 14 +#define STATE_PHONE_CODE_NOT_ENTERED 15 +#define STATE_PHONE_CODE_ENTERED 16 + +// - Client Registration +#define STATE_CLIENT_IS_REGISTERED_SENT 16 +#define STATE_CLIENT_NOT_REGISTERED 17 +#define STATE_CLIENT_CODE_REQUESTED 18 +#define STATE_CLIENT_CODE_NOT_ENTERED 19 +#define STATE_CLIENT_CODE_ENTERED 20 + +// Ready for sending and receiving messages +#define STATE_READY 21 + /** * A telegram session * - * Contains all globals from the telegram-cli application and should - * be passed to + * Contains all globals from the telegram-cli application is passed to every + * query call */ struct telegram { - - /* - * Read and save the configuration files into this directory - * - * Every distinct account needs its own configuration directory, that - * will be used to store encryption data and the protocol state for this - * specific user - */ - char *config_dir; - - /* - * Reserved for custom protocol data - */ void *protocol_data; - + int curr_dc; + char *login; + const char *config_path; + int session_state; + /* - * Events and Callbacks + * MtProto state */ - // TODO: Insert definitions for all function pointers for event and logging + struct protocol_state proto; + struct authorization_state auth; - /* - * Internal protocol state - */ - // TODO: Insert *all* global variables from the telegram-implementation + GList *change_state_listeners; + void (*on_output)(struct telegram *instance); + void *extra; }; -/* +/** * Constructor */ -void telegram_create( /* struct telegram, struct configuration config */ ); - // TODO: Initiate a new telegram instance +struct telegram *telegram_new(struct dc *DC, const char* login, const char* config_path); -/* +/** + * Resume the session to + */ +void telegram_restore_session(struct telegram *instance); + +/** + * Store + */ +void telegram_store_session(struct telegram *instance); + +/** * Destructor */ -void telegram_destroy(struct telegram instance); - // TODO: Write clean-up functions to free all allocated resources of this session - -// Export functions for plugins - -int tg_login (); - -void running_for_first_time (); -void parse_config (); -void store_config (); -void read_auth_file (); +void telegram_free(struct telegram *instance); /** - * Read and write until all queries received a response or errored + * Get the currently active connection */ -void flush_queries (); +struct connection *telegram_get_connection(struct telegram *instance); + +/** + * Return the current working dc + */ +struct dc *telegram_get_working_dc(struct telegram *instance); + +/* + * Events + */ + +/** + * Handler to process a state change + * + * @param instance The telegram instance that changed its state + * @param state The changed state + * @param data Extra data that depends on switched state + */ +typedef void (*state_listener_t)(struct telegram *instance, int state, void *data); + +/** + * Execute this listener when the state has changed + * + * @param instance The telegram instance + * @param listener The listener to execute + */ +void telegram_add_state_change_listener(struct telegram *instance, state_listener_t listener); + +/** + * Change the state of the given telegram instance and execute all event handlers + * + * @param instance The telegram instance that changed its state + * @param state The changed state + * @param data Extra data that depends on switched state + */ +void telegram_change_state(struct telegram *instance, int state, void *data); /** * Connect to the telegram network with the given configuration */ -void network_connect(); +void telegram_network_connect (struct telegram *instance, int fd); + +/** + * Read the authorization_state stored in the given file + */ + +// Export functions for plugins +void running_for_first_time (); + +/* TODO: Remove? +void parse_config (); +void store_config (); +*/ + +/** + * Read and write until all queries received a response or errored + */ +void telegram_flush_queries (struct telegram *instance); + +/** + * Read and process all available input from the network + */ +void telegram_read_input (struct telegram *instance); + +/** + * Write all available output to the network + */ +void telegram_write_output (struct telegram *instance); + +/** + * Try to interpret RPC calls and apply the changes to the current telegram state + */ +void try_rpc_interpret(struct telegram *instance, int op, int len); + +/* + * TODO: Refactor all old calls to take a telegrma instance + */ /** * Request a registration code @@ -130,17 +234,9 @@ void session_update_contact_list(); void on_update_new_message(void (*on_msg)(struct message *M)); void event_update_new_message(struct message *M); -void on_update_user_typing(); -void on_update_chat_user_typing(); -void on_update_user_status(); -void on_update_user_name(); -void on_update_user_photo(); -void on_update_chat_participants(); - /* * Load known users and chats on connect */ - void on_peer_allocated(void (*handler)(peer_t *peer)); void event_peer_allocated(peer_t *peer); @@ -152,37 +248,16 @@ void event_peer_allocated(peer_t *peer); * Set a function to use as a handle to read from a network resource * instead of the regular socket read function */ -void set_net_read_cb(int (*cb)(int fd, void *buff, size_t size)); +void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)); /** * Set a function to use as handle to write to a newtork resource * instead of the regular socket write function */ -void set_net_write_cb(int (*cb)(int fd, const void *buff, size_t size)); - -/** - * The current proxy connection source. - */ -extern void (*proxy_connection_source)(const char *host, int port, void (*on_connection_created)(int fd)); - -/** - * The connection data passed to the connection source. - */ -extern void *proxy_connection_data; - -/** - * Set an alternative connection_source which is used to create open connections instead of the - * regular function. - * - * @param connection_source Called when a new connection is needed. A connection source must accept - * host and port and pass a valid file descriptor to an open TCP-Socket to the - * callback function on_connection_created - * @param data Additional connection data, that will be passed to the callback and may be - * needed for establishing the connection. - */ -void set_proxy_connection_source (void (*connection_source)(const char *host, int port, void (*on_connection_created)(int fd)), void* data); +void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); /** * */ void set_default_username (); + From 8a2c043db4da87fa73372529e2ccd1f63f977d56 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 29 Jul 2014 15:28:04 +0200 Subject: [PATCH 333/465] Refactor - Intermediate Commit 2 --- Makefile.in | 9 +- binlog.c | 38 +++++++-- binlog.h | 3 +- loop.c | 101 ++++++++++------------ loop.h | 7 +- mtproto-client.c | 58 ++++++++----- mtproto-client.h | 4 +- mtproto-common.h | 1 + net.c | 57 ++++++------- net.h | 7 +- purple-plugin/telegram-purple.c | 72 +++++++++++----- purple-plugin/telegram-purple.h | 10 +++ queries.c | 38 ++++----- queries.h | 8 +- telegram.c | 146 ++++++++++++++++++++++---------- telegram.h | 24 +++++- tools.c | 26 ++++++ tools.h | 1 + 18 files changed, 388 insertions(+), 222 deletions(-) diff --git a/Makefile.in b/Makefile.in index 865eb7f..aec2ce2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,6 +53,7 @@ PRPL_CFLAGS = \ -fPIC \ -DPURPLE_PLUGINS \ -DPIC \ + -DDEBUG \ -g \ $(CFLAGS_PURPLE) @@ -84,10 +85,6 @@ plugin: $(PRPL_LIBNAME) strip: $(PRPL_LIBNAME) $(STRIP) --strip-unneeded $(PRPL_LIBNAME) -debug: PRPL_CFLAGS += -g -DDEBUG -debug: $(PRPL_LIBNAME) - gdb -tui -ex 'break telegram-purple.c:tgprpl_login' pidgin - # TODO: Find a better place for server.pub install: $(PRPL_LIBNAME) install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) @@ -108,6 +105,10 @@ uninstall: $(PRPL_LIBNAME) run: install pidgin -d | grep 'telegram\|plugin\|proxy' +.PHONY: debug +debug: install + gdb -tui -ex "$(shell echo $$GDB_BPOINTS )" pidgin + clean: rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean" diff --git a/binlog.c b/binlog.c index 13dd663..58d85c1 100644 --- a/binlog.c +++ b/binlog.c @@ -56,7 +56,13 @@ extern int seq; #define MAX_LOG_EVENT_SIZE (1 << 17) +// TODO: remove this completely char *get_binlog_file_name (void); +char *get_binlog_file_name() +{ + return "/home/dev-jessie/.telegram/binlog"; +} + //extern struct dc *DC_list[]; //extern int dc_working_num; extern int our_id; @@ -1162,9 +1168,9 @@ void write_binlog (void) { } void add_log_event (const int *data, int len) { - if (verbosity) { - logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); - } + logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); + assert(0); + // TODO: Mit add_log_event_i austauschen assert (!(len & 3)); if (in_replay_log) { return; } rptr = (void *)data; @@ -1185,7 +1191,29 @@ void add_log_event (const int *data, int len) { in_end = end; } -void bl_do_set_auth_key_id (int num, unsigned char *buf) { +void add_log_event_i (struct telegram *instance, const int *data, int len) { + logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); + assert (!(len & 3)); + if (in_replay_log) { return; } + rptr = (void *)data; + wptr = rptr + (len / 4); + int *in = in_ptr; + int *end = in_end; + // TODO: + replay_log_event (instance); + if (rptr != wptr) { + logprintf ("Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len); + assert (rptr == wptr); + } + if (binlog_enabled) { + assert (binlog_fd > 0); + assert (write (binlog_fd, data, len) == len); + } + in_ptr = in; + in_end = end; +} + +void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf) { static unsigned char sha1_buffer[20]; SHA1 (buf, 256, sha1_buffer); long long fingerprint = *(long long *)(sha1_buffer + 12); @@ -1194,7 +1222,7 @@ void bl_do_set_auth_key_id (int num, unsigned char *buf) { ev[1] = num; *(long long *)(ev + 2) = fingerprint; memcpy (ev + 4, buf, 256); - add_log_event (ev, 8 + 8 + 256); + add_log_event_i (instance, ev, 8 + 8 + 256); } void bl_do_set_our_id (int id) { diff --git a/binlog.h b/binlog.h index c72699a..370ea55 100644 --- a/binlog.h +++ b/binlog.h @@ -87,8 +87,9 @@ void *alloc_log_event (int l); void replay_log (struct telegram *instance); void add_log_event (const int *data, int l); +void add_log_event_i (struct telegram *instance, const int *data, int l); void write_binlog (void); -void bl_do_set_auth_key_id (int num, unsigned char *buf); +void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf); void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); diff --git a/loop.c b/loop.c index fd29ca3..e3d20ef 100644 --- a/loop.c +++ b/loop.c @@ -148,6 +148,7 @@ int is_got_it (void) { return got_it_ok; } +/* int net_getline (char **s, size_t *l) { fflush (stdout); // rl_already_prompted = 1; @@ -155,16 +156,19 @@ int net_getline (char **s, size_t *l) { _s = s; _l = l; // rl_callback_handler_install (0, got_it); - net_loop (2, is_got_it); + //net_loop (2, is_got_it); return 0; } +*/ int ret1 (void) { return 0; } +/* int main_loop (void) { net_loop (1, ret1); return 0; } +*/ //struct dc *DC_list[MAX_DC_ID + 1]; @@ -177,6 +181,7 @@ int zero[512]; void write_dc (int auth_file_fd, struct dc *DC) { + logprintf("writing to auth_file: auth_file_fd: %d, port: %d, ip: %s\n", auth_file_fd, DC->port, DC->ip); assert (write (auth_file_fd, &DC->port, 4) == 4); int l = strlen (DC->ip); assert (write (auth_file_fd, &l, 4) == 4); @@ -194,28 +199,28 @@ void write_dc (int auth_file_fd, struct dc *DC) { int our_id; -void write_auth_file (struct authorization_state state, const char *filename) { - if (binlog_enabled) { return; } - int auth_file_fd = open (filename /*get_auth_key_filename ()*/, O_CREAT | O_RDWR, 0600); +void write_auth_file (struct authorization_state *state, const char *filename) { + logprintf("Writing to auth_file: %s\n", filename); + int auth_file_fd = open (filename, O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); 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); - assert (write (auth_file_fd, &state.dc_working_num, 4) == 4); - assert (write (auth_file_fd, &state.auth_state, 4) == 4); + assert (write (auth_file_fd, &state->dc_working_num, 4) == 4); + assert (write (auth_file_fd, &state->auth_state, 4) == 4); int i; for (i = 0; i <= MAX_DC_ID; i++) { - if (state.DC_list[i]) { + if (state->DC_list[i]) { x = 1; assert (write (auth_file_fd, &x, 4) == 4); - write_dc (auth_file_fd, state.DC_list[i]); + write_dc (auth_file_fd, state->DC_list[i]); } else { x = 0; assert (write (auth_file_fd, &x, 4) == 4); } } - assert (write (auth_file_fd, &state.our_id, 4) == 4); + assert (write (auth_file_fd, &state->our_id, 4) == 4); close (auth_file_fd); } @@ -232,9 +237,6 @@ void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) { assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (read (auth_file_fd, &DC->auth_key, 256) == 256); assert (read (auth_file_fd, &DC->server_salt, 8) == 8); - logprintf("auth_key_id: %lli \n", DC->auth_key_id); - logprintf("auth_key_id: ?"); - logprintf("server_salt: %lli \n", DC->server_salt); if (DC->auth_key_id) { DC->flags |= 1; } @@ -247,23 +249,33 @@ void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) { void empty_auth_file (struct authorization_state *state, const char *filename) { + logprintf("empty_auth_file()\n"); alloc_dc (state->DC_list, 1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); state->dc_working_num = 1; state->auth_state = 0; - write_auth_file (*state, filename); + write_auth_file (state, filename); } +/** + * Read the auth-file and return the read authorization state + * + * When the given file doesn't exist, create a new empty + * file containing the default authorization state at this + * path + */ struct authorization_state read_auth_file (const char *filename) { - struct authorization_state state; - state.dc_working_num = 0; - state.auth_state = 0; - state.our_id = 0; + logprintf("read_auth_file()\n"); - if (binlog_enabled) { return state; } - int auth_file_fd = open (filename /*get_auth_key_filename ()*/, O_CREAT | O_RDWR, 0600); + struct authorization_state state; + memset(state.DC_list, 0, 11 * sizeof(void *)); + + int auth_file_fd = open (filename, O_RDWR, 0600); + logprintf("fd: %d\n", auth_file_fd); if (auth_file_fd < 0) { + logprintf("auth_file does not exist, creating empty...\n"); empty_auth_file (&state, filename); } + auth_file_fd = open (filename, O_RDWR, 0600); assert (auth_file_fd >= 0); // amount of data centers @@ -271,6 +283,7 @@ struct authorization_state read_auth_file (const char *filename) { // magic number of file unsigned m; if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) { + logprintf("Invalid File content, wrong Magic numebr\n"); close (auth_file_fd); empty_auth_file (&state, filename); return state; @@ -288,6 +301,10 @@ struct authorization_state read_auth_file (const char *filename) { assert (read (auth_file_fd, &y, 4) == 4); if (y) { read_dc (auth_file_fd, i, m, state.DC_list); + logprintf("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n", + i, state.DC_list[i]->port, state.DC_list[i]->ip, state.DC_list[i]->auth_key_id, state.DC_list[i]->server_salt, state.DC_list[i]->has_auth); + } else { + logprintf("loaded dc[%d] - NULL\n", i); } } int l = read (auth_file_fd, &state.our_id, 4); @@ -299,20 +316,17 @@ struct authorization_state read_auth_file (const char *filename) { if (m == DC_SERIALIZED_MAGIC) { DC_working->has_auth = 1; } + logprintf("loaded authorization state - our_id: %d, auth_state: %d, dc_working_num: %d \n", state.our_id, state.auth_state, state.dc_working_num); return state; } int pts, qts, seq, last_date; struct protocol_state read_state_file (const char *filename) { - struct protocol_state state; - state.last_date = 0; - state.qts = 0; - state.pts = 0; - state.seq = 0; + logprintf("read_state_file()\n"); + struct protocol_state state = {0, 0, 0, 0}; - if (binlog_enabled) { return state; } - int state_file_fd = open (filename/*get_state_filename ()*/, O_CREAT | O_RDWR, 0600); + int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600); if (state_file_fd < 0) { return state; } @@ -331,11 +345,12 @@ struct protocol_state read_state_file (const char *filename) { state.seq = x[2]; state.last_date = x[3]; close (state_file_fd); + logprintf("loaded session state - pts: %d, qts: %d, seq: %d, last_date: %d.\n", state.pts, + state.qts, state.seq, state.last_date); return state; } -void write_state_file (struct protocol_state state, const char* filename) { - if (binlog_enabled) { return; } +void write_state_file (struct protocol_state *state, const char* filename) { /* static int wseq; static int wpts; @@ -350,10 +365,10 @@ void write_state_file (struct protocol_state state, const char* filename) { int x[6]; x[0] = STATE_FILE_MAGIC; x[1] = 0; - x[2] = state.pts; - x[3] = state.qts; - x[4] = state.seq; - x[5] = state.last_date; + x[2] = state->pts; + x[3] = state->qts; + x[4] = state->seq; + x[5] = state->last_date; assert (write (state_file_fd, x, 24) == 24); close (state_file_fd); //wseq = seq; wpts = pts; wqts = qts; wdate = last_date; @@ -569,32 +584,10 @@ int network_verify_phone_registration(const char* code, const char *sms_hash, { logprintf("Registering with code:%s, hash:%s, first:%s, last:%s\n", code, sms_hash, first, last); - if (do_send_code_result_auth (code, sms_hash, first, last) >= 0) { - logprintf ("Authentication successfull, state = 300\n"); - auth_state = 300; - return 1; - } return 0; } */ -/** - * Verify the current client by providing the given code - */ - /* -int network_verify_registration(const char *code, const char *sms_hash) -{ - logprintf("Verifying with hash:%s, code:%s\n", code, sms_hash); - int state; - if ((state = do_send_code_result (code, sms_hash)) >= 0) { - logprintf ("Authentication successfull, state = 300\n"); - auth_state = 300; - return 1; - } - return 0; -} -*/ - /** * Export current authentication state to all known data centers. */ diff --git a/loop.h b/loop.h index 467b454..12a56a5 100644 --- a/loop.h +++ b/loop.h @@ -24,7 +24,6 @@ #ifndef __LOOP_H__ #define __LOOP_H__ int loop(); -void net_loop (int flags, int (*end)(void)); void write_secret_chat_file (const char *filename); #endif @@ -38,14 +37,14 @@ struct protocol_state { struct authorization_state { int dc_working_num; int auth_state; - struct dc *DC_list[11]; + struct dc* DC_list[11]; int our_id; }; -void write_auth_file (struct authorization_state state, const char *filename); +void write_auth_file (struct authorization_state *state, const char *filename); struct authorization_state read_auth_file (const char *filename); -void write_state_file (struct protocol_state state, const char *filename); +void write_state_file (struct protocol_state *state, const char *filename); struct protocol_state read_state_file (const char *filename); void on_start(); diff --git a/mtproto-client.c b/mtproto-client.c index bda8bf7..00aed25 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -85,6 +85,8 @@ int allow_weak_random = 0; int total_packets_sent; long long total_data_sent; +extern int queries_num; + /* int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); @@ -224,6 +226,8 @@ int rpc_send_packet (struct connection *c) { //flush_out (c); total_packets_sent ++; + queries_num++; + logprintf("pending queries: %d\n", queries_num); total_data_sent += total_len; return 1; } @@ -248,6 +252,9 @@ int rpc_send_message (struct connection *c, void *data, int len) { } int send_req_pq_packet (struct connection *c) { + char byte = 0xef; + assert (write_out (c, &byte, 1) == 1); + assert (c_state == st_init); secure_random (nonce, 16); unenc_msg_header.out_msg_id = 0; @@ -255,6 +262,7 @@ int send_req_pq_packet (struct connection *c) { out_int (CODE_req_pq); out_ints ((int *)nonce, 4); rpc_send_packet (c); + c_state = st_reqpq_sent; return 1; } @@ -539,9 +547,7 @@ int check_g_bn (BIGNUM *p, BIGNUM *g) { } int process_dh_answer (struct connection *c, char *packet, int len) { - if (verbosity) { - logprintf ( "process_dh_answer(), len=%d\n", len); - } + logprintf ( "process_dh_answer(), len=%d\n", len); if (len < 116) { logprintf ( "%u * %u = %llu", p1, p2, what); } @@ -633,15 +639,13 @@ int process_dh_answer (struct connection *c, char *packet, int len) { out_cstring ((char *) encrypt_buffer, l); c_state = st_client_dh_sent; - return rpc_send_packet (c); } int process_auth_complete (struct connection *c UU, char *packet, int len) { - if (verbosity) { - logprintf ( "process_dh_answer(), len=%d\n", len); - } + + logprintf ( "process_dh_answer(), len=%d\n", len); assert (len == 72); assert (!*(long long *) packet); assert (*(int *) (packet + 16) == len - 20); @@ -654,7 +658,8 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { tmp[32] = 1; //GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); - bl_do_set_auth_key_id (GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); + bl_do_set_auth_key_id (c->instance, GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); + sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); memcpy (tmp + 33, sha1_buffer, 8); @@ -662,9 +667,8 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; - if (verbosity >= 3) { - logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); - } + logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); + //logprintf ( "auth_key=%s\n", GET_DC(c)->auth_key); //kprintf ("OK\n"); //c->status = conn_error; @@ -672,9 +676,7 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { c_state = st_authorized; //return 1; - if (verbosity) { - logprintf ( "Auth success\n"); - } + logprintf ( "Auth success\n"); auth_success ++; GET_DC(c)->flags |= 1; @@ -804,7 +806,7 @@ void fetch_pts (void) { } else { pts ++; } - bl_do_set_pts (pts); + //bl_do_set_pts (pts); } void fetch_qts (void) { @@ -821,14 +823,14 @@ void fetch_qts (void) { } else { qts ++; } - bl_do_set_qts (qts); + //bl_do_set_qts (qts); } void fetch_date (void) { int p = fetch_int (); if (p > last_date) { last_date = p; - bl_do_set_date (last_date); + //bl_do_set_date (last_date); } } @@ -1252,9 +1254,7 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram case CODE_update_encryption: { struct secret_chat *E = fetch_alloc_encrypted_chat (); - if (verbosity >= 2) { - logprintf ("Secret chat state = %d\n", E->state); - } + logprintf ("Secret chat state = %d\n", E->state); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1776,48 +1776,59 @@ int process_rpc_message (struct telegram *instance, struct encrypted_message *en //} int rpc_execute_req_pq (struct telegram *instance, int len) { + logprintf("rpc_execute_rq_dh()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); + queries_num--; return 0; } int rpc_execute_rq_dh (struct telegram *instance, int len) { + logprintf("rpc_execute_rq_dh()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); + queries_num--; return 0; } int rpc_execute_cdh_sent (struct telegram *instance, int len) { + logprintf("rpc_execute_cdh()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); + queries_num--; return 0; } int rpc_execute_authorized (struct telegram *instance, int op, int len) { + logprintf("rpc_execute_authorized()\n"); struct connection *c = telegram_get_connection(instance); if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { logprintf ( "answer too long (%d bytes), skipping\n", len); + queries_num--; return 0; } int Response_len = len; @@ -1828,11 +1839,10 @@ int rpc_execute_authorized (struct telegram *instance, int op, int len) { } else { process_rpc_message (instance, (void *)(Response/* + 8*/), Response_len/* - 12*/); } + queries_num--; return 0; } - - int tc_close (struct connection *c, int who) { if (verbosity) { logprintf ( "outbound http connection #%d : closing by %d\n", c->fd, who); @@ -1900,11 +1910,13 @@ int auth_ok (void) { return auth_success; } +/* void dc_authorize (struct dc *DC) { c_state = 0; auth_success = 0; if (verbosity) { logprintf ( "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); } - net_loop (0, auth_ok); + //net_loop (0, auth_ok); } +*/ diff --git a/mtproto-client.h b/mtproto-client.h index 49f8891..d5a581f 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -23,7 +23,7 @@ #include void on_start (void); long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); -void dc_authorize (struct dc *DC); +//void dc_authorize (struct dc *DC); void work_update (struct connection *c, long long msg_id); void work_update_binlog (void); int check_g (unsigned char p[256], BIGNUM *g); @@ -32,7 +32,7 @@ int check_DH_params (BIGNUM *p, int g); void secure_random (void *s, int l); -int send_req_pq_packet (struct telegram *instance); +int send_req_pq_packet (struct connection *c); int rpc_execute_req_pq (struct telegram *instance, int len); int rpc_execute_rq_dh (struct telegram *instance, int len); diff --git a/mtproto-common.h b/mtproto-common.h index 0dbf71d..da8c49f 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -20,6 +20,7 @@ #ifndef __MTPROTO_COMMON_H__ #define __MTPROTO_COMMON_H__ +#include #include #include #include diff --git a/net.c b/net.c index 0570d65..d42cc6a 100644 --- a/net.c +++ b/net.c @@ -113,10 +113,11 @@ void start_ping_timer (struct connection *c) { insert_event_timer (&c->ev); } -void restart_connection (struct connection *c); int fail_alarm (void *ev) { - ((struct connection *)ev)->in_fail_timer = 0; - restart_connection (ev); + struct connection *c = ev; + c->in_fail_timer = 0; + logprintf("Connection %d FAILED.", c->fd); + telegram_change_state(c->instance, STATE_ERROR, NULL); return 0; } void start_fail_timer (struct connection *c) { @@ -251,13 +252,14 @@ void rotate_port (struct connection *c) { } } -struct connection *create_connection (const char *host, int port, int fd) { +struct connection *create_connection (const char *host, int port, int fd, struct telegram *instance) { struct connection *c = talloc0 (sizeof (*c)); c->fd = fd; c->ip = tstrdup (host); c->flags = 0; c->state = conn_ready; c->port = port; + c->instance = instance; if (verbosity) { logprintf ( "connect to %s:%d successful\n", host, port); } @@ -316,12 +318,11 @@ void restart_connection (struct connection *c) { assert (write_out (c, &byte, 1) == 1); flush_out (c); } - +*/ void fail_connection (struct connection *c) { if (c->state == conn_ready || c->state == conn_connecting) { stop_ping_timer (c); } - rotate_port (c); struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; @@ -338,18 +339,15 @@ void fail_connection (struct connection *c) { c->state = conn_failed; c->out_bytes = c->in_bytes = 0; close (c->fd); - Connections[c->fd] = 0; logprintf ("Lost connection to server... %s:%d\n", c->ip, c->port); - restart_connection (c); + telegram_change_state(c->instance, STATE_ERROR, NULL); } -*/ extern FILE *log_net_f; -void try_write (struct telegram *instance) { +int try_write (struct telegram *instance) { struct connection *c = telegram_get_connection(instance); - if (verbosity) { - logprintf ( "try write: fd = %d\n", c->fd); - } + logprintf ("try write: fd = %d\n", c->fd); + int x = 0; while (c->out_head) { int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); @@ -359,7 +357,6 @@ void try_write (struct telegram *instance) { fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { - fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); } fprintf (log_net_f, "\n"); @@ -387,16 +384,15 @@ void try_write (struct telegram *instance) { logprintf ("fail_connection: write_error %m\n"); } fail_connection (c); - return; + return 0; } else { break; } } } - if (verbosity) { - logprintf ( "Sent %d bytes to %d\n", x, c->fd); - } + logprintf ( "Sent %d bytes to %d\n", x, c->fd); c->out_bytes -= x; + return x; } void hexdump_buf (struct connection_buffer *b) { @@ -423,6 +419,9 @@ void hexdump_buf (struct connection_buffer *b) { } +/** + * Read all rpc responses from the current connection + */ void try_rpc_read (struct telegram *instance) { struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; @@ -467,10 +466,7 @@ void try_rpc_read (struct telegram *instance) { void try_read (struct telegram *instance) { struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; - - if (verbosity) { - logprintf ( "try read: fd = %d\n", c->fd); - } + logprintf ( "try read: fd = %d\n", c->fd); if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } @@ -489,9 +485,11 @@ void try_read (struct telegram *instance) { } if (r > 0) { c->last_receive_time = get_double_time (); + + // TODO: Implement the Ping-Timer // reset ping timer - stop_ping_timer (c); - start_ping_timer (c); + //stop_ping_timer (c); + //start_ping_timer (c); } if (r >= 0) { // write pointer nach vorne setzen @@ -507,9 +505,7 @@ void try_read (struct telegram *instance) { c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - if (verbosity) { - logprintf ("fail_connection: read_error %m\n"); - } + logprintf ("fail_connection: read_error %m\n"); fail_connection (c); return; } else { @@ -517,9 +513,7 @@ void try_read (struct telegram *instance) { } } } - if (verbosity) { - logprintf ( "Received %d bytes from %d\n", x, c->fd); - } + logprintf ( "Received %d bytes from %d\n", x, c->fd); c->in_bytes += x; if (x) { try_rpc_read (instance); @@ -609,10 +603,7 @@ void insert_msg_id (struct session *S, long long id) { } } -extern struct dc *DC_list[]; - struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { - assert (!DC_list[id]); struct dc *DC = talloc0 (sizeof (*DC)); DC->id = id; DC->ip = ip; diff --git a/net.h b/net.h index 10ec628..7725222 100644 --- a/net.h +++ b/net.h @@ -130,6 +130,7 @@ struct connection { void *extra; struct event_timer ev; double last_receive_time; + struct telegram *instance; }; extern struct connection *Connections[]; @@ -140,7 +141,7 @@ int read_in (struct connection *c, void *data, int len); void create_all_outbound_connections (void); -struct connection *create_connection (const char *host, int port, int fd); +struct connection *create_connection (const char *host, int port, int fd, struct telegram *instance); int connections_make_poll_array (struct pollfd *fds, int max); void connections_poll_result (struct pollfd *fds, int max); void insert_msg_id (struct session *S, long long id); @@ -151,8 +152,8 @@ void dc_create_session (struct dc *DC, struct connection *c); void try_read (struct telegram *instance); void try_rpc_read (struct telegram *instance); -void try_write (struct telegram *instance); +int try_write (struct telegram *instance); -#define GET_DC(c) (c->session->dc) +#define GET_DC(c) (telegram_get_working_dc(c->instance)) #endif diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 4cf58c9..cb09b16 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -20,6 +20,7 @@ #include #include #include +#include // test @@ -42,6 +43,7 @@ #include "prpl.h" #include "prefs.h" #include "util.h" +#include "eventloop.h" // struct telegram Includes #include "telegram.h" @@ -105,7 +107,6 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info /** * Request a verification key, save the returned verification_hash in the account settings * for later usage and inform the user. - */ static void login_request_verification(PurpleAccount *acct) { // TODO: we should find a way to request the key @@ -119,6 +120,7 @@ static void login_request_verification(PurpleAccount *acct) "You need to verify this device, please enter the code struct telegram has sent to you by SMS.", NULL, NULL, NULL); } + */ /** * Handle a failed verification, by removing the invalid sms code and @@ -135,25 +137,52 @@ static void login_verification_fail(PurpleAccount *acct) static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition cond) { logprintf("tgprpl_output_cb()\n"); - PurpleConnection *c = data; - telegram_conn *conn = purple_connection_get_protocol_data(c); - telegram_write_output(conn->tg); + struct telegram *tg = data; + telegram_conn *conn = tg->extra; + + int written = telegram_write_output(tg); + logprintf("written(%d): %d.\n", telegram_get_connection(tg)->fd, written); + if (written == 0) { + logprintf("no output, removing output...\n"); + purple_input_remove(conn->wh); + conn->wh = 0; + } +} + +static void tgprpl_has_output(struct telegram *tg) +{ + logprintf("tgprpl_has_output()\n"); + telegram_conn *conn = tg->extra; + if (! conn->wh) { + conn->wh = purple_input_add(telegram_get_connection(tg)->fd, PURPLE_INPUT_WRITE, + tgprpl_output_cb, tg); + logprintf("Attached write handle: %u ", conn->wh); + } } static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition cond) { + struct telegram *tg = data; + //telegram_conn *conn = tg->extra; logprintf("tgprpl_input_cb()\n"); - PurpleConnection *c = data; - telegram_conn *conn = purple_connection_get_protocol_data(c); - telegram_read_input(conn->tg); + + // TODO: remove input handler when no more input + telegram_read_input(tg); + if (telegram_has_output(tg)) { + tgprpl_has_output(tg); + } } -/* -static void tgprpl_on_input(struct telegram *tg) +static void tgprpl_has_input(struct telegram *tg) { - PurpleConnection *c = data; + logprintf("tgprpl_has_input()\n"); + telegram_conn *conn = tg->extra; + if (! conn->rh) { + conn->rh = purple_input_add(telegram_get_connection(tg)->fd, PURPLE_INPUT_READ, + tgprpl_input_cb, tg); + logprintf("Attached read handle: %u ", conn->rh); + } } -*/ static void tgprpl_on_state_change(struct telegram *instance, int state, void *data) { @@ -175,7 +204,8 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d NULL, NULL, NULL); return; } - network_verify_phone_registration(code, hash, first_name, last_name); + + do_send_code_result_auth (instance, code, hash, first_name, last_name); break; case STATE_PHONE_CODE_NOT_ENTERED: @@ -190,7 +220,7 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d case STATE_CLIENT_CODE_NOT_ENTERED: { const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); - network_verify_registration(code, hash); + do_send_code_result(instance, code, hash); // enter SMS code } break; @@ -270,14 +300,13 @@ static void tgprpl_login(PurpleAccount * acct) purple_connection_set_state(gc, PURPLE_CONNECTING); purple_proxy_connect(gc, acct, DC.ip, DC.port, tgprpl_login_on_connected, tg); - purple_debug_info(PLUGIN_ID, "username: %s\n", username); - purple_debug_info(PLUGIN_ID, "hostname: %s\n", DC.ip); } void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) { purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); struct telegram *tg = (struct telegram*) data; + telegram_conn *conn = tg->extra; //running_for_first_time(); if (fd == -1) { @@ -286,9 +315,10 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa return; } - purple_debug_info(PLUGIN_ID, "Connecting to the struct telegram network...\n"); - purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, telegram_get_connection(tg)); - purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, telegram_get_connection(tg)); + + purple_debug_info(PLUGIN_ID, "Connecting to the telegram network...\n"); + conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, tg); + conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg); telegram_network_connect(tg, fd); // // load all settings: the known network topology, secret keys, logs and configuration file paths @@ -896,10 +926,10 @@ static PurplePluginInfo info = { NULL, PURPLE_PRIORITY_DEFAULT, PLUGIN_ID, - "struct telegram", + "Telegram", "0.1", - "struct telegram integration.", - "Adds support for the struct telegram protocol to libpurple.", + "Telegram protocol", + "Adds support for the telegram protocol to libpurple.", "Christopher Althaus , Markus Endres , Matthias Jentsch ", "https://bitbucket.org/telegrampurple/telegram-purple", NULL, // on load diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 433e7f3..24536d8 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -39,4 +39,14 @@ typedef struct { struct telegram *tg; PurpleAccount *pa; PurpleConnection *gc; + + /** + * Write handler returned by purple_input_add + */ + guint wh; + + /** + * Read handler returned by purple_input_add + */ + guint rh; } telegram_conn; diff --git a/queries.c b/queries.c index 3f07807..db61e6e 100644 --- a/queries.c +++ b/queries.c @@ -196,14 +196,10 @@ void query_error (long long id) { int error_code = fetch_int (); int error_len = prefetch_strlen (); char *error = fetch_str (error_len); - if (verbosity) { - logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); - } + logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); struct query *q = query_get (id); if (!q) { - if (verbosity) { - logprintf ( "No such query\n"); - } + logprintf ( "No such query\n"); } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { remove_event_timer (&q->ev); @@ -281,16 +277,12 @@ DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) struct tree_timer *timer_tree; void insert_event_timer (struct event_timer *ev) { - if (verbosity > 2) { - logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - } + logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); timer_tree = tree_insert_timer (timer_tree, ev, lrand48 ()); } void remove_event_timer (struct event_timer *ev) { - if (verbosity > 2) { - logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - } + logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); timer_tree = tree_delete_timer (timer_tree, ev); } @@ -641,14 +633,14 @@ struct query_methods nearest_dc_methods = { .on_error = fail_on_error }; -int do_get_nearest_dc (struct telegram *instance) { +void do_get_nearest_dc (struct telegram *instance) { struct dc *DC_working = telegram_get_working_dc(instance); 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; + //net_loop (0, nr_f); + //return nearest_dc_num; } /* }}} */ @@ -702,7 +694,7 @@ struct query_methods sign_in_methods = { .on_error = sign_in_on_error }; -int do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash) { +void do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash) { struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_auth_sign_in); @@ -710,12 +702,14 @@ int do_send_code_result (struct telegram *instance, const char *code, const char out_string(sms_hash); out_string (code); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, instance); + /* sign_in_ok = 0; - net_loop (0, sign_in_is_ok); + //net_loop (0, sign_in_is_ok); return sign_in_ok; + */ } -int do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { +void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (); out_int (CODE_auth_sign_up); @@ -725,9 +719,11 @@ int do_send_code_result_auth (struct telegram *instance, const char *code, const out_string (first_name); out_string (last_name); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, instance); + /* sign_in_ok = 0; net_loop (0, sign_in_is_ok); return sign_in_ok; + */ } /* }}} */ @@ -1987,9 +1983,9 @@ void load_next_part (struct telegram *instance, struct download *D) { static char buf[PATH_MAX]; int l; if (!D->id) { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", get_downloads_directory (), D->volume, D->local_id); + l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", instance->download_path, D->volume, D->local_id); } else { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", get_downloads_directory (), D->id); + l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", instance->download_path, D->id); } if (l >= (int) sizeof (buf)) { logprintf ("Download filename is too long"); @@ -2195,7 +2191,6 @@ void do_export_auth (struct telegram *instance, int num) { 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); } /* }}} */ @@ -2220,7 +2215,6 @@ void do_import_auth (struct telegram *instance, int num) { out_int (our_id); out_cstring (export_auth_str, export_auth_str_len); send_query (instance->auth.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 dd6588e..a7730fa 100644 --- a/queries.h +++ b/queries.h @@ -69,7 +69,7 @@ extern struct query_methods help_get_config_methods; void do_send_code (struct telegram *instance, const char *user); void do_phone_call (struct telegram *instance, const char *user); -int do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash); +void do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash); double get_double_time (void); void do_update_contact_list (struct telegram *instance); @@ -101,8 +101,8 @@ void do_load_document (struct telegram *instance, struct document *V, int next); void do_load_document_thumb (struct telegram *instance, struct document *video, int next); void do_help_get_config (struct telegram *instance); int do_auth_check_phone (struct telegram *instance, const char *user); -int do_get_nearest_dc (struct telegram*); -int do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name); +void do_get_nearest_dc (struct telegram*); +void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name); void do_import_auth (struct telegram *instance, int num); void do_export_auth (struct telegram *instance, int num); void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); @@ -127,3 +127,5 @@ void fetch_dc_option (struct telegram *instance); #endif const char *get_last_err(); + +int all_queries_done(); diff --git a/telegram.c b/telegram.c index f712483..ba51d03 100755 --- a/telegram.c +++ b/telegram.c @@ -4,17 +4,15 @@ #include #include #include +#include #include "mtproto-common.h" #include "telegram.h" #include "msglog.h" #include "glib.h" +#include "tools.h" #include "mtproto-client.h" -/* - * Events - */ - /* * New message received */ @@ -55,7 +53,7 @@ void telegram_add_state_change_listener(struct telegram *instance, state_listene } void telegram_change_state(struct telegram *instance, int state, void *data) { - logprintf("Changing struct telegram state %d\n", state); + logprintf("telegram connection state changed to: %d\n", state); instance->session_state = state; GList *curr = instance->change_state_listeners; while ((curr = g_list_next(change_listeners)) != NULL) { @@ -65,22 +63,40 @@ void telegram_change_state(struct telegram *instance, int state, void *data) struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path) { + on_start (); struct telegram *this = malloc(sizeof(struct telegram)); this->protocol_data = NULL; this->curr_dc = 0; this->auth.DC_list[0] = DC; this->change_state_listeners = NULL; - this->config_path = config_path; - strcpy(this->login, malloc(strlen(login) + 1)); + + this->login = g_strdup(login); + this->config_path = g_strdup_printf("%s/%s", config_path, login); + this->download_path = telegram_get_config(this, "downloads"); + this->auth_path = telegram_get_config(this, "auth"); + this->state_path = telegram_get_config(this, "state"); + this->secret_path = telegram_get_config(this, "secret"); + + logprintf("%s\n", this->login); + logprintf("%s\n", this->config_path); + logprintf("%s\n", this->download_path); + logprintf("%s\n", this->auth_path); + logprintf("%s\n", this->state_path); + telegram_change_state(this, STATE_INITIALISED, NULL); return this; } -void telegram_free(struct telegram *instance) +void telegram_free(struct telegram *this) { - g_list_free(instance->change_state_listeners); - free(instance->login); - free(instance); + g_list_free(this->change_state_listeners); + g_free(this->login); + g_free(this->config_path); + g_free(this->download_path); + g_free(this->auth_path); + g_free(this->state_path); + g_free(this->secret_path); + free(this); } void assert_file_usable(const char *file) @@ -90,56 +106,80 @@ void assert_file_usable(const char *file) void assure_file_exists(const char *dir, const char *file) { - char f[256]; g_mkdir_with_parents(dir, 0700); - sprintf(f, "%s/%s", dir, file); + char *f = g_strdup_printf("%s/%s", dir, file); close(open(f, O_RDWR | O_CREAT, S_IRUSR, S_IWUSR)); assert_file_usable(f); + g_free(f); } +/** + * Get the currently used connection + * + * Will only work after telegram_connect has been called and the connection has + * not errored. + */ struct connection *telegram_get_connection(struct telegram *instance) { - struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num]; + assert(instance->session_state != STATE_ERROR); + + struct dc *DC = telegram_get_working_dc(instance); + assert(DC); + assert(DC->sessions[0]); + assert(DC->sessions[0]->c); + //logprintf("get_connection() -> fd: %d\n", DC->sessions[0]->c->fd); return DC->sessions[0]->c; } +/** + * Get the currently used DC + * + * Will only work after restore_session has been called and the data center configuration + * was properly loaded + */ struct dc *telegram_get_working_dc(struct telegram *instance) { + assert(instance->session_state != STATE_ERROR); + + assert(instance->auth.DC_list); + assert(instance->auth.dc_working_num > 0); struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num]; return DC; } +/** + * Store the current session state to a file + */ void telegram_restore_session(struct telegram *instance) { - char file[256]; - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "auth"); - instance->auth = read_auth_file(file); - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "state"); - instance->proto = read_state_file(file); + g_mkdir_with_parents(instance->config_path, 0700); + instance->auth = read_auth_file(instance->auth_path); + instance->proto = read_state_file(instance->state_path); } +/** + * Load the current session state from a file + */ void telegram_store_session(struct telegram *instance) { - char file[256]; - sprintf(file, "%s/%s", instance->config_path, instance->login); - assure_file_exists(file, "auth"); - assure_file_exists(file, "state"); - - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "auth"); - write_auth_file(instance->auth, file); - - sprintf(file, "%s/%s/%s", instance->config_path, instance->login, "state"); - write_state_file(instance->proto, file); + assure_file_exists(instance->config_path, "auth"); + assure_file_exists(instance->config_path, "state"); + write_auth_file(&instance->auth, instance->auth_path); + write_state_file(&instance->proto, instance->state_path); } -void telegram_get_downloads_dir(struct telegram *instance) +char *telegram_get_config(struct telegram *instance, char *config) { - + return g_strdup_printf("%s/%s", instance->config_path, config); } void telegram_network_connect(struct telegram *instance, int fd) { - on_start (); + logprintf("telegram_network_connect()\n"); + if (!instance->auth.DC_list) { + logprintf("telegram_network_connect(): cannot connect, restore / initialise a session first.\n"); + assert(0); + } struct dc *DC_working = telegram_get_working_dc(instance); // check whether authentication is needed @@ -147,14 +187,12 @@ void telegram_network_connect(struct telegram *instance, int fd) logprintf("No working DC, authenticating.\n"); // init a new connection - struct connection *c = create_connection (DC_working->ip, DC_working->port, fd); + struct connection *c = create_connection (DC_working->ip, DC_working->port, fd, instance); // init a new session with random session id dc_create_session(DC_working, c); // Request PQ - char byte = 0xef; - assert (write_out (c, &byte, 1) == 1); - send_req_pq_packet (instance); + send_req_pq_packet (c); telegram_change_state(instance, STATE_PQ_REQUESTED, NULL); } else { logprintf("Already working session, setting state to connected.\n"); @@ -175,11 +213,23 @@ void on_state_change(struct telegram *instance, int state, void *data) case STATE_CONNECTED: on_connected(instance); break; + case STATE_ERROR: { const char* err = data; logprintf("Telegram errored: %s \n", err); - break; } + break; + + case STATE_AUTH_DONE: + logprintf("requesting configuration"); + telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); + do_help_get_config (instance); + break; + + case STATE_CONFIG_REQUESTED: + logprintf("switch: config_requested\n"); + telegram_store_session(instance); + break; } } @@ -191,31 +241,39 @@ void try_rpc_interpret(struct telegram *instance, int op, int len) { switch (instance->session_state) { case STATE_PQ_REQUESTED: + logprintf("switch: pq_requested\n"); rpc_execute_req_pq(instance, len); telegram_change_state(instance, STATE_DH_REQUESTED, NULL); break; case STATE_DH_REQUESTED: + logprintf("switch: dh_requested\n"); rpc_execute_rq_dh(instance, len); telegram_change_state(instance, STATE_CDH_REQUESTED, NULL); break; case STATE_CDH_REQUESTED: + logprintf("switch: cdh_requested\n"); rpc_execute_cdh_sent(instance, len); telegram_change_state(instance, STATE_AUTH_DONE, NULL); break; case STATE_AUTH_DONE: + logprintf("switch: auth_done\n"); rpc_execute_authorized(instance, op, len); - telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); - do_help_get_config (instance); - break; - case STATE_CONFIG_REQUESTED: - // ? - telegram_store_session(instance); break; } } void telegram_read_input (struct telegram *instance) { - try_read(instance); + return try_read(instance); +} + +int telegram_write_output (struct telegram *instance) +{ + return try_write(instance); +} + +int telegram_has_output (struct telegram *instance) +{ + return !all_queries_done(); } diff --git a/telegram.h b/telegram.h index 77ac0c5..e5cda6a 100644 --- a/telegram.h +++ b/telegram.h @@ -70,8 +70,14 @@ struct telegram { void *protocol_data; int curr_dc; + char *login; - const char *config_path; + char *config_path; + char *download_path; + char *auth_path; + char *state_path; + char *secret_path; + int session_state; /* @@ -81,6 +87,10 @@ struct telegram { struct authorization_state auth; GList *change_state_listeners; + + /* + * Callbacks + */ void (*on_output)(struct telegram *instance); void *extra; @@ -89,13 +99,16 @@ struct telegram { /** * Constructor */ -struct telegram *telegram_new(struct dc *DC, const char* login, const char* config_path); +struct telegram *telegram_new(struct dc *DC, const char* login, + const char* config_path); /** * Resume the session to */ void telegram_restore_session(struct telegram *instance); +char *telegram_get_config(struct telegram *instance, char *config); + /** * Store */ @@ -176,7 +189,12 @@ void telegram_read_input (struct telegram *instance); /** * Write all available output to the network */ -void telegram_write_output (struct telegram *instance); +int telegram_write_output (struct telegram *instance); + +/** + * Return whether there is pending output. + */ +int telegram_has_output (struct telegram *instance); /** * Try to interpret RPC calls and apply the changes to the current telegram state diff --git a/tools.c b/tools.c index c9c4255..5dcc439 100644 --- a/tools.c +++ b/tools.c @@ -105,6 +105,32 @@ void tfree (void *ptr, int size __attribute__ ((unused))) { #endif } +/** + * Add a variable amount of strings together + */ +//char *stradd(const char *strs, ...) +//{ +// va_list args; +// size_t size = 0; +// char *result; +// +// // count strlen +// va_start(args, strs); +// for (int i = 0; strs[i] != '\0'; i++) { +// size += strlen(va_arg(args, char*)); +// } +// va_end(args); +// +// // create the new string +// result = talloc0(size + 1); +// va_start(args, strs); +// for (int i = 0; strs[i] != '\0'; i++) { +// strcat(result, va_arg(args, char*)); +// } +// va_end(args); +// return result; +//} + void tfree_str (void *ptr) { if (!ptr) { return; } tfree (ptr, strlen (ptr) + 1); diff --git a/tools.h b/tools.h index e63b133..dc8bfd9 100644 --- a/tools.h +++ b/tools.h @@ -25,6 +25,7 @@ void *trealloc (void *ptr, size_t old_size, size_t size); void *talloc0 (size_t size); char *tstrdup (const char *s); char *tstrndup (const char *s, size_t n); +//char *stradd(const char *, ...); int tinflate (void *input, int ilen, void *output, int olen); void ensure (int r); void ensure_ptr (void *p); From 9e5b4ca5ecc2047adc63cca33cf79a3269001c3f Mon Sep 17 00:00:00 2001 From: mjentsch Date: Wed, 6 Aug 2014 19:45:46 +0200 Subject: [PATCH 334/465] Refactor - Intermediate Commit 3 --- Makefile.in | 3 +- binlog.c | 889 ++++++++++--------- binlog.h | 108 +-- interface.c | 1 - loop.c | 22 +- loop.h | 16 +- mtproto-client.c | 1246 +++++++++++++------------- mtproto-client.h | 479 +++++++++- mtproto-common.c | 167 ++-- mtproto-common.h | 357 -------- net.c | 246 ++++-- net.h | 43 +- purple-plugin/telegram-purple.c | 20 +- purple-plugin/telegram-purple.h | 20 +- queries.c | 1467 +++++++++++++++++-------------- queries.h | 7 +- structures.c | 1187 ++++++++++++------------- structures.h | 51 +- telegram.c | 74 +- telegram.h | 49 +- tools.h | 4 +- 21 files changed, 3355 insertions(+), 3101 deletions(-) delete mode 100644 mtproto-common.h diff --git a/Makefile.in b/Makefile.in index aec2ce2..c0a9367 100644 --- a/Makefile.in +++ b/Makefile.in @@ -14,7 +14,8 @@ EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h + INCLUDE=-I. -I${srcdir} CC=@CC@ OBJECTS=loop.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o msglog.o telegram.o diff --git a/binlog.c b/binlog.c index 58d85c1..2113a0b 100644 --- a/binlog.c +++ b/binlog.c @@ -34,7 +34,6 @@ #include #include "binlog.h" -#include "mtproto-common.h" #include "net.h" #include "include.h" #include "mtproto-client.h" @@ -82,6 +81,7 @@ void *alloc_log_event (int l UU) { long long binlog_pos; void replay_log_event (struct telegram *instance) { + struct mtproto_connection *self = instance->connection; int *start = rptr; in_replay_log = 1; @@ -92,27 +92,27 @@ void replay_log_event (struct telegram *instance) { logprintf ("log_pos %lld, op 0x%08x\n", binlog_pos, op); } - in_ptr = rptr; - in_end = wptr; + self->in_ptr = rptr; + self->in_end = wptr; switch (op) { case LOG_START: rptr ++; break; case CODE_binlog_dc_option: - in_ptr ++; + self->in_ptr ++; { - int id = fetch_int (); - int l1 = prefetch_strlen (); - char *name = fetch_str (l1); - int l2 = prefetch_strlen (); - char *ip = fetch_str (l2); - int port = fetch_int (); + int id = fetch_int (self); + int l1 = prefetch_strlen (self); + char *name = fetch_str (self, l1); + int l2 = prefetch_strlen (self); + char *ip = fetch_str (self, l2); + int port = fetch_int (self); if (verbosity) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } alloc_dc (instance->auth.DC_list, id, tstrndup (ip, l2), port); } - rptr = in_ptr; + rptr = self->in_ptr; break; case LOG_AUTH_KEY: rptr ++; @@ -166,12 +166,12 @@ void replay_log_event (struct telegram *instance) { // case CODE_user_request: // case CODE_user_foreign: case CODE_user_deleted: - fetch_alloc_user (); - rptr = in_ptr; + fetch_alloc_user (self); + rptr = self->in_ptr; break; case LOG_DH_CONFIG: get_dh_config_on_answer (0); - rptr = in_ptr; + rptr = self->in_ptr; break; case LOG_ENCR_CHAT_KEY: rptr ++; @@ -298,9 +298,9 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_new_user: - in_ptr ++; + self->in_ptr ++; { - peer_id_t id = MK_USER (fetch_int ()); + peer_id_t id = MK_USER (fetch_int (self)); peer_t *_U = user_chat_get (id); if (!_U) { _U = talloc0 (sizeof (*_U)); @@ -314,18 +314,18 @@ void replay_log_event (struct telegram *instance) { if (get_peer_id (id) == our_id) { U->flags |= FLAG_USER_SELF; } - U->first_name = fetch_str_dup (); - U->last_name = fetch_str_dup (); + U->first_name = fetch_str_dup (self); + U->last_name = fetch_str_dup (self); assert (!U->print_name); U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); peer_insert_name ((void *)U); - U->access_hash = fetch_long (); - U->phone = fetch_str_dup (); - if (fetch_int ()) { + U->access_hash = fetch_long (self); + U->phone = fetch_str_dup (self); + if (fetch_int (self)) { U->flags |= FLAG_USER_CONTACT; } } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_user_delete: rptr ++; @@ -347,15 +347,15 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_set_user_phone: - in_ptr ++; + self->in_ptr ++; { - peer_id_t id = MK_USER (fetch_int ()); + peer_id_t id = MK_USER (fetch_int (self)); peer_t *U = user_chat_get (id); assert (U); if (U->user.phone) { tfree_str (U->user.phone); } - U->user.phone = fetch_str_dup (); + U->user.phone = fetch_str_dup (self); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_set_user_friend: rptr ++; @@ -369,17 +369,17 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_user_full_photo: - in_ptr ++; + self->in_ptr ++; { - peer_id_t id = MK_USER (fetch_int ()); + peer_id_t id = MK_USER (fetch_int (self)); peer_t *U = user_chat_get (id); assert (U); if (U->flags & FLAG_HAS_PHOTO) { free_photo (&U->user.photo); } - fetch_photo (&U->user.photo); + fetch_photo (self, &U->user.photo); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_user_blocked: rptr ++; @@ -391,17 +391,17 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_set_user_full_name: - in_ptr ++; + self->in_ptr ++; { - peer_id_t id = MK_USER (fetch_int ()); + peer_id_t id = MK_USER (fetch_int (self)); peer_t *U = user_chat_get (id); assert (U); if (U->user.real_first_name) { tfree_str (U->user.real_first_name); } if (U->user.real_last_name) { tfree_str (U->user.real_last_name); } - U->user.real_first_name = fetch_str_dup (); - U->user.real_last_name = fetch_str_dup (); + U->user.real_first_name = fetch_str_dup (self); + U->user.real_last_name = fetch_str_dup (self); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_encr_chat_delete: rptr ++; @@ -578,9 +578,9 @@ void replay_log_event (struct telegram *instance) { seq = *(rptr ++); break; case CODE_binlog_chat_create: - in_ptr ++; + self->in_ptr ++; { - peer_id_t id = MK_CHAT (fetch_int ()); + peer_id_t id = MK_CHAT (fetch_int (self)); peer_t *_C = user_chat_get (id); if (!_C) { _C = talloc0 (sizeof (*_C)); @@ -590,18 +590,18 @@ void replay_log_event (struct telegram *instance) { assert (!(_C->flags & FLAG_CREATED)); } struct chat *C = &_C->chat; - C->flags = FLAG_CREATED | fetch_int (); - C->title = fetch_str_dup (); + C->flags = FLAG_CREATED | fetch_int (self); + C->title = fetch_str_dup (self); assert (!C->print_title); C->print_title = create_print_name (id, C->title, 0, 0, 0); peer_insert_name ((void *)C); - 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)); + C->users_num = fetch_int (self); + C->date = fetch_int (self); + C->version = fetch_int (self); + fetch_data (self, &C->photo_big, sizeof (struct file_location)); + fetch_data (self, &C->photo_small, sizeof (struct file_location)); }; - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_chat_change_flags: rptr ++; @@ -613,13 +613,13 @@ void replay_log_event (struct telegram *instance) { }; break; case CODE_binlog_set_chat_title: - in_ptr ++; + self->in_ptr ++; { - peer_t *_C = user_chat_get (MK_CHAT (fetch_int ())); + peer_t *_C = user_chat_get (MK_CHAT (fetch_int (self))); assert (_C && (_C->flags & FLAG_CREATED)); struct chat *C = &_C->chat; if (C->title) { tfree_str (C->title); } - C->title = fetch_str_dup (); + C->title = fetch_str_dup (self); if (C->print_title) { peer_delete_name ((void *)C); tfree_str (C->print_title); @@ -627,17 +627,17 @@ void replay_log_event (struct telegram *instance) { C->print_title = create_print_name (C->id, C->title, 0, 0, 0); peer_insert_name ((void *)C); }; - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_set_chat_photo: - in_ptr ++; + self->in_ptr ++; { - peer_t *C = user_chat_get (MK_CHAT (fetch_int ())); + peer_t *C = user_chat_get (MK_CHAT (fetch_int (self))); assert (C && (C->flags & FLAG_CREATED)); - fetch_data (&C->photo_big, sizeof (struct file_location)); - fetch_data (&C->photo_small, sizeof (struct file_location)); + fetch_data (self, &C->photo_big, sizeof (struct file_location)); + fetch_data (self, &C->photo_small, sizeof (struct file_location)); }; - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_set_chat_date: rptr ++; @@ -678,17 +678,17 @@ void replay_log_event (struct telegram *instance) { }; break; case CODE_binlog_chat_full_photo: - in_ptr ++; + self->in_ptr ++; { - peer_id_t id = MK_CHAT (fetch_int ()); + peer_id_t id = MK_CHAT (fetch_int (self)); 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); + fetch_photo (self, &U->chat.photo); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_add_chat_participant: rptr ++; @@ -745,13 +745,13 @@ void replay_log_event (struct telegram *instance) { break; case CODE_binlog_create_message_text: case CODE_binlog_send_message_text: - in_ptr ++; + self->in_ptr ++; { long long id; if (op == CODE_binlog_create_message_text) { - id = fetch_int (); + id = fetch_int (self); } else { - id = fetch_long (); + id = fetch_long (self); } struct message *M = message_get (id); if (!M) { @@ -763,17 +763,17 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); if (t == PEER_ENCR_CHAT) { M->flags |= FLAG_ENCRYPTED; } - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); - int l = prefetch_strlen (); + int l = prefetch_strlen (self); M->message = talloc (l + 1); - memcpy (M->message, fetch_str (l), l); + memcpy (M->message, fetch_str (self, l), l); M->message[l] = 0; M->message_len = l; @@ -791,12 +791,12 @@ void replay_log_event (struct telegram *instance) { M->flags |= FLAG_PENDING; } } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_create_message_text_fwd: - in_ptr ++; + self->in_ptr ++; { - int id = fetch_int (); + int id = fetch_int (self); struct message *M = message_get (id); if (!M) { M = talloc0 (sizeof (*M)); @@ -807,16 +807,16 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); - M->fwd_from_id = MK_USER (fetch_int ()); - M->fwd_date = fetch_int (); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); + M->fwd_from_id = MK_USER (fetch_int (self)); + M->fwd_date = fetch_int (self); - int l = prefetch_strlen (); + int l = prefetch_strlen (self); M->message = talloc (l + 1); - memcpy (M->message, fetch_str (l), l); + memcpy (M->message, fetch_str (self, l), l); M->message[l] = 0; M->message_len = l; @@ -826,12 +826,12 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_create_message_media: - in_ptr ++; + self->in_ptr ++; { - int id = fetch_int (); + int id = fetch_int (self); struct message *M = message_get (id); if (!M) { M = talloc0 (sizeof (*M)); @@ -842,29 +842,29 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); - int l = prefetch_strlen (); + int l = prefetch_strlen (self); M->message = talloc (l + 1); - memcpy (M->message, fetch_str (l), l); + memcpy (M->message, fetch_str (self, l), l); M->message[l] = 0; M->message_len = l; - fetch_message_media (&M->media); + fetch_message_media (self, &M->media); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_create_message_media_encr: - in_ptr ++; + self->in_ptr ++; { - long long id = fetch_long (); + long long id = fetch_long (self); struct message *M = message_get (id); if (!M) { M = talloc0 (sizeof (*M)); @@ -875,31 +875,31 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); - int l = prefetch_strlen (); + int l = prefetch_strlen (self); M->message = talloc (l + 1); - memcpy (M->message, fetch_str (l), l); + memcpy (M->message, fetch_str (self, l), l); M->message[l] = 0; M->message_len = l; - fetch_message_media_encrypted (&M->media); - fetch_encrypted_message_file (&M->media); + fetch_message_media_encrypted (self, &M->media); + fetch_encrypted_message_file (self, &M->media); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_create_message_media_fwd: - in_ptr ++; + self->in_ptr ++; { - int id = fetch_int (); + int id = fetch_int (self); struct message *M = message_get (id); if (!M) { M = talloc0 (sizeof (*M)); @@ -910,31 +910,31 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); - M->fwd_from_id = MK_USER (fetch_int ()); - M->fwd_date = fetch_int (); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); + M->fwd_from_id = MK_USER (fetch_int (self)); + M->fwd_date = fetch_int (self); - int l = prefetch_strlen (); + int l = prefetch_strlen (self); M->message = talloc (l + 1); - memcpy (M->message, fetch_str (l), l); + memcpy (M->message, fetch_str (self, l), l); M->message[l] = 0; M->message_len = l; - fetch_message_media (&M->media); + fetch_message_media (self, &M->media); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; message_insert (M); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_create_message_service: - in_ptr ++; + self->in_ptr ++; { - int id = fetch_int (); + int id = fetch_int (self); struct message *M = message_get (id); if (!M) { M = talloc0 (sizeof (*M)); @@ -945,24 +945,24 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); - fetch_message_action (&M->action); + fetch_message_action (self, &M->action); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; M->service = 1; message_insert (M); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_create_message_service_encr: - in_ptr ++; + self->in_ptr ++; { - long long id = fetch_long (); + long long id = fetch_long (self); struct message *M = message_get (id); if (!M) { M = talloc0 (sizeof (*M)); @@ -973,12 +973,12 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); - fetch_message_action_encrypted (&M->action); + fetch_message_action_encrypted (self, &M->action); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; @@ -986,12 +986,12 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_create_message_service_fwd: - in_ptr ++; + self->in_ptr ++; { - int id = fetch_int (); + int id = fetch_int (self); struct message *M = message_get (id); if (!M) { M = talloc0 (sizeof (*M)); @@ -1002,20 +1002,20 @@ void replay_log_event (struct telegram *instance) { assert (!(M->flags & FLAG_CREATED)); } M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int ()); - int t = fetch_int (); - M->to_id = set_peer_id (t, fetch_int ()); - M->date = fetch_int (); - M->fwd_from_id = MK_USER (fetch_int ()); - M->fwd_date = fetch_int (); - fetch_message_action (&M->action); + M->from_id = MK_USER (fetch_int (self)); + int t = fetch_int (self); + M->to_id = set_peer_id (t, fetch_int (self)); + M->date = fetch_int (self); + M->fwd_from_id = MK_USER (fetch_int (self)); + M->fwd_date = fetch_int (self); + fetch_message_action (self, &M->action); M->unread = 1; M->out = get_peer_id (M->from_id) == our_id; M->service = 1; message_insert (M); } - rptr = in_ptr; + rptr = self->in_ptr; break; case CODE_binlog_set_unread: rptr ++; @@ -1076,8 +1076,8 @@ void replay_log_event (struct telegram *instance) { break; case CODE_update_user_photo: case CODE_update_user_name: - work_update_binlog (); - rptr = in_ptr; + work_update_binlog (self); + rptr = self->in_ptr; break; default: logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(rptr - 1), op, *(rptr + 1), binlog_pos); @@ -1091,32 +1091,34 @@ void replay_log_event (struct telegram *instance) { binlog_pos += (rptr - start) * 4; } -void create_new_binlog (void) { +void create_new_binlog (struct mtproto_connection *self) { static int s[1000]; - packet_ptr = s; - out_int (LOG_START); - out_int (CODE_binlog_dc_option); - out_int (1); - out_string (""); - out_string (test_dc ? TG_SERVER_TEST : TG_SERVER); - out_int (443); - out_int (LOG_DEFAULT_DC); - out_int (1); + self->packet_ptr = s; + out_int (self, LOG_START); + out_int (self, CODE_binlog_dc_option); + out_int (self, 1); + out_string (self, ""); + out_string (self, test_dc ? TG_SERVER_TEST : TG_SERVER); + out_int (self, 443); + out_int (self, LOG_DEFAULT_DC); + out_int (self, 1); int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL | O_CREAT, 0600); if (fd < 0) { perror ("Write new binlog"); exit (2); } - assert (write (fd, s, (packet_ptr - s) * 4) == (packet_ptr - s) * 4); + assert (write (fd, s, (self->packet_ptr - s) * 4) == (self->packet_ptr - s) * 4); close (fd); } void replay_log (struct telegram *instance) { + struct mtproto_connection *self = instance->connection; + if (access (get_binlog_file_name (), F_OK) < 0) { printf ("No binlog found. Creating new one\n"); - create_new_binlog (); + create_new_binlog (self); } int fd = open (get_binlog_file_name (), O_RDONLY); if (fd < 0) { @@ -1167,7 +1169,8 @@ void write_binlog (void) { } } -void add_log_event (const int *data, int len) { +void add_log_event (struct mtproto_connection *self, const int *data, int len) { + logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); assert(0); // TODO: Mit add_log_event_i austauschen @@ -1175,8 +1178,8 @@ void add_log_event (const int *data, int len) { if (in_replay_log) { return; } rptr = (void *)data; wptr = rptr + (len / 4); - int *in = in_ptr; - int *end = in_end; + int *in = self->in_ptr; + int *end = self->in_end; // TODO: //replay_log_event (); if (rptr != wptr) { @@ -1187,18 +1190,19 @@ void add_log_event (const int *data, int len) { assert (binlog_fd > 0); assert (write (binlog_fd, data, len) == len); } - in_ptr = in; - in_end = end; + self->in_ptr = in; + self->in_end = end; } -void add_log_event_i (struct telegram *instance, const int *data, int len) { +void add_log_event_i (struct mtproto_connection *self, struct telegram *instance, + const int *data, int len) { logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); assert (!(len & 3)); if (in_replay_log) { return; } rptr = (void *)data; wptr = rptr + (len / 4); - int *in = in_ptr; - int *end = in_end; + int *in = self->in_ptr; + int *end = self->in_end; // TODO: replay_log_event (instance); if (rptr != wptr) { @@ -1209,11 +1213,13 @@ void add_log_event_i (struct telegram *instance, const int *data, int len) { assert (binlog_fd > 0); assert (write (binlog_fd, data, len) == len); } - in_ptr = in; - in_end = end; + self->in_ptr = in; + self->in_end = end; } void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf) { + struct mtproto_connection *self = instance->connection; + static unsigned char sha1_buffer[20]; SHA1 (buf, 256, sha1_buffer); long long fingerprint = *(long long *)(sha1_buffer + 12); @@ -1222,38 +1228,41 @@ void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *b ev[1] = num; *(long long *)(ev + 2) = fingerprint; memcpy (ev + 4, buf, 256); - add_log_event_i (instance, ev, 8 + 8 + 256); + add_log_event_i (self, instance, ev, 8 + 8 + 256); } -void bl_do_set_our_id (int id) { +void bl_do_set_our_id (struct mtproto_connection *self, int id) { int *ev = alloc_log_event (8); ev[0] = LOG_OUR_ID; ev[1] = id; - add_log_event (ev, 8); + add_log_event (self, ev, 8); } -void bl_do_new_user (int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact) { - clear_packet (); - out_int (CODE_binlog_new_user); - out_int (id); - out_cstring (f ? f : "", fl); - out_cstring (l ? l : "", ll); - out_long (access_token); - out_cstring (p ? p : "", pl); - out_int (contact); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_new_user (struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, + long long access_token, const char *p, int pl, int contact) { + + clear_packet (self); + out_int (self, CODE_binlog_new_user); + out_int (self, id); + out_cstring (self, f ? f : "", fl); + out_cstring (self, l ? l : "", ll); + out_long (self, access_token); + out_cstring (self, p ? p : "", pl); + out_int (self, contact); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_user_delete (struct user *U) { +void bl_do_user_delete (struct mtproto_connection *self, struct user *U) { if (U->flags & FLAG_DELETED) { return; } int *ev = alloc_log_event (8); ev[0] = CODE_binlog_user_delete; ev[1] = get_peer_id (U->id); - add_log_event (ev, 8); + add_log_event (self, ev, 8); } extern int last_date; -void bl_do_set_user_profile_photo (struct user *U, long long photo_id, struct file_location *big, struct file_location *small) { +void bl_do_set_user_profile_photo (struct mtproto_connection *self, struct user *U, + long long photo_id, struct file_location *big, struct file_location *small) { if (photo_id == U->photo_id) { return; } if (!photo_id) { int *ev = alloc_log_event (20); @@ -1262,153 +1271,158 @@ void bl_do_set_user_profile_photo (struct user *U, long long photo_id, struct fi ev[2] = last_date; ev[3] = CODE_user_profile_photo_empty; ev[4] = CODE_bool_false; - add_log_event (ev, 20); + add_log_event (self, ev, 20); } else { - clear_packet (); - out_int (CODE_update_user_photo); - out_int (get_peer_id (U->id)); - out_int (last_date); - out_int (CODE_user_profile_photo); - out_long (photo_id); + clear_packet (self); + out_int (self, CODE_update_user_photo); + out_int (self, get_peer_id (U->id)); + out_int (self, last_date); + out_int (self, CODE_user_profile_photo); + out_long (self, photo_id); if (small->dc >= 0) { - out_int (CODE_file_location); - out_int (small->dc); - out_long (small->volume); - out_int (small->local_id); - out_long (small->secret); + out_int (self, CODE_file_location); + out_int (self, small->dc); + out_long (self, small->volume); + out_int (self, small->local_id); + out_long (self, small->secret); } else { - out_int (CODE_file_location_unavailable); - out_long (small->volume); - out_int (small->local_id); - out_long (small->secret); + out_int (self, CODE_file_location_unavailable); + out_long (self, small->volume); + out_int (self, small->local_id); + out_long (self, small->secret); } if (big->dc >= 0) { - out_int (CODE_file_location); - out_int (big->dc); - out_long (big->volume); - out_int (big->local_id); - out_long (big->secret); + out_int (self, CODE_file_location); + out_int (self, big->dc); + out_long (self, big->volume); + out_int (self, big->local_id); + out_long (self, big->secret); } else { - out_int (CODE_file_location_unavailable); - out_long (big->volume); - out_int (big->local_id); - out_long (big->secret); + out_int (self, CODE_file_location_unavailable); + out_long (self, big->volume); + out_int (self, big->local_id); + out_long (self, big->secret); } - out_int (CODE_bool_false); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + out_int (self, CODE_bool_false); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } } -void bl_do_set_user_name (struct user *U, const char *f, int fl, const char *l, int ll) { +void bl_do_set_user_name (struct mtproto_connection *self, struct user *U, const char *f, + int fl, const char *l, int ll) { if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) && (U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) { return; } - clear_packet (); - out_int (CODE_update_user_name); - out_int (get_peer_id (U->id)); - out_cstring (f, fl); - out_cstring (l, ll); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + clear_packet (self); + out_int (self, CODE_update_user_name); + out_int (self, get_peer_id (U->id)); + out_cstring (self, f, fl); + out_cstring (self, l, ll); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_user_access_token (struct user *U, long long access_token) { +void bl_do_set_user_access_token (struct mtproto_connection *self, struct user *U, long long access_token) { if (U->access_hash == access_token) { return; } int *ev = alloc_log_event (16); ev[0] = CODE_binlog_set_user_access_token; ev[1] = get_peer_id (U->id); *(long long *)(ev + 2) = access_token; - add_log_event (ev, 16); + add_log_event (self, ev, 16); } -void bl_do_set_user_phone (struct user *U, const char *p, int pl) { +void bl_do_set_user_phone (struct mtproto_connection *self, struct user *U, +const char *p, int pl) { if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) { return; } - clear_packet (); - out_int (CODE_binlog_set_user_phone); - out_int (get_peer_id (U->id)); - out_cstring (p, pl); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + clear_packet (self); + out_int (self, CODE_binlog_set_user_phone); + out_int (self, get_peer_id (U->id)); + out_cstring (self, p, pl); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_user_friend (struct user *U, int friend) { +void bl_do_set_user_friend (struct mtproto_connection *self, struct user *U, int friend) { if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; } int *ev = alloc_log_event (12); ev[0] = CODE_binlog_set_user_friend; ev[1] = get_peer_id (U->id); ev[2] = friend; - add_log_event (ev, 12); + add_log_event (self, ev, 12); } -void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance) { +void bl_do_dc_option (struct mtproto_connection *self, int id, int l1, const char *name, + int l2, const char *ip, int port, struct telegram *instance) { struct dc *DC = instance->auth.DC_list[id]; if (DC) { return; } - clear_packet (); - out_int (CODE_binlog_dc_option); - out_int (id); - out_cstring (name, l1); - out_cstring (ip, l2); - out_int (port); + clear_packet (self); + out_int (self, CODE_binlog_dc_option); + out_int (self, id); + out_cstring (self, name, l1); + out_cstring (self, ip, l2); + out_int (self, port); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_dc_signed (int id) { +void bl_do_dc_signed (struct mtproto_connection *self, int id) { int *ev = alloc_log_event (8); ev[0] = LOG_DC_SIGNED; ev[1] = id; - add_log_event (ev, 8); + add_log_event (self, ev, 8); } -void bl_do_set_working_dc (int num) { +void bl_do_set_working_dc (struct mtproto_connection *self, int num) { int *ev = alloc_log_event (8); ev[0] = LOG_DEFAULT_DC; ev[1] = num; - add_log_event (ev, 8); + add_log_event (self, ev, 8); } -void bl_do_set_user_full_photo (struct user *U, const int *start, int len) { +void bl_do_set_user_full_photo (struct mtproto_connection *self, struct user *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_user_full_photo; ev[1] = get_peer_id (U->id); memcpy (ev + 2, start, len); - add_log_event (ev, len + 8); + add_log_event (self, ev, len + 8); } -void bl_do_set_user_blocked (struct user *U, int blocked) { +void bl_do_set_user_blocked (struct mtproto_connection *self, struct user *U, int blocked) { if (U->blocked == blocked) { return; } int *ev = alloc_log_event (12); ev[0] = CODE_binlog_user_blocked; ev[1] = get_peer_id (U->id); ev[2] = blocked; - add_log_event (ev, 12); + add_log_event (self, ev, 12); } -void bl_do_set_user_real_name (struct user *U, const char *f, int fl, const char *l, int ll) { +void bl_do_set_user_real_name (struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll) { if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) && (U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) { return; } - clear_packet (); - out_int (CODE_binlog_set_user_full_name); - out_int (get_peer_id (U->id)); - out_cstring (f, fl); - out_cstring (l, ll); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + clear_packet (self); + out_int (self, CODE_binlog_set_user_full_name); + out_int (self, get_peer_id (U->id)); + out_cstring (self, f, fl); + out_cstring (self, l, ll); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_encr_chat_delete (struct secret_chat *U) { +void bl_do_encr_chat_delete (struct mtproto_connection *self, struct secret_chat *U) { if (!(U->flags & FLAG_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; } int *ev = alloc_log_event (8); ev[0] = CODE_binlog_encr_chat_delete; ev[1] = get_peer_id (U->id); - add_log_event (ev, 8); + add_log_event (self, ev, 8); } -void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]) { +void bl_do_encr_chat_requested (struct mtproto_connection *self, struct secret_chat *U, + long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], + unsigned char nonce[]) { if (U->state != sc_none) { return; } int *ev = alloc_log_event (540); ev[0] = CODE_binlog_encr_chat_requested; @@ -1419,37 +1433,38 @@ void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, in ev[6] = user_id; memcpy (ev + 7, g_key, 256); memcpy (ev + 7 + 64, nonce, 256); - add_log_event (ev, 540); + add_log_event (self, ev, 540); } -void bl_do_set_encr_chat_access_hash (struct secret_chat *U, long long access_hash) { +void bl_do_set_encr_chat_access_hash (struct mtproto_connection *self, struct secret_chat *U, + long long access_hash) { if (U->access_hash == access_hash) { return; } int *ev = alloc_log_event (16); ev[0] = CODE_binlog_set_encr_chat_access_hash; ev[1] = get_peer_id (U->id); *(long long *)(ev + 2) = access_hash; - add_log_event (ev, 16); + add_log_event (self, ev, 16); } -void bl_do_set_encr_chat_date (struct secret_chat *U, int date) { +void bl_do_set_encr_chat_date (struct mtproto_connection *self, struct secret_chat *U, int date) { if (U->date == date) { return; } int *ev = alloc_log_event (12); ev[0] = CODE_binlog_set_encr_chat_date; ev[1] = get_peer_id (U->id); ev[2] = date; - add_log_event (ev, 12); + add_log_event (self, ev, 12); } -void bl_do_set_encr_chat_state (struct secret_chat *U, enum secret_chat_state state) { +void bl_do_set_encr_chat_state (struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state) { if (U->state == state) { return; } int *ev = alloc_log_event (12); ev[0] = CODE_binlog_set_encr_chat_state; ev[1] = get_peer_id (U->id); ev[2] = state; - add_log_event (ev, 12); + add_log_event (self, ev, 12); } -void bl_do_encr_chat_accepted (struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) { +void bl_do_encr_chat_accepted (struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) { if (U->state != sc_waiting && U->state != sc_request) { return; } int *ev = alloc_log_event (528); ev[0] = CODE_binlog_encr_chat_accepted; @@ -1457,80 +1472,80 @@ void bl_do_encr_chat_accepted (struct secret_chat *U, const unsigned char g_key[ memcpy (ev + 2, g_key, 256); memcpy (ev + 66, nonce, 256); *(long long *)(ev + 130) = key_fingerprint; - add_log_event (ev, 528); + add_log_event (self, ev, 528); } -void bl_do_set_encr_chat_key (struct secret_chat *E, unsigned char key[], long long key_fingerprint) { +void bl_do_set_encr_chat_key (struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint) { int *ev = alloc_log_event (272); ev[0] = CODE_binlog_set_encr_chat_key; ev[1] = get_peer_id (E->id); memcpy (ev + 2, key, 256); *(long long *)(ev + 66) = key_fingerprint; - add_log_event (ev, 272); + add_log_event (self, ev, 272); } -void bl_do_set_dh_params (int root, unsigned char prime[], int version) { +void bl_do_set_dh_params (struct mtproto_connection *self, int root, unsigned char prime[], int version) { int *ev = alloc_log_event (268); ev[0] = CODE_binlog_set_dh_params; ev[1] = root; memcpy (ev + 2, prime, 256); ev[66] = version; - add_log_event (ev, 268); + add_log_event (self, ev, 268); } -void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned char g_a[]) { +void bl_do_encr_chat_init (struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]) { int *ev = alloc_log_event (524); ev[0] = CODE_binlog_encr_chat_init; ev[1] = id; ev[2] = user_id; memcpy (ev + 3, random, 256); memcpy (ev + 67, g_a, 256); - add_log_event (ev, 524); + add_log_event (self, ev, 524); } -void bl_do_set_pts (int pts) { +void bl_do_set_pts (struct mtproto_connection *self, int pts) { int *ev = alloc_log_event (8); ev[0] = CODE_binlog_set_pts; ev[1] = pts; - add_log_event (ev, 8); + add_log_event (self, ev, 8); } -void bl_do_set_qts (int qts) { +void bl_do_set_qts (struct mtproto_connection *self, int qts) { int *ev = alloc_log_event (8); ev[0] = CODE_binlog_set_qts; ev[1] = qts; - add_log_event (ev, 8); + add_log_event (self, ev, 8); } -void bl_do_set_date (int date) { +void bl_do_set_date (struct mtproto_connection *self, int date) { int *ev = alloc_log_event (8); ev[0] = CODE_binlog_set_date; ev[1] = date; - add_log_event (ev, 8); + add_log_event (self, ev, 8); } -void bl_do_set_seq (int seq) { +void bl_do_set_seq (struct mtproto_connection *self, int seq) { int *ev = alloc_log_event (8); ev[0] = CODE_binlog_set_seq; ev[1] = seq; - add_log_event (ev, 8); + add_log_event (self, 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_create_chat (struct mtproto_connection *self, 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 (self); + out_int (self, CODE_binlog_chat_create); + out_int (self, get_peer_id (C->id)); + out_int (self, y); + out_cstring (self, s, l); + out_int (self, users_num); + out_int (self, date); + out_int (self, version); + out_data (self, big, sizeof (struct file_location)); + out_data (self, small, sizeof (struct file_location)); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_chat_forbid (struct chat *C, int on) { +void bl_do_chat_forbid (struct mtproto_connection *self, struct chat *C, int on) { if (on) { if (C->flags & FLAG_FORBIDDEN) { return; } int *ev = alloc_log_event (16); @@ -1538,7 +1553,7 @@ void bl_do_chat_forbid (struct chat *C, int on) { ev[1] = get_peer_id (C->id); ev[2] = FLAG_FORBIDDEN; ev[3] = 0; - add_log_event (ev, 16); + add_log_event (self, ev, 16); } else { if (!(C->flags & FLAG_FORBIDDEN)) { return; } int *ev = alloc_log_event (16); @@ -1546,40 +1561,40 @@ void bl_do_chat_forbid (struct chat *C, int on) { ev[1] = get_peer_id (C->id); ev[2] = 0; ev[3] = FLAG_FORBIDDEN; - add_log_event (ev, 16); + add_log_event (self, ev, 16); } } -void bl_do_set_chat_title (struct chat *C, const char *s, int l) { +void bl_do_set_chat_title (struct mtproto_connection *self, 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)); + clear_packet (self); + out_int (self, CODE_binlog_set_chat_title); + out_int (self, get_peer_id (C->id)); + out_cstring (self, s, l); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_chat_photo (struct chat *C, struct file_location *big, struct file_location *small) { +void bl_do_set_chat_photo (struct mtproto_connection *self, 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)); + clear_packet (self); + out_int (self, CODE_binlog_set_chat_photo); + out_int (self, get_peer_id (C->id)); + out_data (self, big, sizeof (struct file_location)); + out_data (self, small, sizeof (struct file_location)); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_chat_date (struct chat *C, int date) { +void bl_do_set_chat_date (struct mtproto_connection *self, 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); + add_log_event (self, ev, 12); } -void bl_do_set_chat_set_in_chat (struct chat *C, int on) { +void bl_do_set_chat_set_in_chat (struct mtproto_connection *self, struct chat *C, int on) { if (on) { if (C->flags & FLAG_CHAT_IN_CHAT) { return; } int *ev = alloc_log_event (16); @@ -1587,7 +1602,7 @@ void bl_do_set_chat_set_in_chat (struct chat *C, int on) { ev[1] = get_peer_id (C->id); ev[2] = FLAG_CHAT_IN_CHAT; ev[3] = 0; - add_log_event (ev, 16); + add_log_event (self, ev, 16); } else { if (!(C->flags & FLAG_CHAT_IN_CHAT)) { return; } int *ev = alloc_log_event (16); @@ -1595,30 +1610,30 @@ void bl_do_set_chat_set_in_chat (struct chat *C, int on) { ev[1] = get_peer_id (C->id); ev[2] = 0; ev[3] = FLAG_CHAT_IN_CHAT; - add_log_event (ev, 16); + add_log_event (self, ev, 16); } } -void bl_do_set_chat_version (struct chat *C, int version, int user_num) { +void bl_do_set_chat_version (struct mtproto_connection *self, 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); + add_log_event (self, ev, 16); } -void bl_do_set_chat_admin (struct chat *C, int admin) { +void bl_do_set_chat_admin (struct mtproto_connection *self, 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); + add_log_event (self, ev, 12); } -void bl_do_set_chat_participants (struct chat *C, int version, int user_num, struct chat_user *users) { +void bl_do_set_chat_participants (struct mtproto_connection *self, 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; @@ -1626,19 +1641,19 @@ void bl_do_set_chat_participants (struct chat *C, int version, int user_num, str ev[2] = version; ev[3] = user_num; memcpy (ev + 4, users, 12 * user_num); - add_log_event (ev, 12 * user_num + 16); + add_log_event (self, ev, 12 * user_num + 16); } -void bl_do_set_chat_full_photo (struct chat *U, const int *start, int len) { +void bl_do_set_chat_full_photo (struct mtproto_connection *self, 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); + add_log_event (self, ev, len + 8); } -void bl_do_chat_add_user (struct chat *C, int version, int user, int inviter, int date) { +void bl_do_chat_add_user (struct mtproto_connection *self, 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; @@ -1647,164 +1662,164 @@ void bl_do_chat_add_user (struct chat *C, int version, int user, int inviter, in ev[3] = user; ev[4] = inviter; ev[5] = date; - add_log_event (ev, 24); + add_log_event (self, ev, 24); } -void bl_do_chat_del_user (struct chat *C, int version, int user) { +void bl_do_chat_del_user (struct mtproto_connection *self, 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); + add_log_event (self, ev, 16); } -void bl_do_create_message_text (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { - clear_packet (); - out_int (CODE_binlog_create_message_text); - out_int (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_cstring (s, l); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_text (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_text); + out_int (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_cstring (self, s, l); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_send_message_text (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { - clear_packet (); - out_int (CODE_binlog_send_message_text); - out_long (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_cstring (s, l); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_send_message_text (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { + clear_packet (self); + out_int (self, CODE_binlog_send_message_text); + out_long (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_cstring (self, s, l); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_text_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s) { - clear_packet (); - out_int (CODE_binlog_create_message_text_fwd); - out_int (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_int (fwd); - out_int (fwd_date); - out_cstring (s, l); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_text_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_text_fwd); + out_int (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_int (self, fwd); + out_int (self, fwd_date); + out_cstring (self, s, l); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_media (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len) { - clear_packet (); - out_int (CODE_binlog_create_message_media); - out_int (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_cstring (s, l); - out_ints (data, len); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_media (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_media); + out_int (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_cstring (self, s, l); + out_ints (self, data, len); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_media_encr (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2) { - clear_packet (); - out_int (CODE_binlog_create_message_media_encr); - out_long (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_cstring (s, l); - out_ints (data, len); - out_ints (data2, len2); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_media_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_media_encr); + out_long (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_cstring (self, s, l); + out_ints (self, data, len); + out_ints (self, data2, len2); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_media_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len) { - clear_packet (); - out_int (CODE_binlog_create_message_media_fwd); - out_int (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_int (fwd); - out_int (fwd_date); - out_cstring (s, l); - out_ints (data, len); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_media_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_media_fwd); + out_int (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_int (self, fwd); + out_int (self, fwd_date); + out_cstring (self, s, l); + out_ints (self, data, len); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_service (int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { - clear_packet (); - out_int (CODE_binlog_create_message_service); - out_int (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_ints (data, len); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_service (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_service); + out_int (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_ints (self, data, len); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_service_encr (long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { - clear_packet (); - out_int (CODE_binlog_create_message_service_encr); - out_long (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_ints (data, len); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_service_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_service_encr); + out_long (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_ints (self, data, len); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_service_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len) { - clear_packet (); - out_int (CODE_binlog_create_message_service_fwd); - out_int (msg_id); - out_int (from_id); - out_int (to_type); - out_int (to_id); - out_int (date); - out_int (fwd); - out_int (fwd_date); - out_ints (data, len); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_create_message_service_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len) { + clear_packet (self); + out_int (self, CODE_binlog_create_message_service_fwd); + out_int (self, msg_id); + out_int (self, from_id); + out_int (self, to_type); + out_int (self, to_id); + out_int (self, date); + out_int (self, fwd); + out_int (self, fwd_date); + out_ints (self, data, len); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_unread (struct message *M, int unread) { +void bl_do_set_unread (struct mtproto_connection *self, struct message *M, int unread) { if (unread || !M->unread) { return; } - clear_packet (); - out_int (CODE_binlog_set_unread); - out_int (M->id); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + clear_packet (self); + out_int (self, CODE_binlog_set_unread); + out_int (self, M->id); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_message_sent (struct message *M) { +void bl_do_set_message_sent (struct mtproto_connection *self, struct message *M) { if (!(M->flags & FLAG_PENDING)) { return; } - clear_packet (); - out_int (CODE_binlog_set_message_sent); - out_long (M->id); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + clear_packet (self); + out_int (self, CODE_binlog_set_message_sent); + out_long (self, M->id); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_msg_id (struct message *M, int id) { +void bl_do_set_msg_id (struct mtproto_connection *self, struct message *M, int id) { if (M->id == id) { return; } - clear_packet (); - out_int (CODE_binlog_set_msg_id); - out_long (M->id); - out_int (id); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); + clear_packet (self); + out_int (self, CODE_binlog_set_msg_id); + out_long (self, M->id); + out_int (self, id); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_delete_msg (struct message *M) { - clear_packet (); - out_int (CODE_binlog_delete_msg); - out_long (M->id); - add_log_event (packet_buffer, 4 * (packet_ptr - packet_buffer)); +void bl_do_delete_msg (struct mtproto_connection *self, struct message *M) { + clear_packet (self); + out_int (self, CODE_binlog_delete_msg); + out_long (self, M->id); + add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } diff --git a/binlog.h b/binlog.h index 370ea55..8adc853 100644 --- a/binlog.h +++ b/binlog.h @@ -86,67 +86,67 @@ void *alloc_log_event (int l); void replay_log (struct telegram *instance); -void add_log_event (const int *data, int l); -void add_log_event_i (struct telegram *instance, const int *data, int l); +void add_log_event (struct mtproto_connection *self, const int *data, int l); +void add_log_event_i (struct mtproto_connection *self, struct telegram *instance, const int *data, int l); void write_binlog (void); void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf); -void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); +void bl_do_dc_option (struct mtproto_connection *self, int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); -void bl_do_set_our_id (int id); -void bl_do_new_user (int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); -void bl_do_user_delete (struct user *U); -void bl_do_set_user_profile_photo (struct user *U, long long photo_id, struct file_location *big, struct file_location *small); -void bl_do_set_user_name (struct user *U, const char *f, int fl, const char *l, int ll); -void bl_do_set_user_access_token (struct user *U, long long access_token); -void bl_do_set_user_phone (struct user *U, const char *p, int pl); -void bl_do_set_user_friend (struct user *U, int friend); -void bl_do_set_user_full_photo (struct user *U, const int *start, int len); -void bl_do_set_user_blocked (struct user *U, int blocked); -void bl_do_set_user_real_name (struct user *U, const char *f, int fl, const char *l, int ll); +void bl_do_set_our_id (struct mtproto_connection *self, int id); +void bl_do_new_user (struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); +void bl_do_user_delete (struct mtproto_connection *self, struct user *U); +void bl_do_set_user_profile_photo (struct mtproto_connection *self, struct user *U, long long photo_id, struct file_location *big, struct file_location *small); +void bl_do_set_user_name (struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); +void bl_do_set_user_access_token (struct mtproto_connection *self, struct user *U, long long access_token); +void bl_do_set_user_phone (struct mtproto_connection *self, struct user *U, const char *p, int pl); +void bl_do_set_user_friend (struct mtproto_connection *self, struct user *U, int friend); +void bl_do_set_user_full_photo (struct mtproto_connection *self, struct user *U, const int *start, int len); +void bl_do_set_user_blocked (struct mtproto_connection *self, struct user *U, int blocked); +void bl_do_set_user_real_name (struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); -void bl_do_encr_chat_delete (struct secret_chat *U); -void bl_do_encr_chat_requested (struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); -void bl_do_set_encr_chat_access_hash (struct secret_chat *U, long long access_hash); -void bl_do_set_encr_chat_date (struct secret_chat *U, int date); -void bl_do_set_encr_chat_state (struct secret_chat *U, enum secret_chat_state state); -void bl_do_encr_chat_accepted (struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint); -void bl_do_set_encr_chat_key (struct secret_chat *E, unsigned char key[], long long key_fingerprint); -void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned char g_a[]); +void bl_do_encr_chat_delete (struct mtproto_connection *self, struct secret_chat *U); +void bl_do_encr_chat_requested (struct mtproto_connection *self, struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); +void bl_do_set_encr_chat_access_hash (struct mtproto_connection *self, struct secret_chat *U, long long access_hash); +void bl_do_set_encr_chat_date (struct mtproto_connection *self, struct secret_chat *U, int date); +void bl_do_set_encr_chat_state (struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state); +void bl_do_encr_chat_accepted (struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint); +void bl_do_set_encr_chat_key (struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint); +void bl_do_encr_chat_init (struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]); -void bl_do_dc_signed (int id); -void bl_do_set_working_dc (int num); -void bl_do_set_dh_params (int root, unsigned char prime[], int version); +void bl_do_dc_signed (struct mtproto_connection *self, int id); +void bl_do_set_working_dc (struct mtproto_connection *self, int num); +void bl_do_set_dh_params (struct mtproto_connection *self, int root, unsigned char prime[], int version); -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_set_pts (struct mtproto_connection *self, int pts); +void bl_do_set_qts (struct mtproto_connection *self, int qts); +void bl_do_set_seq (struct mtproto_connection *self, int seq); +void bl_do_set_date (struct mtproto_connection *self, 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); -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); +void bl_do_create_chat (struct mtproto_connection *self, 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 mtproto_connection *self, struct chat *C, int on); +void bl_do_set_chat_title (struct mtproto_connection *self, struct chat *C, const char *s, int l); +void bl_do_set_chat_photo (struct mtproto_connection *self, struct chat *C, struct file_location *big, struct file_location *small); +void bl_do_set_chat_date (struct mtproto_connection *self, struct chat *C, int date); +void bl_do_set_chat_set_in_chat (struct mtproto_connection *self, struct chat *C, int on); +void bl_do_set_chat_version (struct mtproto_connection *self, struct chat *C, int version, int user_num); +void bl_do_set_chat_admin (struct mtproto_connection *self, struct chat *C, int admin); +void bl_do_set_chat_participants (struct mtproto_connection *self, struct chat *C, int version, int user_num, struct chat_user *users); +void bl_do_set_chat_full_photo (struct mtproto_connection *self, struct chat *U, const int *start, int len); +void bl_do_chat_add_user (struct mtproto_connection *self, struct chat *C, int version, int user, int inviter, int date); +void bl_do_chat_del_user (struct mtproto_connection *self, struct chat *C, int version, int user); -void bl_do_create_message_text (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); -void bl_do_create_message_text_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s); -void bl_do_create_message_service (int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); -void bl_do_create_message_service_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len); -void bl_do_create_message_media (int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len); -void bl_do_create_message_media_fwd (int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len); -void bl_do_create_message_media_encr (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2); -void bl_do_create_message_service_encr (long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); -void bl_do_send_message_text (long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); -void bl_do_set_unread (struct message *M, int unread); -void bl_do_set_message_sent (struct message *M); -void bl_do_set_msg_id (struct message *M, int id); -void bl_do_delete_msg (struct message *M); +void bl_do_create_message_text (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); +void bl_do_create_message_text_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s); +void bl_do_create_message_service (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); +void bl_do_create_message_service_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len); +void bl_do_create_message_media (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len); +void bl_do_create_message_media_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len); +void bl_do_create_message_media_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2); +void bl_do_create_message_service_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); +void bl_do_send_message_text (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); +void bl_do_set_unread (struct mtproto_connection *self, struct message *M, int unread); +void bl_do_set_message_sent (struct mtproto_connection *self, struct message *M); +void bl_do_set_msg_id (struct mtproto_connection *self, struct message *M, int id); +void bl_do_delete_msg (struct mtproto_connection *self, struct message *M); #endif diff --git a/interface.c b/interface.c index 1cf7d34..79a7a96 100644 --- a/interface.c +++ b/interface.c @@ -43,7 +43,6 @@ #include "telegram.h" #include "structures.h" -#include "mtproto-common.h" // libpurple debugging-messages #include "debug.h" diff --git a/loop.c b/loop.c index e3d20ef..95dc4da 100644 --- a/loop.c +++ b/loop.c @@ -45,7 +45,6 @@ #include "net.h" #include "mtproto-client.h" -#include "mtproto-common.h" #include "queries.h" #include "telegram.h" #include "loop.h" @@ -68,7 +67,6 @@ extern int unknown_user_list_pos; extern int unknown_user_list[]; int register_mode; extern int safe_quit; -extern int queries_num; int unread_messages; void got_it (char *line, int len); @@ -248,12 +246,15 @@ void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) { } -void empty_auth_file (struct authorization_state *state, const char *filename) { +void empty_auth_file (const char *filename) { + struct authorization_state state; + memset(state.DC_list, 0, 11 * sizeof(void *)); + logprintf("empty_auth_file()\n"); - alloc_dc (state->DC_list, 1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); - state->dc_working_num = 1; - state->auth_state = 0; - write_auth_file (state, filename); + alloc_dc (state.DC_list, 1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); + state.dc_working_num = 1; + state.auth_state = 0; + write_auth_file (&state, filename); } /** @@ -273,7 +274,7 @@ struct authorization_state read_auth_file (const char *filename) { logprintf("fd: %d\n", auth_file_fd); if (auth_file_fd < 0) { logprintf("auth_file does not exist, creating empty...\n"); - empty_auth_file (&state, filename); + empty_auth_file (filename); } auth_file_fd = open (filename, O_RDWR, 0600); assert (auth_file_fd >= 0); @@ -285,7 +286,7 @@ struct authorization_state read_auth_file (const char *filename) { if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) { logprintf("Invalid File content, wrong Magic numebr\n"); close (auth_file_fd); - empty_auth_file (&state, filename); + empty_auth_file (filename); return state; } assert (read (auth_file_fd, &x, 4) == 4); @@ -302,7 +303,8 @@ struct authorization_state read_auth_file (const char *filename) { if (y) { read_dc (auth_file_fd, i, m, state.DC_list); logprintf("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n", - i, state.DC_list[i]->port, state.DC_list[i]->ip, state.DC_list[i]->auth_key_id, state.DC_list[i]->server_salt, state.DC_list[i]->has_auth); + i, state.DC_list[i]->port, state.DC_list[i]->ip, state.DC_list[i]->auth_key_id, + state.DC_list[i]->server_salt, state.DC_list[i]->has_auth); } else { logprintf("loaded dc[%d] - NULL\n", i); } diff --git a/loop.h b/loop.h index 12a56a5..5b6a999 100644 --- a/loop.h +++ b/loop.h @@ -17,15 +17,19 @@ Copyright Vitaly Valtman 2013 */ -#pragma once - -#include "net.h" - #ifndef __LOOP_H__ #define __LOOP_H__ +// forward declarations + +struct dc; + +#ifndef __TELEGRAM_H__ +struct authorization_state; +struct protocol_state; +#endif + int loop(); void write_secret_chat_file (const char *filename); -#endif struct protocol_state { int pts; @@ -48,3 +52,5 @@ void write_state_file (struct protocol_state *state, const char *filename); struct protocol_state read_state_file (const char *filename); void on_start(); + +#endif diff --git a/mtproto-client.c b/mtproto-client.c index 00aed25..f96424d 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -22,7 +22,7 @@ #include "config.h" #endif -#define _FILE_OFFSET_BITS 64 +#define _FILE_OFFSET_BITS 64 #include #include @@ -63,31 +63,30 @@ #define sha1 SHA1 -#include "mtproto-common.h" - +#include "mtproto-client.h" #define MAX_NET_RES (1L << 16) -extern int log_level; -int log_level = 1; +int log_level = 2; -int verbosity; -int auth_success; + +int verbosity = 0; +int allow_weak_random = 0; +int disable_auto_accept = 0; + +/* enum dc_state c_state; char nonce[256]; char new_nonce[256]; char server_nonce[256]; extern int binlog_enabled; extern int disable_auto_accept; -int disable_auto_accept = 0; extern int allow_weak_random; -int allow_weak_random = 0; int total_packets_sent; long long total_data_sent; +*/ -extern int queries_num; -/* int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); int rpc_close (struct connection *c); @@ -97,7 +96,6 @@ struct connection_methods auth_methods = { .ready = rpc_becomes_ready, .close = rpc_close }; -*/ long long precise_time; @@ -175,42 +173,32 @@ int auth_work_start (struct connection *c); * */ -BIGNUM dh_prime, dh_g, g_a, dh_power, auth_key_num; -char s_power [256]; -struct { - long long auth_key_id; - long long out_msg_id; - int msg_len; -} unenc_msg_header; - - -#define ENCRYPT_BUFFER_INTS 16384 -int encrypt_buffer[ENCRYPT_BUFFER_INTS]; - -#define DECRYPT_BUFFER_INTS 16384 -int decrypt_buffer[ENCRYPT_BUFFER_INTS]; - -int encrypt_packet_buffer (void) { - return pad_rsa_encrypt ((char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4, pubKey->n, pubKey->e); +int encrypt_packet_buffer (struct mtproto_connection *self) { + return pad_rsa_encrypt (self, (char *) self->packet_buffer, (self->packet_ptr - self->packet_buffer) * 4, (char *) self->encrypt_buffer, + ENCRYPT_BUFFER_INTS * 4, pubKey->n, pubKey->e); } -int encrypt_packet_buffer_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32]) { - init_aes_unauth (server_nonce, hidden_client_nonce, AES_ENCRYPT); - return pad_aes_encrypt ((char *) packet_buffer, (packet_ptr - packet_buffer) * 4, (char *) encrypt_buffer, ENCRYPT_BUFFER_INTS * 4); +int encrypt_packet_buffer_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32]) { + init_aes_unauth (self, server_nonce, hidden_client_nonce, AES_ENCRYPT); + return pad_aes_encrypt (self, (char *) self->packet_buffer, (self->packet_ptr - self->packet_buffer) * 4, + (char *) self->encrypt_buffer, ENCRYPT_BUFFER_INTS * 4); } int rpc_send_packet (struct connection *c) { - int len = (packet_ptr - packet_buffer) * 4; + logprintf("rpc_send_packet()\n"); + struct mtproto_connection *self = c->mtconnection; + + int len = (self->packet_ptr - self->packet_buffer) * 4; c->out_packet_num ++; long long next_msg_id = (long long) ((1LL << 32) * get_utime (CLOCK_REALTIME)) & -4; - if (next_msg_id <= unenc_msg_header.out_msg_id) { - unenc_msg_header.out_msg_id += 4; + if (next_msg_id <= self->unenc_msg_header.out_msg_id) { + self->unenc_msg_header.out_msg_id += 4; } else { - unenc_msg_header.out_msg_id = next_msg_id; + self->unenc_msg_header.out_msg_id = next_msg_id; } - unenc_msg_header.msg_len = len; + self->unenc_msg_header.msg_len = len; int total_len = len + 20; assert (total_len > 0 && !(total_len & 0xfc000003)); @@ -221,18 +209,20 @@ int rpc_send_packet (struct connection *c) { total_len = (total_len << 8) | 0x7f; assert (write_out (c, &total_len, 4) == 4); } - write_out (c, &unenc_msg_header, 20); - write_out (c, packet_buffer, len); - //flush_out (c); + write_out (c, &self->unenc_msg_header, 20); + write_out (c, self->packet_buffer, len); + flush_out (c); - total_packets_sent ++; - queries_num++; - logprintf("pending queries: %d\n", queries_num); - total_data_sent += total_len; + self->total_packets_sent ++; + self->total_data_sent += total_len; + self->queries_num ++; + logprintf("queries_num=%d\n", self->queries_num); return 1; } int rpc_send_message (struct connection *c, void *data, int len) { + struct mtproto_connection *self = c->mtconnection; + logprintf("rpc_send_message(...)\n"); assert (len > 0 && !(len & 0xfc000003)); int total_len = len >> 2; @@ -246,24 +236,22 @@ int rpc_send_message (struct connection *c, void *data, int len) { assert (write_out (c, data, len) == len); flush_out (c); - total_packets_sent ++; - total_data_sent += total_len; + self->total_packets_sent ++; + self->total_data_sent += total_len; return 1; } int send_req_pq_packet (struct connection *c) { - char byte = 0xef; - assert (write_out (c, &byte, 1) == 1); + struct mtproto_connection *self = c->mtconnection; - assert (c_state == st_init); - secure_random (nonce, 16); - unenc_msg_header.out_msg_id = 0; - clear_packet (); - out_int (CODE_req_pq); - out_ints ((int *)nonce, 4); + assert (self->c_state == st_init); + secure_random (self->nonce, 16); + self->unenc_msg_header.out_msg_id = 0; + clear_packet (self); + out_int (self, CODE_req_pq); + out_ints (self, (int *)self->nonce, 4); rpc_send_packet (c); - - c_state = st_reqpq_sent; + self->c_state = st_reqpq_sent; return 1; } @@ -273,42 +261,38 @@ unsigned long long gcd (unsigned long long a, unsigned long long b) { } //typedef unsigned int uint128_t __attribute__ ((mode(TI))); -unsigned long long what; -unsigned p1, p2; int process_respq_answer (struct connection *c, char *packet, int len) { + logprintf ( "process_respq_answer(), len=%d\n", len); + + struct mtproto_connection *self = c->mtconnection; int i; - if (verbosity) { - logprintf ( "process_respq_answer(), len=%d\n", len); - } assert (len >= 76); assert (!*(long long *) packet); assert (*(int *) (packet + 16) == len - 20); assert (!(len & 3)); assert (*(int *) (packet + 20) == CODE_resPQ); - assert (!memcmp (packet + 24, nonce, 16)); - memcpy (server_nonce, packet + 40, 16); + assert (!memcmp (packet + 24, self->nonce, 16)); + memcpy (self->server_nonce, packet + 40, 16); char *from = packet + 56; int clen = *from++; assert (clen <= 8); - what = 0; + self->what = 0; for (i = 0; i < clen; i++) { - what = (what << 8) + (unsigned char)*from++; + self->what = (self->what << 8) + (unsigned char)*from++; } while (((unsigned long)from) & 3) ++from; - p1 = 0, p2 = 0; + self->p1 = 0, self->p2 = 0; - if (verbosity >= 2) { - logprintf ( "%lld received\n", what); - } + logprintf ( "%lld received\n", self->what); int it = 0; unsigned long long g = 0; for (i = 0; i < 3 || it < 1000; i++) { - int q = ((lrand48() & 15) + 17) % what; - unsigned long long x = (long long)lrand48 () % (what - 1) + 1, y = x; + int q = ((lrand48() & 15) + 17) % self->what; + unsigned long long x = (long long)lrand48 () % (self->what - 1) + 1, y = x; int lim = 1 << (i + 18); int j; for (j = 1; j < lim; j++) { @@ -317,19 +301,19 @@ int process_respq_answer (struct connection *c, char *packet, int len) { while (b) { if (b & 1) { c += a; - if (c >= what) { - c -= what; + if (c >= self->what) { + c -= self->what; } } a += a; - if (a >= what) { - a -= what; + if (a >= self->what) { + a -= self->what; } b >>= 1; } x = c; - unsigned long long z = x < y ? what + x - y : x - y; - g = gcd (z, what); + unsigned long long z = x < y ? self->what + x - y : x - y; + g = gcd (z, self->what); if (g != 1) { break; } @@ -337,20 +321,17 @@ int process_respq_answer (struct connection *c, char *packet, int len) { y = x; } } - if (g > 1 && g < what) break; + if (g > 1 && g < self->what) break; } - assert (g > 1 && g < what); - p1 = g; - p2 = what / g; - if (p1 > p2) { - unsigned t = p1; p1 = p2; p2 = t; + assert (g > 1 && g < self->what); + self->p1 = g; + self->p2 = self->what / g; + if (self->p1 > self->p2) { + unsigned t = self->p1; self->p1 = self->p2; self->p2 = t; } - - if (verbosity) { - logprintf ( "p1 = %d, p2 = %d, %d iterations\n", p1, p2, it); - } + logprintf ( "Calculated primes: self->p1 = %d, self->p2 = %d, %d iterations\n", self->p1, self->p2, it); /// ++p1; /// @@ -358,9 +339,10 @@ int process_respq_answer (struct connection *c, char *packet, int len) { int fingerprints_num = *(int *)(from + 4); assert (fingerprints_num >= 1 && fingerprints_num <= 64 && len == fingerprints_num * 8 + 8 + (from - packet)); long long *fingerprints = (long long *) (from + 8); + logprintf("Got %d fingerprints\n", fingerprints_num); for (i = 0; i < fingerprints_num; i++) { if (fingerprints[i] == pk_fingerprint) { - //logprintf ( "found our public key at position %d\n", i); + logprintf ( "found our public key at position %d\n", i); break; } } @@ -369,106 +351,106 @@ int process_respq_answer (struct connection *c, char *packet, int len) { exit (2); } // create inner part (P_Q_inner_data) - clear_packet (); - packet_ptr += 5; - out_int (CODE_p_q_inner_data); - out_cstring (packet + 57, clen); + clear_packet (self); + self->packet_ptr += 5; + out_int (self, CODE_p_q_inner_data); + out_cstring (self, packet + 57, clen); //out_int (0x0f01); // pq=15 - if (p1 < 256) { + if (self->p1 < 256) { clen = 1; - } else if (p1 < 65536) { + } else if (self->p1 < 65536) { clen = 2; - } else if (p1 < 16777216) { + } else if (self->p1 < 16777216) { clen = 3; } else { clen = 4; } - p1 = __builtin_bswap32 (p1); - out_cstring ((char *)&p1 + 4 - clen, clen); - p1 = __builtin_bswap32 (p1); + self->p1 = __builtin_bswap32 (self->p1); + out_cstring (self, (char *)&self->p1 + 4 - clen, clen); + self->p1 = __builtin_bswap32 (self->p1); - if (p2 < 256) { + if (self->p2 < 256) { clen = 1; - } else if (p2 < 65536) { + } else if (self->p2 < 65536) { clen = 2; - } else if (p2 < 16777216) { + } else if (self->p2 < 16777216) { clen = 3; } else { clen = 4; } - p2 = __builtin_bswap32 (p2); - out_cstring ((char *)&p2 + 4 - clen, clen); - p2 = __builtin_bswap32 (p2); + self->p2 = __builtin_bswap32 (self->p2); + out_cstring (self, (char *)&self->p2 + 4 - clen, clen); + self->p2 = __builtin_bswap32 (self->p2); //out_int (0x0301); // p=3 //out_int (0x0501); // q=5 - out_ints ((int *) nonce, 4); - out_ints ((int *) server_nonce, 4); - secure_random (new_nonce, 32); - out_ints ((int *) new_nonce, 8); - sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); + out_ints (self, (int *) self->nonce, 4); + out_ints (self, (int *) self->server_nonce, 4); + secure_random (self->new_nonce, 32); + out_ints (self, (int *) self->new_nonce, 8); + sha1 ((unsigned char *) (self->packet_buffer + 5), (self->packet_ptr - self->packet_buffer - 5) * 4, (unsigned char *) self->packet_buffer); - int l = encrypt_packet_buffer (); + int l = encrypt_packet_buffer (self); - clear_packet (); - out_int (CODE_req_DH_params); - out_ints ((int *) nonce, 4); - out_ints ((int *) server_nonce, 4); + clear_packet (self); + out_int (self, CODE_req_DH_params); + out_ints (self, (int *) self->nonce, 4); + out_ints (self, (int *) self->server_nonce, 4); //out_int (0x0301); // p=3 //out_int (0x0501); // q=5 - if (p1 < 256) { + if (self->p1 < 256) { clen = 1; - } else if (p1 < 65536) { + } else if (self->p1 < 65536) { clen = 2; - } else if (p1 < 16777216) { + } else if (self->p1 < 16777216) { clen = 3; } else { clen = 4; } - p1 = __builtin_bswap32 (p1); - out_cstring ((char *)&p1 + 4 - clen, clen); - p1 = __builtin_bswap32 (p1); - if (p2 < 256) { + self->p1 = __builtin_bswap32 (self->p1); + out_cstring (self, (char *)&self->p1 + 4 - clen, clen); + self->p1 = __builtin_bswap32 (self->p1); + if (self->p2 < 256) { clen = 1; - } else if (p2 < 65536) { + } else if (self->p2 < 65536) { clen = 2; - } else if (p2 < 16777216) { + } else if (self->p2 < 16777216) { clen = 3; } else { clen = 4; } - p2 = __builtin_bswap32 (p2); - out_cstring ((char *)&p2 + 4 - clen, clen); - p2 = __builtin_bswap32 (p2); + self->p2 = __builtin_bswap32 (self->p2); + out_cstring (self, (char *)&self->p2 + 4 - clen, clen); + self->p2 = __builtin_bswap32 (self->p2); - out_long (pk_fingerprint); - out_cstring ((char *) encrypt_buffer, l); + out_long (self, pk_fingerprint); + out_cstring (self, (char *) self->encrypt_buffer, l); - c_state = st_reqdh_sent; + self->c_state = st_reqdh_sent; return rpc_send_packet (c); } -int check_prime (BIGNUM *p) { - int r = BN_is_prime (p, BN_prime_checks, 0, BN_ctx, 0); +int check_prime (struct mtproto_connection *self, BIGNUM *p) { + int r = BN_is_prime (p, BN_prime_checks, 0, self->BN_ctx, 0); ensure (r >= 0); return r; } -int check_DH_params (BIGNUM *p, int g) { +int check_DH_params (struct mtproto_connection *self, BIGNUM *p, int g) { if (g < 2 || g > 7) { return -1; } BIGNUM t; BN_init (&t); - BN_init (&dh_g); - ensure (BN_set_word (&dh_g, 4 * g)); + BN_init (&self->dh_g); + ensure (BN_set_word (&self->dh_g, 4 * g)); - ensure (BN_mod (&t, p, &dh_g, BN_ctx)); + ensure (BN_mod (&t, p, &self->dh_g, self->BN_ctx)); int x = BN_get_word (&t); assert (x >= 0 && x < 4 * g); - BN_free (&dh_g); + BN_free (&self->dh_g); switch (g) { case 2: @@ -490,13 +472,13 @@ int check_DH_params (BIGNUM *p, int g) { break; } - if (!check_prime (p)) { return -1; } + if (!check_prime (self, p)) { return -1; } BIGNUM b; BN_init (&b); ensure (BN_set_word (&b, 2)); - ensure (BN_div (&t, 0, p, &b, BN_ctx)); - if (!check_prime (&t)) { return -1; } + ensure (BN_div (&t, 0, p, &b, self->BN_ctx)); + if (!check_prime (self, &t)) { return -1; } BN_free (&b); BN_free (&t); return 0; @@ -548,136 +530,136 @@ int check_g_bn (BIGNUM *p, BIGNUM *g) { int process_dh_answer (struct connection *c, char *packet, int len) { logprintf ( "process_dh_answer(), len=%d\n", len); + struct mtproto_connection *self = c->mtconnection; if (len < 116) { - logprintf ( "%u * %u = %llu", p1, p2, what); + logprintf ( "%u * %u = %llu", self->p1, self->p2, self->what); } assert (len >= 116); assert (!*(long long *) packet); assert (*(int *) (packet + 16) == len - 20); assert (!(len & 3)); assert (*(int *) (packet + 20) == (int)CODE_server_DH_params_ok); - assert (!memcmp (packet + 24, nonce, 16)); - assert (!memcmp (packet + 40, server_nonce, 16)); - init_aes_unauth (server_nonce, new_nonce, AES_DECRYPT); - in_ptr = (int *)(packet + 56); - in_end = (int *)(packet + len); - int l = prefetch_strlen (); + assert (!memcmp (packet + 24, self->nonce, 16)); + assert (!memcmp (packet + 40, self->server_nonce, 16)); + init_aes_unauth (self, self->server_nonce, self->new_nonce, AES_DECRYPT); + self->in_ptr = (int *)(packet + 56); + self->in_end = (int *)(packet + len); + int l = prefetch_strlen (self); assert (l > 0); - l = pad_aes_decrypt (fetch_str (l), l, (char *) decrypt_buffer, DECRYPT_BUFFER_INTS * 4 - 16); - assert (in_ptr == in_end); + l = pad_aes_decrypt (self, fetch_str (self, l), l, (char *) self->decrypt_buffer, DECRYPT_BUFFER_INTS * 4 - 16); + assert (self->in_ptr == self->in_end); assert (l >= 60); - assert (decrypt_buffer[5] == (int)CODE_server_DH_inner_data); - assert (!memcmp (decrypt_buffer + 6, nonce, 16)); - assert (!memcmp (decrypt_buffer + 10, server_nonce, 16)); - int g = decrypt_buffer[14]; - in_ptr = decrypt_buffer + 15; - in_end = decrypt_buffer + (l >> 2); - BN_init (&dh_prime); - BN_init (&g_a); - assert (fetch_bignum (&dh_prime) > 0); - assert (fetch_bignum (&g_a) > 0); - assert (check_g_bn (&dh_prime, &g_a) >= 0); - int server_time = *in_ptr++; - assert (in_ptr <= in_end); + assert (self->decrypt_buffer[5] == (int)CODE_server_DH_inner_data); + assert (!memcmp (self->decrypt_buffer + 6, self->nonce, 16)); + assert (!memcmp (self->decrypt_buffer + 10, self->server_nonce, 16)); + int g = self->decrypt_buffer[14]; + self->in_ptr = self->decrypt_buffer + 15; + self->in_end = self->decrypt_buffer + (l >> 2); + BN_init (&self->dh_prime); + BN_init (&self->g_a); + assert (fetch_bignum (self, &self->dh_prime) > 0); + assert (fetch_bignum (self, &self->g_a) > 0); + assert (check_g_bn (&self->dh_prime, &self->g_a) >= 0); + int server_time = *self->in_ptr++; + assert (self->in_ptr <= self->in_end); - assert (check_DH_params (&dh_prime, g) >= 0); + assert (check_DH_params (self, &self->dh_prime, g) >= 0); static char sha1_buffer[20]; - sha1 ((unsigned char *) decrypt_buffer + 20, (in_ptr - decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); - assert (!memcmp (decrypt_buffer, sha1_buffer, 20)); - assert ((char *) in_end - (char *) in_ptr < 16); + sha1 ((unsigned char *) self->decrypt_buffer + 20, (self->in_ptr - self->decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); + assert (!memcmp (self->decrypt_buffer, sha1_buffer, 20)); + assert ((char *) self->in_end - (char *) self->in_ptr < 16); GET_DC(c)->server_time_delta = server_time - time (0); GET_DC(c)->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); //logprintf ( "server time is %d, delta = %d\n", server_time, server_time_delta); // Build set_client_DH_params answer - clear_packet (); - packet_ptr += 5; - out_int (CODE_client_DH_inner_data); - out_ints ((int *) nonce, 4); - out_ints ((int *) server_nonce, 4); - out_long (0LL); + clear_packet (self); + self->packet_ptr += 5; + out_int (self, CODE_client_DH_inner_data); + out_ints (self, (int *) self->nonce, 4); + out_ints (self, (int *) self->server_nonce, 4); + out_long (self, 0LL); - BN_init (&dh_g); - ensure (BN_set_word (&dh_g, g)); + BN_init (&self->dh_g); + ensure (BN_set_word (&self->dh_g, g)); - secure_random (s_power, 256); - BIGNUM *dh_power = BN_bin2bn ((unsigned char *)s_power, 256, 0); + secure_random (self->s_power, 256); + BIGNUM *dh_power = BN_bin2bn ((unsigned char *)self->s_power, 256, 0); ensure_ptr (dh_power); BIGNUM *y = BN_new (); ensure_ptr (y); - ensure (BN_mod_exp (y, &dh_g, dh_power, &dh_prime, BN_ctx)); - out_bignum (y); + ensure (BN_mod_exp (y, &self->dh_g, dh_power, &self->dh_prime, self->BN_ctx)); + out_bignum (self, y); BN_free (y); - BN_init (&auth_key_num); - ensure (BN_mod_exp (&auth_key_num, &g_a, dh_power, &dh_prime, BN_ctx)); - l = BN_num_bytes (&auth_key_num); + BN_init (&self->auth_key_num); + ensure (BN_mod_exp (&self->auth_key_num, &self->g_a, dh_power, &self->dh_prime, self->BN_ctx)); + l = BN_num_bytes (&self->auth_key_num); assert (l >= 250 && l <= 256); - assert (BN_bn2bin (&auth_key_num, (unsigned char *)GET_DC(c)->auth_key)); + assert (BN_bn2bin (&self->auth_key_num, (unsigned char *)GET_DC(c)->auth_key)); memset (GET_DC(c)->auth_key + l, 0, 256 - l); BN_free (dh_power); - BN_free (&auth_key_num); - BN_free (&dh_g); - BN_free (&g_a); - BN_free (&dh_prime); + BN_free (&self->auth_key_num); + BN_free (&self->dh_g); + BN_free (&self->g_a); + BN_free (&self->dh_prime); //hexdump (auth_key, auth_key + 256); - sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); + sha1 ((unsigned char *) (self->packet_buffer + 5), (self->packet_ptr - self->packet_buffer - 5) * 4, (unsigned char *) self->packet_buffer); //hexdump ((char *)packet_buffer, (char *)packet_ptr); - l = encrypt_packet_buffer_aes_unauth (server_nonce, new_nonce); + l = encrypt_packet_buffer_aes_unauth (self, self->server_nonce, self->new_nonce); - clear_packet (); - out_int (CODE_set_client_DH_params); - out_ints ((int *) nonce, 4); - out_ints ((int *) server_nonce, 4); - out_cstring ((char *) encrypt_buffer, l); + clear_packet (self); + out_int (self, CODE_set_client_DH_params); + out_ints (self, (int *) self->nonce, 4); + out_ints (self, (int *) self->server_nonce, 4); + out_cstring (self, (char *) self->encrypt_buffer, l); + + self->c_state = st_client_dh_sent; - c_state = st_client_dh_sent; return rpc_send_packet (c); } -int process_auth_complete (struct connection *c UU, char *packet, int len) { - - logprintf ( "process_dh_answer(), len=%d\n", len); +int process_auth_complete (struct connection *c, char *packet, int len) { + logprintf ( "process_auth_complete(), len=%d\n", len); + struct mtproto_connection *self = c->mtconnection; assert (len == 72); assert (!*(long long *) packet); assert (*(int *) (packet + 16) == len - 20); assert (!(len & 3)); assert (*(int *) (packet + 20) == CODE_dh_gen_ok); - assert (!memcmp (packet + 24, nonce, 16)); - assert (!memcmp (packet + 40, server_nonce, 16)); + assert (!memcmp (packet + 24, self->nonce, 16)); + assert (!memcmp (packet + 40, self->server_nonce, 16)); static unsigned char tmp[44], sha1_buffer[20]; - memcpy (tmp, new_nonce, 32); + memcpy (tmp, self->new_nonce, 32); tmp[32] = 1; //GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); bl_do_set_auth_key_id (c->instance, GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); - sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); memcpy (tmp + 33, sha1_buffer, 8); sha1 (tmp, 41, sha1_buffer); assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); - GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; + GET_DC(c)->server_salt = *(long long *)self->server_nonce ^ *(long long *)self->new_nonce; logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); - //logprintf ( "auth_key=%s\n", GET_DC(c)->auth_key); //kprintf ("OK\n"); //c->status = conn_error; //sleep (1); - c_state = st_authorized; + self->c_state = st_authorized; //return 1; logprintf ( "Auth success\n"); - auth_success ++; + self->auth_success ++; GET_DC(c)->flags |= 1; return 1; @@ -689,10 +671,6 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { * */ -struct encrypted_message enc_msg; - -long long client_last_msg_id, server_last_msg_id; - double get_server_time (struct dc *DC) { if (!DC->server_time_udelta) { DC->server_time_udelta = get_utime (CLOCK_REALTIME) - get_utime (CLOCK_MONOTONIC); @@ -700,38 +678,38 @@ double get_server_time (struct dc *DC) { return get_utime (CLOCK_MONOTONIC) + DC->server_time_udelta; } -long long generate_next_msg_id (struct dc *DC) { +long long generate_next_msg_id (struct mtproto_connection *self, struct dc *DC) { long long next_id = (long long) (get_server_time (DC) * (1LL << 32)) & -4; - if (next_id <= client_last_msg_id) { - next_id = client_last_msg_id += 4; + if (next_id <= self->client_last_msg_id) { + next_id = self->client_last_msg_id += 4; } else { - client_last_msg_id = next_id; + self->client_last_msg_id = next_id; } return next_id; } -void init_enc_msg (struct session *S, int useful) { +void init_enc_msg (struct mtproto_connection *self, struct session *S, int useful) { struct dc *DC = S->dc; assert (DC->auth_key_id); - enc_msg.auth_key_id = DC->auth_key_id; + self->enc_msg.auth_key_id = DC->auth_key_id; // assert (DC->server_salt); - enc_msg.server_salt = DC->server_salt; + self->enc_msg.server_salt = DC->server_salt; if (!S->session_id) { secure_random (&S->session_id, 8); } - enc_msg.session_id = S->session_id; + self->enc_msg.session_id = S->session_id; //enc_msg.auth_key_id2 = auth_key_id; - enc_msg.msg_id = generate_next_msg_id (DC); + self->enc_msg.msg_id = generate_next_msg_id (self, DC); //enc_msg.msg_id -= 0x10000000LL * (lrand48 () & 15); //kprintf ("message id %016llx\n", enc_msg.msg_id); - enc_msg.seq_no = S->seq_no; + self->enc_msg.seq_no = S->seq_no; if (useful) { - enc_msg.seq_no |= 1; + self->enc_msg.seq_no |= 1; } S->seq_no += 2; }; -int aes_encrypt_message (struct dc *DC, struct encrypted_message *enc) { +int aes_encrypt_message (struct mtproto_connection *self, struct dc *DC, struct encrypted_message *enc) { unsigned char sha1_buffer[20]; const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); @@ -743,12 +721,14 @@ int aes_encrypt_message (struct dc *DC, struct encrypted_message *enc) { logprintf ( "sending message with sha1 %08x\n", *(int *)sha1_buffer); } memcpy (enc->msg_key, sha1_buffer + 4, 16); - init_aes_auth (DC->auth_key, enc->msg_key, AES_ENCRYPT); + init_aes_auth (self, DC->auth_key, enc->msg_key, AES_ENCRYPT); //hexdump ((char *)enc, (char *)enc + enc_len + 24); - return pad_aes_encrypt ((char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); + return pad_aes_encrypt (self, (char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); } -long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful) { +long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful) { + struct connection *c = self->connection; + logprintf("encrypt_send_message(...)\n"); struct dc *DC = GET_DC(c); struct session *S = c->session; @@ -758,100 +738,92 @@ long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, in return -1; } if (msg) { - memcpy (enc_msg.message, msg, msg_ints * 4); - enc_msg.msg_len = msg_ints * 4; + memcpy (self->enc_msg.message, msg, msg_ints * 4); + self->enc_msg.msg_len = msg_ints * 4; } else { - if ((enc_msg.msg_len & 0x80000003) || enc_msg.msg_len > MAX_MESSAGE_INTS * 4 - 16) { + if ((self->enc_msg.msg_len & 0x80000003) || self->enc_msg.msg_len > MAX_MESSAGE_INTS * 4 - 16) { return -1; } } - init_enc_msg (S, useful); + init_enc_msg (self, S, useful); //hexdump ((char *)msg, (char *)msg + (msg_ints * 4)); - int l = aes_encrypt_message (DC, &enc_msg); + int l = aes_encrypt_message (self, DC, &self->enc_msg); //hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24); assert (l > 0); - rpc_send_message (c, &enc_msg, l + UNENCSZ); - - return client_last_msg_id; + rpc_send_message (c, &self->enc_msg, l + UNENCSZ); + + return self->client_last_msg_id; } -int longpoll_count, good_messages; int auth_work_start (struct connection *c UU) { return 1; } -void rpc_execute_answer (struct telegram *instance, long long msg_id UU); +void rpc_execute_answer (struct connection *c, long long msg_id UU); -int unread_messages; -int our_id; -int pts; -int qts; -int last_date; -int seq; - -void fetch_pts (void) { - int p = fetch_int (); - if (p <= pts) { return; } - if (p != pts + 1) { - if (pts) { +void fetch_pts (struct mtproto_connection *self) { + int p = fetch_int (self); + if (p <= self->pts) { return; } + if (p != self->pts + 1) { + if (self->pts) { //logprintf ("Hole in pts p = %d, pts = %d\n", p, pts); // get difference should be here - pts = p; + self->pts = p; } else { - pts = p; + self->pts = p; } } else { - pts ++; + self->pts ++; } - //bl_do_set_pts (pts); + bl_do_set_pts (self, self->pts); } -void fetch_qts (void) { - int p = fetch_int (); - if (p <= qts) { return; } - if (p != qts + 1) { - if (qts) { +void fetch_qts (struct mtproto_connection *self) { + int p = fetch_int (self); + if (p <= self->qts) { return; } + if (p != self->qts + 1) { + if (self->qts) { //logprintf ("Hole in qts\n"); // get difference should be here - qts = p; + self->qts = p; } else { - qts = p; + self->qts = p; } } else { - qts ++; + self->qts ++; } - //bl_do_set_qts (qts); + bl_do_set_qts (self, self->qts); } -void fetch_date (void) { - int p = fetch_int (); - if (p > last_date) { - last_date = p; - //bl_do_set_date (last_date); +void fetch_date (struct mtproto_connection *self) { + int p = fetch_int (self); + if (p > self->last_date) { + self->last_date = p; + bl_do_set_date (self, self->last_date); } } -void fetch_seq (void) { - int x = fetch_int (); - if (x > seq + 1) { - logprintf ("Hole in seq: seq = %d, x = %d\n", seq, x); +void fetch_seq (struct mtproto_connection *self) { + int x = fetch_int (self); + if (x > self->seq + 1) { + logprintf ("Hole in seq: seq = %d, x = %d\n", self->seq, x); //do_get_difference (); //seq = x; - } else if (x == seq + 1) { - seq = x; - bl_do_set_seq (seq); + } else if (x == self->seq + 1) { + self->seq = x; + bl_do_set_seq (self, self->seq); } } -void work_update_binlog (void) { - unsigned op = fetch_int (); +void work_update_binlog (struct mtproto_connection *self) { + unsigned op = fetch_int (self); switch (op) { case CODE_update_user_name: { - peer_id_t user_id = MK_USER (fetch_int ()); + peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; @@ -861,47 +833,47 @@ void work_update_binlog (void) { peer_delete_name (UC); tfree_str (U->print_name); } - U->first_name = fetch_str_dup (); - U->last_name = fetch_str_dup (); + U->first_name = fetch_str_dup (self); + U->last_name = fetch_str_dup (self); U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); peer_insert_name ((void *)U); } else { - fetch_skip_str (); - fetch_skip_str (); + fetch_skip_str (self); + fetch_skip_str (self); } } break; case CODE_update_user_photo: { - peer_id_t user_id = MK_USER (fetch_int ()); + peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *UC = user_chat_get (user_id); - fetch_date (); + fetch_date (self); if (UC) { struct user *U = &UC->user; - unsigned y = fetch_int (); + unsigned y = fetch_int (self); 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); + U->photo_id = fetch_long (self); + fetch_file_location (self, &U->photo_small); + fetch_file_location (self, &U->photo_big); } } else { struct file_location t; - unsigned y = fetch_int (); + unsigned y = fetch_int (self); if (y == CODE_user_profile_photo_empty) { } else { assert (y == CODE_user_profile_photo); - fetch_long (); // photo_id - fetch_file_location (&t); - fetch_file_location (&t); + fetch_long (self); // photo_id + fetch_file_location (self, &t); + fetch_file_location (self, &t); } } - fetch_bool (); + fetch_bool (self); } break; default: @@ -909,44 +881,47 @@ void work_update_binlog (void) { } } -void work_update (struct connection *c UU, long long msg_id UU, struct telegram *instance) { - unsigned op = fetch_int (); +void work_update (struct mtproto_connection *self, long long msg_id UU) { + struct connection *c UU = self->connection; + struct telegram *tg = c->instance; + + unsigned op = fetch_int (self); logprintf("work_update(): OP:%d\n", op); switch (op) { case CODE_update_new_message: { - struct message *M = fetch_alloc_message (instance); + struct message *M = fetch_alloc_message (self, tg); assert (M); - fetch_pts (); - unread_messages ++; + fetch_pts (self); + self->unread_messages ++; event_update_new_message(M); - ////print_message (M); + //print_message (M); //update_prompt (); break; }; case CODE_update_message_i_d: { - int id = fetch_int (); // id - int new = fetch_long (); // random_id + int id = fetch_int (self); // id + int new = fetch_long (self); // random_id struct message *M = message_get (new); if (M) { - bl_do_set_msg_id (M, id); + bl_do_set_msg_id (self, M, id); } } break; case CODE_update_read_messages: { - assert (fetch_int () == (int)CODE_vector); - int n = fetch_int (); + assert (fetch_int (self) == (int)CODE_vector); + int n = fetch_int (self); int i; for (i = 0; i < n; i++) { - int id = fetch_int (); + int id = fetch_int (self); struct message *M = message_get (id); if (M) { - bl_do_set_unread (M, 0); + bl_do_set_unread (self, M, 0); } } - fetch_pts (); + fetch_pts (self); if (log_level >= 1) { //print_start (); //push_color (COLOR_YELLOW); @@ -959,8 +934,8 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_user_typing: { - peer_id_t id = MK_USER (fetch_int ()); - peer_t *U = user_chat_get (id); + peer_id_t id = MK_USER (fetch_int (self)); + peer_t *U UU = user_chat_get (id); if (log_level >= 2) { //print_start (); //push_color (COLOR_YELLOW); @@ -975,10 +950,10 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_chat_user_typing: { - peer_id_t chat_id = MK_CHAT (fetch_int ()); - peer_id_t id = MK_USER (fetch_int ()); - peer_t *C = user_chat_get (chat_id); - peer_t *U = user_chat_get (id); + peer_id_t chat_id = MK_CHAT (fetch_int (self)); + peer_id_t id = MK_USER (fetch_int (self)); + peer_t *C UU = user_chat_get (chat_id); + peer_t *U UU = user_chat_get (id); if (log_level >= 2) { //print_start (); //push_color (COLOR_YELLOW); @@ -995,10 +970,10 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_user_status: { - peer_id_t user_id = MK_USER (fetch_int ()); + peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *U = user_chat_get (user_id); if (U) { - fetch_user_status (&U->user.status); + fetch_user_status (self, &U->user.status); if (log_level >= 3) { //print_start (); //push_color (COLOR_YELLOW); @@ -1012,21 +987,21 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram } } else { struct user_status t; - fetch_user_status (&t); + fetch_user_status (self, &t); } } break; case CODE_update_user_name: { - peer_id_t user_id = MK_USER (fetch_int ()); + peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *UC = user_chat_get (user_id); if (UC && (UC->flags & FLAG_CREATED)) { - int l1 = prefetch_strlen (); - char *f = fetch_str (l1); - int l2 = prefetch_strlen (); - char *l = fetch_str (l2); + int l1 = prefetch_strlen (self); + char *f = fetch_str (self, l1); + int l2 = prefetch_strlen (self); + char *l = fetch_str (self, l2); struct user *U = &UC->user; - bl_do_set_user_real_name (U, f, l1, l, l2); + bl_do_set_user_real_name (self, U, f, l1, l, l2); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1038,19 +1013,19 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram //pop_color (); //print_end (); } else { - fetch_skip_str (); - fetch_skip_str (); + fetch_skip_str (self); + fetch_skip_str (self); } } break; case CODE_update_user_photo: { - peer_id_t user_id = MK_USER (fetch_int ()); + peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *UC = user_chat_get (user_id); - fetch_date (); + fetch_date (self); if (UC && (UC->flags & FLAG_CREATED)) { struct user *U = &UC->user; - unsigned y = fetch_int (); + unsigned y = fetch_int (self); long long photo_id; struct file_location big; struct file_location small; @@ -1062,11 +1037,11 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram small.dc = -2; } else { assert (y == CODE_user_profile_photo); - photo_id = fetch_long (); - fetch_file_location (&small); - fetch_file_location (&big); + photo_id = fetch_long (self); + fetch_file_location (self, &small); + fetch_file_location (self, &big); } - bl_do_set_user_profile_photo (U, photo_id, &big, &small); + bl_do_set_user_profile_photo (self, U, photo_id, &big, &small); //print_start (); //push_color (COLOR_YELLOW); @@ -1078,76 +1053,76 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram //print_end (); } else { struct file_location t; - unsigned y = fetch_int (); + unsigned y = fetch_int (self); if (y == CODE_user_profile_photo_empty) { } else { assert (y == CODE_user_profile_photo); - fetch_long (); // photo_id - fetch_file_location (&t); - fetch_file_location (&t); + fetch_long (self); // photo_id + fetch_file_location (self, &t); + fetch_file_location (self, &t); } } - fetch_bool (); + fetch_bool (self); } break; case CODE_update_restore_messages: { - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (self) == CODE_vector); + int n = fetch_int (self); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); printf (" Restored %d messages\n", n); //pop_color (); //print_end (); - fetch_skip (n); - fetch_pts (); + fetch_skip (self, n); + fetch_pts (self); } break; case CODE_update_delete_messages: { - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (self) == CODE_vector); + int n = fetch_int (self); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); printf (" Deleted %d messages\n", n); //pop_color (); //print_end (); - fetch_skip (n); - fetch_pts (); + fetch_skip (self, n); + fetch_pts (self); } break; case CODE_update_chat_participants: { - unsigned x = fetch_int (); + unsigned x = fetch_int (self); assert (x == CODE_chat_participants || x == CODE_chat_participants_forbidden); - peer_id_t chat_id = MK_CHAT (fetch_int ()); + peer_id_t chat_id = MK_CHAT (fetch_int (self)); int n = 0; 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 (); + bl_do_set_chat_admin (self, &C->chat, fetch_int (self)); + assert (fetch_int (self) == CODE_vector); + n = fetch_int (self); struct chat_user *users = talloc (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 (); + assert (fetch_int (self) == (int)CODE_chat_participant); + users[i].user_id = fetch_int (self); + users[i].inviter_id = fetch_int (self); + users[i].date = fetch_int (self); } - int version = fetch_int (); - bl_do_set_chat_participants (&C->chat, version, n, users); + int version = fetch_int (self); + bl_do_set_chat_participants (self, &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 + fetch_int (self); // admin_id + assert (fetch_int (self) == CODE_vector); + n = fetch_int (self); + fetch_skip (self, n * 4); + fetch_int (self); // version } } //print_start (); @@ -1166,9 +1141,9 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_contact_registered: { - peer_id_t user_id = MK_USER (fetch_int ()); - peer_t *U = user_chat_get (user_id); - fetch_int (); // date + peer_id_t user_id = MK_USER (fetch_int (self)); + peer_t *U UU = user_chat_get (user_id); + fetch_int (self); // date //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1181,8 +1156,8 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_contact_link: { - peer_id_t user_id = MK_USER (fetch_int ()); - peer_t *U = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int (self)); + peer_t *U UU = user_chat_get (user_id); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1191,22 +1166,22 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram printf ("\n"); //pop_color (); //print_end (); - unsigned t = fetch_int (); + unsigned t = fetch_int (self); assert (t == CODE_contacts_my_link_empty || t == CODE_contacts_my_link_requested || t == CODE_contacts_my_link_contact); if (t == CODE_contacts_my_link_requested) { - fetch_bool (); // has_phone + fetch_bool (self); // has_phone } - t = fetch_int (); + t = fetch_int (self); assert (t == CODE_contacts_foreign_link_unknown || t == CODE_contacts_foreign_link_requested || t == CODE_contacts_foreign_link_mutual); if (t == CODE_contacts_foreign_link_requested) { - fetch_bool (); // has_phone + fetch_bool (self); // has_phone } } break; case CODE_update_activation: { - peer_id_t user_id = MK_USER (fetch_int ()); - peer_t *U = user_chat_get (user_id); + peer_id_t user_id = MK_USER (fetch_int (self)); + peer_t *U UU = user_chat_get (user_id); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1219,10 +1194,10 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_new_authorization: { - fetch_long (); // auth_key_id - fetch_int (); // date - char *s = fetch_str_dup (); - char *location = fetch_str_dup (); + fetch_long (self); // auth_key_id + fetch_int (self); // date + char *s = fetch_str_dup (self); + char *location = fetch_str_dup (self); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1236,25 +1211,27 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_new_geo_chat_message: { - struct message *M = fetch_alloc_geo_message (instance); - unread_messages ++; + struct message *M UU = fetch_alloc_geo_message (self, tg); + self->unread_messages ++; //print_message (M); //update_prompt (); } break; case CODE_update_new_encrypted_message: { - struct message *M = fetch_alloc_encrypted_message (instance); - unread_messages ++; + struct message *M UU = fetch_alloc_encrypted_message (self, tg); + self->unread_messages ++; //print_message (M); //update_prompt (); - fetch_qts (); + fetch_qts (self); } break; case CODE_update_encryption: { - struct secret_chat *E = fetch_alloc_encrypted_chat (); - logprintf ("Secret chat state = %d\n", E->state); + struct secret_chat *E = fetch_alloc_encrypted_chat (self); + if (verbosity >= 2) { + logprintf ("Secret chat state = %d\n", E->state); + } //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1285,21 +1262,21 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram //pop_color (); //print_end (); if (E->state == sc_request && !disable_auto_accept) { - do_accept_encr_chat_request (instance, E); + do_accept_encr_chat_request (tg, E); } - fetch_int (); // date + fetch_int (self); // date } break; case CODE_update_encrypted_chat_typing: { - peer_id_t id = MK_ENCR_CHAT (fetch_int ()); + peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); peer_t *P = user_chat_get (id); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); if (P) { printf (" User "); - peer_id_t user_id = MK_USER (P->encr_chat.user_id); + peer_id_t user_id UU = MK_USER (P->encr_chat.user_id); //print_user_name (user_id, user_chat_get (user_id)); printf (" typing in secret chat "); //print_encr_chat_name (id, P); @@ -1313,9 +1290,9 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_encrypted_messages_read: { - peer_id_t id = MK_ENCR_CHAT (fetch_int ()); // chat_id - fetch_int (); // max_date - fetch_int (); // date + peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); // chat_id + fetch_int (self); // max_date + fetch_int (self); // date peer_t *P = user_chat_get (id); int x = -1; if (P && P->last) { @@ -1343,14 +1320,14 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_chat_participant_add: { - 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 ()); - int version = fetch_int (); + peer_id_t chat_id = MK_CHAT (fetch_int (self)); + peer_id_t user_id = MK_USER (fetch_int (self)); + peer_id_t inviter_id = MK_USER (fetch_int (self)); + int version = fetch_int (self); 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)); + bl_do_chat_add_user (self, &C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); } //print_start (); @@ -1369,13 +1346,13 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_chat_participant_delete: { - peer_id_t chat_id = MK_CHAT (fetch_int ()); - peer_id_t user_id = MK_USER (fetch_int ()); - int version = fetch_int (); + peer_id_t chat_id = MK_CHAT (fetch_int (self)); + peer_id_t user_id = MK_USER (fetch_int (self)); + int version = fetch_int (self); 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)); + bl_do_chat_del_user (self, &C->chat, version, get_peer_id (user_id)); } //print_start (); @@ -1392,12 +1369,12 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram break; case CODE_update_dc_options: { - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (self) == CODE_vector); + int n = fetch_int (self); assert (n >= 0); int i; for (i = 0; i < n; i++) { - fetch_dc_option (instance); + fetch_dc_option (tg); } } break; @@ -1407,79 +1384,84 @@ void work_update (struct connection *c UU, long long msg_id UU, struct telegram } } -void work_update_short (struct telegram *instance, long long msg_id) { - struct connection *c = telegram_get_connection(instance); - assert (fetch_int () == CODE_update_short); - work_update (c, msg_id, instance); - fetch_date (); +void work_update_short (struct connection *c, long long msg_id) { + struct mtproto_connection *self = c->mtconnection; + + assert (fetch_int (self) == CODE_update_short); + work_update (self, msg_id); + fetch_date (self); } -void work_updates (struct telegram *instance, long long msg_id) { - struct connection *c = telegram_get_connection(instance); - assert (fetch_int () == CODE_updates); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); +void work_updates (struct connection *c, long long msg_id) { + struct mtproto_connection *self = c->mtconnection; + + assert (fetch_int (c->mtconnection) == CODE_updates); + assert (fetch_int (c->mtconnection) == CODE_vector); + int n = fetch_int (c->mtconnection); int i; for (i = 0; i < n; i++) { - work_update (c, msg_id, instance); + work_update (c->mtconnection, msg_id); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (c->mtconnection) == CODE_vector); + n = fetch_int (c->mtconnection); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (self); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (c->mtconnection) == CODE_vector); + n = fetch_int (c->mtconnection); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (self); } - bl_do_set_date (fetch_int ()); - bl_do_set_seq (fetch_int ()); + bl_do_set_date (self, fetch_int (c->mtconnection)); + bl_do_set_seq (self, fetch_int (c->mtconnection)); } -void work_update_short_message (struct connection *c UU, long long msg_id UU, struct telegram *instance) { - assert (fetch_int () == (int)CODE_update_short_message); - struct message *M = fetch_alloc_message_short (instance); - unread_messages ++; +void work_update_short_message (struct connection *c UU, long long msg_id UU) { + struct mtproto_connection *self = c->mtconnection; + + assert (fetch_int (c->mtconnection) == (int)CODE_update_short_message); + struct message *M = fetch_alloc_message_short (self, c->instance); + c->mtconnection->unread_messages ++; //print_message (M); //update_prompt (); - if (M->date > last_date) { - last_date = M->date; + if (M->date > c->mtconnection->last_date) { + c->mtconnection->last_date = M->date; } } -void work_update_short_chat_message (struct connection *c UU, long long msg_id UU, struct telegram *instance) { - assert (fetch_int () == CODE_update_short_chat_message); - struct message *M = fetch_alloc_message_short_chat (instance); - unread_messages ++; +void work_update_short_chat_message (struct connection *c, long long msg_id UU) { + struct mtproto_connection *self = c->mtconnection; + + assert (fetch_int (self) == CODE_update_short_chat_message); + struct message *M = fetch_alloc_message_short_chat (self, c->instance); + c->mtconnection->unread_messages ++; //print_message (M); - //update_prompt (); - if (M->date > last_date) { - last_date = M->date; + ////update_prompt (); + if (M->date > c->mtconnection->last_date) { + c->mtconnection->last_date = M->date; } } -void work_container (struct telegram *instance, long long msg_id UU) { - struct connection *c = telegram_get_connection(instance); +void work_container (struct connection *c, long long msg_id UU) { if (verbosity) { logprintf ( "work_container: msg_id = %lld\n", msg_id); } - assert (fetch_int () == CODE_msg_container); - int n = fetch_int (); + assert (fetch_int (c->mtconnection) == CODE_msg_container); + int n = fetch_int (c->mtconnection); int i; for (i = 0; i < n; i++) { - long long id = fetch_long (); + long long id = fetch_long (c->mtconnection); //int seqno = fetch_int (); - fetch_int (); // seq_no + fetch_int (c->mtconnection); // seq_no if (id & 1) { insert_msg_id (c->session, id); } - int bytes = fetch_int (); - int *t = in_end; - in_end = in_ptr + (bytes / 4); - rpc_execute_answer (instance, id); - assert (in_ptr == in_end); - in_end = t; + int bytes = fetch_int (c->mtconnection); + int *t = c->mtconnection->in_end; + c->mtconnection->in_end = c->mtconnection->in_ptr + (bytes / 4); + rpc_execute_answer (c, id); + assert (c->mtconnection->in_ptr == c->mtconnection->in_end); + c->mtconnection->in_end = t; } } @@ -1487,23 +1469,24 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { if (verbosity) { logprintf ( "work_new_session_created: msg_id = %lld\n", msg_id); } - assert (fetch_int () == (int)CODE_new_session_created); - fetch_long (); // first message id + assert (fetch_int (c->mtconnection) == (int)CODE_new_session_created); + fetch_long (c->mtconnection); // first message id //DC->session_id = fetch_long (); - fetch_long (); // unique_id - GET_DC(c)->server_salt = fetch_long (); + fetch_long (c->mtconnection); // unique_id + GET_DC(c)->server_salt = fetch_long (c->mtconnection); + } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { if (verbosity) { logprintf ( "work_msgs_ack: msg_id = %lld\n", msg_id); } - assert (fetch_int () == CODE_msgs_ack); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (c->mtconnection) == CODE_msgs_ack); + assert (fetch_int (c->mtconnection) == CODE_vector); + int n = fetch_int (c->mtconnection); int i; for (i = 0; i < n; i++) { - long long id = fetch_long (); + long long id = fetch_long (c->mtconnection); if (verbosity) { logprintf ("ack for %lld\n", id); } @@ -1515,9 +1498,9 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { if (verbosity) { logprintf ( "work_rpc_result: msg_id = %lld\n", msg_id); } - assert (fetch_int () == (int)CODE_rpc_result); - long long id = fetch_long (); - int op = prefetch_int (); + assert (fetch_int (c->mtconnection) == (int)CODE_rpc_result); + long long id = fetch_long (c->mtconnection); + int op = prefetch_int (c->mtconnection); if (op == CODE_rpc_error) { query_error (id); } else { @@ -1526,87 +1509,86 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { } #define MAX_PACKED_SIZE (1 << 24) -void work_packed (struct telegram *instance, long long msg_id) { - assert (fetch_int () == CODE_gzip_packed); +void work_packed (struct connection *c, long long msg_id) { + assert (fetch_int (c->mtconnection) == CODE_gzip_packed); static int in_gzip; static int buf[MAX_PACKED_SIZE >> 2]; assert (!in_gzip); in_gzip = 1; - int l = prefetch_strlen (); - char *s = fetch_str (l); + int l = prefetch_strlen (c->mtconnection); + char *s = fetch_str (c->mtconnection, l); int total_out = tinflate (s, l, buf, MAX_PACKED_SIZE); - int *end = in_ptr; - int *eend = in_end; + int *end = c->mtconnection->in_ptr; + int *eend = c->mtconnection->in_end; //assert (total_out % 4 == 0); - in_ptr = buf; - in_end = in_ptr + total_out / 4; + c->mtconnection->in_ptr = buf; + c->mtconnection->in_end = c->mtconnection->in_ptr + total_out / 4; if (verbosity >= 4) { logprintf ( "Unzipped data: "); - hexdump_in (); + hexdump_in (c->mtconnection); } - rpc_execute_answer (instance, msg_id); - in_ptr = end; - in_end = eend; + rpc_execute_answer (c, msg_id); + c->mtconnection->in_ptr = end; + c->mtconnection->in_end = eend; in_gzip = 0; } void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == (int)CODE_bad_server_salt); - long long id = fetch_long (); + assert (fetch_int (c->mtconnection) == (int)CODE_bad_server_salt); + long long id = fetch_long (c->mtconnection); query_restart (id); - fetch_int (); // seq_no - fetch_int (); // error_code - long long new_server_salt = fetch_long (); + fetch_int (c->mtconnection); // seq_no + fetch_int (c->mtconnection); // error_code + long long new_server_salt = fetch_long (c->mtconnection); GET_DC(c)->server_salt = new_server_salt; } void work_pong (struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == CODE_pong); - fetch_long (); // msg_id - fetch_long (); // ping_id + assert (fetch_int (c->mtconnection) == CODE_pong); + fetch_long (c->mtconnection); // msg_id + fetch_long (c->mtconnection); // ping_id } void work_detailed_info (struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == CODE_msg_detailed_info); - fetch_long (); // msg_id - fetch_long (); // answer_msg_id - fetch_int (); // bytes - fetch_int (); // status + assert (fetch_int (c->mtconnection) == CODE_msg_detailed_info); + fetch_long (c->mtconnection); // msg_id + fetch_long (c->mtconnection); // answer_msg_id + fetch_int (c->mtconnection); // bytes + fetch_int (c->mtconnection); // status } void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == (int)CODE_msg_new_detailed_info); - fetch_long (); // answer_msg_id - fetch_int (); // bytes - fetch_int (); // status + assert (fetch_int (c->mtconnection) == (int)CODE_msg_new_detailed_info); + fetch_long (c->mtconnection); // answer_msg_id + fetch_int (c->mtconnection); // bytes + fetch_int (c->mtconnection); // status } -void work_updates_to_long (struct telegram *instance, struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == (int)CODE_updates_too_long); +void work_updates_to_long (struct connection *c UU, long long msg_id UU) { + assert (fetch_int (c->mtconnection) == (int)CODE_updates_too_long); logprintf ("updates to long... Getting difference\n"); - do_get_difference (instance); + do_get_difference (c->instance); } void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { - assert (fetch_int () == (int)CODE_bad_msg_notification); - long long m1 = fetch_long (); - int s = fetch_int (); - int e = fetch_int (); + assert (fetch_int (c->mtconnection) == (int)CODE_bad_msg_notification); + long long m1 = fetch_long (c->mtconnection); + int s = fetch_int (c->mtconnection); + int e = fetch_int (c->mtconnection); logprintf ("bad_msg_notification: msg_id = %lld, seq = %d, error = %d\n", m1, s, e); } -void rpc_execute_answer (struct telegram *instance, long long msg_id UU) { - struct connection *c = telegram_get_connection(instance); +void rpc_execute_answer (struct connection *c, long long msg_id UU) { if (verbosity >= 5) { logprintf ("rpc_execute_answer: fd=%d\n", c->fd); - hexdump_in (); + hexdump_in (c->mtconnection); } - int op = prefetch_int (); + int op = prefetch_int (c->mtconnection); switch (op) { case CODE_msg_container: - work_container (instance, msg_id); + work_container (c, msg_id); return; case CODE_new_session_created: work_new_session_created (c, msg_id); @@ -1618,19 +1600,19 @@ void rpc_execute_answer (struct telegram *instance, long long msg_id UU) { work_rpc_result (c, msg_id); return; case CODE_update_short: - work_update_short (instance, msg_id); + work_update_short (c, msg_id); return; case CODE_updates: - work_updates (instance, msg_id); + work_updates (c, msg_id); return; case CODE_update_short_message: - work_update_short_message (c, msg_id, instance); + work_update_short_message (c, msg_id); return; case CODE_update_short_chat_message: - work_update_short_chat_message (c, msg_id, instance); + work_update_short_chat_message (c, msg_id); return; case CODE_gzip_packed: - work_packed (instance, msg_id); + work_packed (c, msg_id); return; case CODE_bad_server_salt: work_bad_server_salt (c, msg_id); @@ -1645,20 +1627,18 @@ void rpc_execute_answer (struct telegram *instance, long long msg_id UU) { work_new_detailed_info (c, msg_id); return; case CODE_updates_too_long: - work_updates_to_long (instance, c, msg_id); + work_updates_to_long (c, msg_id); return; case CODE_bad_msg_notification: work_bad_msg_notification (c, msg_id); return; } logprintf ( "Unknown message: \n"); - hexdump_in (); - in_ptr = in_end; // Will not fail due to assertion in_ptr == in_end + hexdump_in (c->mtconnection); + c->mtconnection->in_ptr = c->mtconnection->in_end; // Will not fail due to assertion in_ptr == in_end } -int process_rpc_message (struct telegram *instance, struct encrypted_message *enc, int len) { - struct connection *c UU = telegram_get_connection(instance); - +int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); if (verbosity) { @@ -1668,8 +1648,8 @@ int process_rpc_message (struct telegram *instance, struct encrypted_message *en struct dc *DC = GET_DC(c); assert (enc->auth_key_id == DC->auth_key_id); assert (DC->auth_key_id); - init_aes_auth (DC->auth_key + 8, enc->msg_key, AES_DECRYPT); - int l = pad_aes_decrypt ((char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); + init_aes_auth (c->mtconnection, DC->auth_key + 8, enc->msg_key, AES_DECRYPT); + int l = pad_aes_decrypt (c->mtconnection, (char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); assert (l == len - UNENCSZ); //assert (enc->auth_key_id2 == enc->auth_key_id); assert (!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12); @@ -1689,159 +1669,100 @@ int process_rpc_message (struct telegram *instance, struct encrypted_message *en } double st = get_server_time (DC); if (this_server_time < st - 300 || this_server_time > st + 30) { - logprintf ("salt = %lld, session_id = %lld, msg_id = %lld, seq_no = %d, st = %lf, now = %lf\n", enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); - in_ptr = enc->message; - in_end = in_ptr + (enc->msg_len / 4); - hexdump_in (); + logprintf ("salt = %lld, session_id = %lld, msg_id = %lld, seq_no = %d, st = %lf, now = %lf\n", + enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); + c->mtconnection->in_ptr = enc->message; + c->mtconnection->in_end = c->mtconnection->in_ptr + (enc->msg_len / 4); + hexdump_in (c->mtconnection); } assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); if (verbosity >= 1) { logprintf ( "received mesage id %016llx\n", enc->msg_id); - hexdump_in (); + hexdump_in (c->mtconnection); } - server_last_msg_id = enc->msg_id; + c->mtconnection->server_last_msg_id = enc->msg_id; //*(long long *)(longpoll_query + 3) = *(long long *)((char *)(&enc->msg_id) + 0x3c); //*(long long *)(longpoll_query + 5) = *(long long *)((char *)(&enc->msg_id) + 0x3c); assert (l >= (MINSZ - UNENCSZ) + 8); //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); - ++good_messages; + ++c->mtconnection->good_messages; - in_ptr = enc->message; - in_end = in_ptr + (enc->msg_len / 4); + c->mtconnection->in_ptr = enc->message; + c->mtconnection->in_end = c->mtconnection->in_ptr + (enc->msg_len / 4); if (enc->msg_id & 1) { insert_msg_id (c->session, enc->msg_id); } assert (c->session->session_id == enc->session_id); - rpc_execute_answer (instance, enc->msg_id); - assert (in_ptr == in_end); + rpc_execute_answer (c, enc->msg_id); + assert (c->mtconnection->in_ptr == c->mtconnection->in_end); return 0; } -//int rpc_execute (struct connection *c, int op, int len) { -// if (verbosity) { -// logprintf ( "outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); -// } -// if (op < 0) { -// assert (read_in (c, Response, Response_len) == Response_len); -// return 0; -// } -// -// if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { -// logprintf ( "answer too long (%d bytes), skipping\n", len); -// return 0; -// } -// -// int Response_len = len; -// -// if (verbosity >= 2) { -// logprintf ("Response_len = %d\n", Response_len); -// } -// assert (read_in (c, Response, Response_len) == Response_len); -// Response[Response_len] = 0; -// if (verbosity >= 2) { -// logprintf ( "have %d Response bytes\n", Response_len); -// } -// -// int o = c_state; -// if (GET_DC(c)->flags & 1) { o = st_authorized;} -// switch (o) { -// case st_reqpq_sent: -// process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); -// return 0; -// case st_reqdh_sent: -// process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); -// return 0; -// case st_client_dh_sent: -// process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); -// return 0; -// case st_authorized: -// if (op < 0 && op >= -999) { -// logprintf ("Server error %d\n", op); -// } else { -// process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); -// } -// return 0; -// default: -// logprintf ( "fatal: cannot receive answer in state %d\n", c_state); -// exit (2); -// } -// -// return 0; -//} - -int rpc_execute_req_pq (struct telegram *instance, int len) { - logprintf("rpc_execute_rq_dh()\n"); - struct connection *c = telegram_get_connection(instance); - if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - logprintf ( "answer too long (%d bytes), skipping\n", len); - queries_num--; +int rpc_execute (struct connection *c, int op, int len) { + logprintf ("outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); + struct mtproto_connection *self = c->mtconnection; + + self->queries_num --; + logprintf ("queries_num=%d\n", c->mtconnection->queries_num); + /* + if (op < 0) { + assert (read_in (c, Response, Response_len) == Response_len); return 0; } + */ + + if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { + logprintf ( "answer too long (%d bytes), skipping\n", len); + return 0; + } + int Response_len = len; + + if (verbosity >= 2) { + logprintf ("Response_len = %d\n", Response_len); + } assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; - process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); - queries_num--; + if (verbosity >= 2) { + logprintf ( "have %d Response bytes\n", Response_len); + } + + int o = c->mtconnection->c_state; + if (GET_DC(c)->flags & 1) { o = st_authorized;} + switch (o) { + case st_reqpq_sent: + process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); + return 0; + case st_reqdh_sent: + process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); + return 0; + case st_client_dh_sent: + process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); + if (self->on_ready) { + self->on_ready(self, self->on_ready_data); + } + return 0; + case st_authorized: + if (op < 0 && op >= -999) { + logprintf ("Server error %d\n", op); + } else { + process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); + } + return 0; + default: + logprintf ( "fatal: cannot receive answer in state %d\n", c->mtconnection->c_state); + exit (2); + } + return 0; } -int rpc_execute_rq_dh (struct telegram *instance, int len) { - logprintf("rpc_execute_rq_dh()\n"); - struct connection *c = telegram_get_connection(instance); - if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - logprintf ( "answer too long (%d bytes), skipping\n", len); - queries_num--; - return 0; - } - int Response_len = len; - assert (read_in (c, Response, Response_len) == Response_len); - Response[Response_len] = 0; - process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); - queries_num--; - return 0; -} - -int rpc_execute_cdh_sent (struct telegram *instance, int len) { - logprintf("rpc_execute_cdh()\n"); - struct connection *c = telegram_get_connection(instance); - if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - logprintf ( "answer too long (%d bytes), skipping\n", len); - queries_num--; - return 0; - } - int Response_len = len; - assert (read_in (c, Response, Response_len) == Response_len); - Response[Response_len] = 0; - process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); - queries_num--; - return 0; -} - -int rpc_execute_authorized (struct telegram *instance, int op, int len) { - logprintf("rpc_execute_authorized()\n"); - struct connection *c = telegram_get_connection(instance); - if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - logprintf ( "answer too long (%d bytes), skipping\n", len); - queries_num--; - return 0; - } - int Response_len = len; - assert (read_in (c, Response, Response_len) == Response_len); - Response[Response_len] = 0; - if (op < 0 && op >= -999) { - logprintf ("Server error %d\n", op); - } else { - process_rpc_message (instance, (void *)(Response/* + 8*/), Response_len/* - 12*/); - } - queries_num--; - return 0; -} int tc_close (struct connection *c, int who) { if (verbosity) { @@ -1851,14 +1772,15 @@ int tc_close (struct connection *c, int who) { } int tc_becomes_ready (struct connection *c) { - if (verbosity) { - logprintf ( "outbound connection #%d becomes ready\n", c->fd); - } + logprintf ( "outbound connection #%d becomes ready\n", c->fd); char byte = 0xef; assert (write_out (c, &byte, 1) == 1); + flush_out (c); - int o = c_state; - if (GET_DC(c)->flags & 1) { o = st_authorized; } + int o = c->mtconnection->c_state; + if (GET_DC(c)->flags & 1) { + o = st_authorized; + } switch (o) { case st_init: send_req_pq_packet (c); @@ -1867,7 +1789,7 @@ int tc_becomes_ready (struct connection *c) { auth_work_start (c); break; default: - logprintf ( "c_state = %d\n", c_state); + logprintf ( "c_state = %d\n", c->mtconnection->c_state); assert (0); } return 0; @@ -1881,15 +1803,15 @@ int rpc_close (struct connection *c) { return tc_close (c, 0); } -int auth_is_success (void) { - return auth_success; +int auth_is_success (struct mtproto_connection *m) { + return m->auth_success; } #define RANDSEED_PASSWORD_FILENAME NULL #define RANDSEED_PASSWORD_LENGTH 0 -void on_start (void) { - prng_seed (RANDSEED_PASSWORD_FILENAME, RANDSEED_PASSWORD_LENGTH); +void on_start (struct mtproto_connection *self) { + prng_seed (self, RANDSEED_PASSWORD_FILENAME, RANDSEED_PASSWORD_LENGTH); if (rsa_public_key_name) { if (rsa_load_public_key (rsa_public_key_name) < 0) { @@ -1906,17 +1828,65 @@ void on_start (void) { pk_fingerprint = compute_rsa_key_fingerprint (pubKey); } +/* int auth_ok (void) { return auth_success; } +*/ /* void dc_authorize (struct dc *DC) { c_state = 0; auth_success = 0; + if (!DC->sessions[0]) { + dc_create_session (DC); + } if (verbosity) { logprintf ( "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); } - //net_loop (0, auth_ok); + net_loop (0, auth_ok); } */ + + +struct connection_methods mtproto_methods = { + .execute = rpc_execute, + .ready = rpc_becomes_ready, + .close = rpc_close +}; + +/** + * Create a new struct mtproto_connection connection using the giving datacenter for authorization and + * session handling + */ +struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg) +{ + // init + struct mtproto_connection *mtp = talloc(sizeof(struct mtproto_connection)); + memset(mtp, 0, sizeof(struct mtproto_connection)); + mtp->packet_buffer = mtp->__packet_buffer + 16; + mtp->connection = fd_create_connection(DC, fd, tg, &mtproto_methods, mtp); + return mtp; +} + +/** + * Connect to the network + */ +void mtproto_connect(struct mtproto_connection *c) +{ + on_start(c); + c->connection->methods->ready(c->connection); + + // Don't ping TODO: Really? Timeout callback functions of libpurple + //start_ping_timer (c->connection); +} + +/** + * Free all used resources and close the connection + */ +void mtproto_close(struct mtproto_connection *c) +{ + // TODO: Use Pings? + // stop_ping_timer (c->connection); + fd_close_connection(c->connection); +} diff --git a/mtproto-client.h b/mtproto-client.h index d5a581f..392c392 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -14,29 +14,482 @@ You should have received a copy of the GNU General Public License along with this telegram-client. If not, see . - Copyright Nikolay Durov, Andrey Lopatin 2012-2013 +Copyright Nikolay Durov, Andrey Lopatin 2012-2013 Copyright Vitaly Valtman 2013 */ #ifndef __MTPROTO_CLIENT_H__ #define __MTPROTO_CLIENT_H__ -#include "net.h" + + +/* + * COMMON + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include #include -void on_start (void); -long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); -//void dc_authorize (struct dc *DC); -void work_update (struct connection *c, long long msg_id); -void work_update_binlog (void); +#include +#include +#include +#include +#include +#include +#include + +#include "include.h" +#include "tools.h" +#include "constants.h" +#include "msglog.h" +#include "net.h" + +#ifdef __MACH__ +#include +#include +#endif + + +/* DH key exchange protocol data structures */ +#define CODE_req_pq 0x60469778 +#define CODE_resPQ 0x05162463 +#define CODE_req_DH_params 0xd712e4be +#define CODE_p_q_inner_data 0x83c95aec +#define CODE_server_DH_inner_data 0xb5890dba +#define CODE_server_DH_params_fail 0x79cb045d +#define CODE_server_DH_params_ok 0xd0e8075c +#define CODE_set_client_DH_params 0xf5045f1f +#define CODE_client_DH_inner_data 0x6643b654 +#define CODE_dh_gen_ok 0x3bcbf734 +#define CODE_dh_gen_retry 0x46dc1fb9 +#define CODE_dh_gen_fail 0xa69dae02 + +/* service messages */ +#define CODE_rpc_result 0xf35c6d01 +#define CODE_rpc_error 0x2144ca19 +#define CODE_msg_container 0x73f1f8dc +#define CODE_msg_copy 0xe06046b2 +#define CODE_msgs_ack 0x62d6b459 +#define CODE_bad_msg_notification 0xa7eff811 +#define CODE_bad_server_salt 0xedab447b +#define CODE_msgs_state_req 0xda69fb52 +#define CODE_msgs_state_info 0x04deb57d +#define CODE_msgs_all_info 0x8cc0d131 +#define CODE_new_session_created 0x9ec20908 +#define CODE_msg_resend_req 0x7d861a08 +#define CODE_ping 0x7abe77ec +#define CODE_pong 0x347773c5 +#define CODE_destroy_session 0xe7512126 +#define CODE_destroy_session_ok 0xe22045fc +#define CODE_destroy_session_none 0x62d350c9 +#define CODE_destroy_sessions 0x9a6face8 +#define CODE_destroy_sessions_res 0xa8164668 +#define CODE_get_future_salts 0xb921bd04 +#define CODE_future_salt 0x0949d9dc +#define CODE_future_salts 0xae500895 +#define CODE_rpc_drop_answer 0x58e4a740 +#define CODE_rpc_answer_unknown 0x5e2ad36e +#define CODE_rpc_answer_dropped_running 0xcd78e586 +#define CODE_rpc_answer_dropped 0xa43ad8b7 +#define CODE_msg_detailed_info 0x276d3ec6 +#define CODE_msg_new_detailed_info 0x809db6df +#define CODE_ping_delay_disconnect 0xf3427b8c +#define CODE_gzip_packed 0x3072cfa1 + +#define CODE_input_peer_notify_settings_old 0x3cf4b1be +#define CODE_peer_notify_settings_old 0xddbcd4a5 +#define CODE_user_profile_photo_old 0x990d1493 +#define CODE_config_old 0x232d5905 + +#define CODE_msg_new_detailed_info 0x809db6df + +#define CODE_msg_detailed_info 0x276d3ec6 +/* not really a limit, for struct encrypted_message only */ +// #define MAX_MESSAGE_INTS 16384 +#define MAX_MESSAGE_INTS 1048576 +#define MAX_PROTO_MESSAGE_INTS 1048576 +#define _FILE_OFFSET_BITS 64 + + +#pragma pack(push,4) +struct encrypted_message { + // unencrypted header + long long auth_key_id; + char msg_key[16]; + // encrypted part, starts with encrypted header + long long server_salt; + long long session_id; + // long long auth_key_id2; // removed + // first message follows + long long msg_id; + int seq_no; + int msg_len; // divisible by 4 + int message[MAX_MESSAGE_INTS]; +}; +#pragma pack(pop) + +/* + * CONNECTION STATES + */ + +enum dc_state { + st_init, + st_reqpq_sent, + st_reqdh_sent, + st_client_dh_sent, + st_authorized, + st_error +}; + +/* + * CLIENT + */ + +// forward-declarations +struct timespec; +struct telegram; + +#define DECRYPT_BUFFER_INTS 16384 +#define ENCRYPT_BUFFER_INTS 16384 +#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix + +struct mtproto_connection { + struct connection *connection; + + int auth_success; + enum dc_state c_state; + char nonce[256]; + char new_nonce[256]; + char server_nonce[256]; + + int total_packets_sent; + long long total_data_sent; + + unsigned long long what; + unsigned p1, p2; + + int *in_ptr, *in_end; + + // common + + int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr; + int *packet_buffer; + + long long rsa_encrypted_chunks, rsa_decrypted_chunks; + + BN_CTX *BN_ctx; + + + // DH + + int encrypt_buffer[ENCRYPT_BUFFER_INTS]; + int decrypt_buffer[ENCRYPT_BUFFER_INTS]; + char s_power [256]; + BIGNUM dh_prime, dh_g, g_a, dh_power, auth_key_num; + + struct { + long long auth_key_id; + long long out_msg_id; + int msg_len; + } unenc_msg_header; + + + // AES IGE + + unsigned char aes_key_raw[32], aes_iv[32]; + AES_KEY aes_key; + + // authorized + + struct encrypted_message enc_msg; + long long client_last_msg_id; + long long server_last_msg_id; + + int longpoll_count, good_messages; + + int unread_messages; + int our_id; + int pts; + int qts; + int last_date; + int seq; + + // extra (queries.c) + + int *encr_extra; + int *encr_ptr; + int *encr_end; + + // callbacks + + void (*on_ready)(struct mtproto_connection *self, void* data); + void *on_ready_data; + + void (*on_error)(struct mtproto_connection *self, void *data); + + // the amount of currently outgoing messages that + // have not yet received a response + int queries_num; +}; + +void mtproto_connection_init (struct mtproto_connection *c); +struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg); +void mtproto_connect(struct mtproto_connection *c); + +void on_start (struct mtproto_connection *self); +long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful); +void work_update (struct mtproto_connection *self, long long msg_id); +void work_update_binlog (struct mtproto_connection *self); int check_g (unsigned char p[256], BIGNUM *g); int check_g_bn (BIGNUM *p, BIGNUM *g); -int check_DH_params (BIGNUM *p, int g); +int check_DH_params (struct mtproto_connection *self, BIGNUM *p, int g); void secure_random (void *s, int l); +/* + * Common 2 + */ -int send_req_pq_packet (struct connection *c); +void prng_seed (struct mtproto_connection *self, const char *password_filename, int password_length); +int serialize_bignum (BIGNUM *b, char *buffer, int maxlen); +long long compute_rsa_key_fingerprint (RSA *key); -int rpc_execute_req_pq (struct telegram *instance, int len); -int rpc_execute_rq_dh (struct telegram *instance, int len); -int rpc_execute_cdh_sent (struct telegram *instance, int len); -int rpc_execute_authorized (struct telegram *instance, int op, int len); +static inline void out_ints (struct mtproto_connection *self, const int *what, int len) { + assert (self->packet_ptr + len <= self->packet_buffer + PACKET_BUFFER_SIZE); + memcpy (self->packet_ptr, what, len * 4); + self->packet_ptr += len; +} + + +static inline void out_int (struct mtproto_connection *self, int x) { + assert (self->packet_ptr + 1 <= self->packet_buffer + PACKET_BUFFER_SIZE); + *self->packet_ptr++ = x; +} + + +static inline void out_long (struct mtproto_connection *self, long long x) { + assert (self->packet_ptr + 2 <= self->packet_buffer + PACKET_BUFFER_SIZE); + *(long long *)self->packet_ptr = x; + self->packet_ptr += 2; +} + +static inline void clear_packet (struct mtproto_connection *self) { + self->packet_ptr = self->packet_buffer; +} + +void out_cstring (struct mtproto_connection *self, const char *str, long len); +void out_cstring_careful (struct mtproto_connection *self, const char *str, long len); +void out_data (struct mtproto_connection *self, const void *data, long len); + +static inline void out_string (struct mtproto_connection *self, const char *str) { + out_cstring (self, str, strlen (str)); +} + +static inline void out_bignum (struct mtproto_connection *self, BIGNUM *n) { + int l = serialize_bignum (n, (char *)self->packet_ptr, (PACKET_BUFFER_SIZE - (self->packet_ptr - self->packet_buffer)) * 4); + assert (l > 0); + self->packet_ptr += l >> 2; +} + + +void fetch_pts (struct mtproto_connection *self); +void fetch_qts (struct mtproto_connection *self); +void fetch_date (struct mtproto_connection *self); +void fetch_seq (struct mtproto_connection *self); +static inline int prefetch_strlen (struct mtproto_connection *self) { + if (self->in_ptr >= self->in_end) { + return -1; + } + unsigned l = *self->in_ptr; + if ((l & 0xff) < 0xfe) { + l &= 0xff; + return (self->in_end >= self->in_ptr + (l >> 2) + 1) ? (int)l : -1; + } else if ((l & 0xff) == 0xfe) { + l >>= 8; + return (l >= 254 && self->in_end >= self->in_ptr + ((l + 7) >> 2)) ? (int)l : -1; + } else { + return -1; + } +} + +extern int verbosity; +static inline char *fetch_str (struct mtproto_connection *self, int len) { + assert (len >= 0); + if (verbosity > 6) { + logprintf ("fetch_string: len = %d\n", len); + } + if (len < 254) { + char *str = (char *) self->in_ptr + 1; + self->in_ptr += 1 + (len >> 2); + return str; + } else { + char *str = (char *) self->in_ptr + 4; + self->in_ptr += (len + 7) >> 2; + return str; + } +} + +static inline char *fetch_str_dup (struct mtproto_connection *self) { + int l = prefetch_strlen (self); + assert (l >= 0); + int i; + char *s = fetch_str (self, l); + for (i = 0; i < l; i++) { + if (!s[i]) { break; } + } + char *r = talloc (i + 1); + memcpy (r, s, i); + r[i] = 0; + return r; +} + +static inline int fetch_update_str (struct mtproto_connection *self, char **s) { + if (!*s) { + *s = fetch_str_dup (self); + return 1; + } + int l = prefetch_strlen (self); + char *r = fetch_str (self, l); + if (memcmp (*s, r, l) || (*s)[l]) { + tfree_str (*s); + *s = talloc (l + 1); + memcpy (*s, r, l); + (*s)[l] = 0; + return 1; + } + return 0; +} + +static inline int fetch_update_int (struct mtproto_connection *self, int *value) { + if (*value == *self->in_ptr) { + self->in_ptr ++; + return 0; + } else { + *value = *(self->in_ptr ++); + return 1; + } +} + +static inline int fetch_update_long (struct mtproto_connection *self, long long *value) { + if (*value == *(long long *)self->in_ptr) { + self->in_ptr += 2; + return 0; + } else { + *value = *(long long *)(self->in_ptr); + self->in_ptr += 2; + return 1; + } +} + +static inline int set_update_int (int *value, int new_value) { + if (*value == new_value) { + return 0; + } else { + *value = new_value; + return 1; + } +} + +static inline void fetch_skip (struct mtproto_connection *self, int n) { + self->in_ptr += n; + assert (self->in_ptr <= self->in_end); +} + +static inline void fetch_skip_str (struct mtproto_connection *self) { + int l = prefetch_strlen (self); + assert (l >= 0); + fetch_str (self, l); +} + +static inline long have_prefetch_ints (struct mtproto_connection *self) { + return self->in_end - self->in_ptr; +} + +int fetch_bignum (struct mtproto_connection *self, BIGNUM *x); + +static inline int fetch_int (struct mtproto_connection *self) { + assert (self->in_ptr + 1 <= self->in_end); + if (verbosity > 6) { + logprintf ("fetch_int: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); + } + return *(self->in_ptr ++); +} + +static inline int fetch_bool (struct mtproto_connection *self) { + if (verbosity > 6) { + logprintf ("fetch_bool: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); + } + assert (self->in_ptr + 1 <= self->in_end); + assert (*(self->in_ptr) == (int)CODE_bool_true || *(self->in_ptr) == (int)CODE_bool_false); + return *(self->in_ptr ++) == (int)CODE_bool_true; +} + +static inline int prefetch_int (struct mtproto_connection *self) { + assert (self->in_ptr < self->in_end); + return *(self->in_ptr); +} + +static inline void prefetch_data (struct mtproto_connection *self, void *data, int size) { + assert (self->in_ptr + (size >> 2) <= self->in_end); + memcpy (data, self->in_ptr, size); +} + +static inline void fetch_data (struct mtproto_connection *self, void *data, int size) { + assert (self->in_ptr + (size >> 2) <= self->in_end); + memcpy (data, self->in_ptr, size); + assert (!(size & 3)); + self->in_ptr += (size >> 2); +} + +static inline long long fetch_long (struct mtproto_connection *self) { + assert (self->in_ptr + 2 <= self->in_end); + long long r = *(long long *)self->in_ptr; + self->in_ptr += 2; + return r; +} + +static inline double fetch_double (struct mtproto_connection *self) { + assert (self->in_ptr + 2 <= self->in_end); + double r = *(double *)self->in_ptr; + self->in_ptr += 2; + return r; +} + +static inline void fetch_ints (struct mtproto_connection *self, void *data, int count) { + assert (self->in_ptr + count <= self->in_end); + memcpy (data, self->in_ptr, 4 * count); + self->in_ptr += count; +} + +int get_random_bytes (unsigned char *buf, int n); + +int pad_rsa_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E); +int pad_rsa_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D); + +void init_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32], int encrypt); +void init_aes_auth (struct mtproto_connection *self, char auth_key[192], char msg_key[16], int encrypt); +int pad_aes_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size); +int pad_aes_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size); + +static inline void hexdump_in (struct mtproto_connection *self) { + hexdump (self->in_ptr, self->in_end); +} + +static inline void hexdump_out (struct mtproto_connection *self) { + hexdump (self->packet_buffer, self->packet_ptr); +} + +#ifdef __MACH__ +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#endif +void my_clock_gettime (int clock_id, struct timespec *T); #endif diff --git a/mtproto-common.c b/mtproto-common.c index 28027c4..e1e9535 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -1,60 +1,14 @@ +#include "mtproto-client.h" + /* - This file is part of telegram-client. + * struct mtproto_connection-Common.c + */ - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Nikolay Durov, Andrey Lopatin 2012-2013 - Copyright Vitaly Valtman 2013 -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define _FILE_OFFSET_BITS 64 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mtproto-common.h" -#include "include.h" - -#ifdef __MACH__ -#include -#include -#endif - - -int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr; -int *packet_buffer = __packet_buffer + 16; - -long long rsa_encrypted_chunks, rsa_decrypted_chunks; - -BN_CTX *BN_ctx; int verbosity; +#ifndef __MTPROTO_COMMON_C__ +#define __MTPROTO_COMMON_C__ + int get_random_bytes (unsigned char *buf, int n) { int r = 0, h = open ("/dev/random", O_RDONLY | O_NONBLOCK); if (h >= 0) { @@ -121,7 +75,7 @@ static __inline__ unsigned long long rdtsc (void) { } #endif -void prng_seed (const char *password_filename, int password_length) { +void prng_seed (struct mtproto_connection *self, const char *password_filename, int password_length) { struct timespec T; my_clock_gettime (CLOCK_REALTIME, &T); RAND_add (&T, sizeof (T), 4.0); @@ -158,8 +112,8 @@ void prng_seed (const char *password_filename, int password_length) { tfree_secure (a, password_length); } } - BN_ctx = BN_CTX_new (); - ensure_ptr (BN_ctx); + self->BN_ctx = BN_CTX_new (); + ensure_ptr (self->BN_ctx); } int serialize_bignum (BIGNUM *b, char *buffer, int maxlen) { @@ -204,14 +158,14 @@ long long compute_rsa_key_fingerprint (RSA *key) { return *(long long *)(sha + 12); } -void out_cstring (const char *str, long len) { +void out_cstring (struct mtproto_connection *self, const char *str, long len) { assert (len >= 0 && len < (1 << 24)); - assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); - char *dest = (char *) packet_ptr; + assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE)); + char *dest = (char *) self->packet_ptr; if (len < 254) { *dest++ = len; } else { - *packet_ptr = (len << 8) + 0xfe; + *self->packet_ptr = (len << 8) + 0xfe; dest += 4; } memcpy (dest, str, len); @@ -219,13 +173,13 @@ void out_cstring (const char *str, long len) { while ((long) dest & 3) { *dest++ = 0; } - packet_ptr = (int *) dest; + self->packet_ptr = (int *) dest; } -void out_cstring_careful (const char *str, long len) { +void out_cstring_careful (struct mtproto_connection *self, const char *str, long len) { assert (len >= 0 && len < (1 << 24)); - assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE)); - char *dest = (char *) packet_ptr; + assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE)); + char *dest = (char *) self->packet_ptr; if (len < 254) { dest++; if (dest != str) { @@ -237,36 +191,35 @@ void out_cstring_careful (const char *str, long len) { if (dest != str) { memmove (dest, str, len); } - *packet_ptr = (len << 8) + 0xfe; + *self->packet_ptr = (len << 8) + 0xfe; } dest += len; while ((long) dest & 3) { *dest++ = 0; } - packet_ptr = (int *) dest; + self->packet_ptr = (int *) dest; } -void out_data (const void *data, long len) { +void out_data (struct mtproto_connection *self, 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); - packet_ptr += len >> 2; + assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE)); + memcpy (self->packet_ptr, data, len); + self->packet_ptr += len >> 2; } -int *in_ptr, *in_end; -int fetch_bignum (BIGNUM *x) { - int l = prefetch_strlen (); +int fetch_bignum (struct mtproto_connection *self, BIGNUM *x) { + int l = prefetch_strlen (self); if (l < 0) { return l; } - char *str = fetch_str (l); + char *str = fetch_str (self, l); assert (BN_bin2bn ((unsigned char *) str, l, x) == x); return l; } -int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E) { +int pad_rsa_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E) { int pad = (255000 - from_len - 32) % 255 + 32; int chunks = (from_len + pad) / 255; int bits = BN_num_bits (N); @@ -278,10 +231,10 @@ int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BI BIGNUM x, y; BN_init (&x); BN_init (&y); - rsa_encrypted_chunks += chunks; + self->rsa_encrypted_chunks += chunks; for (i = 0; i < chunks; i++) { BN_bin2bn ((unsigned char *) from, 255, &x); - assert (BN_mod_exp (&y, &x, E, N, BN_ctx) == 1); + assert (BN_mod_exp (&y, &x, E, N, self->BN_ctx) == 1); unsigned l = 256 - BN_num_bytes (&y); assert (l <= 256); memset (to, 0, l); @@ -293,7 +246,7 @@ int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BI return chunks * 256; } -int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D) { +int pad_rsa_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D) { if (from_len < 0 || from_len > 0x1000 || (from_len & 0xff)) { return -1; } @@ -306,9 +259,9 @@ int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BI BN_init (&x); BN_init (&y); for (i = 0; i < chunks; i++) { - ++rsa_decrypted_chunks; + ++self->rsa_decrypted_chunks; BN_bin2bn ((unsigned char *) from, 256, &x); - assert (BN_mod_exp (&y, &x, D, N, BN_ctx) == 1); + assert (BN_mod_exp (&y, &x, D, N, self->BN_ctx) == 1); int l = BN_num_bytes (&y); if (l > 255) { BN_free (&x); @@ -325,31 +278,28 @@ int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BI return chunks * 255; } -unsigned char aes_key_raw[32], aes_iv[32]; -AES_KEY aes_key; - -void init_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32], int encrypt) { +void init_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32], int encrypt) { static unsigned char buffer[64], hash[20]; memcpy (buffer, hidden_client_nonce, 32); memcpy (buffer + 32, server_nonce, 16); - SHA1 (buffer, 48, aes_key_raw); + SHA1 (buffer, 48, self->aes_key_raw); memcpy (buffer + 32, hidden_client_nonce, 32); - SHA1 (buffer, 64, aes_iv + 8); + SHA1 (buffer, 64, self->aes_iv + 8); memcpy (buffer, server_nonce, 16); memcpy (buffer + 16, hidden_client_nonce, 32); SHA1 (buffer, 48, hash); - memcpy (aes_key_raw + 20, hash, 12); - memcpy (aes_iv, hash + 12, 8); - memcpy (aes_iv + 28, hidden_client_nonce, 4); + memcpy (self->aes_key_raw + 20, hash, 12); + memcpy (self->aes_iv, hash + 12, 8); + memcpy (self->aes_iv + 28, hidden_client_nonce, 4); if (encrypt == AES_ENCRYPT) { - AES_set_encrypt_key (aes_key_raw, 32*8, &aes_key); + AES_set_encrypt_key (self->aes_key_raw, 32*8, &self->aes_key); } else { - AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key); + AES_set_decrypt_key (self->aes_key_raw, 32*8, &self->aes_key); } - memset (aes_key_raw, 0, sizeof (aes_key_raw)); + memset (self->aes_key_raw, 0, sizeof (self->aes_key_raw)); } -void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt) { +void init_aes_auth (struct mtproto_connection *self, char auth_key[192], char msg_key[16], int encrypt) { static unsigned char buffer[48], hash[20]; // sha1_a = SHA1 (msg_key + substr (auth_key, 0, 32)); // sha1_b = SHA1 (substr (auth_key, 32, 16) + msg_key + substr (auth_key, 48, 16)); @@ -360,51 +310,50 @@ void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt) { memcpy (buffer, msg_key, 16); memcpy (buffer + 16, auth_key, 32); SHA1 (buffer, 48, hash); - memcpy (aes_key_raw, hash, 8); - memcpy (aes_iv, hash + 8, 12); + memcpy (self->aes_key_raw, hash, 8); + memcpy (self->aes_iv, hash + 8, 12); memcpy (buffer, auth_key + 32, 16); memcpy (buffer + 16, msg_key, 16); memcpy (buffer + 32, auth_key + 48, 16); SHA1 (buffer, 48, hash); - memcpy (aes_key_raw + 8, hash + 8, 12); - memcpy (aes_iv + 12, hash, 8); + memcpy (self->aes_key_raw + 8, hash + 8, 12); + memcpy (self->aes_iv + 12, hash, 8); memcpy (buffer, auth_key + 64, 32); memcpy (buffer + 32, msg_key, 16); SHA1 (buffer, 48, hash); - memcpy (aes_key_raw + 20, hash + 4, 12); - memcpy (aes_iv + 20, hash + 16, 4); + memcpy (self->aes_key_raw + 20, hash + 4, 12); + memcpy (self->aes_iv + 20, hash + 16, 4); memcpy (buffer, msg_key, 16); memcpy (buffer + 16, auth_key + 96, 32); SHA1 (buffer, 48, hash); - memcpy (aes_iv + 24, hash, 8); + memcpy (self->aes_iv + 24, hash, 8); if (encrypt == AES_ENCRYPT) { - AES_set_encrypt_key (aes_key_raw, 32*8, &aes_key); + AES_set_encrypt_key (self->aes_key_raw, 32*8, &self->aes_key); } else { - AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key); + AES_set_decrypt_key (self->aes_key_raw, 32*8, &self->aes_key); } - memset (aes_key_raw, 0, sizeof (aes_key_raw)); + memset (self->aes_key_raw, 0, sizeof (self->aes_key_raw)); } -int pad_aes_encrypt (char *from, int from_len, char *to, int size) { +int pad_aes_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size) { int padded_size = (from_len + 15) & -16; assert (from_len > 0 && padded_size <= size); if (from_len < padded_size) { assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, padded_size - from_len) >= 0); } - AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, padded_size, &aes_key, aes_iv, AES_ENCRYPT); + AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, padded_size, &self->aes_key, self->aes_iv, AES_ENCRYPT); return padded_size; } -int pad_aes_decrypt (char *from, int from_len, char *to, int size) { +int pad_aes_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size) { if (from_len <= 0 || from_len > size || (from_len & 15)) { return -1; } - AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, from_len, &aes_key, aes_iv, AES_DECRYPT); + AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, from_len, &self->aes_key, self->aes_iv, AES_DECRYPT); return from_len; } - - +#endif diff --git a/mtproto-common.h b/mtproto-common.h deleted file mode 100644 index da8c49f..0000000 --- a/mtproto-common.h +++ /dev/null @@ -1,357 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Nikolay Durov, Andrey Lopatin 2012-2013 - Copyright Vitaly Valtman 2013 -*/ -#ifndef __MTPROTO_COMMON_H__ -#define __MTPROTO_COMMON_H__ - -#include -#include -#include -#include -#include -#include - -#include "tools.h" -#include "constants.h" -#include "msglog.h" - -/* DH key exchange protocol data structures */ -#define CODE_req_pq 0x60469778 -#define CODE_resPQ 0x05162463 -#define CODE_req_DH_params 0xd712e4be -#define CODE_p_q_inner_data 0x83c95aec -#define CODE_server_DH_inner_data 0xb5890dba -#define CODE_server_DH_params_fail 0x79cb045d -#define CODE_server_DH_params_ok 0xd0e8075c -#define CODE_set_client_DH_params 0xf5045f1f -#define CODE_client_DH_inner_data 0x6643b654 -#define CODE_dh_gen_ok 0x3bcbf734 -#define CODE_dh_gen_retry 0x46dc1fb9 -#define CODE_dh_gen_fail 0xa69dae02 - -/* service messages */ -#define CODE_rpc_result 0xf35c6d01 -#define CODE_rpc_error 0x2144ca19 -#define CODE_msg_container 0x73f1f8dc -#define CODE_msg_copy 0xe06046b2 -#define CODE_msgs_ack 0x62d6b459 -#define CODE_bad_msg_notification 0xa7eff811 -#define CODE_bad_server_salt 0xedab447b -#define CODE_msgs_state_req 0xda69fb52 -#define CODE_msgs_state_info 0x04deb57d -#define CODE_msgs_all_info 0x8cc0d131 -#define CODE_new_session_created 0x9ec20908 -#define CODE_msg_resend_req 0x7d861a08 -#define CODE_ping 0x7abe77ec -#define CODE_pong 0x347773c5 -#define CODE_destroy_session 0xe7512126 -#define CODE_destroy_session_ok 0xe22045fc -#define CODE_destroy_session_none 0x62d350c9 -#define CODE_destroy_sessions 0x9a6face8 -#define CODE_destroy_sessions_res 0xa8164668 -#define CODE_get_future_salts 0xb921bd04 -#define CODE_future_salt 0x0949d9dc -#define CODE_future_salts 0xae500895 -#define CODE_rpc_drop_answer 0x58e4a740 -#define CODE_rpc_answer_unknown 0x5e2ad36e -#define CODE_rpc_answer_dropped_running 0xcd78e586 -#define CODE_rpc_answer_dropped 0xa43ad8b7 -#define CODE_msg_detailed_info 0x276d3ec6 -#define CODE_msg_new_detailed_info 0x809db6df -#define CODE_ping_delay_disconnect 0xf3427b8c -#define CODE_gzip_packed 0x3072cfa1 - -#define CODE_input_peer_notify_settings_old 0x3cf4b1be -#define CODE_peer_notify_settings_old 0xddbcd4a5 -#define CODE_user_profile_photo_old 0x990d1493 -#define CODE_config_old 0x232d5905 - -#define CODE_msg_new_detailed_info 0x809db6df - -#define CODE_msg_detailed_info 0x276d3ec6 -/* not really a limit, for struct encrypted_message only */ -// #define MAX_MESSAGE_INTS 16384 -#define MAX_MESSAGE_INTS 1048576 -#define MAX_PROTO_MESSAGE_INTS 1048576 - -#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix -#pragma pack(push,4) -struct encrypted_message { - // unencrypted header - long long auth_key_id; - char msg_key[16]; - // encrypted part, starts with encrypted header - long long server_salt; - long long session_id; - // long long auth_key_id2; // removed - // first message follows - long long msg_id; - int seq_no; - int msg_len; // divisible by 4 - int message[MAX_MESSAGE_INTS]; -}; - -#pragma pack(pop) - -BN_CTX *BN_ctx; - -void prng_seed (const char *password_filename, int password_length); -int serialize_bignum (BIGNUM *b, char *buffer, int maxlen); -long long compute_rsa_key_fingerprint (RSA *key); - -extern int *packet_buffer; -extern int *packet_ptr; - -static inline void out_ints (const int *what, int len) { - assert (packet_ptr + len <= packet_buffer + PACKET_BUFFER_SIZE); - memcpy (packet_ptr, what, len * 4); - packet_ptr += len; -} - - -static inline void out_int (int x) { - assert (packet_ptr + 1 <= packet_buffer + PACKET_BUFFER_SIZE); - *packet_ptr++ = x; -} - - -static inline void out_long (long long x) { - assert (packet_ptr + 2 <= packet_buffer + PACKET_BUFFER_SIZE); - *(long long *)packet_ptr = x; - packet_ptr += 2; -} - -static inline void clear_packet (void) { - packet_ptr = packet_buffer; -} - -void out_cstring (const char *str, long len); -void out_cstring_careful (const char *str, long len); -void out_data (const void *data, long len); - -static inline void out_string (const char *str) { - out_cstring (str, strlen (str)); -} - -static inline void out_bignum (BIGNUM *n) { - int l = serialize_bignum (n, (char *)packet_ptr, (PACKET_BUFFER_SIZE - (packet_ptr - packet_buffer)) * 4); - assert (l > 0); - packet_ptr += l >> 2; -} - -extern int *in_ptr, *in_end; - -void fetch_pts (void); -void fetch_qts (void); -void fetch_date (void); -void fetch_seq (void); -static inline int prefetch_strlen (void) { - if (in_ptr >= in_end) { - return -1; - } - unsigned l = *in_ptr; - if ((l & 0xff) < 0xfe) { - l &= 0xff; - return (in_end >= in_ptr + (l >> 2) + 1) ? (int)l : -1; - } else if ((l & 0xff) == 0xfe) { - l >>= 8; - return (l >= 254 && in_end >= in_ptr + ((l + 7) >> 2)) ? (int)l : -1; - } else { - return -1; - } -} - -extern int verbosity; -static inline char *fetch_str (int len) { - assert (len >= 0); - if (verbosity > 6) { - logprintf ("fetch_string: len = %d\n", len); - } - if (len < 254) { - char *str = (char *) in_ptr + 1; - in_ptr += 1 + (len >> 2); - return str; - } else { - char *str = (char *) in_ptr + 4; - in_ptr += (len + 7) >> 2; - return str; - } -} - -static inline char *fetch_str_dup (void) { - int l = prefetch_strlen (); - assert (l >= 0); - int i; - char *s = fetch_str (l); - for (i = 0; i < l; i++) { - if (!s[i]) { break; } - } - char *r = talloc (i + 1); - memcpy (r, s, i); - r[i] = 0; - return r; -} - -static inline int fetch_update_str (char **s) { - if (!*s) { - *s = fetch_str_dup (); - return 1; - } - int l = prefetch_strlen (); - char *r = fetch_str (l); - if (memcmp (*s, r, l) || (*s)[l]) { - tfree_str (*s); - *s = talloc (l + 1); - memcpy (*s, r, l); - (*s)[l] = 0; - return 1; - } - return 0; -} - -static inline int fetch_update_int (int *value) { - if (*value == *in_ptr) { - in_ptr ++; - return 0; - } else { - *value = *(in_ptr ++); - return 1; - } -} - -static inline int fetch_update_long (long long *value) { - if (*value == *(long long *)in_ptr) { - in_ptr += 2; - return 0; - } else { - *value = *(long long *)(in_ptr); - in_ptr += 2; - return 1; - } -} - -static inline int set_update_int (int *value, int new_value) { - if (*value == new_value) { - return 0; - } else { - *value = new_value; - return 1; - } -} - -static inline void fetch_skip (int n) { - in_ptr += n; - assert (in_ptr <= in_end); -} - -static inline void fetch_skip_str (void) { - int l = prefetch_strlen (); - assert (l >= 0); - fetch_str (l); -} - -static inline long have_prefetch_ints (void) { - return in_end - in_ptr; -} - -int fetch_bignum (BIGNUM *x); - -static inline int fetch_int (void) { - assert (in_ptr + 1 <= in_end); - if (verbosity > 6) { - logprintf ("fetch_int: 0x%08x (%d)\n", *in_ptr, *in_ptr); - } - return *(in_ptr ++); -} - -static inline int fetch_bool (void) { - if (verbosity > 6) { - logprintf ("fetch_bool: 0x%08x (%d)\n", *in_ptr, *in_ptr); - } - assert (in_ptr + 1 <= in_end); - assert (*(in_ptr) == (int)CODE_bool_true || *(in_ptr) == (int)CODE_bool_false); - return *(in_ptr ++) == (int)CODE_bool_true; -} - -static inline int prefetch_int (void) { - assert (in_ptr < in_end); - return *(in_ptr); -} - -static inline void prefetch_data (void *data, int size) { - assert (in_ptr + (size >> 2) <= in_end); - memcpy (data, in_ptr, size); -} - -static inline void fetch_data (void *data, int size) { - assert (in_ptr + (size >> 2) <= in_end); - memcpy (data, in_ptr, size); - assert (!(size & 3)); - in_ptr += (size >> 2); -} - -static inline long long fetch_long (void) { - assert (in_ptr + 2 <= in_end); - long long r = *(long long *)in_ptr; - in_ptr += 2; - return r; -} - -static inline double fetch_double (void) { - assert (in_ptr + 2 <= in_end); - double r = *(double *)in_ptr; - in_ptr += 2; - return r; -} - -static inline void fetch_ints (void *data, int count) { - assert (in_ptr + count <= in_end); - memcpy (data, in_ptr, 4 * count); - in_ptr += count; -} - -int get_random_bytes (unsigned char *buf, int n); - -int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E); -int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D); - -extern long long rsa_encrypted_chunks, rsa_decrypted_chunks; - -extern unsigned char aes_key_raw[32], aes_iv[32]; -extern AES_KEY aes_key; - -void init_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32], int encrypt); -void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt); -int pad_aes_encrypt (char *from, int from_len, char *to, int size); -int pad_aes_decrypt (char *from, int from_len, char *to, int size); - -static inline void hexdump_in (void) { - hexdump (in_ptr, in_end); -} - -static inline void hexdump_out (void) { - hexdump (packet_buffer, packet_ptr); -} - -#ifdef __MACH__ -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#endif -void my_clock_gettime (int clock_id, struct timespec *T); -#endif diff --git a/net.c b/net.c index d42cc6a..20f2dc8 100644 --- a/net.c +++ b/net.c @@ -1,12 +1,12 @@ /* This file is part of telegram-client. - struct telegram-client is free software: you can redistribute it and/or modify + Telegram-client is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. - struct telegram-client is distributed in the hope that it will be useful, + Telegram-client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -41,9 +41,8 @@ #include "net.h" #include "include.h" #include "mtproto-client.h" -#include "mtproto-common.h" #include "tree.h" -#include "telegram.h" +#include "interface.h" #ifndef POLLRDHUP #define POLLRDHUP 0 @@ -55,8 +54,8 @@ double get_utime (int clock_id); int verbosity; extern struct connection_methods auth_methods; -extern FILE *log_net_f ; -FILE *log_net_f = NULL; +//extern FILE *log_net_f; +FILE *log_net_f = 0; void fail_connection (struct connection *c); @@ -76,6 +75,27 @@ void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)) { netwrite = cb; } +/* + * Delegate the session creation to an external callback + * + * TODO: use dc_ensure_session instead of dc_create_session to create sessions, + * to make this actually work + */ +void dc_create_session (struct dc *DC); +void dc_ensure_session_local (struct dc *DC, void (*on_session_ready)(void)) { + dc_create_session(DC); + on_session_ready(); +} +void (*dc_ensure_session)(struct dc *DC, void (*on_session_ready)(void)); +void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))) +{ + dc_ensure_session = dc_ens_sess; +} + +/* + * + */ + #define PING_TIMEOUT 10 void start_ping_timer (struct connection *c); @@ -94,7 +114,7 @@ int ping_alarm (struct connection *c) { int x[3]; x[0] = CODE_ping; *(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 (); - encrypt_send_message (c, x, 3, 0); + encrypt_send_message (c->mtconnection, x, 3, 0); start_ping_timer (c); } else { start_ping_timer (c); @@ -113,11 +133,10 @@ void start_ping_timer (struct connection *c) { insert_event_timer (&c->ev); } +void restart_connection (struct connection *c); int fail_alarm (void *ev) { - struct connection *c = ev; - c->in_fail_timer = 0; - logprintf("Connection %d FAILED.", c->fd); - telegram_change_state(c->instance, STATE_ERROR, NULL); + ((struct connection *)ev)->in_fail_timer = 0; + restart_connection (ev); return 0; } void start_fail_timer (struct connection *c) { @@ -235,8 +254,8 @@ void flush_out (struct connection *c UU) { } #define MAX_CONNECTIONS 100 -//struct connection *Connections[MAX_CONNECTIONS]; -//int max_connection_fd; +struct connection *Connections[MAX_CONNECTIONS]; +int max_connection_fd; void rotate_port (struct connection *c) { switch (c->port) { @@ -252,24 +271,76 @@ void rotate_port (struct connection *c) { } } -struct connection *create_connection (const char *host, int port, int fd, struct telegram *instance) { +struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods) { struct connection *c = talloc0 (sizeof (*c)); + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + logprintf ("Can not create socket: %m\n"); + exit (1); + } + assert (fd >= 0 && fd < MAX_CONNECTIONS); + if (fd > max_connection_fd) { + max_connection_fd = fd; + } + int flags = -1; + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); + setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)); + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags)); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + addr.sin_addr.s_addr = inet_addr (host); + + + fcntl (fd, F_SETFL, O_NONBLOCK); + + if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { + if (errno != EINPROGRESS) { + logprintf ( "Can not connect to %s:%d %m\n", host, port); + close (fd); + tfree (c, sizeof (*c)); + return 0; + } + } + + struct pollfd s; + s.fd = fd; + s.events = POLLOUT | POLLERR | POLLRDHUP | POLLHUP; + errno = 0; + + while (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { + if (errno == EINTR) { continue; } + if (errno) { + logprintf ("Problems in poll: %m\n"); + exit (1); + } + logprintf ("Connect with %s:%d timeout\n", host, port); + close (fd); + tfree (c, sizeof (*c)); + return 0; + } + + c->session = session; c->fd = fd; c->ip = tstrdup (host); c->flags = 0; c->state = conn_ready; + c->methods = methods; c->port = port; - c->instance = instance; + assert (!Connections[fd]); + Connections[fd] = c; if (verbosity) { logprintf ( "connect to %s:%d successful\n", host, port); } + if (c->methods->ready) { + c->methods->ready (c); + } c->last_receive_time = get_double_time (); - // Don't ping TODO: Really? Timeout callback functions of libpurple - //start_ping_timer (c); + start_ping_timer (c); return c; } -/* void restart_connection (struct connection *c) { if (c->last_connect_time == time (0)) { start_fail_timer (c); @@ -318,11 +389,12 @@ void restart_connection (struct connection *c) { assert (write_out (c, &byte, 1) == 1); flush_out (c); } -*/ + void fail_connection (struct connection *c) { if (c->state == conn_ready || c->state == conn_connecting) { stop_ping_timer (c); } + rotate_port (c); struct connection_buffer *b = c->out_head; while (b) { struct connection_buffer *d = b; @@ -339,15 +411,16 @@ void fail_connection (struct connection *c) { c->state = conn_failed; c->out_bytes = c->in_bytes = 0; close (c->fd); + Connections[c->fd] = 0; logprintf ("Lost connection to server... %s:%d\n", c->ip, c->port); - telegram_change_state(c->instance, STATE_ERROR, NULL); + restart_connection (c); } extern FILE *log_net_f; -int try_write (struct telegram *instance) { - struct connection *c = telegram_get_connection(instance); - logprintf ("try write: fd = %d\n", c->fd); - +int try_write (struct connection *c) { + if (verbosity) { + logprintf ( "try write: fd = %d\n", c->fd); + } int x = 0; while (c->out_head) { int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); @@ -357,6 +430,7 @@ int try_write (struct telegram *instance) { fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { + fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); } fprintf (log_net_f, "\n"); @@ -390,7 +464,9 @@ int try_write (struct telegram *instance) { } } } - logprintf ( "Sent %d bytes to %d\n", x, c->fd); + if (verbosity) { + logprintf ( "Sent %d bytes to %d\n", x, c->fd); + } c->out_bytes -= x; return x; } @@ -419,12 +495,7 @@ void hexdump_buf (struct connection_buffer *b) { } -/** - * Read all rpc responses from the current connection - */ -void try_rpc_read (struct telegram *instance) { - struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; - +void try_rpc_read (struct connection *c) { assert (c->in_head); if (verbosity >= 3) { hexdump_buf (c->in_head); @@ -458,15 +529,14 @@ void try_rpc_read (struct telegram *instance) { len *= 4; int op; assert (read_in_lookup (c, &op, 4) == 4); - // read - //c->methods->execute (c, op, len); - try_rpc_interpret(instance, op, len); + c->methods->execute (c, op, len); } } -void try_read (struct telegram *instance) { - struct connection *c = instance->auth.DC_list[instance->auth.dc_working_num]->sessions[0]->c; - logprintf ( "try read: fd = %d\n", c->fd); +void try_read (struct connection *c) { + if (verbosity) { + logprintf ( "try read: fd = %d\n", c->fd); + } if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } @@ -477,7 +547,6 @@ void try_read (struct telegram *instance) { fprintf (log_net_f, "%.02lf %d IN %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { - // print all writte bits fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i)); } fprintf (log_net_f, "\n"); @@ -485,19 +554,14 @@ void try_read (struct telegram *instance) { } if (r > 0) { c->last_receive_time = get_double_time (); - - // TODO: Implement the Ping-Timer - // reset ping timer + // TODO implement ping? //stop_ping_timer (c); //start_ping_timer (c); } if (r >= 0) { - // write pointer nach vorne setzen c->in_tail->wptr += r; x += r; - if (c->in_tail->wptr != c->in_tail->end) { - // Paket nicht komplett beschrieben, keine neuen Daten liegen an. break; } struct connection_buffer *b = new_connection_buffer (1 << 20); @@ -505,7 +569,9 @@ void try_read (struct telegram *instance) { c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - logprintf ("fail_connection: read_error %m\n"); + if (verbosity) { + logprintf ("fail_connection: read_error %m\n"); + } fail_connection (c); return; } else { @@ -513,14 +579,15 @@ void try_read (struct telegram *instance) { } } } - logprintf ( "Received %d bytes from %d\n", x, c->fd); + if (verbosity) { + logprintf ( "Received %d bytes from %d\n", x, c->fd); + } c->in_bytes += x; if (x) { - try_rpc_read (instance); + try_rpc_read (c); } } -/* int connections_make_poll_array (struct pollfd *fds, int max) { int _max = max; int i; @@ -545,9 +612,7 @@ int connections_make_poll_array (struct pollfd *fds, int max) { } return _max - max; } -*/ -/* void connections_poll_result (struct pollfd *fds, int max) { if (verbosity >= 10) { logprintf ( "connections_poll_result: max = %d\n", max); @@ -575,19 +640,20 @@ void connections_poll_result (struct pollfd *fds, int max) { } } } -*/ int send_all_acks (struct session *S) { - clear_packet (); - out_int (CODE_msgs_ack); - out_int (CODE_vector); - out_int (tree_count_long (S->ack_tree)); + struct mtproto_connection *mt = S->c->mtconnection; + + clear_packet (mt); + out_int (mt, CODE_msgs_ack); + out_int (mt, CODE_vector); + out_int (mt, tree_count_long (S->ack_tree)); while (S->ack_tree) { long long x = tree_get_min_long (S->ack_tree); - out_long (x); + out_long (mt, x); S->ack_tree = tree_delete_long (S->ack_tree, x); } - encrypt_send_message (S->c, packet_buffer, packet_ptr - packet_buffer, 0); + encrypt_send_message (mt, mt->packet_buffer, mt->packet_ptr - mt->packet_buffer, 0); return 0; } @@ -603,7 +669,10 @@ void insert_msg_id (struct session *S, long long id) { } } +extern struct dc *DC_list[]; + struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { + assert (!DC_list[id]); struct dc *DC = talloc0 (sizeof (*DC)); DC->id = id; DC->ip = ip; @@ -612,13 +681,72 @@ struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { return DC; } -void dc_create_session (struct dc *DC, struct connection *c) { +void dc_create_session (struct dc *DC) { logprintf("dc_create_session(...)\n"); struct session *S = talloc0 (sizeof (*S)); assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); S->dc = DC; - S->c = c; + S->c = create_connection (DC->ip, DC->port, S, &auth_methods); + if (!S->c) { + logprintf ("Can not create connection to DC. Is network down?\n"); + exit (1); + } assert (!DC->sessions[0]); DC->sessions[0] = S; } +/** + * Wrap an existing socket file descriptor and make it usable as a connection, + */ +struct connection *fd_create_connection (struct dc *DC, int fd, + struct telegram *instance, struct connection_methods *methods, struct mtproto_connection *mtp) { + + // create a connection + struct connection *c = talloc0 (sizeof (*c)); + c->fd = fd; + c->ip = tstrdup (DC->ip); + c->flags = 0; + c->state = conn_ready; + c->port = DC->port; + c->methods = methods; + c->instance = instance; + c->last_receive_time = get_double_time (); + logprintf ( "connect to %s:%d successful\n", DC->ip, DC->port); + + // TODO: Load existing session from state file + // create an empty session and attach it to the dc and the connection + if (!DC->sessions[0]) { + struct session *S = talloc0 (sizeof (*S)); + assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); + S->dc = DC; + S->c = c; + DC->sessions[0] = S; + } + + // add backreference to used mtproto-connection + c->mtconnection = mtp; + + return c; +} + +/** + * Close the connection by freeing all attached buffers and setting + * the state to conn_stopped, but does NOT close the attached file descriptor + */ +void fd_close_connection(struct connection *c) { + struct connection_buffer *b = c->out_head; + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + c->out_head = c->out_tail = c->in_head = c->in_tail = 0; + c->state = conn_stopped; + c->out_bytes = c->in_bytes = 0; +} + diff --git a/net.h b/net.h index 7725222..eccac14 100644 --- a/net.h +++ b/net.h @@ -19,11 +19,14 @@ #ifndef __NET_H__ #define __NET_H__ -#define MAX_DC_ID 10 +#pragma once + #include struct dc; -#include "queries.h" +#include "mtproto-client.h" #include "telegram.h" +#include "queries.h" + #define TG_SERVER "173.240.5.1" #define TG_SERVER_TEST "173.240.5.253" #define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" @@ -33,15 +36,10 @@ struct dc; #define TG_VERSION "0.01-beta" #define ACK_TIMEOUT 1 +#define MAX_DC_ID 10 -enum dc_state { - st_init, - st_reqpq_sent, - st_reqdh_sent, - st_client_dh_sent, - st_authorized, - st_error -}; +// typedef struct mtproto_connection not available right now +struct mtproto_connection; struct connection; struct connection_methods { @@ -126,11 +124,15 @@ struct connection { int out_packet_num; int last_connect_time; int in_fail_timer; + struct connection_methods *methods; struct session *session; void *extra; struct event_timer ev; double last_receive_time; + + // backreference to corrent telegram instance struct telegram *instance; + struct mtproto_connection *mtconnection; }; extern struct connection *Connections[]; @@ -141,19 +143,22 @@ int read_in (struct connection *c, void *data, int len); void create_all_outbound_connections (void); -struct connection *create_connection (const char *host, int port, int fd, struct telegram *instance); +struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods); int connections_make_poll_array (struct pollfd *fds, int max); void connections_poll_result (struct pollfd *fds, int max); +void dc_create_session (struct dc *DC); void insert_msg_id (struct session *S, long long id); struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port); -void dc_create_session (struct dc *DC, struct connection *c); - -void try_read (struct telegram *instance); -void try_rpc_read (struct telegram *instance); - -int try_write (struct telegram *instance); - #define GET_DC(c) (telegram_get_working_dc(c->instance)) -#endif +// export read and write methods to redirect network control +void try_read (struct connection *c); +void try_rpc_read (struct connection *c); +int try_write (struct connection *c); + +struct connection *fd_create_connection (struct dc *DC, int fd, struct telegram *instance, + struct connection_methods *methods, struct mtproto_connection *mtp); +void fd_close_connection(struct connection *c); + +#endif diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index cb09b16..4cc93cc 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -22,8 +22,6 @@ #include #include -// test - // Libpurple Plugin Includes #include "notify.h" #include "plugin.h" @@ -46,17 +44,13 @@ #include "eventloop.h" // struct telegram Includes -#include "telegram.h" -#include "msglog.h" -#include "mtproto-client.h" -#include "mtproto-common.h" -#include "structures.h" // telegram-purple includes -#include "loop.h" -#include "queries.h" +#include "telegram.h" #include "telegram-purple.h" -#include "request.h" + +// telegram-cli +#include "net.h" #define BUDDYNAME_MAX_LENGTH 128 @@ -80,7 +74,7 @@ void tg_cli_log_cb(const char* format, va_list ap) } void on_new_message(struct message *M); -void peer_allocated_handler(peer_t *user); +void peer_allocated_handler(void *user); /** * Returns the base icon name for the given buddy and account. @@ -141,6 +135,7 @@ static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition co telegram_conn *conn = tg->extra; int written = telegram_write_output(tg); + logprintf("written(%d): %d.\n", telegram_get_connection(tg)->fd, written); if (written == 0) { logprintf("no output, removing output...\n"); @@ -413,8 +408,9 @@ static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id) } -void peer_allocated_handler(peer_t *user) +void peer_allocated_handler(void *usr) { + peer_t *user = usr; gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); logprintf("Allocated peer: %s\n", name); diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 24536d8..3df5749 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -14,15 +14,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include - -#include "notify.h" -#include "plugin.h" -#include "version.h" -#include "account.h" -#include "connection.h" -#include "telegram.h" - +#ifndef __TG_PURPLE_H__ +#define __TG_PURPLE_H__ #define PLUGIN_ID "prpl-telegram" #define TELEGRAM_APP_API_ID 16944 @@ -35,6 +28,13 @@ #define TELEGRAM_AUTH_MODE_PHONE "phone" #define TELEGRAM_AUTH_MODE_SMS "sms" +#include +#include "notify.h" +#include "plugin.h" +#include "version.h" +#include "account.h" +#include "connection.h" + typedef struct { struct telegram *tg; PurpleAccount *pa; @@ -50,3 +50,5 @@ typedef struct { */ guint rh; } telegram_conn; + +#endif diff --git a/queries.c b/queries.c index db61e6e..7e01d4e 100644 --- a/queries.c +++ b/queries.c @@ -39,7 +39,6 @@ #include "mtproto-client.h" #include "queries.h" #include "tree.h" -#include "mtproto-common.h" #include "loop.h" #include "structures.h" #include "net.h" @@ -76,30 +75,26 @@ extern int binlog_enabled; extern int sync_from_start; int sync_from_start = 0; -int queries_num = 0; - -int all_queries_done() -{ - if (queries_num > 0) { - logprintf("all_queries_done() == false\n"); - return 0; - } else { - logprintf("all_queries_done() == true\n"); - return 1; - } -} +//int queries_num = 0; void telegram_flush_queries (struct telegram *instance) { instance->on_output(instance); } -void out_peer_id (peer_id_t id); +void out_peer_id (struct mtproto_connection *self, peer_id_t id); #define QUERY_TIMEOUT 6.0 #define memcmp8(a,b) memcmp ((a), (b), 8) DEFINE_TREE (query, struct query *, memcmp8, 0) ; struct tree_query *queries_tree; +/** + * Get the struct mtproto_connection connection this connection was attached to + */ +struct mtproto_connection *query_get_mtproto(struct query *q) { + return q->DC->sessions[0]->c->mtconnection; +} + double get_double_time (void) { struct timespec tv; my_clock_gettime (CLOCK_REALTIME, &tv); @@ -121,16 +116,17 @@ int alarm_query (struct query *q) { if (q->session->c->out_bytes >= 100000) { return 0; } - - clear_packet (); - out_int (CODE_msg_container); - out_int (1); - out_long (q->msg_id); - out_int (q->seq_no); - out_int (4 * q->data_len); - out_ints (q->data, q->data_len); - encrypt_send_message (q->session->c, packet_buffer, packet_ptr - packet_buffer, 0); + struct mtproto_connection *mtp = query_get_mtproto(q); + clear_packet (mtp); + out_int (mtp, CODE_msg_container); + out_int (mtp, 1); + out_long (mtp, q->msg_id); + out_int (mtp, q->seq_no); + out_int (mtp, 4 * q->data_len); + out_ints (mtp, q->data, q->data_len); + + encrypt_send_message (mtp, mtp->packet_buffer, mtp->packet_ptr - mtp->packet_buffer, 0); return 0; } @@ -156,7 +152,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth q->data_len = ints; q->data = talloc (4 * ints); memcpy (q->data, data, 4 * ints); - q->msg_id = encrypt_send_message (DC->sessions[0]->c, data, ints, 1); + q->msg_id = encrypt_send_message (DC->sessions[0]->c->mtconnection, data, ints, 1); q->session = DC->sessions[0]; q->seq_no = DC->sessions[0]->seq_no - 1; if (verbosity) { @@ -177,8 +173,8 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth insert_event_timer (&q->ev); q->extra = extra; - queries_num ++; - logprintf("queries_num: %d\n", queries_num); + //queries_num ++; + //logprintf("queries_num: %d\n", queries_num); return q; } @@ -192,12 +188,14 @@ void query_ack (long long id) { } void query_error (long long id) { - assert (fetch_int () == CODE_rpc_error); - int error_code = fetch_int (); - int error_len = prefetch_strlen (); - char *error = fetch_str (error_len); - logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); struct query *q = query_get (id); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == CODE_rpc_error); + int error_code = fetch_int (mtp); + int error_len = prefetch_strlen (mtp); + char *error = fetch_str (mtp, error_len); + logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); if (!q) { logprintf ( "No such query\n"); } else { @@ -213,45 +211,48 @@ void query_error (long long id) { tfree (q->data, q->data_len * 4); tfree (q, sizeof (*q)); } - queries_num --; - logprintf("queries_num: %d\n", queries_num); + //queries_num --; + //logprintf("queries_num: %d\n", queries_num); } #define MAX_PACKED_SIZE (1 << 24) static int packed_buffer[MAX_PACKED_SIZE / 4]; void query_result (long long id UU) { + struct query *q = query_get (id); + struct mtproto_connection *mtp = query_get_mtproto(q); + if (verbosity) { logprintf ( "result for query #%lld\n", id); } if (verbosity >= 4) { logprintf ( "result: "); - hexdump_in (); + hexdump_in (mtp); } - int op = prefetch_int (); + + int op = prefetch_int (mtp); int *end = 0; int *eend = 0; if (op == CODE_gzip_packed) { - fetch_int (); - int l = prefetch_strlen (); - char *s = fetch_str (l); + fetch_int (mtp); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); int total_out = tinflate (s, l, packed_buffer, MAX_PACKED_SIZE); - end = in_ptr; - eend = in_end; + end = mtp->in_ptr; + eend = mtp->in_end; //assert (total_out % 4 == 0); - in_ptr = packed_buffer; - in_end = in_ptr + total_out / 4; + mtp->in_ptr = packed_buffer; + mtp->in_end = mtp->in_ptr + total_out / 4; if (verbosity >= 4) { logprintf ( "Unzipped data: "); - hexdump_in (); + hexdump_in (mtp); } } - struct query *q = query_get (id); if (!q) { if (verbosity) { logprintf ( "No such query\n"); } - in_ptr = in_end; + mtp->in_ptr = mtp->in_end; } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { remove_event_timer (&q->ev); @@ -259,17 +260,17 @@ 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); + assert (mtp->in_ptr == mtp->in_end); } tfree (q->data, 4 * q->data_len); tfree (q, sizeof (*q)); } if (end) { - in_ptr = end; - in_end = eend; + mtp->in_ptr = end; + mtp->in_end = eend; } - queries_num --; - logprintf("queries_num: %d\n", queries_num); + //queries_num --; + //logprintf("queries_num: %d\n", queries_num); } #define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) @@ -313,76 +314,79 @@ int new_dc_num; //extern struct dc *DC_list[]; //extern struct dc *DC_working; -void out_random (int n) { +void out_random (struct mtproto_connection *mtp, int n) { assert (n <= 32); static char buf[32]; secure_random (buf, n); - out_cstring (buf, n); + out_cstring (mtp, buf, n); } int allow_send_linux_version; -void do_insert_header (void) { - out_int (CODE_invoke_with_layer12); - out_int (CODE_init_connection); - out_int (TG_APP_ID); +void do_insert_header (struct mtproto_connection *mtp) { + out_int (mtp, CODE_invoke_with_layer12); + out_int (mtp, CODE_init_connection); + out_int (mtp, TG_APP_ID); if (allow_send_linux_version) { struct utsname st; uname (&st); - out_string (st.machine); + out_string (mtp, st.machine); static char buf[4096]; tsnprintf (buf, sizeof (buf), "%.999s %.999s %.999s\n", st.sysname, st.release, st.version); - out_string (buf); - out_string (TG_VERSION " (build " TG_BUILD ")"); - out_string ("En"); + out_string (mtp, buf); + out_string (mtp, TG_VERSION " (build " TG_BUILD ")"); + out_string (mtp, "En"); } else { - out_string ("x86"); - out_string ("Linux"); - out_string (TG_VERSION); - out_string ("en"); + out_string (mtp, "x86"); + out_string (mtp, "Linux"); + out_string (mtp, TG_VERSION); + out_string (mtp, "en"); } } /* {{{ Get config */ void fetch_dc_option (struct telegram *instance) { - assert (fetch_int () == CODE_dc_option); - int id = fetch_int (); - int l1 = prefetch_strlen (); - char *name = fetch_str (l1); - int l2 = prefetch_strlen (); - char *ip = fetch_str (l2); - int port = fetch_int (); + struct mtproto_connection *mtp = instance->connection; + + assert (fetch_int (mtp) == CODE_dc_option); + int id = fetch_int (mtp); + int l1 = prefetch_strlen (mtp); + char *name = fetch_str (mtp, l1); + int l2 = prefetch_strlen (mtp); + char *ip = fetch_str (mtp, l2); + int port = fetch_int (mtp); if (verbosity) { logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); } - bl_do_dc_option (id, l1, name, l2, ip, port, instance); + bl_do_dc_option (mtp, id, l1, name, l2, ip, port, instance); } int help_get_config_on_answer (struct query *q UU) { struct telegram *instance = q->extra; + struct mtproto_connection *mtp = query_get_mtproto(q); - unsigned op = fetch_int (); + unsigned op = fetch_int (mtp); assert (op == CODE_config || op == CODE_config_old); - fetch_int (); + fetch_int (mtp); - unsigned test_mode = fetch_int (); + unsigned test_mode = fetch_int (mtp); assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false); assert (test_mode == CODE_bool_false || test_mode == CODE_bool_true); - int this_dc = fetch_int (); + int this_dc = fetch_int (mtp); if (verbosity) { logprintf ( "this_dc = %d\n", this_dc); } - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); assert (n <= 10); int i; for (i = 0; i < n; i++) { fetch_dc_option (instance); } - max_chat_size = fetch_int (); + max_chat_size = fetch_int (mtp); if (op == CODE_config) { - max_bcast_size = fetch_int (); + max_bcast_size = fetch_int (mtp); } if (verbosity >= 2) { logprintf ( "chat_size = %d\n", max_chat_size); @@ -396,10 +400,12 @@ struct query_methods help_get_config_methods = { }; void do_help_get_config (struct telegram *instance) { - clear_packet (); - out_int (CODE_help_get_config); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_help_get_config); struct dc *DC_working = telegram_get_working_dc(instance); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, instance); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &help_get_config_methods, instance); } /* }}} */ @@ -407,18 +413,19 @@ void do_help_get_config (struct telegram *instance) { char *phone_code_hash; int send_code_on_answer (struct query *q UU) { struct telegram *instance = q->extra; + struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int () == (int)CODE_auth_sent_code); - fetch_bool (); - int l = prefetch_strlen (); - char *s = fetch_str (l); + assert (fetch_int (mtp) == (int)CODE_auth_sent_code); + fetch_bool (mtp); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); if (phone_code_hash) { tfree_str (phone_code_hash); } phone_code_hash = tstrndup (s, l); logprintf("telegram: phone_code_hash: %s\n", phone_code_hash); - fetch_int (); - fetch_bool (); + fetch_int (mtp); + fetch_bool (mtp); want_dc_num = -1; if (instance->session_state == STATE_PHONE_CODE_REQUESTED) { telegram_change_state(instance, STATE_PHONE_CODE_NOT_ENTERED, phone_code_hash); @@ -462,20 +469,22 @@ int code_is_sent (void) { char *suser; void do_send_code (struct telegram *instance, const char *user) { + struct mtproto_connection *mtp = instance->connection; + logprintf ("sending code\n"); suser = tstrdup (user); want_dc_num = 0; - clear_packet (); - do_insert_header (); - out_int (CODE_auth_send_code); - out_string (user); - out_int (0); - out_int (TG_APP_ID); - out_string (TG_APP_HASH); - out_string ("en"); + clear_packet (mtp); + do_insert_header (mtp); + out_int (mtp, CODE_auth_send_code); + out_string (mtp, user); + out_int (mtp, 0); + out_int (mtp, TG_APP_ID); + out_string (mtp, TG_APP_HASH); + out_string (mtp, "en"); logprintf ("send_code: dc_num = %d\n", instance->auth.dc_working_num); - send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &send_code_methods, instance); + send_query (telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_code_methods, instance); if (instance->session_state == STATE_PHONE_NOT_REGISTERED) { telegram_change_state(instance, STATE_PHONE_CODE_REQUESTED, NULL); } else if (instance->session_state == STATE_CLIENT_NOT_REGISTERED) { @@ -493,7 +502,7 @@ void do_send_code (struct telegram *instance, const char *user) { logprintf ("send_code: dc_num = %d\n", dc_working_num); want_dc_num = 0; - clear_packet (); + clear_packet (mtp); do_insert_header (); out_int (CODE_auth_send_code); out_string (user); @@ -512,7 +521,9 @@ void do_send_code (struct telegram *instance, const char *user) { int phone_call_on_answer (struct query *q UU) { - fetch_bool (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + fetch_bool (mtp); return 0; } @@ -528,17 +539,19 @@ struct query_methods phone_call_methods = { }; void do_phone_call (struct telegram *instance, const char *user) { + struct mtproto_connection *mtp = instance->connection; + logprintf ("calling user\n"); suser = tstrdup (user); want_dc_num = 0; - clear_packet (); - do_insert_header (); - out_int (CODE_auth_send_call); - out_string (user); - out_string (phone_code_hash); + clear_packet (mtp); + do_insert_header (mtp); + out_int (mtp, CODE_auth_send_call); + out_string (mtp, user); + out_string (mtp, phone_code_hash); logprintf ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); - send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &phone_call_methods, 0); + send_query (telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &phone_call_methods, 0); } /* }}} */ @@ -549,9 +562,11 @@ int cr_f (void) { } int check_phone_on_answer (struct query *q UU) { - assert (fetch_int () == (int)CODE_auth_checked_phone); - check_phone_result = fetch_bool (); - fetch_bool (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == (int)CODE_auth_checked_phone); + check_phone_result = fetch_bool (mtp); + fetch_bool (mtp); return 0; } @@ -587,13 +602,15 @@ struct query_methods check_phone_methods = { }; int do_auth_check_phone (struct telegram *instance, const char *user) { + struct mtproto_connection *mtp = instance->connection; + suser = tstrdup (user); - clear_packet (); - out_int (CODE_auth_check_phone); - out_string (user); + clear_packet (mtp); + out_int (mtp, CODE_auth_check_phone); + out_string (mtp, user); check_phone_result = -1; struct dc *DC_working = telegram_get_working_dc(instance); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, instance); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &check_phone_methods, instance); /* net_loop (0, cr_f); check_phone_result = -1; @@ -611,13 +628,15 @@ int nr_f (void) { } int nearest_dc_on_answer (struct query *q UU) { - assert (fetch_int () == (int)CODE_nearest_dc); - char *country = fetch_str_dup (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == (int)CODE_nearest_dc); + char *country = fetch_str_dup (mtp); if (verbosity > 0) { logprintf ("Server thinks that you are in %s\n", country); } - fetch_int (); // this_dc - nearest_dc_num = fetch_int (); + fetch_int (mtp); // this_dc + nearest_dc_num = fetch_int (mtp); assert (nearest_dc_num >= 0); return 0; } @@ -634,11 +653,12 @@ struct query_methods nearest_dc_methods = { }; void do_get_nearest_dc (struct telegram *instance) { + struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_help_get_nearest_dc); + clear_packet (mtp); + out_int (mtp, CODE_help_get_nearest_dc); nearest_dc_num = -1; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &nearest_dc_methods, 0); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &nearest_dc_methods, 0); //net_loop (0, nr_f); //return nearest_dc_num; } @@ -654,13 +674,14 @@ int sign_in_is_ok (void) { struct user User; int sign_in_on_answer (struct query *q UU) { + struct mtproto_connection *mtp = query_get_mtproto(q); struct dc *DC_working = telegram_get_working_dc(q->extra); - assert (fetch_int () == (int)CODE_auth_authorization); - int expires = fetch_int (); - fetch_user (&User); + assert (fetch_int (mtp) == (int)CODE_auth_authorization); + int expires = fetch_int (mtp); + fetch_user (mtp, &User); if (!our_id) { our_id = get_peer_id (User.id); - bl_do_set_our_id (our_id); + bl_do_set_our_id (mtp, our_id); } sign_in_ok = 1; if (verbosity) { @@ -668,7 +689,7 @@ int sign_in_on_answer (struct query *q UU) { } DC_working->has_auth = 1; - bl_do_dc_signed (DC_working->id); + bl_do_dc_signed (mtp, DC_working->id); return 0; } @@ -695,13 +716,15 @@ struct query_methods sign_in_methods = { }; void do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash) { + struct mtproto_connection *mtp = instance->connection; + struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_auth_sign_in); - out_string (suser); - out_string(sms_hash); - out_string (code); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &sign_in_methods, instance); + clear_packet (mtp); + out_int (mtp, CODE_auth_sign_in); + out_string (mtp, suser); + out_string(mtp, sms_hash); + out_string (mtp, code); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); /* sign_in_ok = 0; //net_loop (0, sign_in_is_ok); @@ -711,14 +734,16 @@ void do_send_code_result (struct telegram *instance, const char *code, const cha void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_auth_sign_up); - out_string (suser); - out_string (sms_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, instance); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_auth_sign_up); + out_string (mtp ,suser); + out_string (mtp, sms_hash); + out_string (mtp, code); + out_string (mtp, first_name); + out_string (mtp, last_name); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); /* sign_in_ok = 0; net_loop (0, sign_in_is_ok); @@ -732,19 +757,20 @@ extern char *user_list[]; int contacts_got = 0; int get_contacts_on_answer (struct query *q UU) { + struct mtproto_connection *mtp = query_get_mtproto(q); int i; - assert (fetch_int () == (int)CODE_contacts_contacts); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (mtp) == (int)CODE_contacts_contacts); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); for (i = 0; i < n; i++) { - assert (fetch_int () == (int)CODE_contact); - fetch_int (); // id - fetch_int (); // mutual + assert (fetch_int (mtp) == (int)CODE_contact); + fetch_int (mtp); // id + fetch_int (mtp); // mutual } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); /* //print_start (); //push_color (COLOR_YELLOW); @@ -784,31 +810,30 @@ struct query_methods get_contacts_methods = { void do_update_contact_list (struct telegram *instance) { + struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); + contacts_got = 0; - clear_packet (); - out_int (CODE_contacts_get_contacts); - out_string (""); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, 0); + clear_packet (mtp); + out_int (mtp, CODE_contacts_get_contacts); + out_string (mtp, ""); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_contacts_methods, 0); } /* }}} */ /* {{{ Encrypt decrypted */ -int *encr_extra; -int *encr_ptr; -int *encr_end; -char *encrypt_decrypted_message (struct secret_chat *E) { +char *encrypt_decrypted_message (struct mtproto_connection *mtp, struct secret_chat *E) { static int msg_key[4]; static unsigned char sha1a_buffer[20]; static unsigned char sha1b_buffer[20]; static unsigned char sha1c_buffer[20]; static unsigned char sha1d_buffer[20]; - int x = *(encr_ptr); + int x = *(mtp->encr_ptr); assert (x >= 0 && !(x & 3)); - sha1 ((void *)encr_ptr, 4 + x, sha1a_buffer); + sha1 ((void *)mtp->encr_ptr, 4 + x, sha1a_buffer); memcpy (msg_key, sha1a_buffer + 4, 16); static unsigned char buf[64]; @@ -842,78 +867,81 @@ char *encrypt_decrypted_message (struct secret_chat *E) { AES_KEY aes_key; AES_set_encrypt_key (key, 256, &aes_key); - AES_ige_encrypt ((void *)encr_ptr, (void *)encr_ptr, 4 * (encr_end - encr_ptr), &aes_key, iv, 1); + AES_ige_encrypt ((void *)mtp->encr_ptr, (void *)mtp->encr_ptr, 4 * (mtp->encr_end - mtp->encr_ptr), &aes_key, iv, 1); memset (&aes_key, 0, sizeof (aes_key)); return (void *)msg_key; } -void encr_start (void) { - encr_extra = packet_ptr; - packet_ptr += 1; // str len - packet_ptr += 2; // fingerprint - packet_ptr += 4; // msg_key - packet_ptr += 1; // len +void encr_start (struct mtproto_connection *mtp) { + mtp->encr_extra = mtp->packet_ptr; + mtp->packet_ptr += 1; // str len + mtp->packet_ptr += 2; // fingerprint + mtp->packet_ptr += 4; // msg_key + mtp->packet_ptr += 1; // len } -void encr_finish (struct secret_chat *E) { - int l = packet_ptr - (encr_extra + 8); - while (((packet_ptr - encr_extra) - 3) & 3) { +void encr_finish (struct mtproto_connection *mtp, struct secret_chat *E) { + int l = mtp->packet_ptr - (mtp->encr_extra + 8); + while (((mtp->packet_ptr - mtp->encr_extra) - 3) & 3) { int t; secure_random (&t, 4); - out_int (t); + out_int (mtp, t); } - *encr_extra = ((packet_ptr - encr_extra) - 1) * 4 * 256 + 0xfe; - encr_extra ++; - *(long long *)encr_extra = E->key_fingerprint; - encr_extra += 2; - encr_extra[4] = l * 4; - encr_ptr = encr_extra + 4; - encr_end = packet_ptr; - memcpy (encr_extra, encrypt_decrypted_message (E), 16); + *mtp->encr_extra = ((mtp->packet_ptr - mtp->encr_extra) - 1) * 4 * 256 + 0xfe; + mtp->encr_extra ++; + *(long long *)mtp->encr_extra = E->key_fingerprint; + mtp->encr_extra += 2; + mtp->encr_extra[4] = l * 4; + mtp->encr_ptr = mtp->encr_extra + 4; + mtp->encr_end = mtp->packet_ptr; + memcpy (mtp->encr_extra, encrypt_decrypted_message (mtp, E), 16); } /* }}} */ /* {{{ Seng msg (plain text) */ int msg_send_encr_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_messages_sent_encrypted_message); + struct mtproto_connection *mtp = query_get_mtproto(q); + assert (fetch_int (mtp) == CODE_messages_sent_encrypted_message); logprintf ("Sent\n"); struct message *M = q->extra; - //M->date = fetch_int (); - fetch_int (); - bl_do_set_message_sent (M); + //M->date = fetch_int (mtp); + fetch_int (mtp); + bl_do_set_message_sent (mtp, M); return 0; } int msg_send_on_answer (struct query *q UU) { - unsigned x = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + unsigned x = fetch_int (mtp); assert (x == CODE_messages_sent_message || x == CODE_messages_sent_message_link); - int id = fetch_int (); // id + int id = fetch_int (mtp); // id struct message *M = q->extra; - bl_do_set_msg_id (M, id); - fetch_date (); - fetch_pts (); - fetch_seq (); + bl_do_set_msg_id (mtp, M, id); + fetch_date (mtp); + fetch_pts (mtp); + fetch_seq (mtp); if (x == CODE_messages_sent_message_link) { - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); int i; unsigned a, b; for (i = 0; i < n; i++) { - assert (fetch_int () == (int)CODE_contacts_link); - a = fetch_int (); + assert (fetch_int (mtp) == (int)CODE_contacts_link); + a = fetch_int (mtp); assert (a == CODE_contacts_my_link_empty || a == CODE_contacts_my_link_requested || a == CODE_contacts_my_link_contact); if (a == CODE_contacts_my_link_requested) { - fetch_bool (); + fetch_bool (mtp); } - b = fetch_int (); + b = fetch_int (mtp); assert (b == CODE_contacts_foreign_link_unknown || b == CODE_contacts_foreign_link_requested || b == CODE_contacts_foreign_link_mutual); if (b == CODE_contacts_foreign_link_requested) { - fetch_bool (); + fetch_bool (mtp); } - struct user *U = fetch_alloc_user (); + struct user *U = fetch_alloc_user (mtp); U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); if (a == CODE_contacts_my_link_contact) { @@ -936,14 +964,16 @@ int msg_send_on_answer (struct query *q UU) { } } logprintf ("Sent: id = %d\n", id); - bl_do_set_message_sent (M); + bl_do_set_message_sent (mtp, M); return 0; } int msg_send_on_error (struct query *q, int error_code, int error_len, char *error) { + struct mtproto_connection *mtp = query_get_mtproto(q); + logprintf ( "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error); struct message *M = q->extra; - bl_do_delete_msg (M); + bl_do_delete_msg (mtp, M); return 0; } @@ -960,44 +990,50 @@ int out_message_num; int our_id; void do_send_encr_msg (struct telegram *instance, struct message *M) { + struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); + peer_t *P = user_chat_get (M->to_id); if (!P || P->encr_chat.state != sc_ok) { return; } - clear_packet (); - out_int (CODE_messages_send_encrypted); - out_int (CODE_input_encrypted_chat); - out_int (get_peer_id (M->to_id)); - out_long (P->encr_chat.access_hash); - out_long (M->id); - encr_start (); - out_int (CODE_decrypted_message); - out_long (M->id); + clear_packet (mtp); + out_int (mtp, CODE_messages_send_encrypted); + out_int (mtp, CODE_input_encrypted_chat); + out_int (mtp, get_peer_id (M->to_id)); + out_long (mtp, P->encr_chat.access_hash); + out_long (mtp, M->id); + encr_start (mtp); + out_int (mtp, CODE_decrypted_message); + out_long (mtp, M->id); static int buf[4]; secure_random (buf, 16); - out_cstring ((void *)buf, 16); - out_cstring ((void *)M->message, M->message_len); - out_int (CODE_decrypted_message_media_empty); - encr_finish (&P->encr_chat); + out_cstring (mtp, (void *)buf, 16); + out_cstring (mtp, (void *)M->message, M->message_len); + out_int (mtp, CODE_decrypted_message_media_empty); + encr_finish (mtp, &P->encr_chat); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, + &msg_send_encr_methods, M); } void do_send_msg (struct telegram *instance, struct message *M) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; + if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { do_send_encr_msg (instance ,M); return; } - clear_packet (); - out_int (CODE_messages_send_message); - out_peer_id (M->to_id); - out_cstring (M->message, M->message_len); - out_long (M->id); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M); + clear_packet (mtp); + out_int (mtp, CODE_messages_send_message); + out_peer_id (mtp, M->to_id); + out_cstring (mtp, M->message, M->message_len); + out_long (mtp, M->id); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_send_methods, M); } void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len) { + struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT) { peer_t *P = user_chat_get (id); if (!P) { @@ -1012,7 +1048,7 @@ void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, long long t; secure_random (&t, 8); logprintf ("t = %lld, len = %d\n", t, len); - bl_do_send_message_text (t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); + bl_do_send_message_text (mtp, t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); struct message *M = message_get (t); assert (M); do_send_msg (instance, M); @@ -1046,15 +1082,18 @@ void do_send_text (struct telegram *instance, peer_id_t id, char *file_name) { /* {{{ Mark read */ int mark_read_on_receive (struct query *q UU) { - assert (fetch_int () == (int)CODE_messages_affected_history); - fetch_pts (); - fetch_seq (); - fetch_int (); // offset + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == (int)CODE_messages_affected_history); + fetch_pts (mtp); + fetch_seq (mtp); + fetch_int (mtp); // offset return 0; } int mark_read_encr_on_receive (struct query *q UU) { - fetch_bool (); + struct mtproto_connection *mtp = query_get_mtproto(q); + fetch_bool (mtp); return 0; } @@ -1068,23 +1107,27 @@ struct query_methods mark_read_encr_methods = { void do_messages_mark_read (struct telegram *instance, peer_id_t id, int max_id) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_read_history); - out_peer_id (id); - out_int (max_id); - out_int (0); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, 0); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_messages_read_history); + out_peer_id (mtp, id); + out_int (mtp, max_id); + out_int (mtp, 0); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_methods, 0); } void do_messages_mark_read_encr (struct telegram *instance, peer_id_t id, long long access_hash, int last_time) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_read_encrypted_history); - out_int (CODE_input_encrypted_chat); - out_int (get_peer_id (id)); - out_long (access_hash); - out_int (last_time); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, 0); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_messages_read_encrypted_history); + out_int (mtp, CODE_input_encrypted_chat); + out_int (mtp, get_peer_id (id)); + out_long (mtp, access_hash); + out_int (mtp, last_time); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_encr_methods, 0); } void do_mark_read (struct telegram *instance, peer_id_t id) { @@ -1120,21 +1163,22 @@ struct get_hist_extra { int get_history_on_answer (struct query *q UU) { struct get_hist_extra *extra = q->extra; struct telegram *instance = extra->instance; + struct mtproto_connection *mtp = query_get_mtproto(q); peer_id_t peer_id = extra->peer_id; static struct message *ML[10000]; int i; - int x = fetch_int (); + int x = fetch_int (mtp); if (x == (int)CODE_messages_messages_slice) { - fetch_int (); + fetch_int (mtp); logprintf ("...\n"); } else { assert (x == (int)CODE_messages_messages); } - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); for (i = 0; i < n; i++) { - struct message *M = fetch_alloc_message (instance); + struct message *M = fetch_alloc_message (mtp, instance); if (i <= 9999) { ML[i] = M; } @@ -1144,15 +1188,15 @@ int get_history_on_answer (struct query *q UU) { for (i = n - 1; i >= 0; i--) { //print_message (ML[i]); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } if (sn > 0 && q->extra) { @@ -1184,23 +1228,24 @@ void do_get_local_history (peer_id_t id, int limit) { void do_get_history (struct telegram *instance, peer_id_t id, int limit) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT || offline_mode) { do_get_local_history (id, limit); do_mark_read (instance, id); return; } - clear_packet (); - out_int (CODE_messages_get_history); - out_peer_id (id); - out_int (0); - out_int (0); - out_int (limit); + clear_packet (mtp); + out_int (mtp, CODE_messages_get_history); + out_peer_id (mtp, id); + out_int (mtp, 0); + out_int (mtp, 0); + out_int (mtp, limit); struct get_hist_extra *extra = malloc(sizeof(struct get_hist_extra)); extra->instance = instance; extra->peer_id = id; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_history_methods, extra); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_history_methods, extra); } /* }}} */ @@ -1208,48 +1253,51 @@ void do_get_history (struct telegram *instance, peer_id_t id, int limit) { int dialog_list_got; int get_dialogs_on_answer (struct query *q UU) { struct telegram *instance = q->extra; - unsigned x = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + unsigned x = fetch_int (mtp); assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); if (x == CODE_messages_dialogs_slice) { - fetch_int (); // total_count + fetch_int (mtp); // total_count } - assert (fetch_int () == CODE_vector); + assert (fetch_int (mtp) == CODE_vector); int n, i; - n = fetch_int (); + n = fetch_int (mtp); static int dlist[2 * 100]; static peer_id_t plist[100]; int dl_size = n; for (i = 0; i < n; i++) { - assert (fetch_int () == CODE_dialog); + assert (fetch_int (mtp) == CODE_dialog); if (i < 100) { - plist[i] = fetch_peer_id (); - dlist[2 * i + 0] = fetch_int (); - dlist[2 * i + 1] = fetch_int (); + plist[i] = fetch_peer_id (mtp); + dlist[2 * i + 0] = fetch_int (mtp); + dlist[2 * i + 1] = fetch_int (mtp); } else { - fetch_peer_id (); - fetch_int (); - fetch_int (); + fetch_peer_id (mtp); + fetch_int (mtp); + fetch_int (mtp); } } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_message (instance); + fetch_alloc_message (mtp, instance); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } //print_start (); //push_color (COLOR_YELLOW); for (i = dl_size - 1; i >= 0; i--) { - peer_t *UC; + + // TODO: use peer + peer_t *UC UU; switch (get_peer_type (plist[i])) { case PEER_USER: UC = user_chat_get (plist[i]); @@ -1278,13 +1326,14 @@ struct query_methods get_dialogs_methods = { void do_get_dialog_list (struct telegram *instance) { + struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_get_dialogs); - out_int (0); - out_int (0); - out_int (1000); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, instance); + clear_packet (mtp); + out_int (mtp, CODE_messages_get_dialogs); + out_int (mtp, 0); + out_int (mtp, 0); + out_int (mtp, 1000); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dialogs_methods, instance); } /* }}} */ @@ -1308,22 +1357,22 @@ struct send_file { unsigned char *key; }; -void out_peer_id (peer_id_t id) { +void out_peer_id (struct mtproto_connection *self, peer_id_t id) { peer_t *U; switch (get_peer_type (id)) { case PEER_CHAT: - out_int (CODE_input_peer_chat); - out_int (get_peer_id (id)); + out_int (self, CODE_input_peer_chat); + out_int (self, get_peer_id (id)); break; case PEER_USER: U = user_chat_get (id); if (U && U->user.access_hash) { - out_int (CODE_input_peer_foreign); - out_int (get_peer_id (id)); - out_long (U->user.access_hash); + out_int (self, CODE_input_peer_foreign); + out_int (self, get_peer_id (id)); + out_long (self, U->user.access_hash); } else { - out_int (CODE_input_peer_contact); - out_int (get_peer_id (id)); + out_int (self, CODE_input_peer_contact); + out_int (self, get_peer_id (id)); } break; default: @@ -1338,47 +1387,54 @@ struct send_file_extra { void send_part (struct telegram *instance, struct send_file *f); int send_file_part_on_answer (struct query *q) { + struct mtproto_connection *mtp = query_get_mtproto(q); + struct send_file_extra *extra = q->extra; - assert (fetch_int () == (int)CODE_bool_true); + assert (fetch_int (mtp) == (int)CODE_bool_true); send_part (extra->instance, extra->file); return 0; } int send_file_on_answer (struct query *q UU) { struct telegram *instance = q->extra; - assert (fetch_int () == (int)CODE_messages_stated_message); - struct message *M = fetch_alloc_message (instance); - assert (fetch_int () == CODE_vector); + struct mtproto_connection *mtp = query_get_mtproto(q); + assert (fetch_int (mtp) == (int)CODE_messages_stated_message); + + // TODO: use message + struct message *M UU = fetch_alloc_message (mtp, instance); + + assert (fetch_int (mtp) == CODE_vector); int n, i; - n = fetch_int (); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } - fetch_pts (); - fetch_seq (); + fetch_pts (mtp); + fetch_seq (mtp); //print_message (M); return 0; } int send_encr_file_on_answer (struct query *q UU) { - if (prefetch_int () != (int)CODE_messages_sent_encrypted_file) { - hexdump_in (); + struct mtproto_connection *mtp = query_get_mtproto(q); + if (prefetch_int (mtp) != (int)CODE_messages_sent_encrypted_file) { + hexdump_in (mtp); } - assert (fetch_int () == (int)CODE_messages_sent_encrypted_file); + assert (fetch_int (mtp) == (int)CODE_messages_sent_encrypted_file); struct message *M = q->extra; - M->date = fetch_int (); - assert (fetch_int () == CODE_encrypted_file); - M->media.encr_photo.id = fetch_long (); - M->media.encr_photo.access_hash = fetch_long (); - //M->media.encr_photo.size = fetch_int (); - fetch_int (); - M->media.encr_photo.dc_id = fetch_int (); - assert (fetch_int () == M->media.encr_photo.key_fingerprint); + M->date = fetch_int (mtp); + assert (fetch_int (mtp) == CODE_encrypted_file); + M->media.encr_photo.id = fetch_long (mtp); + M->media.encr_photo.access_hash = fetch_long (mtp); + //M->media.encr_photo.size = fetch_int (mtp); + fetch_int (mtp); + M->media.encr_photo.dc_id = fetch_int (mtp); + assert (fetch_int (mtp) == M->media.encr_photo.key_fingerprint); //print_message (M); message_insert (M); return 0; @@ -1397,22 +1453,22 @@ struct query_methods send_encr_file_methods = { }; void send_part (struct telegram *instance, struct send_file *f) { - + struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); if (f->fd >= 0) { if (!f->part_num) { cur_uploading_bytes += f->size; } - clear_packet (); + clear_packet (mtp); if (f->size < (16 << 20)) { - out_int (CODE_upload_save_file_part); - out_long (f->id); - out_int (f->part_num ++); + out_int (mtp, CODE_upload_save_file_part); + out_long (mtp, f->id); + out_int (mtp, f->part_num ++); } else { - out_int (CODE_upload_save_big_file_part); - out_long (f->id); - out_int (f->part_num ++); - out_int ((f->size + f->part_size - 1) / f->part_size); + out_int (mtp, CODE_upload_save_big_file_part); + out_long (mtp, f->id); + out_int (mtp, f->part_num ++); + out_int (mtp, (f->size + f->part_size - 1) / f->part_size); } static char buf[512 << 10]; int x = read (f->fd, buf, f->part_size); @@ -1432,7 +1488,7 @@ void send_part (struct telegram *instance, struct send_file *f) { AES_ige_encrypt ((void *)buf, (void *)buf, x, &aes_key, f->iv, 1); memset (&aes_key, 0, sizeof (aes_key)); } - out_cstring (buf, x); + out_cstring (mtp, buf, x); if (verbosity >= 2) { logprintf ("offset=%lld size=%lld\n", f->offset, f->size); } @@ -1447,115 +1503,115 @@ void send_part (struct telegram *instance, struct send_file *f) { struct send_file_extra *extra = malloc(sizeof(struct send_file_extra)); extra->instance = instance; extra->file = f; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, extra); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, extra); } else { cur_uploaded_bytes -= f->size; cur_uploading_bytes -= f->size; //update_prompt (); - clear_packet (); + clear_packet (mtp); assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_audio || f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document); if (!f->encr) { - out_int (CODE_messages_send_media); - out_peer_id (f->to_id); - out_int (f->media_type); + out_int (mtp, CODE_messages_send_media); + out_peer_id (mtp, f->to_id); + out_int (mtp, f->media_type); if (f->size < (16 << 20)) { - out_int (CODE_input_file); + out_int (mtp, CODE_input_file); } else { - out_int (CODE_input_file_big); + out_int (mtp, CODE_input_file_big); } - out_long (f->id); - out_int (f->part_num); + out_long (mtp, f->id); + out_int (mtp, f->part_num); char *s = f->file_name + strlen (f->file_name); while (s >= f->file_name && *s != '/') { s --;} - out_string (s + 1); + out_string (mtp, s + 1); if (f->size < (16 << 20)) { - out_string (""); + out_string (mtp, ""); } if (f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_thumb_document) { - out_int (CODE_input_file); - out_long (f->thumb_id); - out_int (1); - out_string ("thumb.jpg"); - out_string (""); + out_int (mtp, CODE_input_file); + out_long (mtp, f->thumb_id); + out_int (mtp, 1); + out_string (mtp, "thumb.jpg"); + out_string (mtp, ""); } if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video) { - out_int (100); - out_int (100); - out_int (100); + out_int (mtp, 100); + out_int (mtp, 100); + out_int (mtp, 100); } if (f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document) { - out_string (s + 1); - out_string ("text"); + out_string (mtp, s + 1); + out_string (mtp, "text"); } if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (60); + out_int (mtp, 60); } - out_long (-lrand48 () * (1ll << 32) - lrand48 ()); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, instance); + out_long (mtp, -lrand48 () * (1ll << 32) - lrand48 ()); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_methods, instance); } else { struct message *M = talloc0 (sizeof (*M)); - out_int (CODE_messages_send_encrypted_file); - out_int (CODE_input_encrypted_chat); - out_int (get_peer_id (f->to_id)); + out_int (mtp, CODE_messages_send_encrypted_file); + out_int (mtp, CODE_input_encrypted_chat); + out_int (mtp, get_peer_id (f->to_id)); peer_t *P = user_chat_get (f->to_id); assert (P); - out_long (P->encr_chat.access_hash); + out_long (mtp, P->encr_chat.access_hash); long long r = -lrand48 () * (1ll << 32) - lrand48 (); - out_long (r); - encr_start (); - out_int (CODE_decrypted_message); - out_long (r); - out_random (15 + 4 * (lrand48 () % 3)); - out_string (""); + out_long (mtp, r); + encr_start (mtp); + out_int (mtp, CODE_decrypted_message); + out_long (mtp, r); + out_random (mtp, 15 + 4 * (lrand48 () % 3)); + out_string (mtp, ""); if (f->media_type == CODE_input_media_uploaded_photo) { - out_int (CODE_decrypted_message_media_photo); + out_int (mtp, CODE_decrypted_message_media_photo); M->media.type = CODE_decrypted_message_media_photo; } else if (f->media_type == CODE_input_media_uploaded_video) { - out_int (CODE_decrypted_message_media_video); + out_int (mtp, CODE_decrypted_message_media_video); M->media.type = CODE_decrypted_message_media_video; } else if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (CODE_decrypted_message_media_audio); + out_int (mtp, CODE_decrypted_message_media_audio); M->media.type = CODE_decrypted_message_media_audio; } else if (f->media_type == CODE_input_media_uploaded_document) { - out_int (CODE_decrypted_message_media_document); + out_int (mtp, CODE_decrypted_message_media_document); M->media.type = CODE_decrypted_message_media_document;; } else { assert (0); } if (f->media_type != CODE_input_media_uploaded_audio) { - out_cstring ((void *)thumb_file, thumb_file_size); - out_int (90); - out_int (90); + out_cstring (mtp, (void *)thumb_file, thumb_file_size); + out_int (mtp, 90); + out_int (mtp, 90); } if (f->media_type == CODE_input_media_uploaded_video) { - out_int (0); + out_int (mtp, 0); } if (f->media_type == CODE_input_media_uploaded_document) { - out_string (f->file_name); - out_string ("text"); + out_string (mtp, f->file_name); + out_string (mtp, "text"); } if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (60); + out_int (mtp, 60); } if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_photo) { - out_int (100); - out_int (100); + out_int (mtp, 100); + out_int (mtp, 100); } - out_int (f->size); - out_cstring ((void *)f->key, 32); - out_cstring ((void *)f->init_iv, 32); - encr_finish (&P->encr_chat); + out_int (mtp, f->size); + out_cstring (mtp, (void *)f->key, 32); + out_cstring (mtp, (void *)f->init_iv, 32); + encr_finish (mtp, &P->encr_chat); if (f->size < (16 << 20)) { - out_int (CODE_input_encrypted_file_uploaded); + out_int (mtp, CODE_input_encrypted_file_uploaded); } else { - out_int (CODE_input_encrypted_file_big_uploaded); + out_int (mtp, CODE_input_encrypted_file_big_uploaded); } - out_long (f->id); - out_int (f->part_num); + out_long (mtp, f->id); + out_int (mtp, f->part_num); if (f->size < (16 << 20)) { - out_string (""); + out_string (mtp, ""); } unsigned char md5[16]; @@ -1563,7 +1619,7 @@ void send_part (struct telegram *instance, struct send_file *f) { memcpy (str, f->key, 32); memcpy (str + 32, f->init_iv, 32); MD5 (str, 64, md5); - out_int ((*(int *)md5) ^ (*(int *)(md5 + 4))); + out_int (mtp, (*(int *)md5) ^ (*(int *)(md5 + 4))); tfree_secure (f->iv, 32); @@ -1581,7 +1637,7 @@ void send_part (struct telegram *instance, struct send_file *f) { M->id = r; M->date = time (0); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_file_methods, M); } tfree_str (f->file_name); tfree (f, sizeof (*f)); @@ -1590,13 +1646,14 @@ void send_part (struct telegram *instance, struct send_file *f) { void send_file_thumb (struct telegram *instance, struct send_file *f) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); f->thumb_id = lrand48 () * (1ll << 32) + lrand48 (); - out_int (CODE_upload_save_file_part); - out_long (f->thumb_id); - out_int (0); - out_cstring ((void *)thumb_file, thumb_file_size); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); + out_int (mtp, CODE_upload_save_file_part); + out_long (mtp, f->thumb_id); + out_int (mtp, 0); + out_cstring (mtp, (void *)thumb_file, thumb_file_size); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, f); } void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name) { @@ -1662,21 +1719,25 @@ void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char * /* {{{ Forward */ int fwd_msg_on_answer (struct query *q UU) { struct telegram *instance = q->extra; - assert (fetch_int () == (int)CODE_messages_stated_message); - struct message *M = fetch_alloc_message (instance); - assert (fetch_int () == CODE_vector); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == (int)CODE_messages_stated_message); + + // TODO: use message + struct message *M UU = fetch_alloc_message (mtp, instance); + assert (fetch_int (mtp) == CODE_vector); int n, i; - n = fetch_int (); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } - fetch_pts (); - fetch_seq (); + fetch_pts (mtp); + fetch_seq (mtp); //print_message (M); return 0; } @@ -1687,38 +1748,42 @@ struct query_methods fwd_msg_methods = { void do_forward_message (struct telegram *instance, peer_id_t id, int n) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT) { logprintf ("Can not forward messages from secret chat\n"); return; } - clear_packet (); - out_int (CODE_messages_forward_message); - out_peer_id (id); - out_int (n); - out_long (lrand48 () * (1ll << 32) + lrand48 ()); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, instance); + clear_packet (mtp); + out_int (mtp, CODE_messages_forward_message); + out_peer_id (mtp, id); + out_int (mtp, n); + out_long (mtp, lrand48 () * (1ll << 32) + lrand48 ()); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &fwd_msg_methods, instance); } /* }}} */ /* {{{ Rename chat */ int rename_chat_on_answer (struct query *q UU) { struct telegram *instance = q->extra; + struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int () == (int)CODE_messages_stated_message); - struct message *M = fetch_alloc_message (instance); - assert (fetch_int () == CODE_vector); + assert (fetch_int (mtp) == (int)CODE_messages_stated_message); + + // TODO: use message + struct message *M UU = fetch_alloc_message (mtp, instance); + assert (fetch_int (mtp) == CODE_vector); int n, i; - n = fetch_int (); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } - fetch_pts (); - fetch_seq (); + fetch_pts (mtp); + fetch_seq (mtp); //print_message (M); return 0; } @@ -1729,18 +1794,22 @@ struct query_methods rename_chat_methods = { void do_rename_chat (struct telegram *instance, peer_id_t id, char *name UU) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_edit_chat_title); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_messages_edit_chat_title); assert (get_peer_type (id) == PEER_CHAT); - out_int (get_peer_id (id)); - out_string (name); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, instance); + out_int (mtp, get_peer_id (id)); + out_string (mtp, name); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &rename_chat_methods, instance); } /* }}} */ /* {{{ Chat info */ void print_chat_info (struct chat *C) { - peer_t *U = (void *)C; + + // TODO: use peer_t + peer_t *U UU= (void *)C; + //print_start (); //push_color (COLOR_YELLOW); logprintf ("Chat "); @@ -1764,7 +1833,11 @@ void print_chat_info (struct chat *C) { } int chat_info_on_answer (struct query *q UU) { - struct chat *C = fetch_alloc_chat_full (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + // TODO: use chat + struct chat *C UU = fetch_alloc_chat_full (mtp); + //print_chat_info (C); return 0; } @@ -1775,6 +1848,7 @@ struct query_methods chat_info_methods = { void do_get_chat_info (struct telegram *instance, peer_id_t id) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; if (offline_mode) { peer_t *C = user_chat_get (id); if (!C) { @@ -1784,18 +1858,20 @@ void do_get_chat_info (struct telegram *instance, peer_id_t id) { } return; } - clear_packet (); - out_int (CODE_messages_get_full_chat); + clear_packet (mtp); + out_int (mtp, CODE_messages_get_full_chat); assert (get_peer_type (id) == PEER_CHAT); - out_int (get_peer_id (id)); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0); + out_int (mtp, get_peer_id (id)); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &chat_info_methods, 0); } /* }}} */ /* {{{ User info */ void print_user_info (struct user *U) { - peer_t *C = (void *)U; + // TODO: use peer + peer_t *C UU = (void *)U; + //print_start (); //push_color (COLOR_YELLOW); logprintf ("User "); @@ -1815,7 +1891,10 @@ void print_user_info (struct user *U) { } int user_info_on_answer (struct query *q UU) { - struct user *U = fetch_alloc_user_full (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + // TODO: Use user info + struct user *U UU = fetch_alloc_user_full (mtp); //print_user_info (U); return 0; } @@ -1826,6 +1905,7 @@ struct query_methods user_info_methods = { void do_get_user_info (struct telegram *instance, peer_id_t id) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; if (offline_mode) { peer_t *C = user_chat_get (id); if (!C) { @@ -1835,29 +1915,30 @@ void do_get_user_info (struct telegram *instance, peer_id_t id) { } return; } - clear_packet (); - out_int (CODE_users_get_full_user); + clear_packet (mtp); + out_int (mtp, CODE_users_get_full_user); assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (id); if (U && U->user.access_hash) { - out_int (CODE_input_user_foreign); - out_int (get_peer_id (id)); - out_long (U->user.access_hash); + out_int (mtp, CODE_input_user_foreign); + out_int (mtp, get_peer_id (id)); + out_long (mtp, U->user.access_hash); } else { - out_int (CODE_input_user_contact); - out_int (get_peer_id (id)); + out_int (mtp, CODE_input_user_contact); + out_int (mtp, get_peer_id (id)); } - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, 0); } /* }}} */ /* {{{ Get user info silently */ int user_list_info_silent_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); int i; for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } return 0; } @@ -1868,17 +1949,18 @@ struct query_methods user_list_info_silent_methods = { void do_get_user_list_info_silent (struct telegram *instance, int num, int *list) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_users_get_users); - out_int (CODE_vector); - out_int (num); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_users_get_users); + out_int (mtp, CODE_vector); + out_int (mtp, num); int i; for (i = 0; i < num; i++) { - out_int (CODE_input_user_contact); - out_int (list[i]); + out_int (mtp, CODE_input_user_contact); + out_int (mtp, list[i]); //out_long (0); } - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_list_info_silent_methods, 0); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_list_info_silent_methods, 0); } /* }}} */ @@ -1936,22 +2018,24 @@ void load_next_part (struct telegram *instance, struct download *D); int download_on_answer (struct query *q) { struct download_extra *extra = q->extra; struct telegram *instance = extra->instance; + struct mtproto_connection *mtp = query_get_mtproto(q); + struct download *D = extra->dl; free(extra); - assert (fetch_int () == (int)CODE_upload_file); - unsigned x = fetch_int (); + assert (fetch_int (mtp) == (int)CODE_upload_file); + unsigned x = fetch_int (mtp); assert (x); if (D->fd == -1) { D->fd = open (D->name, O_CREAT | O_WRONLY, 0640); } - fetch_int (); // mtime - int len = prefetch_strlen (); + fetch_int (mtp); // mtime + int len = prefetch_strlen (mtp); assert (len >= 0); cur_downloaded_bytes += len; //update_prompt (); if (D->iv) { - unsigned char *ptr = (void *)fetch_str (len); + unsigned char *ptr = (void *)fetch_str (mtp, len); assert (!(len & 15)); AES_KEY aes_key; AES_set_decrypt_key (D->key, 256, &aes_key); @@ -1962,7 +2046,7 @@ int download_on_answer (struct query *q) { } assert (write (D->fd, ptr, len) == len); } else { - assert (write (D->fd, fetch_str (len), len) == len); + assert (write (D->fd, fetch_str (mtp, len), len) == len); } D->offset += len; if (D->offset < D->size) { @@ -1979,6 +2063,7 @@ struct query_methods download_methods = { }; void load_next_part (struct telegram *instance, struct download *D) { + struct mtproto_connection *mtp = instance->connection; if (!D->offset) { static char buf[PATH_MAX]; int l; @@ -2008,30 +2093,30 @@ void load_next_part (struct telegram *instance, struct download *D) { cur_downloaded_bytes += D->offset; //update_prompt (); } - clear_packet (); - out_int (CODE_upload_get_file); + clear_packet (mtp); + out_int (mtp, CODE_upload_get_file); if (!D->id) { - out_int (CODE_input_file_location); - out_long (D->volume); - out_int (D->local_id); - out_long (D->secret); + out_int (mtp, CODE_input_file_location); + out_long (mtp, D->volume); + out_int (mtp, D->local_id); + out_long (mtp, D->secret); } else { if (D->iv) { - out_int (CODE_input_encrypted_file_location); + out_int (mtp, CODE_input_encrypted_file_location); } else { - out_int (D->type); + out_int (mtp, D->type); } - out_long (D->id); - out_long (D->access_hash); + out_long (mtp, D->id); + out_long (mtp, D->access_hash); } - out_int (D->offset); - out_int (1 << 14); + out_int (mtp, D->offset); + out_int (mtp, 1 << 14); struct download_extra *extra = malloc(sizeof(struct download_extra)); extra->instance = instance; extra->dl = D; - send_query (instance->auth.DC_list[D->dc], packet_ptr - packet_buffer, packet_buffer, &download_methods, extra); + send_query (instance->auth.DC_list[D->dc], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &download_methods, extra); //send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); } @@ -2164,16 +2249,18 @@ int isn_export_auth_str (void) { } int export_auth_on_answer (struct query *q UU) { - assert (fetch_int () == (int)CODE_auth_exported_authorization); - int l = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == (int)CODE_auth_exported_authorization); + int l = fetch_int (mtp); if (!our_id) { our_id = l; } else { assert (our_id == l); } - l = prefetch_strlen (); + l = prefetch_strlen (mtp); char *s = talloc (l); - memcpy (s, fetch_str (l), l); + memcpy (s, fetch_str (mtp, l), l); export_auth_str_len = l; export_auth_str = s; return 0; @@ -2186,19 +2273,22 @@ struct query_methods export_auth_methods = { void do_export_auth (struct telegram *instance, int num) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; 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); + clear_packet (mtp); + out_int (mtp, CODE_auth_export_authorization); + out_int (mtp, num); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, 0); } /* }}} */ /* {{{ Import auth */ int import_auth_on_answer (struct query *q UU) { - assert (fetch_int () == (int)CODE_auth_authorization); - fetch_int (); // expires - fetch_alloc_user (); + struct mtproto_connection *mtp = query_get_mtproto(q); + assert (fetch_int (mtp) == (int)CODE_auth_authorization); + + fetch_int (mtp); // expires + fetch_alloc_user (mtp); tfree_str (export_auth_str); export_auth_str = 0; return 0; @@ -2210,19 +2300,22 @@ struct query_methods import_auth_methods = { }; void do_import_auth (struct telegram *instance, 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 (instance->auth.DC_list[num], packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, 0); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_auth_import_authorization); + out_int (mtp, our_id); + out_cstring (mtp, export_auth_str, export_auth_str_len); + send_query (instance->auth.DC_list[num], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &import_auth_methods, 0); } /* }}} */ /* {{{ Add contact */ int add_contact_on_answer (struct query *q UU) { - assert (fetch_int () == (int)CODE_contacts_imported_contacts); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == (int)CODE_contacts_imported_contacts); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); if (n > 0) { logprintf ("Added successfully"); } else { @@ -2230,14 +2323,14 @@ int add_contact_on_answer (struct query *q UU) { } int i; for (i = 0; i < n ; i++) { - assert (fetch_int () == (int)CODE_imported_contact); - fetch_int (); // uid - fetch_long (); // client_id + assert (fetch_int (mtp) == (int)CODE_imported_contact); + fetch_int (mtp); // uid + fetch_long (mtp); // client_id } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n ; i++) { - struct user *U = fetch_alloc_user (); + struct user *U = fetch_alloc_user (mtp); //print_start (); //push_color (COLOR_YELLOW); logprintf ("User #%d: ", get_peer_id (U->id)); @@ -2275,17 +2368,18 @@ struct query_methods add_contact_methods = { void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_contacts_import_contacts); - out_int (CODE_vector); - out_int (1); - out_int (CODE_input_phone_contact); - out_long (lrand48 () * (1ll << 32) + lrand48 ()); - out_cstring (phone, phone_len); - out_cstring (first_name, first_name_len); - out_cstring (last_name, last_name_len); - out_int (force ? CODE_bool_true : CODE_bool_false); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_contact_methods, 0); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_contacts_import_contacts); + out_int (mtp, CODE_vector); + out_int (mtp, 1); + out_int (mtp, CODE_input_phone_contact); + out_long (mtp, lrand48 () * (1ll << 32) + lrand48 ()); + out_cstring (mtp, phone, phone_len); + out_cstring (mtp, first_name, first_name_len); + out_cstring (mtp, last_name, last_name_len); + out_int (mtp, force ? CODE_bool_true : CODE_bool_false); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_contact_methods, 0); } /* }}} */ @@ -2300,44 +2394,47 @@ struct query_methods msg_search_methods = { void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT) { logprintf ("Can not search in secure chat\n"); return; } - clear_packet (); - out_int (CODE_messages_search); + clear_packet (mtp); + out_int (mtp, CODE_messages_search); if (get_peer_type (id) == PEER_UNKNOWN) { - out_int (CODE_input_peer_empty); + out_int (mtp, CODE_input_peer_empty); } else { - out_peer_id (id); + out_peer_id (mtp, id); } - out_string (s); - out_int (CODE_input_messages_filter_empty); - out_int (from); - out_int (to); - out_int (0); // offset - out_int (0); // max_id - out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_search_methods, 0); + out_string (mtp, s); + out_int (mtp, CODE_input_messages_filter_empty); + out_int (mtp, from); + out_int (mtp, to); + out_int (mtp, 0); // offset + out_int (mtp, 0); // max_id + out_int (mtp, limit); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_search_methods, 0); } /* }}} */ /* {{{ Contacts search */ int contacts_search_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_contacts_found); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == CODE_contacts_found); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); int i; for (i = 0; i < n; i++) { - assert (fetch_int () == (int)CODE_contact_found); - fetch_int (); + assert (fetch_int (mtp) == (int)CODE_contact_found); + fetch_int (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); //print_start (); //push_color (COLOR_YELLOW); for (i = 0; i < n; i++) { - struct user *U = fetch_alloc_user (); + struct user *U = fetch_alloc_user (mtp); logprintf ("User "); //push_color (COLOR_RED); logprintf ("%s %s", U->first_name, U->last_name); @@ -2355,17 +2452,20 @@ struct query_methods contacts_search_methods = { void do_contacts_search (struct telegram *instance, int limit, const char *s) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_contacts_search); - out_string (s); - out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &contacts_search_methods, 0); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_contacts_search); + out_string (mtp, s); + out_int (mtp, limit); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &contacts_search_methods, 0); } /* }}} */ /* {{{ Encr accept */ int send_encr_accept_on_answer (struct query *q UU) { - struct secret_chat *E = fetch_alloc_encrypted_chat (); + struct mtproto_connection *mtp = query_get_mtproto(q); + struct secret_chat *E = fetch_alloc_encrypted_chat (mtp); if (E->state == sc_ok) { //print_start (); @@ -2388,7 +2488,8 @@ int send_encr_accept_on_answer (struct query *q UU) { } int send_encr_request_on_answer (struct query *q UU) { - struct secret_chat *E = fetch_alloc_encrypted_chat (); + struct mtproto_connection *mtp = query_get_mtproto(q); + struct secret_chat *E = fetch_alloc_encrypted_chat (mtp); if (E->state == sc_deleted) { //print_start (); //push_color (COLOR_YELLOW); @@ -2426,6 +2527,7 @@ BN_CTX *ctx; void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, unsigned char *random) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; int i; int ok = 0; for (i = 0; i < 64; i++) { @@ -2463,28 +2565,28 @@ void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, static unsigned char sha_buffer[20]; sha1 (kk, 256, sha_buffer); - bl_do_set_encr_chat_key (E, kk, *(long long *)(sha_buffer + 12)); + bl_do_set_encr_chat_key (mtp, E, kk, *(long long *)(sha_buffer + 12)); - clear_packet (); - out_int (CODE_messages_accept_encryption); - out_int (CODE_input_encrypted_chat); - out_int (get_peer_id (E->id)); - out_long (E->access_hash); + clear_packet (mtp); + out_int (mtp, CODE_messages_accept_encryption); + out_int (mtp, CODE_input_encrypted_chat); + out_int (mtp, get_peer_id (E->id)); + out_long (mtp, E->access_hash); ensure (BN_set_word (g_a, encr_root)); ensure (BN_mod_exp (r, g_a, b, p, ctx)); static unsigned char buf[256]; memset (buf, 0, sizeof (buf)); BN_bn2bin (r, buf); - out_cstring ((void *)buf, 256); + out_cstring (mtp, (void *)buf, 256); - out_long (E->key_fingerprint); + out_long (mtp, E->key_fingerprint); BN_clear_free (b); BN_clear_free (g_a); BN_clear_free (p); BN_clear_free (r); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_accept_methods, E); } void do_create_keys_end (struct secret_chat *U) { @@ -2538,6 +2640,8 @@ void do_create_keys_end (struct secret_chat *U) { void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char *random) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; + int user_id = (long)x; int i; unsigned char random_here[256]; @@ -2576,25 +2680,25 @@ void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char t = lrand48 (); } - bl_do_encr_chat_init (t, user_id, (void *)random, (void *)g_a); + bl_do_encr_chat_init (mtp, t, user_id, (void *)random, (void *)g_a); peer_t *_E = user_chat_get (MK_ENCR_CHAT (t)); assert (_E); struct secret_chat *E = &_E->encr_chat; - clear_packet (); - out_int (CODE_messages_request_encryption); + clear_packet (mtp); + out_int (mtp, CODE_messages_request_encryption); peer_t *U = user_chat_get (MK_USER (E->user_id)); assert (U); if (U && U->user.access_hash) { - out_int (CODE_input_user_foreign); - out_int (E->user_id); - out_long (U->user.access_hash); + out_int (mtp, CODE_input_user_foreign); + out_int (mtp, E->user_id); + out_long (mtp, U->user.access_hash); } else { - out_int (CODE_input_user_contact); - out_int (E->user_id); + out_int (mtp, CODE_input_user_contact); + out_int (mtp, E->user_id); } - out_int (get_peer_id (E->id)); - out_cstring (g_a, 256); + out_int (mtp, get_peer_id (E->id)); + out_cstring (mtp, g_a, 256); // TODO: properly... write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); @@ -2602,7 +2706,7 @@ void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char BN_clear_free (p); BN_clear_free (r); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_request_methods, E); } struct create_encr_chat_extra { @@ -2612,26 +2716,28 @@ struct create_encr_chat_extra { }; int get_dh_config_on_answer (struct query *q UU) { - unsigned x = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + unsigned x = fetch_int (mtp); assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { - int a = fetch_int (); - int l = prefetch_strlen (); + int a = fetch_int (mtp); + int l = prefetch_strlen (mtp); assert (l == 256); - char *s = fetch_str (l); - int v = fetch_int (); - bl_do_set_dh_params (a, (void *)s, v); + char *s = fetch_str (mtp, l); + int v = fetch_int (mtp); + bl_do_set_dh_params (mtp, a, (void *)s, v); BIGNUM *p = BN_bin2bn ((void *)s, 256, 0); ensure_ptr (p); - assert (check_DH_params (p, a) >= 0); + assert (check_DH_params (mtp, p, a) >= 0); BN_free (p); } if (x == LOG_DH_CONFIG) { return 0; } - int l = prefetch_strlen (); + int l = prefetch_strlen (mtp); assert (l == 256); unsigned char *random = talloc (256); - memcpy (random, fetch_str (256), 256); + memcpy (random, fetch_str (mtp, 256), 256); if (q->extra) { //((void (*)(void *, void *))(*x))(x[1], random); @@ -2653,32 +2759,35 @@ struct query_methods get_dh_config_methods = { void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E) { struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; assert (E->state == sc_request); - clear_packet (); - out_int (CODE_messages_get_dh_config); - out_int (encr_param_version); - out_int (256); + clear_packet (mtp); + out_int (mtp, CODE_messages_get_dh_config); + out_int (mtp, encr_param_version); + out_int (mtp, 256); struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); extra->callback = do_send_accept_encr_chat; extra->instance = instance; extra->data = (void*)E; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, extra); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); } void do_create_encr_chat_request (struct telegram *instance, int user_id) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_get_dh_config); - out_int (encr_param_version); - out_int (256); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_messages_get_dh_config); + out_int (mtp, encr_param_version); + out_int (mtp, 256); struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); extra->callback = do_send_accept_encr_chat; extra->instance = instance; extra->data = (void *)(long)user_id; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, extra); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); } /* }}} */ @@ -2687,13 +2796,15 @@ int unread_messages; int difference_got; int seq, pts, qts, last_date; int get_state_on_answer (struct query *q UU) { + struct mtproto_connection *mtp = query_get_mtproto(q); + logprintf("get_state_on_answer()\n"); - assert (fetch_int () == (int)CODE_updates_state); - bl_do_set_pts (fetch_int ()); - bl_do_set_qts (fetch_int ()); - bl_do_set_date (fetch_int ()); - bl_do_set_seq (fetch_int ()); - unread_messages = fetch_int (); + assert (fetch_int (mtp) == (int)CODE_updates_state); + bl_do_set_pts (mtp, fetch_int (mtp)); + bl_do_set_qts (mtp, fetch_int (mtp)); + bl_do_set_date (mtp, fetch_int (mtp)); + bl_do_set_seq (mtp, fetch_int (mtp)); + unread_messages = fetch_int (mtp); //write_state_file (); difference_got = 1; return 0; @@ -2701,60 +2812,61 @@ int get_state_on_answer (struct query *q UU) { int get_difference_active; int get_difference_on_answer (struct query *q UU) { + struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = q->extra; logprintf("get_difference_on_answer()\n"); get_difference_active = 0; - unsigned x = fetch_int (); + unsigned x = fetch_int (mtp); if (x == CODE_updates_difference_empty) { - bl_do_set_date (fetch_int ()); - bl_do_set_seq (fetch_int ()); + bl_do_set_date (mtp, fetch_int (mtp)); + bl_do_set_seq (mtp, fetch_int (mtp)); difference_got = 1; } else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) { int n, i; - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); static struct message *ML[10000]; int ml_pos = 0; for (i = 0; i < n; i++) { if (ml_pos < 10000) { - ML[ml_pos ++] = fetch_alloc_message (instance); + ML[ml_pos ++] = fetch_alloc_message (mtp, instance); } else { - fetch_alloc_message (instance); + fetch_alloc_message (mtp, instance); } } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { if (ml_pos < 10000) { - ML[ml_pos ++] = fetch_alloc_encrypted_message (instance); + ML[ml_pos ++] = fetch_alloc_encrypted_message (mtp, instance); } else { - fetch_alloc_encrypted_message (instance); + fetch_alloc_encrypted_message (mtp, instance); } } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { work_update (0, 0); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); logprintf("Found %d chats\n", n); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); logprintf("Found %d users\n", n); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } - assert (fetch_int () == (int)CODE_updates_state); - bl_do_set_pts (fetch_int ()); - bl_do_set_qts (fetch_int ()); - bl_do_set_date (fetch_int ()); - bl_do_set_seq (fetch_int ()); - unread_messages = fetch_int (); + assert (fetch_int (mtp) == (int)CODE_updates_state); + bl_do_set_pts (mtp, fetch_int (mtp)); + bl_do_set_qts (mtp, fetch_int (mtp)); + bl_do_set_date (mtp, fetch_int (mtp)); + bl_do_set_seq (mtp, fetch_int (mtp)); + unread_messages = fetch_int (mtp); //write_state_file (); for (i = 0; i < ml_pos; i++) { event_update_new_message(ML[i]); @@ -2780,24 +2892,26 @@ struct query_methods get_difference_methods = { }; void do_get_difference (struct telegram *instance) { + struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); + logprintf("do_get_difference()\n"); get_difference_active = 1; difference_got = 0; - clear_packet (); - do_insert_header (); + clear_packet (mtp); + do_insert_header (mtp); if (seq > 0 || sync_from_start) { if (pts == 0) { pts = 1; } if (qts == 0) { qts = 1; } if (last_date == 0) { last_date = 1; } - out_int (CODE_updates_get_difference); - out_int (pts); - out_int (last_date); - out_int (qts); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_difference_methods, instance); + out_int (mtp, CODE_updates_get_difference); + out_int (mtp, pts); + out_int (mtp, last_date); + out_int (mtp, qts); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); } else { - out_int (CODE_updates_get_state); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0); + out_int (mtp, CODE_updates_get_state); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, 0); } } /* }}} */ @@ -2836,25 +2950,27 @@ void do_visualize_key (peer_id_t id) { /* {{{ Get suggested */ int get_suggested_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_contacts_suggested); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == CODE_contacts_suggested); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); logprintf ("n = %d\n", n); assert (n <= 200); int l[400]; int i; for (i = 0; i < n; i++) { - assert (fetch_int () == CODE_contact_suggested); - l[2 * i] = fetch_int (); - l[2 * i + 1] = fetch_int (); + assert (fetch_int (mtp) == CODE_contact_suggested); + l[2 * i] = fetch_int (mtp); + l[2 * i + 1] = fetch_int (mtp); } - assert (fetch_int () == CODE_vector); - int m = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + int m = fetch_int (mtp); assert (n == m); //print_start (); //push_color (COLOR_YELLOW); for (i = 0; i < m; i++) { - peer_t *U = (void *)fetch_alloc_user (); + peer_t *U = (void *)fetch_alloc_user (mtp); assert (get_peer_id (U->id) == l[2 * i]); //print_user_name (U->id, U); logprintf (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); @@ -2870,10 +2986,11 @@ struct query_methods get_suggested_methods = { void do_get_suggested (struct telegram *instance) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_contacts_get_suggested); - out_int (100); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_suggested_methods, 0); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_contacts_get_suggested); + out_int (mtp, 100); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_suggested_methods, 0); } /* }}} */ @@ -2885,41 +3002,43 @@ struct query_methods add_user_to_chat_methods = { void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_add_chat_user); - out_int (get_peer_id (chat_id)); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_messages_add_chat_user); + out_int (mtp, get_peer_id (chat_id)); assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (id); if (U && U->user.access_hash) { - out_int (CODE_input_user_foreign); - out_int (get_peer_id (id)); - out_long (U->user.access_hash); + out_int (mtp, CODE_input_user_foreign); + out_int (mtp, get_peer_id (id)); + out_long (mtp, U->user.access_hash); } else { - out_int (CODE_input_user_contact); - out_int (get_peer_id (id)); + out_int (mtp, CODE_input_user_contact); + out_int (mtp, get_peer_id (id)); } - out_int (limit); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_user_to_chat_methods, 0); + out_int (mtp, limit); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); } void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_delete_chat_user); - out_int (get_peer_id (chat_id)); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_messages_delete_chat_user); + out_int (mtp, get_peer_id (chat_id)); assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (id); if (U && U->user.access_hash) { - out_int (CODE_input_user_foreign); - out_int (get_peer_id (id)); - out_long (U->user.access_hash); + out_int (mtp, CODE_input_user_foreign); + out_int (mtp, get_peer_id (id)); + out_long (mtp, U->user.access_hash); } else { - out_int (CODE_input_user_contact); - out_int (get_peer_id (id)); + out_int (mtp, CODE_input_user_contact); + out_int (mtp, get_peer_id (id)); } - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_user_to_chat_methods, 0); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); } /* }}} */ @@ -2944,26 +3063,27 @@ struct query_methods create_group_chat_methods = { }; void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic) { + struct mtproto_connection *mtp = instance->connection; assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (id); if (!U) { logprintf ("Can not create chat with unknown user\n"); return; } - clear_packet (); - out_int (CODE_messages_create_chat); - out_int (CODE_vector); - out_int (1); // Number of users, currently we support only 1 user. + clear_packet (mtp); + out_int (mtp, CODE_messages_create_chat); + out_int (mtp, CODE_vector); + out_int (mtp, 1); // Number of users, currently we support only 1 user. if (U && U->user.access_hash) { - out_int (CODE_input_user_foreign); - out_int (get_peer_id (id)); - out_long (U->user.access_hash); + out_int (mtp, CODE_input_user_foreign); + out_int (mtp, get_peer_id (id)); + out_long (mtp, U->user.access_hash); } else { - out_int (CODE_input_user_contact); - out_int (get_peer_id (id)); + out_int (mtp, CODE_input_user_contact); + out_int (mtp, get_peer_id (id)); } - out_string (chat_topic); - send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &create_group_chat_methods, 0); + out_string (mtp, chat_topic); + send_query (telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &create_group_chat_methods, 0); } /* }}} */ @@ -2971,9 +3091,11 @@ void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_t /* {{{ Delete msg */ int delete_msg_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_vector); - int n = fetch_int (); - fetch_skip (n); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); + fetch_skip (mtp, n); logprintf ("Deleted %d messages\n", n); return 0; } @@ -2984,21 +3106,24 @@ struct query_methods delete_msg_methods = { void do_delete_msg (struct telegram *instance, long long id) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_delete_messages); - out_int (CODE_vector); - out_int (1); - out_int (id); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &delete_msg_methods, 0); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_messages_delete_messages); + out_int (mtp, CODE_vector); + out_int (mtp, 1); + out_int (mtp, id); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &delete_msg_methods, 0); } /* }}} */ /* {{{ Restore msg */ int restore_msg_on_answer (struct query *q UU) { - assert (fetch_int () == CODE_vector); - int n = fetch_int (); - fetch_skip (n); + struct mtproto_connection *mtp = query_get_mtproto(q); + + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); + fetch_skip (mtp, n); logprintf ("Restored %d messages\n", n); return 0; } @@ -3009,16 +3134,19 @@ struct query_methods restore_msg_methods = { void do_restore_msg (struct telegram *instance, long long id) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_messages_restore_messages); - out_int (CODE_vector); - out_int (1); - out_int (id); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &restore_msg_methods, 0); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_messages_restore_messages); + out_int (mtp, CODE_vector); + out_int (mtp, 1); + out_int (mtp, id); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &restore_msg_methods, 0); } /* }}} */ int update_status_on_answer (struct query *q UU) { - fetch_bool (); + struct mtproto_connection *mtp = query_get_mtproto(q); + + fetch_bool (mtp); return 0; } @@ -3028,9 +3156,10 @@ struct query_methods update_status_methods = { void do_update_status (struct telegram *instance, int online UU) { struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (); - out_int (CODE_account_update_status); - out_int (online ? CODE_bool_false : CODE_bool_true); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &update_status_methods, 0); + struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); + out_int (mtp, CODE_account_update_status); + out_int (mtp, online ? CODE_bool_false : CODE_bool_true); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); } diff --git a/queries.h b/queries.h index a7730fa..2dca703 100644 --- a/queries.h +++ b/queries.h @@ -16,14 +16,17 @@ Copyright Vitaly Valtman 2013 */ -#include "net.h" -#include "telegram.h" #ifndef __QUERIES_H__ #define __QUERIES_H__ + +#pragma once #include "structures.h" // forward declare telegram struct telegram; +struct encr_video; +struct document; +struct secret_chat; #define QUERY_ACK_RECEIVED 1 diff --git a/structures.c b/structures.c index 3d68143..1edc1a5 100644 --- a/structures.c +++ b/structures.c @@ -23,8 +23,8 @@ #include #include +#include "constants.h" #include "structures.h" -#include "mtproto-common.h" #include "telegram.h" #include "tree.h" #include "loop.h" @@ -32,6 +32,7 @@ #include #include "queries.h" #include "binlog.h" +#include "net.h" #define sha1 SHA1 @@ -67,7 +68,7 @@ peer_t *Peers[MAX_PEER_NUM]; extern int binlog_enabled; -void fetch_skip_photo (void); +void fetch_skip_photo (struct mtproto_connection *mtp); #define code_assert(x) if (!(x)) { logprintf ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } #define code_try(x) if ((x) == -1) { return -1; } @@ -78,26 +79,26 @@ void fetch_skip_photo (void); * */ -int fetch_file_location (struct file_location *loc) { - int x = fetch_int (); +int fetch_file_location (struct mtproto_connection *mtp, struct file_location *loc) { + int x = fetch_int (mtp); code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); if (x == CODE_file_location_unavailable) { loc->dc = -1; - loc->volume = fetch_long (); - loc->local_id = fetch_int (); - loc->secret = fetch_long (); + loc->volume = fetch_long (mtp); + loc->local_id = fetch_int (mtp); + loc->secret = fetch_long (mtp); } else { - loc->dc = fetch_int (); - loc->volume = fetch_long (); - loc->local_id = fetch_int (); - loc->secret = fetch_long (); + loc->dc = fetch_int (mtp); + loc->volume = fetch_long (mtp); + loc->local_id = fetch_int (mtp); + loc->secret = fetch_long (mtp); } return 0; } -int fetch_user_status (struct user_status *S) { - unsigned x = fetch_int (); +int fetch_user_status (struct mtproto_connection *mtp, struct user_status *S) { + unsigned x = fetch_int (mtp); code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); switch (x) { case CODE_user_status_empty: @@ -106,11 +107,11 @@ int fetch_user_status (struct user_status *S) { break; case CODE_user_status_online: S->online = 1; - S->when = fetch_int (); + S->when = fetch_int (mtp); break; case CODE_user_status_offline: S->online = -1; - S->when = fetch_int (); + S->when = fetch_int (mtp); break; default: assert (0); @@ -124,23 +125,23 @@ int fetch_user_status (struct user_status *S) { * */ -int fetch_skip_file_location (void) { - int x = fetch_int (); +int fetch_skip_file_location (struct mtproto_connection *mtp) { + int x = fetch_int (mtp); code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); if (x == CODE_file_location_unavailable) { - in_ptr += 5; + mtp->in_ptr += 5; } else { - in_ptr += 6; + mtp->in_ptr += 6; } return 0; } -int fetch_skip_user_status (void) { - unsigned x = fetch_int (); +int fetch_skip_user_status (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); if (x != CODE_user_status_empty) { - fetch_int (); + fetch_int (mtp); } return 0; } @@ -184,23 +185,23 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha * */ -long long fetch_user_photo (struct user *U) { - unsigned x = fetch_int (); +long long fetch_user_photo (struct mtproto_connection *mtp, struct user *U) { + unsigned x = fetch_int (mtp); code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); if (x == CODE_user_profile_photo_empty) { - bl_do_set_user_profile_photo (U, 0, 0, 0); + bl_do_set_user_profile_photo (mtp, U, 0, 0, 0); return 0; } long long photo_id = 1; if (x == CODE_user_profile_photo) { - photo_id = fetch_long (); + photo_id = fetch_long (mtp); } struct file_location big; struct file_location small; - code_try (fetch_file_location (&small)); - code_try (fetch_file_location (&big)); + code_try (fetch_file_location (mtp, &small)); + code_try (fetch_file_location (mtp, &big)); - bl_do_set_user_profile_photo (U, photo_id, &big, &small); + bl_do_set_user_profile_photo (mtp, U, photo_id, &big, &small); return 0; } @@ -219,10 +220,10 @@ int user_get_alias(peer_t *user, char *buffer, int maxlen) } } -int fetch_user (struct user *U) { - unsigned x = fetch_int (); +int fetch_user (struct mtproto_connection *mtp, struct user *U) { + unsigned x = fetch_int (mtp); code_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 = MK_USER (fetch_int ()); + U->id = MK_USER (fetch_int (mtp)); if (x == CODE_user_empty) { return 0; } @@ -230,7 +231,7 @@ int fetch_user (struct user *U) { if (x == CODE_user_self) { assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { - bl_do_set_our_id (get_peer_id (U->id)); + bl_do_set_our_id (mtp, get_peer_id (U->id)); // TODO: What to do here? //write_auth_file (); } @@ -241,78 +242,78 @@ int fetch_user (struct user *U) { new = 1; } if (new) { - int l1 = prefetch_strlen (); + int l1 = prefetch_strlen (mtp); code_assert (l1 >= 0); - char *s1 = fetch_str (l1); - int l2 = prefetch_strlen (); + char *s1 = fetch_str (mtp, l1); + int l2 = prefetch_strlen (mtp); code_assert (l2 >= 0); - char *s2 = fetch_str (l2); + char *s2 = fetch_str (mtp, l2); if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_new_user (get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); - bl_do_user_delete (U); + bl_do_new_user (mtp, get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); + bl_do_user_delete (mtp, U); } if (x != CODE_user_deleted) { long long access_token = 0; if (x != CODE_user_self) { - access_token = fetch_long (); + access_token = fetch_long (mtp); } int phone_len = 0; char *phone = 0; if (x != CODE_user_foreign) { - phone_len = prefetch_strlen (); + phone_len = prefetch_strlen (mtp); code_assert (phone_len >= 0); - phone = fetch_str (phone_len); + phone = fetch_str (mtp, phone_len); } - bl_do_new_user (get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); - if (fetch_user_photo (U) < 0) { return -1; } + bl_do_new_user (mtp, get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); + if (fetch_user_photo (mtp, U) < 0) { return -1; } - if (fetch_user_status (&U->status) < 0) { return -1; } + if (fetch_user_status (mtp, &U->status) < 0) { return -1; } if (x == CODE_user_self) { - fetch_bool (); + fetch_bool (mtp); } } } else { - int l1 = prefetch_strlen (); - char *s1 = fetch_str (l1); - int l2 = prefetch_strlen (); - char *s2 = fetch_str (l2); + int l1 = prefetch_strlen (mtp); + char *s1 = fetch_str (mtp, l1); + int l2 = prefetch_strlen (mtp); + char *s2 = fetch_str (mtp, l2); - bl_do_set_user_name (U, s1, l1, s2, l2); + bl_do_set_user_name (mtp, U, s1, l1, s2, l2); if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_user_delete (U); + bl_do_user_delete (mtp, U); } if (x != CODE_user_deleted) { if (x != CODE_user_self) { - bl_do_set_user_access_token (U, fetch_long ()); + bl_do_set_user_access_token (mtp, U, fetch_long (mtp)); } if (x != CODE_user_foreign) { - int l = prefetch_strlen (); - char *s = fetch_str (l); - bl_do_set_user_phone (U, s, l); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); + bl_do_set_user_phone (mtp, U, s, l); } - if (fetch_user_photo (U) < 0) { return -1; } + if (fetch_user_photo (mtp, U) < 0) { return -1; } - fetch_user_status (&U->status); + fetch_user_status (mtp, &U->status); if (x == CODE_user_self) { - fetch_bool (); + fetch_bool (mtp); } if (x == CODE_user_contact) { - bl_do_set_user_friend (U, 1); + bl_do_set_user_friend (mtp, U, 1); } else { - bl_do_set_user_friend (U, 0); + bl_do_set_user_friend (mtp, U, 0); } } } return 0; } -void fetch_encrypted_chat (struct secret_chat *U) { - unsigned x = fetch_int (); +void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U) { + unsigned x = fetch_int (mtp); assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); - U->id = MK_ENCR_CHAT (fetch_int ()); + U->id = MK_ENCR_CHAT (fetch_int (mtp)); if (x == CODE_encrypted_chat_empty) { return; } @@ -323,7 +324,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { logprintf ("Unknown chat in deleted state. May be we forgot something...\n"); return; } - bl_do_encr_chat_delete (U); + bl_do_encr_chat_delete (mtp, U); // TODO: properly write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); @@ -333,10 +334,10 @@ void fetch_encrypted_chat (struct secret_chat *U) { static char g_key[256]; static char nonce[256]; if (new) { - long long access_hash = fetch_long (); - int date = fetch_int (); - int admin_id = fetch_int (); - int user_id = fetch_int () + admin_id - our_id; + long long access_hash = fetch_long (mtp); + int date = fetch_int (mtp); + int admin_id = fetch_int (mtp); + int user_id = fetch_int (mtp) + admin_id - our_id; if (x == CODE_encrypted_chat_waiting) { logprintf ("Unknown chat in waiting state. May be we forgot something...\n"); @@ -347,8 +348,8 @@ void fetch_encrypted_chat (struct secret_chat *U) { memset (nonce, 0, sizeof (nonce)); } - int l = prefetch_strlen (); - char *s = fetch_str (l); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (g_key + 256 - l, s, l); @@ -356,8 +357,8 @@ void fetch_encrypted_chat (struct secret_chat *U) { memcpy (g_key, s + (l - 256), 256); } - /*l = prefetch_strlen (); - s = fetch_str (l); + /*l = prefetch_strlen (mtp); + s = fetch_str (mtp, l); if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); @@ -366,7 +367,7 @@ void fetch_encrypted_chat (struct secret_chat *U) { }*/ if (x == CODE_encrypted_chat) { - fetch_long (); // fingerprint + fetch_long (mtp); // fingerprint } if (x == CODE_encrypted_chat) { @@ -374,21 +375,21 @@ void fetch_encrypted_chat (struct secret_chat *U) { return; } - bl_do_encr_chat_requested (U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); + bl_do_encr_chat_requested (mtp, U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); } else { - bl_do_set_encr_chat_access_hash (U, fetch_long ()); - bl_do_set_encr_chat_date (U, fetch_int ()); - if (fetch_int () != U->admin_id) { + bl_do_set_encr_chat_access_hash (mtp, U, fetch_long (mtp)); + bl_do_set_encr_chat_date (mtp, U, fetch_int (mtp)); + if (fetch_int (mtp) != U->admin_id) { logprintf ("Changed admin in secret chat. WTF?\n"); return; } - if (U->user_id != U->admin_id + fetch_int () - our_id) { + if (U->user_id != U->admin_id + fetch_int (mtp) - our_id) { logprintf ("Changed partner in secret chat. WTF?\n"); return; } if (x == CODE_encrypted_chat_waiting) { - bl_do_set_encr_chat_state (U, sc_waiting); + bl_do_set_encr_chat_state (mtp, U, sc_waiting); write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); return; // We needed only access hash from here } @@ -398,8 +399,8 @@ void fetch_encrypted_chat (struct secret_chat *U) { memset (nonce, 0, sizeof (nonce)); } - int l = prefetch_strlen (); - char *s = fetch_str (l); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (g_key + 256 - l, s, l); @@ -407,8 +408,8 @@ void fetch_encrypted_chat (struct secret_chat *U) { memcpy (g_key, s + (l - 256), 256); } - /*l = prefetch_strlen (); - s = fetch_str (l); + /*l = prefetch_strlen (mtp); + s = fetch_str (mtp, l); if (l != 256) { logprintf ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); @@ -419,47 +420,47 @@ void fetch_encrypted_chat (struct secret_chat *U) { if (x == CODE_encrypted_chat_requested) { return; // Duplicate? } - bl_do_encr_chat_accepted (U, (void *)g_key, (void *)nonce, fetch_long ()); + bl_do_encr_chat_accepted (mtp, U, (void *)g_key, (void *)nonce, fetch_long (mtp)); } write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); } -void fetch_notify_settings (void); -void fetch_user_full (struct user *U) { - assert (fetch_int () == CODE_user_full); - fetch_alloc_user (); +void fetch_notify_settings (struct mtproto_connection *mtp); +void fetch_user_full (struct mtproto_connection *mtp, struct user *U) { + assert (fetch_int (mtp) == CODE_user_full); + fetch_alloc_user (mtp); unsigned x; - assert (fetch_int () == (int)CODE_contacts_link); - x = fetch_int (); + assert (fetch_int (mtp) == (int)CODE_contacts_link); + x = fetch_int (mtp); assert (x == CODE_contacts_my_link_empty || x == CODE_contacts_my_link_requested || x == CODE_contacts_my_link_contact); if (x == CODE_contacts_my_link_requested) { - fetch_bool (); + fetch_bool (mtp); } - x = fetch_int (); + x = fetch_int (mtp); assert (x == CODE_contacts_foreign_link_unknown || x == CODE_contacts_foreign_link_requested || x == CODE_contacts_foreign_link_mutual); if (x == CODE_contacts_foreign_link_requested) { - fetch_bool (); + fetch_bool (mtp); } - fetch_alloc_user (); + fetch_alloc_user (mtp); - int *start = in_ptr; - fetch_skip_photo (); - bl_do_set_user_full_photo (U, start, 4 * (in_ptr - start)); + int *start = mtp->in_ptr; + fetch_skip_photo (mtp); + bl_do_set_user_full_photo (mtp, U, start, 4 * (mtp->in_ptr - start)); - fetch_notify_settings (); + fetch_notify_settings (mtp); - bl_do_set_user_blocked (U, fetch_bool ()); - int l1 = prefetch_strlen (); - char *s1 = fetch_str (l1); - int l2 = prefetch_strlen (); - char *s2 = fetch_str (l2); - bl_do_set_user_real_name (U, s1, l1, s2, l2); + bl_do_set_user_blocked (mtp, U, fetch_bool (mtp)); + int l1 = prefetch_strlen (mtp); + char *s1 = fetch_str (mtp, l1); + int l2 = prefetch_strlen (mtp); + char *s2 = fetch_str (mtp, l2); + bl_do_set_user_real_name (mtp, U, s1, l1, s2, l2); } -void fetch_chat (struct chat *C) { - unsigned x = fetch_int (); +void fetch_chat (struct mtproto_connection *mtp, struct chat *C) { + unsigned x = fetch_int (mtp); assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); - C->id = MK_CHAT (fetch_int ()); + C->id = MK_CHAT (fetch_int (mtp)); if (x == CODE_chat_empty) { return; } @@ -469,8 +470,8 @@ void fetch_chat (struct chat *C) { if (x == CODE_chat_forbidden) { y |= FLAG_FORBIDDEN; } - int l = prefetch_strlen (); - char *s = fetch_str (l); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); struct file_location small; struct file_location big; @@ -481,39 +482,39 @@ void fetch_chat (struct chat *C) { int version = -1; if (x == CODE_chat) { - unsigned z = fetch_int (); + unsigned z = fetch_int (mtp); if (z == CODE_chat_photo_empty) { small.dc = -2; big.dc = -2; } else { assert (z == CODE_chat_photo); - fetch_file_location (&small); - fetch_file_location (&big); + fetch_file_location (mtp, &small); + fetch_file_location (mtp, &big); } - users_num = fetch_int (); - date = fetch_int (); - if (fetch_bool ()) { + users_num = fetch_int (mtp); + date = fetch_int (mtp); + if (fetch_bool (mtp)) { y |= FLAG_CHAT_IN_CHAT; } - version = fetch_int (); + version = fetch_int (mtp); } else { small.dc = -2; big.dc = -2; users_num = -1; - date = fetch_int (); + date = fetch_int (mtp); version = -1; } - bl_do_create_chat (C, y, s, l, users_num, date, version, &big, &small); + bl_do_create_chat (mtp, C, y, s, l, users_num, date, version, &big, &small); } else { if (x == CODE_chat_forbidden) { - bl_do_chat_forbid (C, 1); + bl_do_chat_forbid (mtp, C, 1); } else { - bl_do_chat_forbid (C, 0); + bl_do_chat_forbid (mtp, C, 0); } - int l = prefetch_strlen (); - char *s = fetch_str (l); - bl_do_set_chat_title (C, s, l); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); + bl_do_set_chat_title (mtp, C, s, l); struct file_location small; struct file_location big; @@ -521,141 +522,141 @@ void fetch_chat (struct chat *C) { memset (&big, 0, sizeof (big)); if (x == CODE_chat) { - unsigned y = fetch_int (); + unsigned y = fetch_int (mtp); 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); + fetch_file_location (mtp, &small); + fetch_file_location (mtp, &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 ()); + bl_do_set_chat_photo (mtp, C, &big, &small); + int users_num = fetch_int (mtp); + bl_do_set_chat_date (mtp, C, fetch_int (mtp)); + bl_do_set_chat_set_in_chat (mtp, C, fetch_bool (mtp)); + bl_do_set_chat_version (mtp, C, users_num, fetch_int (mtp)); } else { - bl_do_set_chat_date (C, fetch_int ()); + bl_do_set_chat_date (mtp, C, fetch_int (mtp)); } } } -void fetch_notify_settings (void) { - unsigned x = fetch_int (); +void fetch_notify_settings (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); assert (x == CODE_peer_notify_settings || x == CODE_peer_notify_settings_empty || x == CODE_peer_notify_settings_old); if (x == CODE_peer_notify_settings_old) { - fetch_int (); // mute_until - int l = prefetch_strlen (); - fetch_str (l); - fetch_bool (); // show_previews - fetch_int (); // peer notify events + fetch_int (mtp); // mute_until + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); + fetch_bool (mtp); // show_previews + fetch_int (mtp); // peer notify events } if (x == CODE_peer_notify_settings) { - fetch_int (); // mute_until - int l = prefetch_strlen (); - fetch_str (l); - fetch_bool (); // show_previews - fetch_int (); // events_mask + fetch_int (mtp); // mute_until + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); + fetch_bool (mtp); // show_previews + fetch_int (mtp); // events_mask } } -void fetch_chat_full (struct chat *C) { - unsigned x = fetch_int (); +void fetch_chat_full (struct mtproto_connection *mtp, struct chat *C) { + unsigned x = fetch_int (mtp); assert (x == CODE_messages_chat_full); - assert (fetch_int () == CODE_chat_full); - C->id = MK_CHAT (fetch_int ()); + assert (fetch_int (mtp) == CODE_chat_full); + C->id = MK_CHAT (fetch_int (mtp)); //C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); //C->flags |= FLAG_CREATED; - x = fetch_int (); + x = fetch_int (mtp); 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)); - admin_id = fetch_int (); - assert (fetch_int () == CODE_vector); - users_num = fetch_int (); + assert (fetch_int (mtp) == get_peer_id (C->id)); + admin_id = fetch_int (mtp); + assert (fetch_int (mtp) == CODE_vector); + users_num = fetch_int (mtp); users = talloc (sizeof (struct chat_user) * users_num); int i; for (i = 0; i < users_num; 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 (); + assert (fetch_int (mtp) == (int)CODE_chat_participant); + users[i].user_id = fetch_int (mtp); + users[i].inviter_id = fetch_int (mtp); + users[i].date = fetch_int (mtp); } - version = fetch_int (); + version = fetch_int (mtp); } - int *start = in_ptr; - fetch_skip_photo (); - int *end = in_ptr; - fetch_notify_settings (); + int *start = mtp->in_ptr; + fetch_skip_photo (mtp); + int *end = mtp->in_ptr; + fetch_notify_settings (mtp); int n, i; - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_chat (); + fetch_alloc_chat (mtp); } - assert (fetch_int () == CODE_vector); - n = fetch_int (); + assert (fetch_int (mtp) == CODE_vector); + n = fetch_int (mtp); for (i = 0; i < n; i++) { - fetch_alloc_user (); + fetch_alloc_user (mtp); } if (admin_id) { - bl_do_set_chat_admin (C, admin_id); + bl_do_set_chat_admin (mtp, C, admin_id); } if (version > 0) { - bl_do_set_chat_participants (C, version, users_num, users); + bl_do_set_chat_participants (mtp, C, version, users_num, users); tfree (users, sizeof (struct chat_user) * users_num); } - bl_do_set_chat_full_photo (C, start, 4 * (end - start)); + bl_do_set_chat_full_photo (mtp, C, start, 4 * (end - start)); } -void fetch_photo_size (struct photo_size *S) { +void fetch_photo_size (struct mtproto_connection *mtp, struct photo_size *S) { memset (S, 0, sizeof (*S)); - unsigned x = fetch_int (); + unsigned x = fetch_int (mtp); assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); - S->type = fetch_str_dup (); + S->type = fetch_str_dup (mtp); if (x != CODE_photo_size_empty) { - fetch_file_location (&S->loc); - S->w = fetch_int (); - S->h = fetch_int (); + fetch_file_location (mtp, &S->loc); + S->w = fetch_int (mtp); + S->h = fetch_int (mtp); if (x == CODE_photo_size) { - S->size = fetch_int (); + S->size = fetch_int (mtp); } else { - S->size = prefetch_strlen (); + S->size = prefetch_strlen (mtp); // S->data = talloc (S->size); - fetch_str (S->size); -// memcpy (S->data, fetch_str (S->size), S->size); + fetch_str (mtp, S->size); +// memcpy (S->data, fetch_str (mtp, S->size), S->size); } } } -void fetch_skip_photo_size (void) { - unsigned x = fetch_int (); +void fetch_skip_photo_size (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); - int l = prefetch_strlen (); - fetch_str (l); // type + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); // type if (x != CODE_photo_size_empty) { - fetch_skip_file_location (); - in_ptr += 2; // w, h + fetch_skip_file_location (mtp); + mtp->in_ptr += 2; // w, h if (x == CODE_photo_size) { - in_ptr ++; + mtp->in_ptr ++; } else { - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); } } } -void fetch_geo (struct geo *G) { - unsigned x = fetch_int (); +void fetch_geo (struct mtproto_connection *mtp, struct geo *G) { + unsigned x = fetch_int (mtp); if (x == CODE_geo_point) { - G->longitude = fetch_double (); - G->latitude = fetch_double (); + G->longitude = fetch_double (mtp); + G->latitude = fetch_double (mtp); } else { assert (x == CODE_geo_point_empty); G->longitude = 0; @@ -663,305 +664,305 @@ void fetch_geo (struct geo *G) { } } -void fetch_skip_geo (void) { - unsigned x = fetch_int (); +void fetch_skip_geo (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); assert (x == CODE_geo_point || x == CODE_geo_point_empty); if (x == CODE_geo_point) { - in_ptr += 4; + mtp->in_ptr += 4; } } -void fetch_photo (struct photo *P) { +void fetch_photo (struct mtproto_connection *mtp, struct photo *P) { memset (P, 0, sizeof (*P)); - unsigned x = fetch_int (); + unsigned x = fetch_int (mtp); assert (x == CODE_photo_empty || x == CODE_photo); - P->id = fetch_long (); + P->id = fetch_long (mtp); 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->access_hash = fetch_long (mtp); + P->user_id = fetch_int (mtp); + P->date = fetch_int (mtp); + P->caption = fetch_str_dup (mtp); + fetch_geo (mtp, &P->geo); + assert (fetch_int (mtp) == CODE_vector); + P->sizes_num = fetch_int (mtp); P->sizes = talloc (sizeof (struct photo_size) * P->sizes_num); int i; for (i = 0; i < P->sizes_num; i++) { - fetch_photo_size (&P->sizes[i]); + fetch_photo_size (mtp, &P->sizes[i]); } } -void fetch_skip_photo (void) { - unsigned x = fetch_int (); +void fetch_skip_photo (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); assert (x == CODE_photo_empty || x == CODE_photo); - in_ptr += 2; // id + mtp->in_ptr += 2; // id if (x == CODE_photo_empty) { return; } - in_ptr += 2 +1 + 1; // access_hash, user_id, date - int l = prefetch_strlen (); - fetch_str (l); // caption - fetch_skip_geo (); - assert (fetch_int () == CODE_vector); - int n = fetch_int (); + mtp->in_ptr += 2 +1 + 1; // access_hash, user_id, date + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); // caption + fetch_skip_geo (mtp); + assert (fetch_int (mtp) == CODE_vector); + int n = fetch_int (mtp); int i; for (i = 0; i < n; i++) { - fetch_skip_photo_size (); + fetch_skip_photo_size (mtp); } } -void fetch_video (struct video *V) { +void fetch_video (struct mtproto_connection *mtp, struct video *V) { memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (); - V->id = fetch_long (); + unsigned x = fetch_int (mtp); + V->id = fetch_long (mtp); 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 (); + V->access_hash = fetch_long (mtp); + V->user_id = fetch_int (mtp); + V->date = fetch_int (mtp); + V->caption = fetch_str_dup (mtp); + V->duration = fetch_int (mtp); + V->size = fetch_int (mtp); + fetch_photo_size (mtp, &V->thumb); + V->dc_id = fetch_int (mtp); + V->w = fetch_int (mtp); + V->h = fetch_int (mtp); } -void fetch_skip_video (void) { - unsigned x = fetch_int (); - fetch_long (); +void fetch_skip_video (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); + fetch_long (mtp); if (x == CODE_video_empty) { return; } - fetch_skip (4); - int l = prefetch_strlen (); - fetch_str (l); - fetch_skip (2); - fetch_skip_photo_size (); - fetch_skip (3); + fetch_skip (mtp, 4); + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); + fetch_skip (mtp, 2); + fetch_skip_photo_size (mtp); + fetch_skip (mtp, 3); } -void fetch_audio (struct audio *V) { +void fetch_audio (struct mtproto_connection *mtp, struct audio *V) { memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (); - V->id = fetch_long (); + unsigned x = fetch_int (mtp); + V->id = fetch_long (mtp); if (x == CODE_audio_empty) { return; } - V->access_hash = fetch_long (); - V->user_id = fetch_int (); - V->date = fetch_int (); - V->duration = fetch_int (); - V->size = fetch_int (); - V->dc_id = fetch_int (); + V->access_hash = fetch_long (mtp); + V->user_id = fetch_int (mtp); + V->date = fetch_int (mtp); + V->duration = fetch_int (mtp); + V->size = fetch_int (mtp); + V->dc_id = fetch_int (mtp); } -void fetch_skip_audio (void) { - unsigned x = fetch_int (); - fetch_skip (2); +void fetch_skip_audio (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); + fetch_skip (mtp, 2); if (x == CODE_audio_empty) { return; } - fetch_skip (7); + fetch_skip (mtp, 7); } -void fetch_document (struct document *V) { +void fetch_document (struct mtproto_connection *mtp, struct document *V) { memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (); - V->id = fetch_long (); + unsigned x = fetch_int (mtp); + V->id = fetch_long (mtp); if (x == CODE_document_empty) { return; } - V->access_hash = fetch_long (); - V->user_id = fetch_int (); - V->date = fetch_int (); - V->caption = fetch_str_dup (); - V->mime_type = fetch_str_dup (); - V->size = fetch_int (); - fetch_photo_size (&V->thumb); - V->dc_id = fetch_int (); + V->access_hash = fetch_long (mtp); + V->user_id = fetch_int (mtp); + V->date = fetch_int (mtp); + V->caption = fetch_str_dup (mtp); + V->mime_type = fetch_str_dup (mtp); + V->size = fetch_int (mtp); + fetch_photo_size (mtp, &V->thumb); + V->dc_id = fetch_int (mtp); } -void fetch_skip_document (void) { - unsigned x = fetch_int (); - fetch_skip (2); +void fetch_skip_document (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); + fetch_skip (mtp, 2); if (x == CODE_document_empty) { return; } - fetch_skip (4); - int l = prefetch_strlen (); - fetch_str (l); - l = prefetch_strlen (); - fetch_str (l); - fetch_skip (1); - fetch_skip_photo_size (); - fetch_skip (1); + fetch_skip (mtp, 4); + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); + fetch_skip (mtp, 1); + fetch_skip_photo_size (mtp); + fetch_skip (mtp, 1); } -void fetch_message_action (struct message_action *M) { +void fetch_message_action (struct mtproto_connection *mtp, struct message_action *M) { memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (); + unsigned x = fetch_int (mtp); M->type = x; 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); + int l = prefetch_strlen (mtp); // title + char *s = fetch_str (mtp, l); + int l2 = prefetch_strlen (mtp); // checkin + char *s2 = fetch_str (mtp, 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); - M->user_num = fetch_int (); + M->title = fetch_str_dup (mtp); + assert (fetch_int (mtp) == (int)CODE_vector); + M->user_num = fetch_int (mtp); M->users = talloc (M->user_num * 4); - fetch_ints (M->users, M->user_num); + fetch_ints (mtp, M->users, M->user_num); break; case CODE_message_action_chat_edit_title: - M->new_title = fetch_str_dup (); + M->new_title = fetch_str_dup (mtp); break; case CODE_message_action_chat_edit_photo: - fetch_photo (&M->photo); + fetch_photo (mtp, &M->photo); break; case CODE_message_action_chat_delete_photo: break; case CODE_message_action_chat_add_user: - M->user = fetch_int (); + M->user = fetch_int (mtp); break; case CODE_message_action_chat_delete_user: - M->user = fetch_int (); + M->user = fetch_int (mtp); break; default: assert (0); } } -void fetch_skip_message_action (void) { - unsigned x = fetch_int (); +void fetch_skip_message_action (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); int l; switch (x) { case CODE_message_action_empty: break; case CODE_message_action_geo_chat_create: { - l = prefetch_strlen (); - fetch_str (l); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); } break; case CODE_message_action_geo_chat_checkin: break; case CODE_message_action_chat_create: - l = prefetch_strlen (); - fetch_str (l); - assert (fetch_int () == (int)CODE_vector); - l = fetch_int (); - fetch_skip (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); + assert (fetch_int (mtp) == (int)CODE_vector); + l = fetch_int (mtp); + fetch_skip (mtp, l); break; case CODE_message_action_chat_edit_title: - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); break; case CODE_message_action_chat_edit_photo: - fetch_skip_photo (); + fetch_skip_photo (mtp); break; case CODE_message_action_chat_delete_photo: break; case CODE_message_action_chat_add_user: - fetch_int (); + fetch_int (mtp); break; case CODE_message_action_chat_delete_user: - fetch_int (); + fetch_int (mtp); break; default: assert (0); } } -void fetch_message_short (struct message *M) { +void fetch_message_short (struct mtproto_connection *mtp, struct message *M) { int new = !(M->flags & FLAG_CREATED); if (new) { - int id = fetch_int (); - int from_id = fetch_int (); + int id = fetch_int (mtp); + int from_id = fetch_int (mtp); int to_id = our_id; - int l = prefetch_strlen (); - char *s = fetch_str (l); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); - fetch_pts (); + fetch_pts (mtp); - int date = fetch_int (); - fetch_seq (); + int date = fetch_int (mtp); + fetch_seq (mtp); - bl_do_create_message_text (id, from_id, PEER_USER, to_id, date, l, s); + bl_do_create_message_text (mtp, id, from_id, PEER_USER, to_id, date, l, s); } else { - fetch_int (); // id - fetch_int (); // from_id - int l = prefetch_strlen (); - fetch_str (l); // text + fetch_int (mtp); // id + fetch_int (mtp); // from_id + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); // text - fetch_pts (); - fetch_int (); - fetch_seq (); + fetch_pts (mtp); + fetch_int (mtp); + fetch_seq (mtp); } } -void fetch_message_short_chat (struct message *M) { +void fetch_message_short_chat (struct mtproto_connection *mtp, struct message *M) { int new = !(M->flags & FLAG_CREATED); if (new) { - int id = fetch_int (); - int from_id = fetch_int (); - int to_id = fetch_int (); - int l = prefetch_strlen (); - char *s = fetch_str (l); + int id = fetch_int (mtp); + int from_id = fetch_int (mtp); + int to_id = fetch_int (mtp); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); - fetch_pts (); + fetch_pts (mtp); - int date = fetch_int (); - fetch_seq (); + int date = fetch_int (mtp); + fetch_seq (mtp); - bl_do_create_message_text (id, from_id, PEER_CHAT, to_id, date, l, s); + bl_do_create_message_text (mtp, id, from_id, PEER_CHAT, to_id, date, l, s); } else { - fetch_int (); // id - fetch_int (); // from_id - fetch_int (); // to_id - int l = prefetch_strlen (); - fetch_str (l); // text + fetch_int (mtp); // id + fetch_int (mtp); // from_id + fetch_int (mtp); // to_id + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); // text - fetch_pts (); - fetch_int (); - fetch_seq (); + fetch_pts (mtp); + fetch_int (mtp); + fetch_seq (mtp); } } -void fetch_message_media (struct message_media *M) { +void fetch_message_media (struct mtproto_connection *mtp, struct message_media *M) { memset (M, 0, sizeof (*M)); - M->type = fetch_int (); + M->type = fetch_int (mtp); switch (M->type) { case CODE_message_media_empty: break; case CODE_message_media_photo: - fetch_photo (&M->photo); + fetch_photo (mtp, &M->photo); break; case CODE_message_media_video: - fetch_video (&M->video); + fetch_video (mtp, &M->video); break; case CODE_message_media_audio: - fetch_audio (&M->audio); + fetch_audio (mtp, &M->audio); break; case CODE_message_media_document: - fetch_document (&M->document); + fetch_document (mtp, &M->document); break; case CODE_message_media_geo: - fetch_geo (&M->geo); + fetch_geo (mtp, &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 (); + M->phone = fetch_str_dup (mtp); + M->first_name = fetch_str_dup (mtp); + M->last_name = fetch_str_dup (mtp); + M->user_id = fetch_int (mtp); break; case CODE_message_media_unsupported: - M->data_size = prefetch_strlen (); + M->data_size = prefetch_strlen (mtp); M->data = talloc (M->data_size); - memcpy (M->data, fetch_str (M->data_size), M->data_size); + memcpy (M->data, fetch_str (mtp, M->data_size), M->data_size); break; default: logprintf ("type = 0x%08x\n", M->type); @@ -969,42 +970,42 @@ void fetch_message_media (struct message_media *M) { } } -void fetch_skip_message_media (void) { - unsigned x = fetch_int (); +void fetch_skip_message_media (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); switch (x) { case CODE_message_media_empty: break; case CODE_message_media_photo: - fetch_skip_photo (); + fetch_skip_photo (mtp); break; case CODE_message_media_video: - fetch_skip_video (); + fetch_skip_video (mtp); break; case CODE_message_media_audio: - fetch_skip_audio (); + fetch_skip_audio (mtp); break; case CODE_message_media_document: - fetch_skip_document (); + fetch_skip_document (mtp); break; case CODE_message_media_geo: - fetch_skip_geo (); + fetch_skip_geo (mtp); break; case CODE_message_media_contact: { int l; - l = prefetch_strlen (); - fetch_str (l); - l = prefetch_strlen (); - fetch_str (l); - l = prefetch_strlen (); - fetch_str (l); - fetch_int (); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); + fetch_int (mtp); } break; case CODE_message_media_unsupported: { - int l = prefetch_strlen (); - fetch_str (l); + int l = prefetch_strlen (mtp); + fetch_str (mtp, l); } break; default: @@ -1013,73 +1014,73 @@ void fetch_skip_message_media (void) { } } -void fetch_skip_message_media_encrypted (void) { - unsigned x = fetch_int (); +void fetch_skip_message_media_encrypted (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); int l; switch (x) { case CODE_decrypted_message_media_empty: break; case CODE_decrypted_message_media_photo: - l = prefetch_strlen (); - fetch_str (l); // thumb - fetch_skip (5); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + fetch_skip (mtp, 5); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); break; case CODE_decrypted_message_media_video: - l = prefetch_strlen (); - fetch_str (l); // thumb + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb - fetch_skip (6); + fetch_skip (mtp, 6); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); break; case CODE_decrypted_message_media_audio: - fetch_skip (2); + fetch_skip (mtp, 2); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); break; case CODE_decrypted_message_media_document: - l = prefetch_strlen (); - fetch_str (l); // thumb + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb - fetch_skip (2); + fetch_skip (mtp, 2); - l = prefetch_strlen (); - fetch_str (l); // thumb - l = prefetch_strlen (); - fetch_str (l); // thumb - fetch_skip (1); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + fetch_skip (mtp, 1); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); - l = prefetch_strlen (); - fetch_str (l); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); break; case CODE_decrypted_message_media_geo_point: - fetch_skip (4); + fetch_skip (mtp, 4); break; case CODE_decrypted_message_media_contact: - l = prefetch_strlen (); - fetch_str (l); // thumb - l = prefetch_strlen (); - fetch_str (l); // thumb - l = prefetch_strlen (); - fetch_str (l); // thumb - fetch_skip (1); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + fetch_skip (mtp, 1); break; default: logprintf ("type = 0x%08x\n", x); @@ -1087,9 +1088,9 @@ void fetch_skip_message_media_encrypted (void) { } } -void fetch_message_media_encrypted (struct message_media *M) { +void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct message_media *M) { memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (); + unsigned x = fetch_int (mtp); int l; switch (x) { case CODE_decrypted_message_media_empty: @@ -1097,138 +1098,138 @@ void fetch_message_media_encrypted (struct message_media *M) { break; case CODE_decrypted_message_media_photo: M->type = x; - l = prefetch_strlen (); - fetch_str (l); // thumb - fetch_int (); // thumb_w - fetch_int (); // thumb_h - M->encr_photo.w = fetch_int (); - M->encr_photo.h = fetch_int (); - M->encr_photo.size = fetch_int (); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + fetch_int (mtp); // thumb_w + fetch_int (mtp); // thumb_h + M->encr_photo.w = fetch_int (mtp); + M->encr_photo.h = fetch_int (mtp); + M->encr_photo.size = fetch_int (mtp); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); M->encr_photo.key = talloc (32); memset (M->encr_photo.key, 0, 32); if (l <= 32) { - memcpy (M->encr_photo.key + (32 - l), fetch_str (l), l); + memcpy (M->encr_photo.key + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_photo.key, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_photo.key, fetch_str (mtp, l) + (l - 32), 32); } M->encr_photo.iv = talloc (32); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); memset (M->encr_photo.iv, 0, 32); if (l <= 32) { - memcpy (M->encr_photo.iv + (32 - l), fetch_str (l), l); + memcpy (M->encr_photo.iv + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_photo.iv, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_photo.iv, fetch_str (mtp, l) + (l - 32), 32); } break; case CODE_decrypted_message_media_video: M->type = x; - l = prefetch_strlen (); - fetch_str (l); // thumb - fetch_int (); // thumb_w - fetch_int (); // thumb_h - M->encr_video.duration = fetch_int (); - M->encr_video.w = fetch_int (); - M->encr_video.h = fetch_int (); - M->encr_video.size = fetch_int (); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + fetch_int (mtp); // thumb_w + fetch_int (mtp); // thumb_h + M->encr_video.duration = fetch_int (mtp); + M->encr_video.w = fetch_int (mtp); + M->encr_video.h = fetch_int (mtp); + M->encr_video.size = fetch_int (mtp); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); M->encr_video.key = talloc0 (32); if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); } M->encr_video.iv = talloc (32); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); memset (M->encr_video.iv, 0, 32); if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); } break; case CODE_decrypted_message_media_audio: M->type = x; - M->encr_audio.duration = fetch_int (); - M->encr_audio.size = fetch_int (); + M->encr_audio.duration = fetch_int (mtp); + M->encr_audio.size = fetch_int (mtp); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); M->encr_video.key = talloc0 (32); if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); } M->encr_video.iv = talloc0 (32); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); } break; case CODE_decrypted_message_media_document: M->type = x; - l = prefetch_strlen (); - fetch_str (l); // thumb - fetch_int (); // thumb_w - fetch_int (); // thumb_h - M->encr_document.file_name = fetch_str_dup (); - M->encr_document.mime_type = fetch_str_dup (); - M->encr_video.size = fetch_int (); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + fetch_int (mtp); // thumb_w + fetch_int (mtp); // thumb_h + M->encr_document.file_name = fetch_str_dup (mtp); + M->encr_document.mime_type = fetch_str_dup (mtp); + M->encr_video.size = fetch_int (mtp); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); M->encr_video.key = talloc0 (32); if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); } M->encr_video.iv = talloc0 (32); - l = prefetch_strlen (); + l = prefetch_strlen (mtp); assert (l > 0); if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); } else { - memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); } break; /* case CODE_decrypted_message_media_file: M->type = x; - M->encr_file.filename = fetch_str_dup (); - l = prefetch_strlen (); - fetch_str (l); // thumb - l = fetch_int (); + M->encr_file.filename = fetch_str_dup (mtp); + l = prefetch_strlen (mtp); + fetch_str (mtp, l); // thumb + l = fetch_int (mtp); assert (l > 0); M->encr_file.key = talloc (l); - memcpy (M->encr_file.key, fetch_str (l), l); + memcpy (M->encr_file.key, fetch_str (mtp, l), l); - l = fetch_int (); + l = fetch_int (mtp); assert (l > 0); M->encr_file.iv = talloc (l); - memcpy (M->encr_file.iv, fetch_str (l), l); + memcpy (M->encr_file.iv, fetch_str (mtp, l), l); break; */ case CODE_decrypted_message_media_geo_point: - M->geo.longitude = fetch_double (); - M->geo.latitude = fetch_double (); + M->geo.longitude = fetch_double (mtp); + M->geo.latitude = fetch_double (mtp); M->type = CODE_message_media_geo; break; case CODE_decrypted_message_media_contact: M->type = 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 (); + M->phone = fetch_str_dup (mtp); + M->first_name = fetch_str_dup (mtp); + M->last_name = fetch_str_dup (mtp); + M->user_id = fetch_int (mtp); break; default: logprintf ("type = 0x%08x\n", x); @@ -1236,11 +1237,11 @@ void fetch_message_media_encrypted (struct message_media *M) { } } -void fetch_skip_message_action_encrypted (void) { - unsigned x = fetch_int (); +void fetch_skip_message_action_encrypted (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); switch (x) { case CODE_decrypted_message_action_set_message_t_t_l: - fetch_skip (1); + fetch_skip (mtp, 1); break; default: logprintf ("x = 0x%08x\n", x); @@ -1248,12 +1249,12 @@ void fetch_skip_message_action_encrypted (void) { } } -void fetch_message_action_encrypted (struct message_action *M) { - unsigned x = fetch_int (); +void fetch_message_action_encrypted (struct mtproto_connection *mtp, struct message_action *M) { + unsigned x = fetch_int (mtp); switch (x) { case CODE_decrypted_message_action_set_message_t_t_l: M->type = x; - M->ttl = fetch_int (); + M->ttl = fetch_int (mtp); break; default: logprintf ("x = 0x%08x\n", x); @@ -1261,20 +1262,20 @@ void fetch_message_action_encrypted (struct message_action *M) { } } -peer_id_t fetch_peer_id (void) { - unsigned x =fetch_int (); +peer_id_t fetch_peer_id (struct mtproto_connection *mtp) { + unsigned x =fetch_int (mtp); if (x == CODE_peer_user) { - return MK_USER (fetch_int ()); + return MK_USER (fetch_int (mtp)); } else { assert (CODE_peer_chat); - return MK_CHAT (fetch_int ()); + return MK_CHAT (fetch_int (mtp)); } } -void fetch_message (struct message *M) { - unsigned x = fetch_int (); +void fetch_message (struct mtproto_connection *mtp, struct message *M) { + unsigned x = fetch_int (mtp); assert (x == CODE_message_empty || x == CODE_message || x == CODE_message_forwarded || x == CODE_message_service); - int id = fetch_int (); + int id = fetch_int (mtp); assert (M->id == id); if (x == CODE_message_empty) { return; @@ -1283,64 +1284,68 @@ void fetch_message (struct message *M) { int fwd_date = 0; if (x == CODE_message_forwarded) { - fwd_from_id = fetch_int (); - fwd_date = fetch_int (); + fwd_from_id = fetch_int (mtp); + fwd_date = fetch_int (mtp); } - int from_id = fetch_int (); - peer_id_t to_id = fetch_peer_id (); + int from_id = fetch_int (mtp); + peer_id_t to_id = fetch_peer_id (mtp); - fetch_bool (); // out. + fetch_bool (mtp); // out. - int unread = fetch_bool (); - int date = fetch_int (); + int unread = fetch_bool (mtp); + int date = fetch_int (mtp); int new = !(M->flags & FLAG_CREATED); if (x == CODE_message_service) { - int *start = in_ptr; - fetch_skip_message_action (); + int *start = mtp->in_ptr; + fetch_skip_message_action (mtp); if (new) { if (fwd_from_id) { - bl_do_create_message_service_fwd (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, fwd_from_id, fwd_date, start, (in_ptr - start)); + bl_do_create_message_service_fwd (mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), + date, fwd_from_id, fwd_date, start, (mtp->in_ptr - start)); } else { - bl_do_create_message_service (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, start, (in_ptr - start)); + bl_do_create_message_service (mtp, id, from_id, get_peer_type (to_id), + get_peer_id (to_id), date, start, (mtp->in_ptr - start)); } } } else { - int l = prefetch_strlen (); - char *s = fetch_str (l); - int *start = in_ptr; - fetch_skip_message_media (); + int l = prefetch_strlen (mtp); + char *s = fetch_str (mtp, l); + int *start = mtp->in_ptr; + fetch_skip_message_media (mtp); if (new) { if (fwd_from_id) { - bl_do_create_message_media_fwd (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, fwd_from_id, fwd_date, l, s, start, in_ptr - start); + bl_do_create_message_media_fwd (mtp, id, from_id, get_peer_type (to_id), + get_peer_id (to_id), date, fwd_from_id, fwd_date, l, s, start, mtp->in_ptr - start); } else { - bl_do_create_message_media (id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, l, s, start, in_ptr - start); + bl_do_create_message_media (mtp, id, from_id, get_peer_type (to_id), + get_peer_id (to_id), date, l, s, start, mtp->in_ptr - start); } } } - bl_do_set_unread (M, unread); + bl_do_set_unread (mtp, M, unread); } -void fetch_geo_message (struct message *M) { +void fetch_geo_message (struct mtproto_connection *mtp, struct message *M) { memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (); + unsigned x = fetch_int (mtp); assert (x == CODE_geo_chat_message_empty || x == CODE_geo_chat_message || x == CODE_geo_chat_message_service); - M->to_id = MK_GEO_CHAT (fetch_int ()); - M->id = fetch_int (); + M->to_id = MK_GEO_CHAT (fetch_int (mtp)); + M->id = fetch_int (mtp); if (x == CODE_geo_chat_message_empty) { M->flags |= 1; return; } - M->from_id = MK_USER (fetch_int ()); - M->date = fetch_int (); + M->from_id = MK_USER (fetch_int (mtp)); + M->date = fetch_int (mtp); if (x == CODE_geo_chat_message_service) { M->service = 1; - fetch_message_action (&M->action); + fetch_message_action (mtp, &M->action); } else { - M->message = fetch_str_dup (); + M->message = fetch_str_dup (mtp); M->message_len = strlen (M->message); - fetch_message_media (&M->media); + fetch_message_media (mtp, &M->media); } } @@ -1404,15 +1409,15 @@ int decrypt_encrypted_message (struct secret_chat *E) { return 0; } -void fetch_encrypted_message (struct message *M) { - unsigned x = fetch_int (); +void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) { + unsigned x = fetch_int (mtp); assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service); unsigned sx = x; int new = !(M->flags & FLAG_CREATED); - long long id = fetch_long (); - int to_id = fetch_int (); + long long id = fetch_long (mtp); + int to_id = fetch_int (mtp); peer_id_t chat = MK_ENCR_CHAT (to_id); - int date = fetch_int (); + int date = fetch_int (mtp); peer_t *P = user_chat_get (chat); if (!P) { @@ -1421,9 +1426,9 @@ void fetch_encrypted_message (struct message *M) { } - int len = prefetch_strlen (); + int len = prefetch_strlen (mtp); assert ((len & 15) == 8); - decr_ptr = (void *)fetch_str (len); + decr_ptr = (void *)fetch_str (mtp, len); decr_end = decr_ptr + (len / 4); int ok = 0; if (P) { @@ -1440,48 +1445,48 @@ void fetch_encrypted_message (struct message *M) { x = 0; if (P && decrypt_encrypted_message (&P->encr_chat) >= 0 && new) { ok = 1; - int *save_in_ptr = in_ptr; - int *save_in_end = in_end; - in_ptr = decr_ptr; - int ll = fetch_int (); - in_end = in_ptr + ll; - x = fetch_int (); + int *save_in_ptr = mtp->in_ptr; + int *save_in_end = mtp->in_end; + mtp->in_ptr = decr_ptr; + int ll = fetch_int (mtp); + mtp->in_end = mtp->in_ptr + ll; + x = fetch_int (mtp); if (x == CODE_decrypted_message_layer) { - int layer = fetch_int (); + int layer = fetch_int (mtp); assert (layer >= 0); - x = fetch_int (); + x = fetch_int (mtp); } assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service); - //assert (id == fetch_long ()); - fetch_long (); - ll = prefetch_strlen (); - fetch_str (ll); // random_bytes + //assert (id == fetch_long (mtp)); + fetch_long (mtp); + ll = prefetch_strlen (mtp); + fetch_str (mtp, ll); // random_bytes if (x == CODE_decrypted_message) { - l = prefetch_strlen (); - s = fetch_str (l); - start = in_ptr; - fetch_skip_message_media_encrypted (); - end = in_ptr; + l = prefetch_strlen (mtp); + s = fetch_str (mtp, l); + start = mtp->in_ptr; + fetch_skip_message_media_encrypted (mtp); + end = mtp->in_ptr; } else { - start = in_ptr; - fetch_skip_message_action_encrypted (); - end = in_ptr; + start = mtp->in_ptr; + fetch_skip_message_action_encrypted (mtp); + end = mtp->in_ptr; } - in_ptr = save_in_ptr; - in_end = save_in_end; + mtp->in_ptr = save_in_ptr; + mtp->in_end = save_in_end; } if (sx == CODE_encrypted_message) { if (ok) { - int *start_file = in_ptr; - fetch_skip_encrypted_message_file (); + int *start_file = mtp->in_ptr; + fetch_skip_encrypted_message_file (mtp); if (x == CODE_decrypted_message) { - bl_do_create_message_media_encr (id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, in_ptr - start_file); + bl_do_create_message_media_encr (mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, mtp->in_ptr - start_file); } } else { - x = fetch_int (); + x = fetch_int (mtp); if (x == CODE_encrypted_file) { - fetch_skip (7); + fetch_skip (mtp, 7); } else { assert (x == CODE_encrypted_file_empty); } @@ -1489,37 +1494,37 @@ void fetch_encrypted_message (struct message *M) { } } else { if (ok && x == CODE_decrypted_message_service) { - bl_do_create_message_service_encr (id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, start, end - start); + bl_do_create_message_service_encr (mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, start, end - start); } } } -void fetch_encrypted_message_file (struct message_media *M) { - unsigned x = fetch_int (); +void fetch_encrypted_message_file (struct mtproto_connection *mtp, struct message_media *M) { + unsigned x = fetch_int (mtp); assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); if (x == CODE_encrypted_file_empty) { assert (M->type != CODE_decrypted_message_media_photo && M->type != CODE_decrypted_message_media_video); } else { assert (M->type == CODE_decrypted_message_media_document || M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video || M->type == CODE_decrypted_message_media_audio); - M->encr_photo.id = fetch_long(); - M->encr_photo.access_hash = fetch_long(); + M->encr_photo.id = fetch_long(mtp); + M->encr_photo.access_hash = fetch_long(mtp); if (!M->encr_photo.size) { - M->encr_photo.size = fetch_int (); + M->encr_photo.size = fetch_int (mtp); } else { - fetch_int (); + fetch_int (mtp); } - M->encr_photo.dc_id = fetch_int(); - M->encr_photo.key_fingerprint = fetch_int(); + M->encr_photo.dc_id = fetch_int(mtp); + M->encr_photo.key_fingerprint = fetch_int(mtp); } } -void fetch_skip_encrypted_message_file (void) { - unsigned x = fetch_int (); +void fetch_skip_encrypted_message_file (struct mtproto_connection *mtp) { + unsigned x = fetch_int (mtp); assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); if (x == CODE_encrypted_file_empty) { } else { - fetch_skip (7); + fetch_skip (mtp, 7); } } @@ -1529,11 +1534,11 @@ static int id_cmp (struct message *M1, struct message *M2) { else { return 0; } } -struct user *fetch_alloc_user (void) { +struct user *fetch_alloc_user (struct mtproto_connection *mtp) { logprintf("fetch_alloc_user()\n"); int send_event = 0; int data[2]; - prefetch_data (data, 8); + prefetch_data (mtp, data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); if (!U) { send_event = 1; @@ -1544,17 +1549,17 @@ struct user *fetch_alloc_user (void) { assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; } - fetch_user (&U->user); + fetch_user (mtp, &U->user); if (send_event) { event_peer_allocated(U); } return &U->user; } -struct secret_chat *fetch_alloc_encrypted_chat (void) { +struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp) { logprintf("fetch_alloc_encrypted_chat()\n"); int data[2]; - prefetch_data (data, 8); + prefetch_data (mtp, data, 8); peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); if (!U) { U = talloc0 (sizeof (*U)); @@ -1564,7 +1569,7 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) { assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; } - fetch_encrypted_chat (&U->encr_chat); + fetch_encrypted_chat (mtp, &U->encr_chat); event_peer_allocated(U); return &U->encr_chat; } @@ -1590,19 +1595,19 @@ void insert_chat (peer_t *P) { Peers[peer_num ++] = P; } -struct user *fetch_alloc_user_full (void) { +struct user *fetch_alloc_user_full (struct mtproto_connection *mtp) { int data[3]; - prefetch_data (data, 12); + prefetch_data (mtp, data, 12); peer_t *U = user_chat_get (MK_USER (data[2])); if (U) { - fetch_user_full (&U->user); + fetch_user_full (mtp, &U->user); return &U->user; } else { users_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_USER (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - fetch_user_full (&U->user); + fetch_user_full (mtp, &U->user); assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; return &U->user; @@ -1811,10 +1816,10 @@ void message_del_peer (struct message *M) { } } -struct message *fetch_alloc_message (struct telegram *instance) { +struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct telegram *instance) { logprintf("fetch_alloc_message()\n"); int data[2]; - prefetch_data (data, 8); + prefetch_data (mtp, data, 8); struct message *M = message_get (data[1]); M->instance = instance; @@ -1824,15 +1829,15 @@ struct message *fetch_alloc_message (struct telegram *instance) { message_insert_tree (M); messages_allocated ++; } - fetch_message (M); + fetch_message (mtp, M); return M; } -struct message *fetch_alloc_geo_message (struct telegram *instance) { +struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct telegram *instance) { logprintf("fetch_alloc_geo_message()\n"); struct message *M = talloc (sizeof (*M)); M->instance = instance; - fetch_geo_message (M); + fetch_geo_message (mtp, M); struct message *M1 = tree_lookup_message (message_tree, M); messages_allocated ++; if (M1) { @@ -1853,10 +1858,11 @@ struct message *fetch_alloc_geo_message (struct telegram *instance) { } } -struct message *fetch_alloc_encrypted_message (struct telegram *instance) { +struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, + struct telegram *instance) { logprintf("fetch_alloc_encrypted_message()\n"); int data[3]; - prefetch_data (data, 12); + prefetch_data (mtp, data, 12); struct message *M = message_get (*(long long *)(data + 1)); M->instance = instance; @@ -1868,13 +1874,14 @@ struct message *fetch_alloc_encrypted_message (struct telegram *instance) { assert (message_get (M->id) == M); logprintf ("id = %lld\n", M->id); } - fetch_encrypted_message (M); + fetch_encrypted_message (mtp, M); return M; } -struct message *fetch_alloc_message_short (struct telegram *instance) { +struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, + struct telegram *instance) { int data[1]; - prefetch_data (data, 4); + prefetch_data (mtp, data, 4); struct message *M = message_get (data[0]); M->instance = instance; @@ -1884,13 +1891,13 @@ struct message *fetch_alloc_message_short (struct telegram *instance) { message_insert_tree (M); messages_allocated ++; } - fetch_message_short (M); + fetch_message_short (mtp, M); return M; } -struct message *fetch_alloc_message_short_chat (struct telegram *instance) { +struct message *fetch_alloc_message_short_chat (struct mtproto_connection *mtp, struct telegram *instance) { int data[1]; - prefetch_data (data, 4); + prefetch_data (mtp, data, 4); struct message *M = message_get (data[0]); M->instance = instance; @@ -1900,14 +1907,14 @@ struct message *fetch_alloc_message_short_chat (struct telegram *instance) { message_insert_tree (M); messages_allocated ++; } - fetch_message_short_chat (M); + fetch_message_short_chat (mtp, M); return M; } -struct chat *fetch_alloc_chat (void) { +struct chat *fetch_alloc_chat (struct mtproto_connection *mtp) { logprintf("fetch_alloc_chat()\n"); int data[2]; - prefetch_data (data, 8); + prefetch_data (mtp, data, 8); peer_t *U = user_chat_get (MK_CHAT (data[1])); logprintf("id %d\n", U->id.id); logprintf("type %d\n", U->id.type); @@ -1919,24 +1926,24 @@ struct chat *fetch_alloc_chat (void) { assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; } - fetch_chat (&U->chat); + fetch_chat (mtp, &U->chat); event_peer_allocated(U); return &U->chat; } -struct chat *fetch_alloc_chat_full (void) { +struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp) { int data[3]; - prefetch_data (data, 12); + prefetch_data (mtp, data, 12); peer_t *U = user_chat_get (MK_CHAT (data[2])); if (U) { - fetch_chat_full (&U->chat); + fetch_chat_full (mtp, &U->chat); return &U->chat; } else { chats_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[2]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - fetch_chat_full (&U->chat); + fetch_chat_full (mtp, &U->chat); assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; return &U->chat; diff --git a/structures.h b/structures.h index e9b9c59..616f417 100644 --- a/structures.h +++ b/structures.h @@ -18,9 +18,13 @@ */ #ifndef __STRUCTURES_H__ #define __STRUCTURES_H__ +#pragma once + +// forward-declrataions +struct mtproto_connection; +typedef struct { int type; int id; } peer_id_t; #include -typedef struct { int type; int id; } peer_id_t; //#define FLAG_EMPTY 1 #define FLAG_MESSAGE_EMPTY 1 @@ -329,28 +333,27 @@ struct message { }; }; -int fetch_file_location (struct file_location *loc); -int fetch_user_status (struct user_status *S); -int fetch_user (struct user *U); -struct user *fetch_alloc_user (void); -struct user *fetch_alloc_user_full (void); -struct chat *fetch_alloc_chat (void); -struct chat *fetch_alloc_chat_full (void); -struct secret_chat *fetch_alloc_encrypted_chat (void); -struct message *fetch_alloc_message (struct telegram *instance); -struct message *fetch_alloc_geo_message (struct telegram *instance); -struct message *fetch_alloc_message_short (struct telegram *instance); -struct message *fetch_alloc_message_short_chat (struct telegram *instance); -struct message *fetch_alloc_encrypted_message (struct telegram *instance); -void fetch_encrypted_message_file (struct message_media *M); -void fetch_skip_encrypted_message_file (void); -void fetch_encrypted_message_file (struct message_media *M); -void fetch_message_action_encrypted (struct message_action *M); -peer_id_t fetch_peer_id (void); +int fetch_file_location (struct mtproto_connection *mtp, struct file_location *loc); +int fetch_user_status (struct mtproto_connection *mtp, struct user_status *S); +int fetch_user (struct mtproto_connection *mtp, struct user *U); +struct user *fetch_alloc_user (struct mtproto_connection *mtp); +struct user *fetch_alloc_user_full (struct mtproto_connection *mtp); +struct chat *fetch_alloc_chat (struct mtproto_connection *mtp); +struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp); +struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp); +struct message *fetch_alloc_message (struct mtproto_connection *self, struct telegram *instance); +struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct telegram *instance); +struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, struct telegram *instance); +struct message *fetch_alloc_message_short_chat (struct mtproto_connection *self, struct telegram *instance); +struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, struct telegram *instance); +void fetch_encrypted_message_file (struct mtproto_connection *mtp, struct message_media *M); +void fetch_skip_encrypted_message_file (struct mtproto_connection *mtp); +void fetch_message_action_encrypted (struct mtproto_connection *mtp, struct message_action *M); +peer_id_t fetch_peer_id (struct mtproto_connection *mtp); -void fetch_message_media (struct message_media *M); -void fetch_message_media_encrypted (struct message_media *M); -void fetch_message_action (struct message_action *M); +void fetch_message_media (struct mtproto_connection *mtp, struct message_media *M); +void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct message_media *M); +void fetch_message_action (struct mtproto_connection *mtp, struct message_action *M); void message_insert_tree (struct message *M); void free_user (struct user *U); @@ -363,12 +366,10 @@ peer_t *user_chat_get (peer_id_t id); struct message *message_get (long long id); void update_message_id (struct message *M, long long id); void message_insert (struct message *M); -void free_photo (struct photo *P); -void fetch_photo (struct photo *P); +void fetch_photo (struct mtproto_connection *mtp, 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); void message_insert_unsent (struct message *M); void message_remove_unsent (struct message *M); diff --git a/telegram.c b/telegram.c index ba51d03..f275b13 100755 --- a/telegram.c +++ b/telegram.c @@ -6,7 +6,6 @@ #include #include -#include "mtproto-common.h" #include "telegram.h" #include "msglog.h" #include "glib.h" @@ -31,12 +30,12 @@ void event_update_new_message(struct message *M) /* * Peer allocated */ -void (*on_peer_allocated_handler)(peer_t *peer); -void on_peer_allocated(void (*handler)(peer_t *peer)) +void (*on_peer_allocated_handler)(void *peer); +void on_peer_allocated(void (*handler)(void *peer)) { on_peer_allocated_handler = handler; } -void event_peer_allocated(peer_t *peer) +void event_peer_allocated(void *peer) { if (on_peer_allocated_handler) { on_peer_allocated_handler(peer); @@ -63,10 +62,9 @@ void telegram_change_state(struct telegram *instance, int state, void *data) struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path) { - on_start (); struct telegram *this = malloc(sizeof(struct telegram)); this->protocol_data = NULL; - this->curr_dc = 0; + //this->curr_dc = 0; this->auth.DC_list[0] = DC; this->change_state_listeners = NULL; @@ -173,6 +171,7 @@ char *telegram_get_config(struct telegram *instance, char *config) return g_strdup_printf("%s/%s", instance->config_path, config); } +void on_connected(struct mtproto_connection *c, void* data); void telegram_network_connect(struct telegram *instance, int fd) { logprintf("telegram_network_connect()\n"); @@ -181,29 +180,16 @@ void telegram_network_connect(struct telegram *instance, int fd) assert(0); } struct dc *DC_working = telegram_get_working_dc(instance); - - // check whether authentication is needed - if (!DC_working->auth_key_id) { - logprintf("No working DC, authenticating.\n"); - - // init a new connection - struct connection *c = create_connection (DC_working->ip, DC_working->port, fd, instance); - // init a new session with random session id - dc_create_session(DC_working, c); - - // Request PQ - send_req_pq_packet (c); - telegram_change_state(instance, STATE_PQ_REQUESTED, NULL); - } else { - logprintf("Already working session, setting state to connected.\n"); - telegram_change_state(instance, STATE_CONNECTED, NULL); - } + instance->connection = mtproto_new(DC_working, fd, instance); + instance->connection->on_ready = on_connected; + instance->connection->on_ready_data = instance; + mtproto_connect(instance->connection); } -void on_connected(struct telegram *instance) +void on_connected(struct mtproto_connection *c, void *data) { - assert (telegram_get_working_dc(instance)->auth_key_id); - logprintf("Done...\n"); + struct telegram *instance = data; + logprintf("Authorized... storing current session.\n"); telegram_store_session(instance); } @@ -211,7 +197,6 @@ void on_state_change(struct telegram *instance, int state, void *data) { switch (state) { case STATE_CONNECTED: - on_connected(instance); break; case STATE_ERROR: { @@ -233,47 +218,18 @@ void on_state_change(struct telegram *instance, int state, void *data) } } - -/** - * Read newest rpc response and update state - */ -void try_rpc_interpret(struct telegram *instance, int op, int len) -{ - switch (instance->session_state) { - case STATE_PQ_REQUESTED: - logprintf("switch: pq_requested\n"); - rpc_execute_req_pq(instance, len); - telegram_change_state(instance, STATE_DH_REQUESTED, NULL); - break; - case STATE_DH_REQUESTED: - logprintf("switch: dh_requested\n"); - rpc_execute_rq_dh(instance, len); - telegram_change_state(instance, STATE_CDH_REQUESTED, NULL); - break; - case STATE_CDH_REQUESTED: - logprintf("switch: cdh_requested\n"); - rpc_execute_cdh_sent(instance, len); - telegram_change_state(instance, STATE_AUTH_DONE, NULL); - break; - case STATE_AUTH_DONE: - logprintf("switch: auth_done\n"); - rpc_execute_authorized(instance, op, len); - break; - } -} - void telegram_read_input (struct telegram *instance) { - return try_read(instance); + return try_read(instance->connection->connection); } int telegram_write_output (struct telegram *instance) { - return try_write(instance); + return try_write(instance->connection->connection); } int telegram_has_output (struct telegram *instance) { - return !all_queries_done(); + return instance->connection->queries_num > 0; } diff --git a/telegram.h b/telegram.h index e5cda6a..9b4d6e2 100644 --- a/telegram.h +++ b/telegram.h @@ -5,7 +5,9 @@ * struct telegram library based on the telegram cli application, that was originally made by vysheng (see https://github.com/vysheng/tg) */ -#pragma once +#ifndef __TELEGRAM_H__ +#define __TELEGRAM_H__ + #define MAX_DC_NUM 9 #define MAX_PEER_NUM 100000 @@ -14,12 +16,14 @@ #endif #include -#include "net.h" -#include "mtproto-common.h" -#include "structures.h" #include "glib.h" #include "loop.h" +//#include "mtproto-client.h" +// forward declarations +struct message; +struct protocol_state; +struct authorization_state; /* * Libtelegram states @@ -69,7 +73,7 @@ */ struct telegram { void *protocol_data; - int curr_dc; + //int curr_dc; char *login; char *config_path; @@ -81,7 +85,7 @@ struct telegram { int session_state; /* - * MtProto state + * protocol state */ struct protocol_state proto; struct authorization_state auth; @@ -89,7 +93,12 @@ struct telegram { GList *change_state_listeners; /* - * Callbacks + * connection + */ + struct mtproto_connection *connection; + + /* + * callbacks */ void (*on_output)(struct telegram *instance); @@ -97,7 +106,7 @@ struct telegram { }; /** - * Constructor + * constructor */ struct telegram *telegram_new(struct dc *DC, const char* login, const char* config_path); @@ -171,16 +180,6 @@ void telegram_network_connect (struct telegram *instance, int fd); // Export functions for plugins void running_for_first_time (); -/* TODO: Remove? -void parse_config (); -void store_config (); -*/ - -/** - * Read and write until all queries received a response or errored - */ -void telegram_flush_queries (struct telegram *instance); - /** * Read and process all available input from the network */ @@ -255,12 +254,8 @@ void event_update_new_message(struct message *M); /* * Load known users and chats on connect */ -void on_peer_allocated(void (*handler)(peer_t *peer)); -void event_peer_allocated(peer_t *peer); - -// template -//void on_blarg(void (*on_msg)(struct message *M)); -//void event_blarg(struct message *M); +void on_peer_allocated(void (*handler)(void *peer)); +void event_peer_allocated(void *peer); /** * Set a function to use as a handle to read from a network resource @@ -274,8 +269,4 @@ void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)); */ void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); -/** - * - */ -void set_default_username (); - +#endif diff --git a/tools.h b/tools.h index dc8bfd9..3f3eca2 100644 --- a/tools.h +++ b/tools.h @@ -17,8 +17,7 @@ Copyright Vitaly Valtman 2013 */ -#ifndef __TOOLS_H__ -#define __TOOLS_H__ +#pragma once void *talloc (size_t size); void *trealloc (void *ptr, size_t old_size, size_t size); @@ -42,4 +41,3 @@ int tasprintf (char **res, const char *format, ...) __attribute__ ((format (prin void tcheck (void); void texists (void *ptr, int size); #endif -#endif From f1a2738783634453ff4c0f965e8d7a42e9e2df35 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 8 Aug 2014 08:44:56 +0200 Subject: [PATCH 335/465] remove redundant functions from binlog --- binlog.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/binlog.c b/binlog.c index 2113a0b..c5d2316 100644 --- a/binlog.c +++ b/binlog.c @@ -1170,32 +1170,6 @@ void write_binlog (void) { } void add_log_event (struct mtproto_connection *self, const int *data, int len) { - - logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); - assert(0); - // TODO: Mit add_log_event_i austauschen - assert (!(len & 3)); - if (in_replay_log) { return; } - rptr = (void *)data; - wptr = rptr + (len / 4); - int *in = self->in_ptr; - int *end = self->in_end; - // TODO: - //replay_log_event (); - if (rptr != wptr) { - logprintf ("Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len); - assert (rptr == wptr); - } - if (binlog_enabled) { - assert (binlog_fd > 0); - assert (write (binlog_fd, data, len) == len); - } - self->in_ptr = in; - self->in_end = end; -} - -void add_log_event_i (struct mtproto_connection *self, struct telegram *instance, - const int *data, int len) { logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); assert (!(len & 3)); if (in_replay_log) { return; } @@ -1203,8 +1177,7 @@ void add_log_event_i (struct mtproto_connection *self, struct telegram *instance wptr = rptr + (len / 4); int *in = self->in_ptr; int *end = self->in_end; - // TODO: - replay_log_event (instance); + replay_log_event (self->connection->instance); if (rptr != wptr) { logprintf ("Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len); assert (rptr == wptr); @@ -1228,7 +1201,7 @@ void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *b ev[1] = num; *(long long *)(ev + 2) = fingerprint; memcpy (ev + 4, buf, 256); - add_log_event_i (self, instance, ev, 8 + 8 + 256); + add_log_event (self, ev, 8 + 8 + 256); } void bl_do_set_our_id (struct mtproto_connection *self, int id) { From 1170ae5710c6a111d34b5b76fc10d663c531712b Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 8 Aug 2014 08:45:58 +0200 Subject: [PATCH 336/465] Implement state machine for dc discovery and login. --- mtproto-client.c | 5 ++ net.c | 3 +- purple-plugin/telegram-purple.c | 21 +++---- queries.c | 51 +++++++++------- queries.h | 2 +- structures.c | 2 +- telegram.c | 105 ++++++++++++++++++++++---------- telegram.h | 34 ++++++----- 8 files changed, 139 insertions(+), 84 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index f96424d..a4b94d9 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -238,6 +238,9 @@ int rpc_send_message (struct connection *c, void *data, int len) { self->total_packets_sent ++; self->total_data_sent += total_len; + + self->queries_num ++; + logprintf("queries_num=%d\n", self->queries_num); return 1; } @@ -1787,6 +1790,7 @@ int tc_becomes_ready (struct connection *c) { break; case st_authorized: auth_work_start (c); + telegram_change_state(c->instance, STATE_AUTHORIZED, NULL); break; default: logprintf ( "c_state = %d\n", c->mtconnection->c_state); @@ -1890,3 +1894,4 @@ void mtproto_close(struct mtproto_connection *c) // stop_ping_timer (c->connection); fd_close_connection(c->connection); } + diff --git a/net.c b/net.c index 20f2dc8..01c88ff 100644 --- a/net.c +++ b/net.c @@ -722,10 +722,11 @@ struct connection *fd_create_connection (struct dc *DC, int fd, S->c = c; DC->sessions[0] = S; } + // add backreference to session + c->session = DC->sessions[0]; // add backreference to used mtproto-connection c->mtconnection = mtp; - return c; } diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 4cc93cc..5fd923e 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -203,18 +203,18 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d do_send_code_result_auth (instance, code, hash, first_name, last_name); break; - case STATE_PHONE_CODE_NOT_ENTERED: - purple_connection_set_state(_gc, PURPLE_CONNECTED); + case STATE_PHONE_CODE_NOT_ENTERED: { + char *hash = data; + const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); + do_send_code_result(instance, code, hash); // TODO: Request SMS code - break; - - case STATE_CLIENT_NOT_REGISTERED: - // ask for registration type + } break; case STATE_CLIENT_CODE_NOT_ENTERED: { + char *hash = data; const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); - const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); + //const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); do_send_code_result(instance, code, hash); // enter SMS code } @@ -248,7 +248,9 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d // get new messages purple_debug_info(PLUGIN_ID, "Fetching new messages...\n"); do_get_difference(instance); - telegram_flush_queries(instance); + + tgprpl_has_output(instance); + //telegram_flush_queries(instance); break; case STATE_ERROR: { @@ -302,15 +304,12 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); struct telegram *tg = (struct telegram*) data; telegram_conn *conn = tg->extra; - //running_for_first_time(); - if (fd == -1) { logprintf("purple_proxy_connect failed: %s\n", error_message); telegram_free(tg); return; } - purple_debug_info(PLUGIN_ID, "Connecting to the telegram network...\n"); conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, tg); conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg); diff --git a/queries.c b/queries.c index 7e01d4e..494b627 100644 --- a/queries.c +++ b/queries.c @@ -140,11 +140,6 @@ void query_restart (long long id) { struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { logprintf("send_query(...)\n"); - /* - if (!DC->sessions[0]) { - dc_create_session (DC); - } - */ if (verbosity) { logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); } @@ -173,8 +168,10 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth insert_event_timer (&q->ev); q->extra = extra; - //queries_num ++; - //logprintf("queries_num: %d\n", queries_num); + + struct mtproto_connection *mtp = DC->sessions[0]->c->mtconnection; + mtp->queries_num ++; + logprintf("queries_num: %d\n", mtp->queries_num); return q; } @@ -211,8 +208,9 @@ void query_error (long long id) { tfree (q->data, q->data_len * 4); tfree (q, sizeof (*q)); } - //queries_num --; - //logprintf("queries_num: %d\n", queries_num); + + mtp->queries_num --; + logprintf("queries_num: %d\n", mtp->queries_num); } #define MAX_PACKED_SIZE (1 << 24) @@ -355,9 +353,7 @@ void fetch_dc_option (struct telegram *instance) { int l2 = prefetch_strlen (mtp); char *ip = fetch_str (mtp, l2); int port = fetch_int (mtp); - if (verbosity) { - logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - } + logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); bl_do_dc_option (mtp, id, l1, name, l2, ip, port, instance); } @@ -374,9 +370,7 @@ int help_get_config_on_answer (struct query *q UU) { assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false); assert (test_mode == CODE_bool_false || test_mode == CODE_bool_true); int this_dc = fetch_int (mtp); - if (verbosity) { - logprintf ( "this_dc = %d\n", this_dc); - } + logprintf ( "this_dc = %d\n", this_dc); assert (fetch_int (mtp) == CODE_vector); int n = fetch_int (mtp); assert (n <= 10); @@ -388,10 +382,9 @@ int help_get_config_on_answer (struct query *q UU) { if (op == CODE_config) { max_bcast_size = fetch_int (mtp); } - if (verbosity >= 2) { - logprintf ( "chat_size = %d\n", max_chat_size); - } - telegram_change_state(instance, STATE_CONNECTED, 0); + logprintf ( "max_chat_size = %d\n", max_chat_size); + + telegram_change_state(instance, STATE_CONFIG_RECEIVED, NULL); return 0; } @@ -405,7 +398,8 @@ void do_help_get_config (struct telegram *instance) { clear_packet (mtp); out_int (mtp, CODE_help_get_config); struct dc *DC_working = telegram_get_working_dc(instance); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &help_get_config_methods, instance); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, + mtp->packet_buffer, &help_get_config_methods, instance); } /* }}} */ @@ -567,6 +561,18 @@ int check_phone_on_answer (struct query *q UU) { assert (fetch_int (mtp) == (int)CODE_auth_checked_phone); check_phone_result = fetch_bool (mtp); fetch_bool (mtp); + + if (mtp->connection->instance->session_state != STATE_CONFIG_RECEIVED) { + logprintf("check_phone_on_answer(): invalid state: %d\n", mtp->connection->instance->session_state); + telegram_change_state(mtp->connection->instance, STATE_ERROR, NULL); + return -1; + } + logprintf("check_phone_result=%d\n", check_phone_result); + if (check_phone_result) { + telegram_change_state(mtp->connection->instance, STATE_CLIENT_NOT_REGISTERED, NULL); + } else { + telegram_change_state(mtp->connection->instance, STATE_PHONE_NOT_REGISTERED, NULL); + } return 0; } @@ -592,7 +598,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error } else { logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); } - telegram_change_state(instance, STATE_ERROR, error); + telegram_change_state(instance, STATE_DISCONNECTED_SWITCH_DC, error); return 0; } @@ -601,7 +607,7 @@ struct query_methods check_phone_methods = { .on_error = check_phone_on_error }; -int do_auth_check_phone (struct telegram *instance, const char *user) { +void do_auth_check_phone (struct telegram *instance, const char *user) { struct mtproto_connection *mtp = instance->connection; suser = tstrdup (user); @@ -617,7 +623,6 @@ int do_auth_check_phone (struct telegram *instance, const char *user) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, instance); net_loop (0, cr_f); */ - return check_phone_result; } /* }}} */ diff --git a/queries.h b/queries.h index 2dca703..2e5917e 100644 --- a/queries.h +++ b/queries.h @@ -103,7 +103,7 @@ void do_load_video (struct telegram *instance, struct video *V, int next); void do_load_document (struct telegram *instance, struct document *V, int next); void do_load_document_thumb (struct telegram *instance, struct document *video, int next); void do_help_get_config (struct telegram *instance); -int do_auth_check_phone (struct telegram *instance, const char *user); +void do_auth_check_phone (struct telegram *instance, const char *user); void do_get_nearest_dc (struct telegram*); void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name); void do_import_auth (struct telegram *instance, int num); diff --git a/structures.c b/structures.c index 1edc1a5..2dd3101 100644 --- a/structures.c +++ b/structures.c @@ -1535,7 +1535,7 @@ static int id_cmp (struct message *M1, struct message *M2) { } struct user *fetch_alloc_user (struct mtproto_connection *mtp) { - logprintf("fetch_alloc_user()\n"); + logprintf("fetch_alloc_user()\n"); int send_event = 0; int data[2]; prefetch_data (mtp, data, 8); diff --git a/telegram.c b/telegram.c index f275b13..30058a3 100755 --- a/telegram.c +++ b/telegram.c @@ -55,8 +55,57 @@ void telegram_change_state(struct telegram *instance, int state, void *data) logprintf("telegram connection state changed to: %d\n", state); instance->session_state = state; GList *curr = instance->change_state_listeners; - while ((curr = g_list_next(change_listeners)) != NULL) { + do { ((state_listener_t)curr->data)(instance, state, data); + } while ((curr = g_list_next(change_listeners)) != NULL); +} + +void on_state_change(struct telegram *instance, int state, void *data) +{ + logprintf("on_state_change: %d\n", state); + switch (state) { + case STATE_ERROR: { + const char* err = data; + logprintf("Telegram errored: %s \n", err); + } + break; + + case STATE_AUTHORIZED: + logprintf("requesting configuration"); + telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); + do_help_get_config (instance); + break; + + case STATE_CONFIG_RECEIVED: + logprintf("received network configuration, checking whether phone is registered."); + telegram_store_session(instance); + do_auth_check_phone(instance, instance->login); + break; + + case STATE_PHONE_NOT_REGISTERED: + logprintf("phone is not registered, need to register phone number.\n"); + do_send_code(instance, instance->login); + break; + + case STATE_PHONE_CODE_REQUESTED: + logprintf("phone authenticion, user needs to enter code, first and last name.\n"); + // wait for user input ... + break; + + case STATE_CLIENT_NOT_REGISTERED: + logprintf("phone is already registered, need to register client.\n"); + do_send_code(instance, instance->login); + break; + + case STATE_CLIENT_CODE_NOT_ENTERED: + logprintf("client authentication, user needs to enter code"); + // wait for user input ... + break; + + case STATE_DISCONNECTED_SWITCH_DC: + logprintf("Have to migrate to other DC"); + instance->connection + break; } } @@ -81,6 +130,7 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf logprintf("%s\n", this->auth_path); logprintf("%s\n", this->state_path); + telegram_add_state_change_listener(this, on_state_change); telegram_change_state(this, STATE_INITIALISED, NULL); return this; } @@ -125,7 +175,6 @@ struct connection *telegram_get_connection(struct telegram *instance) assert(DC); assert(DC->sessions[0]); assert(DC->sessions[0]->c); - //logprintf("get_connection() -> fd: %d\n", DC->sessions[0]->c->fd); return DC->sessions[0]->c; } @@ -171,51 +220,45 @@ char *telegram_get_config(struct telegram *instance, char *config) return g_strdup_printf("%s/%s", instance->config_path, config); } -void on_connected(struct mtproto_connection *c, void* data); +void on_authorized(struct mtproto_connection *c, void* data); + +/** + * Connect to the currently active data center + */ void telegram_network_connect(struct telegram *instance, int fd) { logprintf("telegram_network_connect()\n"); if (!instance->auth.DC_list) { - logprintf("telegram_network_connect(): cannot connect, restore / initialise a session first.\n"); + logprintf("telegram_network_connect(): cannot connect, restore / init a session first.\n"); assert(0); } struct dc *DC_working = telegram_get_working_dc(instance); instance->connection = mtproto_new(DC_working, fd, instance); - instance->connection->on_ready = on_connected; + instance->connection->on_ready = on_authorized; instance->connection->on_ready_data = instance; mtproto_connect(instance->connection); } -void on_connected(struct mtproto_connection *c, void *data) +/** + * Login, and perform a registration when needed + */ +int telegram_login(struct telegram *instance) { - struct telegram *instance = data; - logprintf("Authorized... storing current session.\n"); - telegram_store_session(instance); + if (instance->session_state != STATE_AUTHORIZED) { + logprintf("Cannot log in, invalid state: %d \n", instance->session_state); + return -1; + } + do_help_get_config(instance); + telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); + return 0; } -void on_state_change(struct telegram *instance, int state, void *data) +void on_authorized(struct mtproto_connection *c, void *data) { - switch (state) { - case STATE_CONNECTED: - break; - - case STATE_ERROR: { - const char* err = data; - logprintf("Telegram errored: %s \n", err); - } - break; - - case STATE_AUTH_DONE: - logprintf("requesting configuration"); - telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); - do_help_get_config (instance); - break; - - case STATE_CONFIG_REQUESTED: - logprintf("switch: config_requested\n"); - telegram_store_session(instance); - break; - } + struct telegram *instance = data; + logprintf("Authorized... storing current session %d.\n", c->connection->session[0]); + telegram_store_session(instance); + telegram_change_state(instance, STATE_AUTHORIZED, NULL); } void telegram_read_input (struct telegram *instance) diff --git a/telegram.h b/telegram.h index 9b4d6e2..30f70ee 100644 --- a/telegram.h +++ b/telegram.h @@ -26,7 +26,7 @@ struct protocol_state; struct authorization_state; /* - * Libtelegram states + * telegram states */ #define STATE_INITIALISED 0 @@ -35,35 +35,35 @@ struct authorization_state; // Error #define STATE_ERROR 2 -// Authentication -#define STATE_PQ_REQUESTED 3 -#define STATE_DH_REQUESTED 4 -#define STATE_CDH_REQUESTED 5 -#define STATE_AUTH_DONE 6 +// intermediate authorization states already present and handled in mtproto-client.c +//#define STATE_PQ_REQUESTED 3 +//#define STATE_DH_REQUESTED 4 +//#define STATE_CDH_REQUESTED 5 +#define STATE_AUTHORIZED 6 + +// dc discovery #define STATE_CONFIG_REQUESTED 7 #define STATE_EXPORTING_CONFIG 8 #define STATE_DISCONNECTED_SWITCH_DC 9 +#define STATE_CONFIG_RECEIVED 11 -// Login -#define STATE_CONNECTED 10 +// login // - Phone Registration -#define STATE_PHONE_IS_REGISTERED_SENT 11 -#define STATE_PHONE_IS_REGISTERED_SENT_2 12 #define STATE_PHONE_NOT_REGISTERED 13 #define STATE_PHONE_CODE_REQUESTED 14 #define STATE_PHONE_CODE_NOT_ENTERED 15 #define STATE_PHONE_CODE_ENTERED 16 // - Client Registration -#define STATE_CLIENT_IS_REGISTERED_SENT 16 -#define STATE_CLIENT_NOT_REGISTERED 17 -#define STATE_CLIENT_CODE_REQUESTED 18 -#define STATE_CLIENT_CODE_NOT_ENTERED 19 -#define STATE_CLIENT_CODE_ENTERED 20 +#define STATE_CLIENT_IS_REGISTERED_SENT 17 +#define STATE_CLIENT_NOT_REGISTERED 18 +#define STATE_CLIENT_CODE_REQUESTED 19 +#define STATE_CLIENT_CODE_NOT_ENTERED 20 +#define STATE_CLIENT_CODE_ENTERED 21 // Ready for sending and receiving messages -#define STATE_READY 21 +#define STATE_READY 22 /** * A telegram session @@ -173,6 +173,8 @@ void telegram_change_state(struct telegram *instance, int state, void *data); */ void telegram_network_connect (struct telegram *instance, int fd); +int telegram_login (struct telegram *instance); + /** * Read the authorization_state stored in the given file */ From 188f890df50ef11013da24203c542721b1e03667 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 8 Aug 2014 08:46:39 +0200 Subject: [PATCH 337/465] Ignore app-hash --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d8a3631..074eef7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ tags .DS_Store .ycm_extra_conf.py *.pyc +app-hash.png From 331d63165910280e2c870a543fb150a934b2b6d7 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 16:43:45 +0200 Subject: [PATCH 338/465] Ignore gdb files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 074eef7..6a40545 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ tags .ycm_extra_conf.py *.pyc app-hash.png +.gdbinit From 32799a90864b755aca763f2acc1968b2159489fe Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 17:05:29 +0200 Subject: [PATCH 339/465] Move binlog globals into a structure --- binlog.c | 789 ++++++++++++++++++++++++----------------------- binlog.h | 111 ++++--- mtproto-client.c | 32 +- mtproto-client.h | 8 + queries.c | 42 +-- structures.c | 84 ++--- telegram.c | 5 + telegram.h | 18 ++ 8 files changed, 574 insertions(+), 515 deletions(-) diff --git a/binlog.c b/binlog.c index c5d2316..9be90c0 100644 --- a/binlog.c +++ b/binlog.c @@ -41,13 +41,6 @@ #include -#define BINLOG_BUFFER_SIZE (1 << 20) -int binlog_buffer[BINLOG_BUFFER_SIZE]; -int *rptr; -int *wptr; -int test_dc = 0; -extern int test_dc; - extern int pts; extern int qts; extern int last_date; @@ -65,38 +58,34 @@ char *get_binlog_file_name() //extern struct dc *DC_list[]; //extern int dc_working_num; extern int our_id; -extern int binlog_enabled; int binlog_enabled = 0; extern int encr_root; extern unsigned char *encr_prime; extern int encr_param_version; extern int messages_allocated; -int in_replay_log; - -void *alloc_log_event (int l UU) { - return binlog_buffer; +void *alloc_log_event (struct binlog *bl, int l UU) { + return bl->binlog_buffer; } -long long binlog_pos; - void replay_log_event (struct telegram *instance) { struct mtproto_connection *self = instance->connection; + struct binlog *bl = instance->bl; - int *start = rptr; - in_replay_log = 1; - assert (rptr < wptr); - int op = *rptr; + int *start = bl->rptr; + bl->in_replay_log = 1; + assert (bl->rptr < bl->wptr); + int op = *bl->rptr; if (verbosity >= 2) { - logprintf ("log_pos %lld, op 0x%08x\n", binlog_pos, op); + logprintf ("log_pos %lld, op 0x%08x\n", bl->binlog_pos, op); } - self->in_ptr = rptr; - self->in_end = wptr; + self->in_ptr = bl->rptr; + self->in_end = bl->wptr; switch (op) { case LOG_START: - rptr ++; + bl->rptr ++; break; case CODE_binlog_dc_option: self->in_ptr ++; @@ -112,52 +101,52 @@ void replay_log_event (struct telegram *instance) { } alloc_dc (instance->auth.DC_list, id, tstrndup (ip, l2), port); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case LOG_AUTH_KEY: - rptr ++; + bl->rptr ++; { - int num = *(rptr ++); + int num = *(bl->rptr ++); assert (num >= 0 && num <= MAX_DC_ID); assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->auth_key_id = *(long long *)rptr; - rptr += 2; - memcpy (instance->auth.DC_list[num]->auth_key, rptr, 256); - rptr += 64; + instance->auth.DC_list[num]->auth_key_id = *(long long *)bl->rptr; + bl->rptr += 2; + memcpy (instance->auth.DC_list[num]->auth_key, bl->rptr, 256); + bl->rptr += 64; instance->auth.DC_list[num]->flags |= 1; }; break; case LOG_DEFAULT_DC: - rptr ++; + bl->rptr ++; { - int num = *(rptr ++); + int num = *(bl->rptr ++); assert (num >= 0 && num <= MAX_DC_ID); instance->auth.dc_working_num = num; } break; case LOG_OUR_ID: - rptr ++; + bl->rptr ++; { - our_id = *(rptr ++); + our_id = *(bl->rptr ++); } break; case LOG_DC_SIGNED: - rptr ++; + bl->rptr ++; { - int num = *(rptr ++); + int num = *(bl->rptr ++); assert (num >= 0 && num <= MAX_DC_ID); assert (instance->auth.DC_list[num]); instance->auth.DC_list[num]->has_auth = 1; } break; case LOG_DC_SALT: - rptr ++; + bl->rptr ++; { - int num = *(rptr ++); + int num = *(bl->rptr ++); assert (num >= 0 && num <= MAX_DC_ID); assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->server_salt = *(long long *)rptr; - rptr += 2; + instance->auth.DC_list[num]->server_salt = *(long long *)bl->rptr; + bl->rptr += 2; }; break; // case CODE_user_empty: @@ -167,45 +156,45 @@ void replay_log_event (struct telegram *instance) { // case CODE_user_foreign: case CODE_user_deleted: fetch_alloc_user (self); - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case LOG_DH_CONFIG: get_dh_config_on_answer (0); - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case LOG_ENCR_CHAT_KEY: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); - U->key_fingerprint = *(long long *)rptr; - rptr += 2; - memcpy (U->key, rptr, 256); - rptr += 64; + U->key_fingerprint = *(long long *)bl->rptr; + bl->rptr += 2; + memcpy (U->key, bl->rptr, 256); + bl->rptr += 64; }; break; case LOG_ENCR_CHAT_SEND_ACCEPT: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); - U->key_fingerprint = *(long long *)rptr; - rptr += 2; - memcpy (U->key, rptr, 256); - rptr += 64; + U->key_fingerprint = *(long long *)bl->rptr; + bl->rptr += 2; + memcpy (U->key, bl->rptr, 256); + bl->rptr += 64; if (!U->g_key) { U->g_key = talloc (256); } - memcpy (U->g_key, rptr, 256); - rptr += 64; + memcpy (U->g_key, bl->rptr, 256); + bl->rptr += 64; }; break; case LOG_ENCR_CHAT_SEND_CREATE: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (!U || !(U->flags & FLAG_CREATED)); if (!U) { @@ -214,9 +203,9 @@ void replay_log_event (struct telegram *instance) { insert_encrypted_chat ((void *)U); } U->flags |= FLAG_CREATED; - U->user_id = *(rptr ++); - memcpy (U->key, rptr, 256); - rptr += 64; + U->user_id = *(bl->rptr ++); + memcpy (U->key, bl->rptr, 256); + bl->rptr += 64; if (!U->print_name) { peer_t *P = user_chat_get (MK_USER (U->user_id)); if (P) { @@ -231,9 +220,9 @@ void replay_log_event (struct telegram *instance) { }; break; case LOG_ENCR_CHAT_DELETED: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); if (!U) { U = talloc0 (sizeof (peer_t)); @@ -245,23 +234,23 @@ void replay_log_event (struct telegram *instance) { }; break; case LOG_ENCR_CHAT_WAITING: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->state = sc_waiting; - U->date = *(rptr ++); - U->admin_id = *(rptr ++); - U->user_id = *(rptr ++); - U->access_hash = *(long long *)rptr; - rptr += 2; + U->date = *(bl->rptr ++); + U->admin_id = *(bl->rptr ++); + U->user_id = *(bl->rptr ++); + U->access_hash = *(long long *)bl->rptr; + bl->rptr += 2; }; break; case LOG_ENCR_CHAT_REQUESTED: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); if (!U) { U = talloc0 (sizeof (peer_t)); @@ -270,10 +259,10 @@ void replay_log_event (struct telegram *instance) { } U->flags |= FLAG_CREATED; U->state = sc_request; - U->date = *(rptr ++); - U->admin_id = *(rptr ++); - U->user_id = *(rptr ++); - U->access_hash = *(long long *)rptr; + U->date = *(bl->rptr ++); + U->admin_id = *(bl->rptr ++); + U->user_id = *(bl->rptr ++); + U->access_hash = *(long long *)bl->rptr; if (!U->print_name) { peer_t *P = user_chat_get (MK_USER (U->user_id)); if (P) { @@ -285,13 +274,13 @@ void replay_log_event (struct telegram *instance) { } peer_insert_name ((void *)U); } - rptr += 2; + bl->rptr += 2; }; break; case LOG_ENCR_CHAT_OK: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); struct secret_chat *U = (void *)user_chat_get (id); assert (U); U->state = sc_ok; @@ -325,25 +314,25 @@ void replay_log_event (struct telegram *instance) { U->flags |= FLAG_USER_CONTACT; } } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_user_delete: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_USER (*(rptr ++)); + peer_id_t id = MK_USER (*(bl->rptr ++)); peer_t *U = user_chat_get (id); assert (U); U->flags |= FLAG_DELETED; } break; case CODE_binlog_set_user_access_token: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_USER (*(rptr ++)); + peer_id_t id = MK_USER (*(bl->rptr ++)); peer_t *U = user_chat_get (id); assert (U); - U->user.access_hash = *(long long *)rptr; - rptr += 2; + U->user.access_hash = *(long long *)bl->rptr; + bl->rptr += 2; } break; case CODE_binlog_set_user_phone: @@ -355,15 +344,15 @@ void replay_log_event (struct telegram *instance) { if (U->user.phone) { tfree_str (U->user.phone); } U->user.phone = fetch_str_dup (self); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_set_user_friend: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_USER (*(rptr ++)); + peer_id_t id = MK_USER (*(bl->rptr ++)); peer_t *U = user_chat_get (id); assert (U); - int friend = *(rptr ++); + int friend = *(bl->rptr ++); if (friend) { U->flags |= FLAG_USER_CONTACT; } else { U->flags &= ~FLAG_USER_CONTACT; } } @@ -379,15 +368,15 @@ void replay_log_event (struct telegram *instance) { } fetch_photo (self, &U->user.photo); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_user_blocked: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_USER (*(rptr ++)); + peer_id_t id = MK_USER (*(bl->rptr ++)); peer_t *U = user_chat_get (id); assert (U); - U->user.blocked = *(rptr ++); + U->user.blocked = *(bl->rptr ++); } break; case CODE_binlog_set_user_full_name: @@ -401,12 +390,12 @@ void replay_log_event (struct telegram *instance) { U->user.real_first_name = fetch_str_dup (self); U->user.real_last_name = fetch_str_dup (self); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_encr_chat_delete: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); peer_t *_U = user_chat_get (id); assert (_U); struct secret_chat *U = &_U->encr_chat; @@ -424,9 +413,9 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_encr_chat_requested: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); peer_t *_U = user_chat_get (id); if (!_U) { _U = talloc0 (sizeof (*_U)); @@ -436,11 +425,11 @@ void replay_log_event (struct telegram *instance) { assert (!(_U->flags & FLAG_CREATED)); } struct secret_chat *U = (void *)_U; - U->access_hash = *(long long *)rptr; - rptr += 2; - U->date = *(rptr ++); - U->admin_id = *(rptr ++); - U->user_id = *(rptr ++); + U->access_hash = *(long long *)bl->rptr; + bl->rptr += 2; + U->date = *(bl->rptr ++); + U->admin_id = *(bl->rptr ++); + U->user_id = *(bl->rptr ++); peer_t *Us = user_chat_get (MK_USER (U->user_id)); assert (!U->print_name); @@ -454,47 +443,47 @@ void replay_log_event (struct telegram *instance) { peer_insert_name ((void *)U); U->g_key = talloc (256); U->nonce = talloc (256); - memcpy (U->g_key, rptr, 256); - rptr += 64; - memcpy (U->nonce, rptr, 256); - rptr += 64; + memcpy (U->g_key, bl->rptr, 256); + bl->rptr += 64; + memcpy (U->nonce, bl->rptr, 256); + bl->rptr += 64; U->flags |= FLAG_CREATED; U->state = sc_request; } break; case CODE_binlog_set_encr_chat_access_hash: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); peer_t *U = user_chat_get (id); assert (U); - U->encr_chat.access_hash = *(long long *)rptr; - rptr += 2; + U->encr_chat.access_hash = *(long long *)bl->rptr; + bl->rptr += 2; } break; case CODE_binlog_set_encr_chat_date: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); peer_t *U = user_chat_get (id); assert (U); - U->encr_chat.date = *(rptr ++); + U->encr_chat.date = *(bl->rptr ++); } break; case CODE_binlog_set_encr_chat_state: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); peer_t *U = user_chat_get (id); assert (U); - U->encr_chat.state = *(rptr ++); + U->encr_chat.state = *(bl->rptr ++); } break; case CODE_binlog_encr_chat_accepted: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); peer_t *_U = user_chat_get (id); assert (_U); struct secret_chat *U = &_U->encr_chat; @@ -504,12 +493,12 @@ void replay_log_event (struct telegram *instance) { if (!U->nonce) { U->nonce = talloc (256); } - memcpy (U->g_key, rptr, 256); - rptr += 64; - memcpy (U->nonce, rptr, 256); - rptr += 64; - U->key_fingerprint = *(long long *)rptr; - rptr += 2; + memcpy (U->g_key, bl->rptr, 256); + bl->rptr += 64; + memcpy (U->nonce, bl->rptr, 256); + bl->rptr += 64; + U->key_fingerprint = *(long long *)bl->rptr; + bl->rptr += 2; if (U->state == sc_waiting) { do_create_keys_end (U); } @@ -517,65 +506,65 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_set_encr_chat_key: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); peer_t *_U = user_chat_get (id); assert (_U); struct secret_chat *U = &_U->encr_chat; - memcpy (U->key, rptr, 256); - rptr += 64; - U->key_fingerprint = *(long long *)rptr; - rptr += 2; + memcpy (U->key, bl->rptr, 256); + bl->rptr += 64; + U->key_fingerprint = *(long long *)bl->rptr; + bl->rptr += 2; } break; case CODE_binlog_set_dh_params: - rptr ++; + bl->rptr ++; { if (encr_prime) { tfree (encr_prime, 256); } - encr_root = *(rptr ++); + encr_root = *(bl->rptr ++); encr_prime = talloc (256); - memcpy (encr_prime, rptr, 256); - rptr += 64; - encr_param_version = *(rptr ++); + memcpy (encr_prime, bl->rptr, 256); + bl->rptr += 64; + encr_param_version = *(bl->rptr ++); } break; case CODE_binlog_encr_chat_init: - rptr ++; + bl->rptr ++; { peer_t *P = talloc0 (sizeof (*P)); - P->id = MK_ENCR_CHAT (*(rptr ++)); + P->id = MK_ENCR_CHAT (*(bl->rptr ++)); assert (!user_chat_get (P->id)); - P->encr_chat.user_id = *(rptr ++); + P->encr_chat.user_id = *(bl->rptr ++); P->encr_chat.admin_id = our_id; insert_encrypted_chat (P); peer_t *Us = user_chat_get (MK_USER (P->encr_chat.user_id)); assert (Us); P->print_name = create_print_name (P->id, "!", Us->user.first_name, Us->user.last_name, 0); peer_insert_name (P); - memcpy (P->encr_chat.key, rptr, 256); - rptr += 64; + memcpy (P->encr_chat.key, bl->rptr, 256); + bl->rptr += 64; P->encr_chat.g_key = talloc (256); - memcpy (P->encr_chat.g_key, rptr, 256); - rptr += 64; + memcpy (P->encr_chat.g_key, bl->rptr, 256); + bl->rptr += 64; P->flags |= FLAG_CREATED; } break; case CODE_binlog_set_pts: - rptr ++; - pts = *(rptr ++); + bl->rptr ++; + pts = *(bl->rptr ++); break; case CODE_binlog_set_qts: - rptr ++; - qts = *(rptr ++); + bl->rptr ++; + qts = *(bl->rptr ++); break; case CODE_binlog_set_date: - rptr ++; - last_date = *(rptr ++); + bl->rptr ++; + last_date = *(bl->rptr ++); break; case CODE_binlog_set_seq: - rptr ++; - seq = *(rptr ++); + bl->rptr ++; + seq = *(bl->rptr ++); break; case CODE_binlog_chat_create: self->in_ptr ++; @@ -601,15 +590,15 @@ void replay_log_event (struct telegram *instance) { fetch_data (self, &C->photo_big, sizeof (struct file_location)); fetch_data (self, &C->photo_small, sizeof (struct file_location)); }; - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_chat_change_flags: - rptr ++; + bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); - C->flags |= *(rptr ++); - C->flags &= ~*(rptr ++); + C->flags |= *(bl->rptr ++); + C->flags &= ~*(bl->rptr ++); }; break; case CODE_binlog_set_chat_title: @@ -627,7 +616,7 @@ void replay_log_event (struct telegram *instance) { C->print_title = create_print_name (C->id, C->title, 0, 0, 0); peer_insert_name ((void *)C); }; - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_set_chat_photo: self->in_ptr ++; @@ -637,44 +626,44 @@ void replay_log_event (struct telegram *instance) { fetch_data (self, &C->photo_big, sizeof (struct file_location)); fetch_data (self, &C->photo_small, sizeof (struct file_location)); }; - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_set_chat_date: - rptr ++; + bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); - C->chat.date = *(rptr ++); + C->chat.date = *(bl->rptr ++); }; break; case CODE_binlog_set_chat_version: - rptr ++; + bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); - C->chat.version = *(rptr ++); - C->chat.users_num = *(rptr ++); + C->chat.version = *(bl->rptr ++); + C->chat.users_num = *(bl->rptr ++); }; break; case CODE_binlog_set_chat_admin: - rptr ++; + bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); - C->chat.admin_id = *(rptr ++); + C->chat.admin_id = *(bl->rptr ++); }; break; case CODE_binlog_set_chat_participants: - rptr ++; + bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(rptr ++))); + peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); - C->chat.user_list_version = *(rptr ++); + C->chat.user_list_version = *(bl->rptr ++); if (C->chat.user_list) { tfree (C->chat.user_list, 12 * C->chat.user_list_size); } - C->chat.user_list_size = *(rptr ++); + C->chat.user_list_size = *(bl->rptr ++); C->chat.user_list = talloc (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; + memcpy (C->chat.user_list, bl->rptr, 12 * C->chat.user_list_size); + bl->rptr += 3 * C->chat.user_list_size; }; break; case CODE_binlog_chat_full_photo: @@ -688,20 +677,20 @@ void replay_log_event (struct telegram *instance) { } fetch_photo (self, &U->chat.photo); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_add_chat_participant: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_CHAT (*(rptr ++)); + peer_id_t id = MK_CHAT (*(bl->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 ++); + int version = *(bl->rptr ++); + int user = *(bl->rptr ++); + int inviter = *(bl->rptr ++); + int date = *(bl->rptr ++); assert (C->user_list_version < version); int i; @@ -717,15 +706,15 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_del_chat_participant: - rptr ++; + bl->rptr ++; { - peer_id_t id = MK_CHAT (*(rptr ++)); + peer_id_t id = MK_CHAT (*(bl->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 version = *(bl->rptr ++); + int user = *(bl->rptr ++); assert (C->user_list_version < version); int i; @@ -791,7 +780,7 @@ void replay_log_event (struct telegram *instance) { M->flags |= FLAG_PENDING; } } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_create_message_text_fwd: self->in_ptr ++; @@ -826,7 +815,7 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_create_message_media: self->in_ptr ++; @@ -859,7 +848,7 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_create_message_media_encr: self->in_ptr ++; @@ -894,7 +883,7 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_create_message_media_fwd: self->in_ptr ++; @@ -929,7 +918,7 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_create_message_service: self->in_ptr ++; @@ -957,7 +946,7 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_create_message_service_encr: self->in_ptr ++; @@ -986,7 +975,7 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_create_message_service_fwd: self->in_ptr ++; @@ -1015,31 +1004,31 @@ void replay_log_event (struct telegram *instance) { message_insert (M); } - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; case CODE_binlog_set_unread: - rptr ++; + bl->rptr ++; { - struct message *M = message_get (*(rptr ++)); + struct message *M = message_get (*(bl->rptr ++)); assert (M); M->unread = 0; } break; case CODE_binlog_set_message_sent: - rptr ++; + bl->rptr ++; { - struct message *M = message_get (*(long long *)rptr); - rptr += 2; + struct message *M = message_get (*(long long *)bl->rptr); + bl->rptr += 2; assert (M); message_remove_unsent (M); M->flags &= ~FLAG_PENDING; } break; case CODE_binlog_set_msg_id: - rptr ++; + bl->rptr ++; { - struct message *M = message_get (*(long long *)rptr); - rptr += 2; + struct message *M = message_get (*(long long *)bl->rptr); + bl->rptr += 2; assert (M); if (M->flags & FLAG_PENDING) { message_remove_unsent (M); @@ -1047,7 +1036,7 @@ void replay_log_event (struct telegram *instance) { } message_remove_tree (M); message_del_peer (M); - M->id = *(rptr ++); + M->id = *(bl->rptr ++); if (message_get (M->id)) { free_message (M); tfree (M, sizeof (*M)); @@ -1058,10 +1047,10 @@ void replay_log_event (struct telegram *instance) { } break; case CODE_binlog_delete_msg: - rptr ++; + bl->rptr ++; { - struct message *M = message_get (*(long long *)rptr); - rptr += 2; + struct message *M = message_get (*(long long *)bl->rptr); + bl->rptr += 2; assert (M); if (M->flags & FLAG_PENDING) { message_remove_unsent (M); @@ -1077,28 +1066,31 @@ void replay_log_event (struct telegram *instance) { case CODE_update_user_photo: case CODE_update_user_name: work_update_binlog (self); - rptr = self->in_ptr; + bl->rptr = self->in_ptr; break; default: - logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(rptr - 1), op, *(rptr + 1), binlog_pos); + logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(bl->rptr - 1), op, *(bl->rptr + 1), bl->binlog_pos); assert (0); } if (verbosity >= 2) { logprintf ("Event end\n"); } - in_replay_log = 0; - binlog_pos += (rptr - start) * 4; + bl->in_replay_log = 0; + bl->binlog_pos += (bl->rptr - start) * 4; } -void create_new_binlog (struct mtproto_connection *self) { +void create_new_binlog (struct binlog *bl, struct mtproto_connection *self) { + logprintf("create_new_binlog()"); + static int s[1000]; self->packet_ptr = s; + //self->packet_ptr = self->packet_buffer; // (int *)&bl->s; out_int (self, LOG_START); out_int (self, CODE_binlog_dc_option); out_int (self, 1); out_string (self, ""); - out_string (self, test_dc ? TG_SERVER_TEST : TG_SERVER); + out_string (self, bl->test_dc ? TG_SERVER_TEST : TG_SERVER); out_int (self, 443); out_int (self, LOG_DEFAULT_DC); out_int (self, 1); @@ -1112,13 +1104,19 @@ void create_new_binlog (struct mtproto_connection *self) { close (fd); } - +/** + * Loag the logfile and replay all stored log events + */ void replay_log (struct telegram *instance) { + assert(instance->connection); + assert(instance->bl); struct mtproto_connection *self = instance->connection; + struct binlog *bl = instance->bl; + logprintf("replaying binlog...\n"); if (access (get_binlog_file_name (), F_OK) < 0) { printf ("No binlog found. Creating new one\n"); - create_new_binlog (self); + create_new_binlog (bl, self); } int fd = open (get_binlog_file_name (), O_RDONLY); if (fd < 0) { @@ -1127,64 +1125,90 @@ void replay_log (struct telegram *instance) { } int end = 0; while (1) { - if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) { - if (wptr == rptr) { - wptr = rptr = binlog_buffer; + if (!end && bl->wptr - bl->rptr < MAX_LOG_EVENT_SIZE / 4) { + if (bl->wptr == bl->rptr) { + // nothing to read, + // reset read and write pointer to start of buffer + bl->wptr = bl->rptr = bl->binlog_buffer; } else { - int x = wptr - rptr; - memcpy (binlog_buffer, rptr, 4 * x); - wptr -= (rptr - binlog_buffer); - rptr = binlog_buffer; + // get difference between read and write pointer + int x = bl->wptr - bl->rptr; + + // copy everything between read and write pointer + // to the start of the binlog buffer + memcpy (bl->binlog_buffer, bl->rptr, 4 * x); + + // reset binlog buffer position + // +-----------+------+------+ + // ^ ^ ^ ^ + // bl_buffer rptr wptr BUFFER_SIZE + // + // +------+------------------+ + // ^ ^ ^ + // rptr wptr BUFFER_SIZE + // bl_buffer + // + bl->wptr -= (bl->rptr - bl->binlog_buffer); + bl->rptr = bl->binlog_buffer; } - int l = (binlog_buffer + BINLOG_BUFFER_SIZE - wptr) * 4; - int k = read (fd, wptr, l); + // calculate the remaining space in the binlog buffer + int l = (bl->binlog_buffer + BINLOG_BUFFER_SIZE - bl->wptr) * 4; + + // try to read the remining bytes from the file + int k = read (fd, bl->wptr, l); if (k < 0) { perror ("read binlog"); exit (2); } + // amount of read bytes must be divisible by 4, since we + // store 4-byte integers assert (!(k & 3)); if (k < l) { + // reached end of file end = 1; } - wptr += (k / 4); + // move the write pointer to the first empty byte + bl->wptr += (k / 4); + } + if (bl->wptr == bl->rptr) { + // no further log entries, done... + break; } - if (wptr == rptr) { break; } replay_log_event (instance); } close (fd); } -int binlog_fd; -void write_binlog (void) { - binlog_fd = open (get_binlog_file_name (), O_WRONLY); - if (binlog_fd < 0) { +void write_binlog (struct binlog *bl) { + bl->binlog_fd = open (get_binlog_file_name (), O_WRONLY); + if (bl->binlog_fd < 0) { perror ("binlog open"); exit (2); } - assert (lseek (binlog_fd, binlog_pos, SEEK_SET) == binlog_pos); - if (flock (binlog_fd, LOCK_EX | LOCK_NB) < 0) { + assert (lseek (bl->binlog_fd, bl->binlog_pos, SEEK_SET) == bl->binlog_pos); + if (flock (bl->binlog_fd, LOCK_EX | LOCK_NB) < 0) { perror ("get lock"); exit (2); } } -void add_log_event (struct mtproto_connection *self, const int *data, int len) { +void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int len) { logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); assert (!(len & 3)); - if (in_replay_log) { return; } - rptr = (void *)data; - wptr = rptr + (len / 4); + if (bl->in_replay_log) { return; } + bl->rptr = (void *)data; + bl->wptr = bl->rptr + (len / 4); int *in = self->in_ptr; int *end = self->in_end; replay_log_event (self->connection->instance); - if (rptr != wptr) { - logprintf ("Unread %lld ints. Len = %d\n", (long long)(wptr - rptr), len); - assert (rptr == wptr); + if (bl->rptr != bl->wptr) { + logprintf ("Unread %lld ints. Len = %d\n", (long long)(bl->wptr - bl->rptr), len); + assert (bl->rptr == bl->wptr); } - if (binlog_enabled) { - assert (binlog_fd > 0); - assert (write (binlog_fd, data, len) == len); + if (bl->binlog_enabled) { + assert (bl->binlog_fd > 0); + assert (write (bl->binlog_fd, data, len) == len); } self->in_ptr = in; self->in_end = end; @@ -1192,26 +1216,27 @@ void add_log_event (struct mtproto_connection *self, const int *data, int len) { void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf) { struct mtproto_connection *self = instance->connection; + struct binlog *bl = instance->bl; static unsigned char sha1_buffer[20]; SHA1 (buf, 256, sha1_buffer); long long fingerprint = *(long long *)(sha1_buffer + 12); - int *ev = alloc_log_event (8 + 8 + 256); + int *ev = alloc_log_event (bl, 8 + 8 + 256); ev[0] = LOG_AUTH_KEY; ev[1] = num; *(long long *)(ev + 2) = fingerprint; memcpy (ev + 4, buf, 256); - add_log_event (self, ev, 8 + 8 + 256); + add_log_event (bl, self, ev, 8 + 8 + 256); } -void bl_do_set_our_id (struct mtproto_connection *self, int id) { - int *ev = alloc_log_event (8); +void bl_do_set_our_id (struct binlog *bl, struct mtproto_connection *self, int id) { + int *ev = alloc_log_event (bl, 8); ev[0] = LOG_OUR_ID; ev[1] = id; - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_new_user (struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, +void bl_do_new_user (struct binlog *bl, struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact) { clear_packet (self); @@ -1222,29 +1247,29 @@ void bl_do_new_user (struct mtproto_connection *self, int id, const char *f, int out_long (self, access_token); out_cstring (self, p ? p : "", pl); out_int (self, contact); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_user_delete (struct mtproto_connection *self, struct user *U) { +void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct user *U) { if (U->flags & FLAG_DELETED) { return; } - int *ev = alloc_log_event (8); + int *ev = alloc_log_event (bl, 8); ev[0] = CODE_binlog_user_delete; ev[1] = get_peer_id (U->id); - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } extern int last_date; -void bl_do_set_user_profile_photo (struct mtproto_connection *self, struct user *U, +void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long photo_id, struct file_location *big, struct file_location *small) { if (photo_id == U->photo_id) { return; } if (!photo_id) { - int *ev = alloc_log_event (20); + int *ev = alloc_log_event (bl, 20); ev[0] = CODE_update_user_photo; ev[1] = get_peer_id (U->id); ev[2] = last_date; ev[3] = CODE_user_profile_photo_empty; ev[4] = CODE_bool_false; - add_log_event (self, ev, 20); + add_log_event (bl, self, ev, 20); } else { clear_packet (self); out_int (self, CODE_update_user_photo); @@ -1277,11 +1302,11 @@ void bl_do_set_user_profile_photo (struct mtproto_connection *self, struct user out_long (self, big->secret); } out_int (self, CODE_bool_false); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } } -void bl_do_set_user_name (struct mtproto_connection *self, struct user *U, const char *f, +void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll) { if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) && (U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) { @@ -1292,19 +1317,19 @@ void bl_do_set_user_name (struct mtproto_connection *self, struct user *U, const out_int (self, get_peer_id (U->id)); out_cstring (self, f, fl); out_cstring (self, l, ll); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_user_access_token (struct mtproto_connection *self, struct user *U, long long access_token) { +void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long access_token) { if (U->access_hash == access_token) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 16); ev[0] = CODE_binlog_set_user_access_token; ev[1] = get_peer_id (U->id); *(long long *)(ev + 2) = access_token; - add_log_event (self, ev, 16); + add_log_event (bl, self, ev, 16); } -void bl_do_set_user_phone (struct mtproto_connection *self, struct user *U, +void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *p, int pl) { if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) { return; @@ -1313,19 +1338,19 @@ const char *p, int pl) { out_int (self, CODE_binlog_set_user_phone); out_int (self, get_peer_id (U->id)); out_cstring (self, p, pl); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_user_friend (struct mtproto_connection *self, struct user *U, int friend) { +void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct user *U, int friend) { if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; } - int *ev = alloc_log_event (12); + int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_set_user_friend; ev[1] = get_peer_id (U->id); ev[2] = friend; - add_log_event (self, ev, 12); + add_log_event (bl, self, ev, 12); } -void bl_do_dc_option (struct mtproto_connection *self, int id, int l1, const char *name, +void bl_do_dc_option (struct binlog *bl, struct mtproto_connection *self, int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance) { struct dc *DC = instance->auth.DC_list[id]; if (DC) { return; } @@ -1337,42 +1362,42 @@ void bl_do_dc_option (struct mtproto_connection *self, int id, int l1, const cha out_cstring (self, ip, l2); out_int (self, port); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_dc_signed (struct mtproto_connection *self, int id) { - int *ev = alloc_log_event (8); +void bl_do_dc_signed (struct binlog *bl, struct mtproto_connection *self, int id) { + int *ev = alloc_log_event (bl, 8); ev[0] = LOG_DC_SIGNED; ev[1] = id; - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_set_working_dc (struct mtproto_connection *self, int num) { - int *ev = alloc_log_event (8); +void bl_do_set_working_dc (struct binlog *bl, struct mtproto_connection *self, int num) { + int *ev = alloc_log_event (bl, 8); ev[0] = LOG_DEFAULT_DC; ev[1] = num; - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_set_user_full_photo (struct mtproto_connection *self, struct user *U, const int *start, int len) { +void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, const int *start, int len) { if (U->photo.id == *(long long *)(start + 1)) { return; } - int *ev = alloc_log_event (len + 8); + int *ev = alloc_log_event (bl, len + 8); ev[0] = CODE_binlog_user_full_photo; ev[1] = get_peer_id (U->id); memcpy (ev + 2, start, len); - add_log_event (self, ev, len + 8); + add_log_event (bl, self, ev, len + 8); } -void bl_do_set_user_blocked (struct mtproto_connection *self, struct user *U, int blocked) { +void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct user *U, int blocked) { if (U->blocked == blocked) { return; } - int *ev = alloc_log_event (12); + int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_user_blocked; ev[1] = get_peer_id (U->id); ev[2] = blocked; - add_log_event (self, ev, 12); + add_log_event (bl, self, ev, 12); } -void bl_do_set_user_real_name (struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll) { +void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll) { if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) && (U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) { return; @@ -1382,22 +1407,22 @@ void bl_do_set_user_real_name (struct mtproto_connection *self, struct user *U, out_int (self, get_peer_id (U->id)); out_cstring (self, f, fl); out_cstring (self, l, ll); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_encr_chat_delete (struct mtproto_connection *self, struct secret_chat *U) { +void bl_do_encr_chat_delete (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U) { if (!(U->flags & FLAG_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; } - int *ev = alloc_log_event (8); + int *ev = alloc_log_event (bl, 8); ev[0] = CODE_binlog_encr_chat_delete; ev[1] = get_peer_id (U->id); - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_encr_chat_requested (struct mtproto_connection *self, struct secret_chat *U, +void bl_do_encr_chat_requested (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]) { if (U->state != sc_none) { return; } - int *ev = alloc_log_event (540); + int *ev = alloc_log_event (bl, 540); ev[0] = CODE_binlog_encr_chat_requested; ev[1] = get_peer_id (U->id); *(long long *)(ev + 2) = access_hash; @@ -1406,105 +1431,105 @@ void bl_do_encr_chat_requested (struct mtproto_connection *self, struct secret_c ev[6] = user_id; memcpy (ev + 7, g_key, 256); memcpy (ev + 7 + 64, nonce, 256); - add_log_event (self, ev, 540); + add_log_event (bl, self, ev, 540); } -void bl_do_set_encr_chat_access_hash (struct mtproto_connection *self, struct secret_chat *U, +void bl_do_set_encr_chat_access_hash (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash) { if (U->access_hash == access_hash) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 16); ev[0] = CODE_binlog_set_encr_chat_access_hash; ev[1] = get_peer_id (U->id); *(long long *)(ev + 2) = access_hash; - add_log_event (self, ev, 16); + add_log_event (bl, self, ev, 16); } -void bl_do_set_encr_chat_date (struct mtproto_connection *self, struct secret_chat *U, int date) { +void bl_do_set_encr_chat_date (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, int date) { if (U->date == date) { return; } - int *ev = alloc_log_event (12); + int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_set_encr_chat_date; ev[1] = get_peer_id (U->id); ev[2] = date; - add_log_event (self, ev, 12); + add_log_event (bl, self, ev, 12); } -void bl_do_set_encr_chat_state (struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state) { +void bl_do_set_encr_chat_state (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state) { if (U->state == state) { return; } - int *ev = alloc_log_event (12); + int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_set_encr_chat_state; ev[1] = get_peer_id (U->id); ev[2] = state; - add_log_event (self, ev, 12); + add_log_event (bl, self, ev, 12); } -void bl_do_encr_chat_accepted (struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) { +void bl_do_encr_chat_accepted (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) { if (U->state != sc_waiting && U->state != sc_request) { return; } - int *ev = alloc_log_event (528); + int *ev = alloc_log_event (bl, 528); ev[0] = CODE_binlog_encr_chat_accepted; ev[1] = get_peer_id (U->id); memcpy (ev + 2, g_key, 256); memcpy (ev + 66, nonce, 256); *(long long *)(ev + 130) = key_fingerprint; - add_log_event (self, ev, 528); + add_log_event (bl, self, ev, 528); } -void bl_do_set_encr_chat_key (struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint) { - int *ev = alloc_log_event (272); +void bl_do_set_encr_chat_key (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint) { + int *ev = alloc_log_event (bl, 272); ev[0] = CODE_binlog_set_encr_chat_key; ev[1] = get_peer_id (E->id); memcpy (ev + 2, key, 256); *(long long *)(ev + 66) = key_fingerprint; - add_log_event (self, ev, 272); + add_log_event (bl, self, ev, 272); } -void bl_do_set_dh_params (struct mtproto_connection *self, int root, unsigned char prime[], int version) { - int *ev = alloc_log_event (268); +void bl_do_set_dh_params (struct binlog *bl, struct mtproto_connection *self, int root, unsigned char prime[], int version) { + int *ev = alloc_log_event (bl, 268); ev[0] = CODE_binlog_set_dh_params; ev[1] = root; memcpy (ev + 2, prime, 256); ev[66] = version; - add_log_event (self, ev, 268); + add_log_event (bl, self, ev, 268); } -void bl_do_encr_chat_init (struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]) { - int *ev = alloc_log_event (524); +void bl_do_encr_chat_init (struct binlog *bl, struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]) { + int *ev = alloc_log_event (bl, 524); ev[0] = CODE_binlog_encr_chat_init; ev[1] = id; ev[2] = user_id; memcpy (ev + 3, random, 256); memcpy (ev + 67, g_a, 256); - add_log_event (self, ev, 524); + add_log_event (bl, self, ev, 524); } -void bl_do_set_pts (struct mtproto_connection *self, int pts) { - int *ev = alloc_log_event (8); +void bl_do_set_pts (struct binlog *bl, struct mtproto_connection *self, int pts) { + int *ev = alloc_log_event (bl, 8); ev[0] = CODE_binlog_set_pts; ev[1] = pts; - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_set_qts (struct mtproto_connection *self, int qts) { - int *ev = alloc_log_event (8); +void bl_do_set_qts (struct binlog *bl, struct mtproto_connection *self, int qts) { + int *ev = alloc_log_event (bl, 8); ev[0] = CODE_binlog_set_qts; ev[1] = qts; - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_set_date (struct mtproto_connection *self, int date) { - int *ev = alloc_log_event (8); +void bl_do_set_date (struct binlog *bl, struct mtproto_connection *self, int date) { + int *ev = alloc_log_event (bl, 8); ev[0] = CODE_binlog_set_date; ev[1] = date; - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_set_seq (struct mtproto_connection *self, int seq) { - int *ev = alloc_log_event (8); +void bl_do_set_seq (struct binlog *bl, struct mtproto_connection *self, int seq) { + int *ev = alloc_log_event (bl, 8); ev[0] = CODE_binlog_set_seq; ev[1] = seq; - add_log_event (self, ev, 8); + add_log_event (bl, self, ev, 8); } -void bl_do_create_chat (struct mtproto_connection *self, 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_create_chat (struct binlog *bl, struct mtproto_connection *self, 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 (self); out_int (self, CODE_binlog_chat_create); out_int (self, get_peer_id (C->id)); @@ -1515,39 +1540,39 @@ void bl_do_create_chat (struct mtproto_connection *self, struct chat *C, int y, out_int (self, version); out_data (self, big, sizeof (struct file_location)); out_data (self, small, sizeof (struct file_location)); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_chat_forbid (struct mtproto_connection *self, struct chat *C, int on) { +void bl_do_chat_forbid (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on) { if (on) { if (C->flags & FLAG_FORBIDDEN) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 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 (self, ev, 16); + add_log_event (bl, self, ev, 16); } else { if (!(C->flags & FLAG_FORBIDDEN)) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 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 (self, ev, 16); + add_log_event (bl, self, ev, 16); } } -void bl_do_set_chat_title (struct mtproto_connection *self, struct chat *C, const char *s, int l) { +void bl_do_set_chat_title (struct binlog *bl, struct mtproto_connection *self, struct chat *C, const char *s, int l) { if (C->title && (int)strlen (C->title) == l && !strncmp (C->title, s, l)) { return; } clear_packet (self); out_int (self, CODE_binlog_set_chat_title); out_int (self, get_peer_id (C->id)); out_cstring (self, s, l); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_chat_photo (struct mtproto_connection *self, struct chat *C, struct file_location *big, struct file_location *small) { +void bl_do_set_chat_photo (struct binlog *bl, struct mtproto_connection *self, 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 (self); @@ -1555,100 +1580,100 @@ void bl_do_set_chat_photo (struct mtproto_connection *self, struct chat *C, stru out_int (self, get_peer_id (C->id)); out_data (self, big, sizeof (struct file_location)); out_data (self, small, sizeof (struct file_location)); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_chat_date (struct mtproto_connection *self, struct chat *C, int date) { +void bl_do_set_chat_date (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int date) { if (C->date == date) { return; } - int *ev = alloc_log_event (12); + int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_set_chat_date; ev[1] = get_peer_id (C->id); ev[2] = date; - add_log_event (self, ev, 12); + add_log_event (bl, self, ev, 12); } -void bl_do_set_chat_set_in_chat (struct mtproto_connection *self, struct chat *C, int on) { +void bl_do_set_chat_set_in_chat (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on) { if (on) { if (C->flags & FLAG_CHAT_IN_CHAT) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 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 (self, ev, 16); + add_log_event (bl, self, ev, 16); } else { if (!(C->flags & FLAG_CHAT_IN_CHAT)) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 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 (self, ev, 16); + add_log_event (bl, self, ev, 16); } } -void bl_do_set_chat_version (struct mtproto_connection *self, struct chat *C, int version, int user_num) { +void bl_do_set_chat_version (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num) { if (C->version >= version) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 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 (self, ev, 16); + add_log_event (bl, self, ev, 16); } -void bl_do_set_chat_admin (struct mtproto_connection *self, struct chat *C, int admin) { +void bl_do_set_chat_admin (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int admin) { if (C->admin_id == admin) { return; } - int *ev = alloc_log_event (12); + int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_set_chat_admin; ev[1] = get_peer_id (C->id); ev[2] = admin; - add_log_event (self, ev, 12); + add_log_event (bl, self, ev, 12); } -void bl_do_set_chat_participants (struct mtproto_connection *self, struct chat *C, int version, int user_num, struct chat_user *users) { +void bl_do_set_chat_participants (struct binlog *bl, struct mtproto_connection *self, 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); + int *ev = alloc_log_event (bl, 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 (self, ev, 12 * user_num + 16); + add_log_event (bl, self, ev, 12 * user_num + 16); } -void bl_do_set_chat_full_photo (struct mtproto_connection *self, struct chat *U, const int *start, int len) { +void bl_do_set_chat_full_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *U, const int *start, int len) { if (U->photo.id == *(long long *)(start + 1)) { return; } - int *ev = alloc_log_event (len + 8); + int *ev = alloc_log_event (bl, len + 8); ev[0] = CODE_binlog_chat_full_photo; ev[1] = get_peer_id (U->id); memcpy (ev + 2, start, len); - add_log_event (self, ev, len + 8); + add_log_event (bl, self, ev, len + 8); } -void bl_do_chat_add_user (struct mtproto_connection *self, struct chat *C, int version, int user, int inviter, int date) { +void bl_do_chat_add_user (struct binlog *bl, struct mtproto_connection *self, 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); + int *ev = alloc_log_event (bl, 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 (self, ev, 24); + add_log_event (bl, self, ev, 24); } -void bl_do_chat_del_user (struct mtproto_connection *self, struct chat *C, int version, int user) { +void bl_do_chat_del_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user) { if (C->user_list_version >= version || !C->user_list_version) { return; } - int *ev = alloc_log_event (16); + int *ev = alloc_log_event (bl, 16); ev[0] = CODE_binlog_add_chat_participant; ev[1] = get_peer_id (C->id); ev[2] = version; ev[3] = user; - add_log_event (self, ev, 16); + add_log_event (bl, self, ev, 16); } -void bl_do_create_message_text (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { +void bl_do_create_message_text (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { clear_packet (self); out_int (self, CODE_binlog_create_message_text); out_int (self, msg_id); @@ -1657,10 +1682,10 @@ void bl_do_create_message_text (struct mtproto_connection *self, int msg_id, int out_int (self, to_id); out_int (self, date); out_cstring (self, s, l); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_send_message_text (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { +void bl_do_send_message_text (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { clear_packet (self); out_int (self, CODE_binlog_send_message_text); out_long (self, msg_id); @@ -1669,10 +1694,10 @@ void bl_do_send_message_text (struct mtproto_connection *self, long long msg_id, out_int (self, to_id); out_int (self, date); out_cstring (self, s, l); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_text_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s) { +void bl_do_create_message_text_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s) { clear_packet (self); out_int (self, CODE_binlog_create_message_text_fwd); out_int (self, msg_id); @@ -1683,10 +1708,10 @@ void bl_do_create_message_text_fwd (struct mtproto_connection *self, int msg_id, out_int (self, fwd); out_int (self, fwd_date); out_cstring (self, s, l); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_media (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len) { +void bl_do_create_message_media (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len) { clear_packet (self); out_int (self, CODE_binlog_create_message_media); out_int (self, msg_id); @@ -1696,10 +1721,10 @@ void bl_do_create_message_media (struct mtproto_connection *self, int msg_id, in out_int (self, date); out_cstring (self, s, l); out_ints (self, data, len); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_media_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2) { +void bl_do_create_message_media_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2) { clear_packet (self); out_int (self, CODE_binlog_create_message_media_encr); out_long (self, msg_id); @@ -1710,10 +1735,10 @@ void bl_do_create_message_media_encr (struct mtproto_connection *self, long long out_cstring (self, s, l); out_ints (self, data, len); out_ints (self, data2, len2); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_media_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len) { +void bl_do_create_message_media_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len) { clear_packet (self); out_int (self, CODE_binlog_create_message_media_fwd); out_int (self, msg_id); @@ -1725,10 +1750,10 @@ void bl_do_create_message_media_fwd (struct mtproto_connection *self, int msg_id out_int (self, fwd_date); out_cstring (self, s, l); out_ints (self, data, len); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_service (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { +void bl_do_create_message_service (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { clear_packet (self); out_int (self, CODE_binlog_create_message_service); out_int (self, msg_id); @@ -1737,9 +1762,9 @@ void bl_do_create_message_service (struct mtproto_connection *self, int msg_id, out_int (self, to_id); out_int (self, date); out_ints (self, data, len); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_service_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { +void bl_do_create_message_service_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { clear_packet (self); out_int (self, CODE_binlog_create_message_service_encr); out_long (self, msg_id); @@ -1748,10 +1773,10 @@ void bl_do_create_message_service_encr (struct mtproto_connection *self, long lo out_int (self, to_id); out_int (self, date); out_ints (self, data, len); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_create_message_service_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len) { +void bl_do_create_message_service_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len) { clear_packet (self); out_int (self, CODE_binlog_create_message_service_fwd); out_int (self, msg_id); @@ -1762,37 +1787,37 @@ void bl_do_create_message_service_fwd (struct mtproto_connection *self, int msg_ out_int (self, fwd); out_int (self, fwd_date); out_ints (self, data, len); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_unread (struct mtproto_connection *self, struct message *M, int unread) { +void bl_do_set_unread (struct binlog *bl, struct mtproto_connection *self, struct message *M, int unread) { if (unread || !M->unread) { return; } clear_packet (self); out_int (self, CODE_binlog_set_unread); out_int (self, M->id); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_message_sent (struct mtproto_connection *self, struct message *M) { +void bl_do_set_message_sent (struct binlog *bl, struct mtproto_connection *self, struct message *M) { if (!(M->flags & FLAG_PENDING)) { return; } clear_packet (self); out_int (self, CODE_binlog_set_message_sent); out_long (self, M->id); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_msg_id (struct mtproto_connection *self, struct message *M, int id) { +void bl_do_set_msg_id (struct binlog *bl, struct mtproto_connection *self, struct message *M, int id) { if (M->id == id) { return; } clear_packet (self); out_int (self, CODE_binlog_set_msg_id); out_long (self, M->id); out_int (self, id); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_delete_msg (struct mtproto_connection *self, struct message *M) { +void bl_do_delete_msg (struct binlog *bl, struct mtproto_connection *self, struct message *M) { clear_packet (self); out_int (self, CODE_binlog_delete_msg); out_long (self, M->id); - add_log_event (self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); + add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } diff --git a/binlog.h b/binlog.h index 8adc853..fcc73bb 100644 --- a/binlog.h +++ b/binlog.h @@ -84,69 +84,68 @@ #define CODE_binlog_create_message_service_encr 0x8b4b9395 #define CODE_binlog_delete_msg 0xa1d6ab6d -void *alloc_log_event (int l); +void *alloc_log_event (struct binlog *bl, int l); void replay_log (struct telegram *instance); -void add_log_event (struct mtproto_connection *self, const int *data, int l); -void add_log_event_i (struct mtproto_connection *self, struct telegram *instance, const int *data, int l); -void write_binlog (void); +void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int l); +void write_binlog (struct binlog *bl); void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf); -void bl_do_dc_option (struct mtproto_connection *self, int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); +void bl_do_dc_option (struct binlog *bl, struct mtproto_connection *self, int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); -void bl_do_set_our_id (struct mtproto_connection *self, int id); -void bl_do_new_user (struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); -void bl_do_user_delete (struct mtproto_connection *self, struct user *U); -void bl_do_set_user_profile_photo (struct mtproto_connection *self, struct user *U, long long photo_id, struct file_location *big, struct file_location *small); -void bl_do_set_user_name (struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); -void bl_do_set_user_access_token (struct mtproto_connection *self, struct user *U, long long access_token); -void bl_do_set_user_phone (struct mtproto_connection *self, struct user *U, const char *p, int pl); -void bl_do_set_user_friend (struct mtproto_connection *self, struct user *U, int friend); -void bl_do_set_user_full_photo (struct mtproto_connection *self, struct user *U, const int *start, int len); -void bl_do_set_user_blocked (struct mtproto_connection *self, struct user *U, int blocked); -void bl_do_set_user_real_name (struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); +void bl_do_set_our_id (struct binlog *bl, struct mtproto_connection *self, int id); +void bl_do_new_user (struct binlog *bl, struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); +void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct user *U); +void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long photo_id, struct file_location *big, struct file_location *small); +void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); +void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long access_token); +void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *p, int pl); +void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct user *U, int friend); +void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, const int *start, int len); +void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct user *U, int blocked); +void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); -void bl_do_encr_chat_delete (struct mtproto_connection *self, struct secret_chat *U); -void bl_do_encr_chat_requested (struct mtproto_connection *self, struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); -void bl_do_set_encr_chat_access_hash (struct mtproto_connection *self, struct secret_chat *U, long long access_hash); -void bl_do_set_encr_chat_date (struct mtproto_connection *self, struct secret_chat *U, int date); -void bl_do_set_encr_chat_state (struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state); -void bl_do_encr_chat_accepted (struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint); -void bl_do_set_encr_chat_key (struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint); -void bl_do_encr_chat_init (struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]); +void bl_do_encr_chat_delete (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U); +void bl_do_encr_chat_requested (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); +void bl_do_set_encr_chat_access_hash (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash); +void bl_do_set_encr_chat_date (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, int date); +void bl_do_set_encr_chat_state (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state); +void bl_do_encr_chat_accepted (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint); +void bl_do_set_encr_chat_key (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint); +void bl_do_encr_chat_init (struct binlog *bl, struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]); -void bl_do_dc_signed (struct mtproto_connection *self, int id); -void bl_do_set_working_dc (struct mtproto_connection *self, int num); -void bl_do_set_dh_params (struct mtproto_connection *self, int root, unsigned char prime[], int version); +void bl_do_dc_signed (struct binlog *bl, struct mtproto_connection *self, int id); +void bl_do_set_working_dc (struct binlog *bl, struct mtproto_connection *self, int num); +void bl_do_set_dh_params (struct binlog *bl, struct mtproto_connection *self, int root, unsigned char prime[], int version); -void bl_do_set_pts (struct mtproto_connection *self, int pts); -void bl_do_set_qts (struct mtproto_connection *self, int qts); -void bl_do_set_seq (struct mtproto_connection *self, int seq); -void bl_do_set_date (struct mtproto_connection *self, int date); +void bl_do_set_pts (struct binlog *bl, struct mtproto_connection *self, int pts); +void bl_do_set_qts (struct binlog *bl, struct mtproto_connection *self, int qts); +void bl_do_set_seq (struct binlog *bl, struct mtproto_connection *self, int seq); +void bl_do_set_date (struct binlog *bl, struct mtproto_connection *self, int date); -void bl_do_create_chat (struct mtproto_connection *self, 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 mtproto_connection *self, struct chat *C, int on); -void bl_do_set_chat_title (struct mtproto_connection *self, struct chat *C, const char *s, int l); -void bl_do_set_chat_photo (struct mtproto_connection *self, struct chat *C, struct file_location *big, struct file_location *small); -void bl_do_set_chat_date (struct mtproto_connection *self, struct chat *C, int date); -void bl_do_set_chat_set_in_chat (struct mtproto_connection *self, struct chat *C, int on); -void bl_do_set_chat_version (struct mtproto_connection *self, struct chat *C, int version, int user_num); -void bl_do_set_chat_admin (struct mtproto_connection *self, struct chat *C, int admin); -void bl_do_set_chat_participants (struct mtproto_connection *self, struct chat *C, int version, int user_num, struct chat_user *users); -void bl_do_set_chat_full_photo (struct mtproto_connection *self, struct chat *U, const int *start, int len); -void bl_do_chat_add_user (struct mtproto_connection *self, struct chat *C, int version, int user, int inviter, int date); -void bl_do_chat_del_user (struct mtproto_connection *self, struct chat *C, int version, int user); +void bl_do_create_chat (struct binlog *bl, struct mtproto_connection *self, 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 binlog *bl, struct mtproto_connection *self, struct chat *C, int on); +void bl_do_set_chat_title (struct binlog *bl, struct mtproto_connection *self, struct chat *C, const char *s, int l); +void bl_do_set_chat_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *C, struct file_location *big, struct file_location *small); +void bl_do_set_chat_date (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int date); +void bl_do_set_chat_set_in_chat (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on); +void bl_do_set_chat_version (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num); +void bl_do_set_chat_admin (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int admin); +void bl_do_set_chat_participants (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num, struct chat_user *users); +void bl_do_set_chat_full_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *U, const int *start, int len); +void bl_do_chat_add_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user, int inviter, int date); +void bl_do_chat_del_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user); -void bl_do_create_message_text (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); -void bl_do_create_message_text_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s); -void bl_do_create_message_service (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); -void bl_do_create_message_service_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len); -void bl_do_create_message_media (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len); -void bl_do_create_message_media_fwd (struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len); -void bl_do_create_message_media_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2); -void bl_do_create_message_service_encr (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); -void bl_do_send_message_text (struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); -void bl_do_set_unread (struct mtproto_connection *self, struct message *M, int unread); -void bl_do_set_message_sent (struct mtproto_connection *self, struct message *M); -void bl_do_set_msg_id (struct mtproto_connection *self, struct message *M, int id); -void bl_do_delete_msg (struct mtproto_connection *self, struct message *M); +void bl_do_create_message_text (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); +void bl_do_create_message_text_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s); +void bl_do_create_message_service (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); +void bl_do_create_message_service_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len); +void bl_do_create_message_media (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len); +void bl_do_create_message_media_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len); +void bl_do_create_message_media_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2); +void bl_do_create_message_service_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); +void bl_do_send_message_text (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); +void bl_do_set_unread (struct binlog *bl, struct mtproto_connection *self, struct message *M, int unread); +void bl_do_set_message_sent (struct binlog *bl, struct mtproto_connection *self, struct message *M); +void bl_do_set_msg_id (struct binlog *bl, struct mtproto_connection *self, struct message *M, int id); +void bl_do_delete_msg (struct binlog *bl, struct mtproto_connection *self, struct message *M); #endif diff --git a/mtproto-client.c b/mtproto-client.c index a4b94d9..2b8f84a 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -781,7 +781,7 @@ void fetch_pts (struct mtproto_connection *self) { } else { self->pts ++; } - bl_do_set_pts (self, self->pts); + bl_do_set_pts (self->bl, self, self->pts); } void fetch_qts (struct mtproto_connection *self) { @@ -798,14 +798,14 @@ void fetch_qts (struct mtproto_connection *self) { } else { self->qts ++; } - bl_do_set_qts (self, self->qts); + bl_do_set_qts (self->bl, self, self->qts); } void fetch_date (struct mtproto_connection *self) { int p = fetch_int (self); if (p > self->last_date) { self->last_date = p; - bl_do_set_date (self, self->last_date); + bl_do_set_date (self->bl, self, self->last_date); } } @@ -817,7 +817,7 @@ void fetch_seq (struct mtproto_connection *self) { //seq = x; } else if (x == self->seq + 1) { self->seq = x; - bl_do_set_seq (self, self->seq); + bl_do_set_seq (self->bl, self, self->seq); } } @@ -908,7 +908,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { int new = fetch_long (self); // random_id struct message *M = message_get (new); if (M) { - bl_do_set_msg_id (self, M, id); + bl_do_set_msg_id (self->bl, self, M, id); } } break; @@ -921,7 +921,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { int id = fetch_int (self); struct message *M = message_get (id); if (M) { - bl_do_set_unread (self, M, 0); + bl_do_set_unread (self->bl, self, M, 0); } } fetch_pts (self); @@ -1004,7 +1004,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { int l2 = prefetch_strlen (self); char *l = fetch_str (self, l2); struct user *U = &UC->user; - bl_do_set_user_real_name (self, U, f, l1, l, l2); + bl_do_set_user_real_name (self->bl, self, U, f, l1, l, l2); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1044,7 +1044,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { fetch_file_location (self, &small); fetch_file_location (self, &big); } - bl_do_set_user_profile_photo (self, U, photo_id, &big, &small); + bl_do_set_user_profile_photo (self->bl, self, U, photo_id, &big, &small); //print_start (); //push_color (COLOR_YELLOW); @@ -1105,7 +1105,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_t *C = user_chat_get (chat_id); if (C && (C->flags & FLAG_CREATED)) { if (x == CODE_chat_participants) { - bl_do_set_chat_admin (self, &C->chat, fetch_int (self)); + bl_do_set_chat_admin (self->bl, self, &C->chat, fetch_int (self)); assert (fetch_int (self) == CODE_vector); n = fetch_int (self); struct chat_user *users = talloc (12 * n); @@ -1117,7 +1117,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { users[i].date = fetch_int (self); } int version = fetch_int (self); - bl_do_set_chat_participants (self, &C->chat, version, n, users); + bl_do_set_chat_participants (self->bl, self, &C->chat, version, n, users); } } else { if (x == CODE_chat_participants) { @@ -1330,7 +1330,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_t *C = user_chat_get (chat_id); if (C && (C->flags & FLAG_CREATED)) { - bl_do_chat_add_user (self, &C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); + bl_do_chat_add_user (self->bl, self, &C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); } //print_start (); @@ -1355,7 +1355,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_t *C = user_chat_get (chat_id); if (C && (C->flags & FLAG_CREATED)) { - bl_do_chat_del_user (self, &C->chat, version, get_peer_id (user_id)); + bl_do_chat_del_user (self->bl, self, &C->chat, version, get_peer_id (user_id)); } //print_start (); @@ -1415,8 +1415,8 @@ void work_updates (struct connection *c, long long msg_id) { for (i = 0; i < n; i++) { fetch_alloc_chat (self); } - bl_do_set_date (self, fetch_int (c->mtconnection)); - bl_do_set_seq (self, fetch_int (c->mtconnection)); + bl_do_set_date (self->bl, self, fetch_int (c->mtconnection)); + bl_do_set_seq (self->bl, self, fetch_int (c->mtconnection)); } void work_update_short_message (struct connection *c UU, long long msg_id UU) { @@ -1870,6 +1870,10 @@ struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *t memset(mtp, 0, sizeof(struct mtproto_connection)); mtp->packet_buffer = mtp->__packet_buffer + 16; mtp->connection = fd_create_connection(DC, fd, tg, &mtproto_methods, mtp); + + // binlog must exist + assert (tg->bl); + mtp->bl = tg->bl; return mtp; } diff --git a/mtproto-client.h b/mtproto-client.h index 392c392..c2d38d8 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -238,10 +238,18 @@ struct mtproto_connection { // the amount of currently outgoing messages that // have not yet received a response int queries_num; + + // binlog that consumes all updates and events of this connection + struct binlog *bl; + + // marks this connection for destruction, so it + // will be freed once all queries received a response or timed out + int destroy; }; void mtproto_connection_init (struct mtproto_connection *c); struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg); +void mtproto_close(struct mtproto_connection *c); void mtproto_connect(struct mtproto_connection *c); void on_start (struct mtproto_connection *self); diff --git a/queries.c b/queries.c index 494b627..6de2a83 100644 --- a/queries.c +++ b/queries.c @@ -355,7 +355,7 @@ void fetch_dc_option (struct telegram *instance) { int port = fetch_int (mtp); logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - bl_do_dc_option (mtp, id, l1, name, l2, ip, port, instance); + bl_do_dc_option (mtp->bl, mtp, id, l1, name, l2, ip, port, instance); } int help_get_config_on_answer (struct query *q UU) { @@ -686,7 +686,7 @@ int sign_in_on_answer (struct query *q UU) { fetch_user (mtp, &User); if (!our_id) { our_id = get_peer_id (User.id); - bl_do_set_our_id (mtp, our_id); + bl_do_set_our_id (mtp->bl, mtp, our_id); } sign_in_ok = 1; if (verbosity) { @@ -694,7 +694,7 @@ int sign_in_on_answer (struct query *q UU) { } DC_working->has_auth = 1; - bl_do_dc_signed (mtp, DC_working->id); + bl_do_dc_signed (mtp->bl, mtp, DC_working->id); return 0; } @@ -914,7 +914,7 @@ int msg_send_encr_on_answer (struct query *q UU) { struct message *M = q->extra; //M->date = fetch_int (mtp); fetch_int (mtp); - bl_do_set_message_sent (mtp, M); + bl_do_set_message_sent (mtp->bl, mtp, M); return 0; } @@ -925,7 +925,7 @@ int msg_send_on_answer (struct query *q UU) { assert (x == CODE_messages_sent_message || x == CODE_messages_sent_message_link); int id = fetch_int (mtp); // id struct message *M = q->extra; - bl_do_set_msg_id (mtp, M, id); + bl_do_set_msg_id (mtp->bl, mtp, M, id); fetch_date (mtp); fetch_pts (mtp); fetch_seq (mtp); @@ -969,7 +969,7 @@ int msg_send_on_answer (struct query *q UU) { } } logprintf ("Sent: id = %d\n", id); - bl_do_set_message_sent (mtp, M); + bl_do_set_message_sent (mtp->bl, mtp, M); return 0; } @@ -978,7 +978,7 @@ int msg_send_on_error (struct query *q, int error_code, int error_len, char *err logprintf ( "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error); struct message *M = q->extra; - bl_do_delete_msg (mtp, M); + bl_do_delete_msg (mtp->bl, mtp, M); return 0; } @@ -1053,7 +1053,7 @@ void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, long long t; secure_random (&t, 8); logprintf ("t = %lld, len = %d\n", t, len); - bl_do_send_message_text (mtp, t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); + bl_do_send_message_text (mtp->bl, mtp, t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); struct message *M = message_get (t); assert (M); do_send_msg (instance, M); @@ -2570,7 +2570,7 @@ void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, static unsigned char sha_buffer[20]; sha1 (kk, 256, sha_buffer); - bl_do_set_encr_chat_key (mtp, E, kk, *(long long *)(sha_buffer + 12)); + bl_do_set_encr_chat_key (mtp->bl, mtp, E, kk, *(long long *)(sha_buffer + 12)); clear_packet (mtp); out_int (mtp, CODE_messages_accept_encryption); @@ -2685,7 +2685,7 @@ void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char t = lrand48 (); } - bl_do_encr_chat_init (mtp, t, user_id, (void *)random, (void *)g_a); + bl_do_encr_chat_init (mtp->bl, mtp, t, user_id, (void *)random, (void *)g_a); peer_t *_E = user_chat_get (MK_ENCR_CHAT (t)); assert (_E); struct secret_chat *E = &_E->encr_chat; @@ -2731,7 +2731,7 @@ int get_dh_config_on_answer (struct query *q UU) { assert (l == 256); char *s = fetch_str (mtp, l); int v = fetch_int (mtp); - bl_do_set_dh_params (mtp, a, (void *)s, v); + bl_do_set_dh_params (mtp->bl, mtp, a, (void *)s, v); BIGNUM *p = BN_bin2bn ((void *)s, 256, 0); ensure_ptr (p); @@ -2805,10 +2805,10 @@ int get_state_on_answer (struct query *q UU) { logprintf("get_state_on_answer()\n"); assert (fetch_int (mtp) == (int)CODE_updates_state); - bl_do_set_pts (mtp, fetch_int (mtp)); - bl_do_set_qts (mtp, fetch_int (mtp)); - bl_do_set_date (mtp, fetch_int (mtp)); - bl_do_set_seq (mtp, fetch_int (mtp)); + bl_do_set_pts (mtp->bl, mtp, fetch_int (mtp)); + bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); + bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); + bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); unread_messages = fetch_int (mtp); //write_state_file (); difference_got = 1; @@ -2824,8 +2824,8 @@ int get_difference_on_answer (struct query *q UU) { get_difference_active = 0; unsigned x = fetch_int (mtp); if (x == CODE_updates_difference_empty) { - bl_do_set_date (mtp, fetch_int (mtp)); - bl_do_set_seq (mtp, fetch_int (mtp)); + bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); + bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); difference_got = 1; } else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) { int n, i; @@ -2867,10 +2867,10 @@ int get_difference_on_answer (struct query *q UU) { fetch_alloc_user (mtp); } assert (fetch_int (mtp) == (int)CODE_updates_state); - bl_do_set_pts (mtp, fetch_int (mtp)); - bl_do_set_qts (mtp, fetch_int (mtp)); - bl_do_set_date (mtp, fetch_int (mtp)); - bl_do_set_seq (mtp, fetch_int (mtp)); + bl_do_set_pts (mtp->bl, mtp, fetch_int (mtp)); + bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); + bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); + bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); unread_messages = fetch_int (mtp); //write_state_file (); for (i = 0; i < ml_pos; i++) { diff --git a/structures.c b/structures.c index 2dd3101..30501f0 100644 --- a/structures.c +++ b/structures.c @@ -189,7 +189,7 @@ long long fetch_user_photo (struct mtproto_connection *mtp, struct user *U) { unsigned x = fetch_int (mtp); code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); if (x == CODE_user_profile_photo_empty) { - bl_do_set_user_profile_photo (mtp, U, 0, 0, 0); + bl_do_set_user_profile_photo (mtp->bl, mtp, U, 0, 0, 0); return 0; } long long photo_id = 1; @@ -201,7 +201,7 @@ long long fetch_user_photo (struct mtproto_connection *mtp, struct user *U) { code_try (fetch_file_location (mtp, &small)); code_try (fetch_file_location (mtp, &big)); - bl_do_set_user_profile_photo (mtp, U, photo_id, &big, &small); + bl_do_set_user_profile_photo (mtp->bl, mtp, U, photo_id, &big, &small); return 0; } @@ -231,7 +231,7 @@ int fetch_user (struct mtproto_connection *mtp, struct user *U) { if (x == CODE_user_self) { assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { - bl_do_set_our_id (mtp, get_peer_id (U->id)); + bl_do_set_our_id (mtp->bl, mtp, get_peer_id (U->id)); // TODO: What to do here? //write_auth_file (); } @@ -250,8 +250,8 @@ int fetch_user (struct mtproto_connection *mtp, struct user *U) { char *s2 = fetch_str (mtp, l2); if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_new_user (mtp, get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); - bl_do_user_delete (mtp, U); + bl_do_new_user (mtp->bl, mtp, get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); + bl_do_user_delete (mtp->bl, mtp, U); } if (x != CODE_user_deleted) { long long access_token = 0; @@ -265,7 +265,7 @@ int fetch_user (struct mtproto_connection *mtp, struct user *U) { code_assert (phone_len >= 0); phone = fetch_str (mtp, phone_len); } - bl_do_new_user (mtp, get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); + bl_do_new_user (mtp->bl, mtp, get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); if (fetch_user_photo (mtp, U) < 0) { return -1; } if (fetch_user_status (mtp, &U->status) < 0) { return -1; } @@ -279,19 +279,19 @@ int fetch_user (struct mtproto_connection *mtp, struct user *U) { int l2 = prefetch_strlen (mtp); char *s2 = fetch_str (mtp, l2); - bl_do_set_user_name (mtp, U, s1, l1, s2, l2); + bl_do_set_user_name (mtp->bl, mtp, U, s1, l1, s2, l2); if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_user_delete (mtp, U); + bl_do_user_delete (mtp->bl, mtp, U); } if (x != CODE_user_deleted) { if (x != CODE_user_self) { - bl_do_set_user_access_token (mtp, U, fetch_long (mtp)); + bl_do_set_user_access_token (mtp->bl, mtp, U, fetch_long (mtp)); } if (x != CODE_user_foreign) { int l = prefetch_strlen (mtp); char *s = fetch_str (mtp, l); - bl_do_set_user_phone (mtp, U, s, l); + bl_do_set_user_phone (mtp->bl, mtp, U, s, l); } if (fetch_user_photo (mtp, U) < 0) { return -1; } @@ -301,9 +301,9 @@ int fetch_user (struct mtproto_connection *mtp, struct user *U) { } if (x == CODE_user_contact) { - bl_do_set_user_friend (mtp, U, 1); + bl_do_set_user_friend (mtp->bl, mtp, U, 1); } else { - bl_do_set_user_friend (mtp, U, 0); + bl_do_set_user_friend (mtp->bl, mtp, U, 0); } } } @@ -324,7 +324,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U logprintf ("Unknown chat in deleted state. May be we forgot something...\n"); return; } - bl_do_encr_chat_delete (mtp, U); + bl_do_encr_chat_delete (mtp->bl, mtp, U); // TODO: properly write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); @@ -375,11 +375,11 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U return; } - bl_do_encr_chat_requested (mtp, U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); + bl_do_encr_chat_requested (mtp->bl, mtp, U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); } else { - bl_do_set_encr_chat_access_hash (mtp, U, fetch_long (mtp)); - bl_do_set_encr_chat_date (mtp, U, fetch_int (mtp)); + bl_do_set_encr_chat_access_hash (mtp->bl, mtp, U, fetch_long (mtp)); + bl_do_set_encr_chat_date (mtp->bl, mtp, U, fetch_int (mtp)); if (fetch_int (mtp) != U->admin_id) { logprintf ("Changed admin in secret chat. WTF?\n"); return; @@ -389,7 +389,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U return; } if (x == CODE_encrypted_chat_waiting) { - bl_do_set_encr_chat_state (mtp, U, sc_waiting); + bl_do_set_encr_chat_state (mtp->bl, mtp, U, sc_waiting); write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); return; // We needed only access hash from here } @@ -420,7 +420,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U if (x == CODE_encrypted_chat_requested) { return; // Duplicate? } - bl_do_encr_chat_accepted (mtp, U, (void *)g_key, (void *)nonce, fetch_long (mtp)); + bl_do_encr_chat_accepted (mtp->bl, mtp, U, (void *)g_key, (void *)nonce, fetch_long (mtp)); } write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); } @@ -445,16 +445,16 @@ void fetch_user_full (struct mtproto_connection *mtp, struct user *U) { int *start = mtp->in_ptr; fetch_skip_photo (mtp); - bl_do_set_user_full_photo (mtp, U, start, 4 * (mtp->in_ptr - start)); + bl_do_set_user_full_photo (mtp->bl, mtp, U, start, 4 * (mtp->in_ptr - start)); fetch_notify_settings (mtp); - bl_do_set_user_blocked (mtp, U, fetch_bool (mtp)); + bl_do_set_user_blocked (mtp->bl, mtp, U, fetch_bool (mtp)); int l1 = prefetch_strlen (mtp); char *s1 = fetch_str (mtp, l1); int l2 = prefetch_strlen (mtp); char *s2 = fetch_str (mtp, l2); - bl_do_set_user_real_name (mtp, U, s1, l1, s2, l2); + bl_do_set_user_real_name (mtp->bl, mtp, U, s1, l1, s2, l2); } void fetch_chat (struct mtproto_connection *mtp, struct chat *C) { @@ -505,16 +505,16 @@ void fetch_chat (struct mtproto_connection *mtp, struct chat *C) { version = -1; } - bl_do_create_chat (mtp, C, y, s, l, users_num, date, version, &big, &small); + bl_do_create_chat (mtp->bl, mtp, C, y, s, l, users_num, date, version, &big, &small); } else { if (x == CODE_chat_forbidden) { - bl_do_chat_forbid (mtp, C, 1); + bl_do_chat_forbid (mtp->bl, mtp, C, 1); } else { - bl_do_chat_forbid (mtp, C, 0); + bl_do_chat_forbid (mtp->bl, mtp, C, 0); } int l = prefetch_strlen (mtp); char *s = fetch_str (mtp, l); - bl_do_set_chat_title (mtp, C, s, l); + bl_do_set_chat_title (mtp->bl, mtp, C, s, l); struct file_location small; struct file_location big; @@ -531,13 +531,13 @@ void fetch_chat (struct mtproto_connection *mtp, struct chat *C) { fetch_file_location (mtp, &small); fetch_file_location (mtp, &big); } - bl_do_set_chat_photo (mtp, C, &big, &small); + bl_do_set_chat_photo (mtp->bl, mtp, C, &big, &small); int users_num = fetch_int (mtp); - bl_do_set_chat_date (mtp, C, fetch_int (mtp)); - bl_do_set_chat_set_in_chat (mtp, C, fetch_bool (mtp)); - bl_do_set_chat_version (mtp, C, users_num, fetch_int (mtp)); + bl_do_set_chat_date (mtp->bl, mtp, C, fetch_int (mtp)); + bl_do_set_chat_set_in_chat (mtp->bl, mtp, C, fetch_bool (mtp)); + bl_do_set_chat_version (mtp->bl, mtp, C, users_num, fetch_int (mtp)); } else { - bl_do_set_chat_date (mtp, C, fetch_int (mtp)); + bl_do_set_chat_date (mtp->bl, mtp, C, fetch_int (mtp)); } } } @@ -606,13 +606,13 @@ void fetch_chat_full (struct mtproto_connection *mtp, struct chat *C) { fetch_alloc_user (mtp); } if (admin_id) { - bl_do_set_chat_admin (mtp, C, admin_id); + bl_do_set_chat_admin (mtp->bl, mtp, C, admin_id); } if (version > 0) { - bl_do_set_chat_participants (mtp, C, version, users_num, users); + bl_do_set_chat_participants (mtp->bl, mtp, C, version, users_num, users); tfree (users, sizeof (struct chat_user) * users_num); } - bl_do_set_chat_full_photo (mtp, C, start, 4 * (end - start)); + bl_do_set_chat_full_photo (mtp->bl, mtp, C, start, 4 * (end - start)); } void fetch_photo_size (struct mtproto_connection *mtp, struct photo_size *S) { @@ -889,7 +889,7 @@ void fetch_message_short (struct mtproto_connection *mtp, struct message *M) { int date = fetch_int (mtp); fetch_seq (mtp); - bl_do_create_message_text (mtp, id, from_id, PEER_USER, to_id, date, l, s); + bl_do_create_message_text (mtp->bl, mtp, id, from_id, PEER_USER, to_id, date, l, s); } else { fetch_int (mtp); // id fetch_int (mtp); // from_id @@ -917,7 +917,7 @@ void fetch_message_short_chat (struct mtproto_connection *mtp, struct message *M int date = fetch_int (mtp); fetch_seq (mtp); - bl_do_create_message_text (mtp, id, from_id, PEER_CHAT, to_id, date, l, s); + bl_do_create_message_text (mtp->bl, mtp, id, from_id, PEER_CHAT, to_id, date, l, s); } else { fetch_int (mtp); // id fetch_int (mtp); // from_id @@ -1302,10 +1302,10 @@ void fetch_message (struct mtproto_connection *mtp, struct message *M) { fetch_skip_message_action (mtp); if (new) { if (fwd_from_id) { - bl_do_create_message_service_fwd (mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), + bl_do_create_message_service_fwd (mtp->bl, mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, fwd_from_id, fwd_date, start, (mtp->in_ptr - start)); } else { - bl_do_create_message_service (mtp, id, from_id, get_peer_type (to_id), + bl_do_create_message_service (mtp->bl, mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, start, (mtp->in_ptr - start)); } } @@ -1316,15 +1316,15 @@ void fetch_message (struct mtproto_connection *mtp, struct message *M) { fetch_skip_message_media (mtp); if (new) { if (fwd_from_id) { - bl_do_create_message_media_fwd (mtp, id, from_id, get_peer_type (to_id), + bl_do_create_message_media_fwd (mtp->bl, mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, fwd_from_id, fwd_date, l, s, start, mtp->in_ptr - start); } else { - bl_do_create_message_media (mtp, id, from_id, get_peer_type (to_id), + bl_do_create_message_media (mtp->bl, mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), date, l, s, start, mtp->in_ptr - start); } } } - bl_do_set_unread (mtp, M, unread); + bl_do_set_unread (mtp->bl, mtp, M, unread); } void fetch_geo_message (struct mtproto_connection *mtp, struct message *M) { @@ -1481,7 +1481,7 @@ void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) int *start_file = mtp->in_ptr; fetch_skip_encrypted_message_file (mtp); if (x == CODE_decrypted_message) { - bl_do_create_message_media_encr (mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, mtp->in_ptr - start_file); + bl_do_create_message_media_encr (mtp->bl, mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, mtp->in_ptr - start_file); } } else { x = fetch_int (mtp); @@ -1494,7 +1494,7 @@ void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) } } else { if (ok && x == CODE_decrypted_message_service) { - bl_do_create_message_service_encr (mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, start, end - start); + bl_do_create_message_service_encr (mtp->bl, mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, start, end - start); } } } diff --git a/telegram.c b/telegram.c index 30058a3..87b8dbc 100755 --- a/telegram.c +++ b/telegram.c @@ -11,6 +11,9 @@ #include "glib.h" #include "tools.h" #include "mtproto-client.h" +#include "binlog.h" + + /* * New message received @@ -116,6 +119,7 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf //this->curr_dc = 0; this->auth.DC_list[0] = DC; this->change_state_listeners = NULL; + this->bl = talloc0 (sizeof(struct binlog)); this->login = g_strdup(login); this->config_path = g_strdup_printf("%s/%s", config_path, login); @@ -145,6 +149,7 @@ void telegram_free(struct telegram *this) g_free(this->state_path); g_free(this->secret_path); free(this); + tfree(this->bl, sizeof(struct binlog)); } void assert_file_usable(const char *file) diff --git a/telegram.h b/telegram.h index 30f70ee..c7ce000 100644 --- a/telegram.h +++ b/telegram.h @@ -65,6 +65,24 @@ struct authorization_state; // Ready for sending and receiving messages #define STATE_READY 22 +/** + * Binary log + */ + +#define BINLOG_BUFFER_SIZE (1 << 20) +struct binlog { + int binlog_buffer[BINLOG_BUFFER_SIZE]; + int *rptr; + int *wptr; + int test_dc; // = 0 + int in_replay_log; + int binlog_enabled; // = 0; + int binlog_fd; + long long binlog_pos; + + int s[1000]; +}; + /** * A telegram session * From 7720beab6e2e31ca2e7b1970e2959641fcdcacbc Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 17:13:25 +0200 Subject: [PATCH 340/465] Remove global configuration flags --- loop.c | 2 +- main.c | 2 +- queries.c | 3 --- structures.c | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/loop.c b/loop.c index 95dc4da..90be491 100644 --- a/loop.c +++ b/loop.c @@ -59,7 +59,7 @@ extern char *auth_token; -extern int test_dc; +int test_dc = 0; int default_dc_num; extern int binlog_enabled; diff --git a/main.c b/main.c index ff68e14..0894f86 100644 --- a/main.c +++ b/main.c @@ -89,7 +89,7 @@ char *secret_chat_file_name; char *downloads_directory; char *config_directory; char *binlog_file_name; -int binlog_enabled; +extern int binlog_enabled; extern int log_level; int log_level = 1; int sync_from_start; diff --git a/queries.c b/queries.c index 6de2a83..86c3170 100644 --- a/queries.c +++ b/queries.c @@ -71,12 +71,9 @@ long long cur_uploaded_bytes; long long cur_downloading_bytes; long long cur_downloaded_bytes; -extern int binlog_enabled; extern int sync_from_start; int sync_from_start = 0; -//int queries_num = 0; - void telegram_flush_queries (struct telegram *instance) { instance->on_output(instance); } diff --git a/structures.c b/structures.c index 30501f0..de7f5c5 100644 --- a/structures.c +++ b/structures.c @@ -65,7 +65,6 @@ int our_id; int verbosity; peer_t *Peers[MAX_PEER_NUM]; -extern int binlog_enabled; void fetch_skip_photo (struct mtproto_connection *mtp); From e667299d2fcceeeada0f468e92724a53781081ac Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 17:14:08 +0200 Subject: [PATCH 341/465] Add binlog to telegram struct --- telegram.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/telegram.h b/telegram.h index c7ce000..66fbfd0 100644 --- a/telegram.h +++ b/telegram.h @@ -115,6 +115,11 @@ struct telegram { */ struct mtproto_connection *connection; + /* + * binlog + */ + struct binlog *bl; + /* * callbacks */ From e4bb5bf5a667e4d7810e0118763661ae9dd889dc Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 17:21:46 +0200 Subject: [PATCH 342/465] Count pending queries using the elements in the query tree, instead of counting the incoming and outgoing messages Since the server is able to send queries without any response, and is also able to send multiple responses to an arbitrary query, the current way to count pending queries is not accurate and will lead to errors. Instead, the amount of queries in the query tree will be determined to decide whether there are pending messages. --- mtproto-client.c | 11 ++++------- queries.c | 10 ++++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 2b8f84a..80bd734 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -215,8 +215,6 @@ int rpc_send_packet (struct connection *c) { self->total_packets_sent ++; self->total_data_sent += total_len; - self->queries_num ++; - logprintf("queries_num=%d\n", self->queries_num); return 1; } @@ -238,9 +236,6 @@ int rpc_send_message (struct connection *c, void *data, int len) { self->total_packets_sent ++; self->total_data_sent += total_len; - - self->queries_num ++; - logprintf("queries_num=%d\n", self->queries_num); return 1; } @@ -1711,8 +1706,6 @@ int rpc_execute (struct connection *c, int op, int len) { logprintf ("outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); struct mtproto_connection *self = c->mtconnection; - self->queries_num --; - logprintf ("queries_num=%d\n", c->mtconnection->queries_num); /* if (op < 0) { assert (read_in (c, Response, Response_len) == Response_len); @@ -1747,6 +1740,8 @@ int rpc_execute (struct connection *c, int op, int len) { return 0; case st_client_dh_sent: process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); + self->queries_num --; + logprintf ("queries_num=%d\n", c->mtconnection->queries_num); if (self->on_ready) { self->on_ready(self, self->on_ready_data); } @@ -1786,6 +1781,8 @@ int tc_becomes_ready (struct connection *c) { } switch (o) { case st_init: + c->mtconnection->queries_num ++; + logprintf ("queries_num=%d\n", c->mtconnection->queries_num); send_req_pq_packet (c); break; case st_authorized: diff --git a/queries.c b/queries.c index 86c3170..2b7e845 100644 --- a/queries.c +++ b/queries.c @@ -158,6 +158,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth } } queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); + logprintf("queries_num: %d\n", ++ mtc->queries_num); q->ev.alarm = (void *)alarm_query; q->ev.timeout = get_double_time () + QUERY_TIMEOUT; @@ -197,6 +198,8 @@ void query_error (long long id) { remove_event_timer (&q->ev); } queries_tree = tree_delete_query (queries_tree, q); + logprintf("queries_num: %d\n", -- mtp->queries_num); + if (q->methods && q->methods->on_error) { q->methods->on_error (q, error_code, error_len, error); } else { @@ -204,10 +207,9 @@ void query_error (long long id) { } tfree (q->data, q->data_len * 4); tfree (q, sizeof (*q)); + return; } - mtp->queries_num --; - logprintf("queries_num: %d\n", mtp->queries_num); } #define MAX_PACKED_SIZE (1 << 24) @@ -253,6 +255,8 @@ void query_result (long long id UU) { remove_event_timer (&q->ev); } queries_tree = tree_delete_query (queries_tree, q); + logprintf("queries_num: %d\n", -- mtp->queries_num); + if (q->methods && q->methods->on_answer) { q->methods->on_answer (q); assert (mtp->in_ptr == mtp->in_end); @@ -264,8 +268,6 @@ void query_result (long long id UU) { mtp->in_ptr = end; mtp->in_end = eend; } - //queries_num --; - //logprintf("queries_num: %d\n", queries_num); } #define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) From 54091b26e3752a8964b1377e7b08ad55bde7dd0f Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 17:33:49 +0200 Subject: [PATCH 343/465] Log all output of verbosity-level 1 to libpurple log --- binlog.c | 4 +--- mtproto-client.c | 55 ++++++++++++++++++++++++------------------------ mtproto-client.h | 1 + mtproto-common.c | 4 +--- net.c | 36 ++++++++----------------------- queries.c | 29 +++++++------------------ telegram.c | 10 ++++++--- tools.c | 2 +- 8 files changed, 55 insertions(+), 86 deletions(-) diff --git a/binlog.c b/binlog.c index 9be90c0..d8b7421 100644 --- a/binlog.c +++ b/binlog.c @@ -96,9 +96,7 @@ void replay_log_event (struct telegram *instance) { int l2 = prefetch_strlen (self); char *ip = fetch_str (self, l2); int port = fetch_int (self); - if (verbosity) { - logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - } + logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); alloc_dc (instance->auth.DC_list, id, tstrndup (ip, l2), port); } bl->rptr = self->in_ptr; diff --git a/mtproto-client.c b/mtproto-client.c index 80bd734..23dd2e4 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -154,9 +154,7 @@ static int rsa_load_public_key (const char *public_key_name) { return -1; } - if (verbosity) { - logprintf ( "public key '%s' loaded successfully\n", rsa_public_key_name); - } + logprintf ( "public key '%s' loaded successfully\n", rsa_public_key_name); return 0; } @@ -1441,9 +1439,7 @@ void work_update_short_chat_message (struct connection *c, long long msg_id UU) } void work_container (struct connection *c, long long msg_id UU) { - if (verbosity) { - logprintf ( "work_container: msg_id = %lld\n", msg_id); - } + logprintf ( "work_container: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == CODE_msg_container); int n = fetch_int (c->mtconnection); int i; @@ -1464,38 +1460,47 @@ void work_container (struct connection *c, long long msg_id UU) { } void work_new_session_created (struct connection *c, long long msg_id UU) { - if (verbosity) { - logprintf ( "work_new_session_created: msg_id = %lld\n", msg_id); - } + logprintf ( "work_new_session_created: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == (int)CODE_new_session_created); fetch_long (c->mtconnection); // first message id //DC->session_id = fetch_long (); fetch_long (c->mtconnection); // unique_id GET_DC(c)->server_salt = fetch_long (c->mtconnection); + logprintf ("new server_salt = %lld\n", GET_DC(c)->server_salt); + + + /* + // create a new empty session + assert (DC->working_sess + 1 < 3); + assert (!DC->sessions[++ DC->working_sess]); + struct session *s = DC->sessions[DC->working_sess] = alloc_session(); + // DC->session_id = fetch_long (); + // long las_id = fetch_long (c->mtconnection); + long ses_id = fetch_long (c->mtconnection); + //s->session_id = ses_id; + logprintf ("new sess_id = %ld\n", ses_id); + + // fetch_long (c->mtconnection); // unique_id + DC->server_salt = fetch_long (c->mtconnection); + */ } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { - if (verbosity) { - logprintf ( "work_msgs_ack: msg_id = %lld\n", msg_id); - } + logprintf ( "work_msgs_ack: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == CODE_msgs_ack); assert (fetch_int (c->mtconnection) == CODE_vector); int n = fetch_int (c->mtconnection); int i; for (i = 0; i < n; i++) { long long id = fetch_long (c->mtconnection); - if (verbosity) { - logprintf ("ack for %lld\n", id); - } + logprintf ("ack for %lld\n", id); query_ack (id); } } void work_rpc_result (struct connection *c UU, long long msg_id UU) { - if (verbosity) { - logprintf ( "work_rpc_result: msg_id = %lld\n", msg_id); - } + logprintf ( "work_rpc_result: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == (int)CODE_rpc_result); long long id = fetch_long (c->mtconnection); int op = prefetch_int (c->mtconnection); @@ -1639,9 +1644,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - if (verbosity) { - logprintf ( "process_rpc_message(), len=%d\n", len); - } + logprintf ( "process_rpc_message(), len=%d\n", len); assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); struct dc *DC = GET_DC(c); assert (enc->auth_key_id == DC->auth_key_id); @@ -1676,10 +1679,8 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); - if (verbosity >= 1) { - logprintf ( "received mesage id %016llx\n", enc->msg_id); - hexdump_in (c->mtconnection); - } + logprintf ( "received mesage id %016llx\n", enc->msg_id); + hexdump_in (c->mtconnection); c->mtconnection->server_last_msg_id = enc->msg_id; //*(long long *)(longpoll_query + 3) = *(long long *)((char *)(&enc->msg_id) + 0x3c); @@ -1763,9 +1764,7 @@ int rpc_execute (struct connection *c, int op, int len) { int tc_close (struct connection *c, int who) { - if (verbosity) { - logprintf ( "outbound http connection #%d : closing by %d\n", c->fd, who); - } + logprintf ( "outbound http connection #%d : closing by %d\n", c->fd, who); return 0; } diff --git a/mtproto-client.h b/mtproto-client.h index c2d38d8..2214b3c 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -277,6 +277,7 @@ static inline void out_ints (struct mtproto_connection *self, const int *what, i static inline void out_int (struct mtproto_connection *self, int x) { + logprintf("out_int(): packet_ptr:%p, packet_buffer:%p\n", self->packet_ptr, self->packet_buffer); assert (self->packet_ptr + 1 <= self->packet_buffer + PACKET_BUFFER_SIZE); *self->packet_ptr++ = x; } diff --git a/mtproto-common.c b/mtproto-common.c index e1e9535..362fecd 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -103,9 +103,7 @@ void prng_seed (struct mtproto_connection *self, const char *password_filename, if (l < 0) { logprintf ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename); } else { - if (verbosity > 0) { - logprintf ( "read %d bytes from password file.\n", l); - } + logprintf ( "read %d bytes from password file.\n", l); RAND_add (a, l, l); } close (fd); diff --git a/net.c b/net.c index 01c88ff..c0c76c7 100644 --- a/net.c +++ b/net.c @@ -105,9 +105,7 @@ int ping_alarm (struct connection *c) { } assert (c->state == conn_ready || c->state == conn_connecting); if (get_double_time () - c->last_receive_time > 20 * PING_TIMEOUT) { - if (verbosity) { - logprintf ( "fail connection: reason: ping timeout\n"); - } + logprintf ( "fail connection: reason: ping timeout\n"); c->state = conn_failed; fail_connection (c); } else if (get_double_time () - c->last_receive_time > 5 * PING_TIMEOUT && c->state == conn_ready) { @@ -330,9 +328,7 @@ struct connection *create_connection (const char *host, int port, struct session c->port = port; assert (!Connections[fd]); Connections[fd] = c; - if (verbosity) { - logprintf ( "connect to %s:%d successful\n", host, port); - } + logprintf ( "connect to %s:%d successful\n", host, port); if (c->methods->ready) { c->methods->ready (c); } @@ -418,9 +414,7 @@ void fail_connection (struct connection *c) { extern FILE *log_net_f; int try_write (struct connection *c) { - if (verbosity) { - logprintf ( "try write: fd = %d\n", c->fd); - } + logprintf ( "try write: fd = %d\n", c->fd); int x = 0; while (c->out_head) { int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); @@ -454,9 +448,7 @@ int try_write (struct connection *c) { delete_connection_buffer (b); } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - if (verbosity) { - logprintf ("fail_connection: write_error %m\n"); - } + logprintf ("fail_connection: write_error %m\n"); fail_connection (c); return 0; } else { @@ -464,9 +456,7 @@ int try_write (struct connection *c) { } } } - if (verbosity) { - logprintf ( "Sent %d bytes to %d\n", x, c->fd); - } + logprintf ( "Sent %d bytes to %d\n", x, c->fd); c->out_bytes -= x; return x; } @@ -534,9 +524,7 @@ void try_rpc_read (struct connection *c) { } void try_read (struct connection *c) { - if (verbosity) { - logprintf ( "try read: fd = %d\n", c->fd); - } + logprintf ( "try read: fd = %d\n", c->fd); if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } @@ -569,9 +557,7 @@ void try_read (struct connection *c) { c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - if (verbosity) { - logprintf ("fail_connection: read_error %m\n"); - } + logprintf ("fail_connection: read_error %m\n"); fail_connection (c); return; } else { @@ -579,9 +565,7 @@ void try_read (struct connection *c) { } } } - if (verbosity) { - logprintf ( "Received %d bytes from %d\n", x, c->fd); - } + logprintf ( "Received %d bytes from %d\n", x, c->fd); c->in_bytes += x; if (x) { try_rpc_read (c); @@ -624,9 +608,7 @@ void connections_poll_result (struct pollfd *fds, int max) { try_read (c); } if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) { - if (verbosity) { - logprintf ("fail_connection: events_mask=0x%08x\n", fds[i].revents); - } + logprintf ("fail_connection: events_mask=0x%08x\n", fds[i].revents); fail_connection (c); } else if (fds[i].revents & POLLOUT) { if (c->state == conn_connecting) { diff --git a/queries.c b/queries.c index 2b7e845..b85c5be 100644 --- a/queries.c +++ b/queries.c @@ -137,9 +137,7 @@ void query_restart (long long id) { struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { logprintf("send_query(...)\n"); - if (verbosity) { - logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); - } + logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); struct query *q = talloc0 (sizeof (*q)); q->data_len = ints; q->data = talloc (4 * ints); @@ -147,9 +145,7 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth q->msg_id = encrypt_send_message (DC->sessions[0]->c->mtconnection, data, ints, 1); q->session = DC->sessions[0]; q->seq_no = DC->sessions[0]->seq_no - 1; - if (verbosity) { - logprintf ( "Msg_id is %lld %p\n", q->msg_id, q); - } + logprintf ( "Msg_id is %lld %p\n", q->msg_id, q); q->methods = methods; q->DC = DC; if (queries_tree) { @@ -219,9 +215,7 @@ void query_result (long long id UU) { struct query *q = query_get (id); struct mtproto_connection *mtp = query_get_mtproto(q); - if (verbosity) { - logprintf ( "result for query #%lld\n", id); - } + logprintf ( "result for query #%lld\n", id); if (verbosity >= 4) { logprintf ( "result: "); hexdump_in (mtp); @@ -246,9 +240,7 @@ void query_result (long long id UU) { } } if (!q) { - if (verbosity) { - logprintf ( "No such query\n"); - } + logprintf ( "No such query\n"); mtp->in_ptr = mtp->in_end; } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { @@ -297,9 +289,7 @@ void work_timers (void) { if (ev->timeout > t) { break; } remove_event_timer (ev); assert (ev->alarm); - if (verbosity) { - logprintf ("Alarm\n"); - } + logprintf ("Alarm\n"); ev->alarm (ev->self); } } @@ -394,6 +384,7 @@ struct query_methods help_get_config_methods = { void do_help_get_config (struct telegram *instance) { struct mtproto_connection *mtp = instance->connection; + logprintf ("mtp: %p:%p\n", mtp->packet_ptr, mtp->packet_buffer); clear_packet (mtp); out_int (mtp, CODE_help_get_config); struct dc *DC_working = telegram_get_working_dc(instance); @@ -636,9 +627,7 @@ int nearest_dc_on_answer (struct query *q UU) { assert (fetch_int (mtp) == (int)CODE_nearest_dc); char *country = fetch_str_dup (mtp); - if (verbosity > 0) { - logprintf ("Server thinks that you are in %s\n", country); - } + logprintf ("Server thinks that you are in %s\n", country); fetch_int (mtp); // this_dc nearest_dc_num = fetch_int (mtp); assert (nearest_dc_num >= 0); @@ -688,9 +677,7 @@ int sign_in_on_answer (struct query *q UU) { bl_do_set_our_id (mtp->bl, mtp, our_id); } sign_in_ok = 1; - if (verbosity) { - logprintf ( "telegram: authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); - } + logprintf ( "telegram: 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; bl_do_dc_signed (mtp->bl, mtp, DC_working->id); diff --git a/telegram.c b/telegram.c index 87b8dbc..d299caa 100755 --- a/telegram.c +++ b/telegram.c @@ -69,18 +69,21 @@ void on_state_change(struct telegram *instance, int state, void *data) switch (state) { case STATE_ERROR: { const char* err = data; - logprintf("Telegram errored: %s \n", err); + if (err == NULL) { + err = ""; + } + logprintf("telegram errored: %s\n", err); } break; case STATE_AUTHORIZED: - logprintf("requesting configuration"); + logprintf("requesting configuration\n"); telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); do_help_get_config (instance); break; case STATE_CONFIG_RECEIVED: - logprintf("received network configuration, checking whether phone is registered."); + logprintf("received network configuration, checking whether phone is registered.\n"); telegram_store_session(instance); do_auth_check_phone(instance, instance->login); break; @@ -133,6 +136,7 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf logprintf("%s\n", this->download_path); logprintf("%s\n", this->auth_path); logprintf("%s\n", this->state_path); + logprintf("%s\n", this->secret_path); telegram_add_state_change_listener(this, on_state_change); telegram_change_state(this, STATE_INITIALISED, NULL); diff --git a/tools.c b/tools.c index 5dcc439..888e8c4 100644 --- a/tools.c +++ b/tools.c @@ -239,7 +239,7 @@ int tinflate (void *input, int ilen, void *output, int olen) { logprintf ( "inflated %d bytes\n", (int) strm.total_out); } } - if (verbosity && err != Z_STREAM_END) { + if (err != Z_STREAM_END) { logprintf ( "inflate error = %d\n", err); logprintf ( "inflated %d bytes\n", (int) strm.total_out); } From 1b1c5d132a973a35cd480c497f8bc350d7d30808 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 17:45:40 +0200 Subject: [PATCH 344/465] Remove overlooked incrementation of queries_num --- queries.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/queries.c b/queries.c index b85c5be..57b6c7f 100644 --- a/queries.c +++ b/queries.c @@ -162,10 +162,6 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth insert_event_timer (&q->ev); q->extra = extra; - - struct mtproto_connection *mtp = DC->sessions[0]->c->mtconnection; - mtp->queries_num ++; - logprintf("queries_num: %d\n", mtp->queries_num); return q; } From 1e6598c11c0927ba0a69e7935e49424651fe5d4c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 18:28:58 +0200 Subject: [PATCH 345/465] Request proxy connections by callback Require the user of telegram to provide a callback to create and cleanup proxy connections, to allow the application to create new connections when needed. --- purple-plugin/telegram-purple.c | 84 +++++++++++++++++++++++---------- telegram.c | 23 ++++++--- telegram.h | 27 +++++++++-- 3 files changed, 97 insertions(+), 37 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 5fd923e..ed651c2 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -270,35 +270,34 @@ static void init_dc_settings(PurpleAccount *acc, struct dc *DC) } /** - * This must be implemented. + * Handle a proxy-request of telegram + * + * Request a new proxy connection from purple, and execute tgprpl_login_on_connected + * as callback once the connection is ready */ -static void tgprpl_login(PurpleAccount * acct) +void telegram_on_proxy_request(struct telegram *instance, const char *ip, int port) { - purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); - PurpleConnection *gc = purple_account_get_connection(acct); - char const *username = purple_account_get_username(acct); - _gc = gc; - _pa = acct; - - struct dc DC; - init_dc_settings(acct, &DC); - // TODO: fetch current home directory - // use this as root - struct telegram *tg = telegram_new(&DC, username, "/home/dev-jessie/.telegram"); - telegram_add_state_change_listener(tg, tgprpl_on_state_change); - telegram_restore_session(tg); - - telegram_conn *conn = g_new0(telegram_conn, 1); - conn->tg = tg; - conn->gc = gc; - conn->pa = acct; - purple_connection_set_protocol_data(gc, conn); - tg->extra = conn; - - purple_connection_set_state(gc, PURPLE_CONNECTING); - purple_proxy_connect(gc, acct, DC.ip, DC.port, tgprpl_login_on_connected, tg); + telegram_conn *conn = instance->extra; + purple_proxy_connect (conn->gc, conn->pa, ip, port, tgprpl_login_on_connected, conn->tg); } +/** + * Handle a proxy-close of telegram + * + * Remove all open inputs added to purple + */ +void telegram_on_proxy_close(struct telegram *instance, int fd UU) +{ + telegram_conn *conn = instance->extra; + purple_input_remove (conn->rh); + purple_input_remove (conn->wh); +} + +/** + * A proxy connection was created by purple + * + * Set the proxy to the current telegram-instance, and add callbacks to monitor + */ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) { purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); @@ -313,7 +312,8 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa purple_debug_info(PLUGIN_ID, "Connecting to the telegram network...\n"); conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, tg); conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg); - telegram_network_connect(tg, fd); + + telegram_set_proxy(tg, fd); // // load all settings: the known network topology, secret keys, logs and configuration file paths // purple_debug_info(PLUGIN_ID, "parse_config()\n"); @@ -364,6 +364,38 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa */ } +/** + * This must be implemented. + */ +static void tgprpl_login(PurpleAccount * acct) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); + PurpleConnection *gc = purple_account_get_connection(acct); + char const *username = purple_account_get_username(acct); + _gc = gc; + _pa = acct; + + struct dc DC; + init_dc_settings(acct, &DC); + + // TODO: fetch current home directory + // use this as root + struct telegram *tg = telegram_new(&DC, username, "/home/dev-jessie/.telegram", + telegram_on_proxy_request, telegram_on_proxy_close); + telegram_add_state_change_listener(tg, tgprpl_on_state_change); + telegram_restore_session(tg); + + telegram_conn *conn = g_new0(telegram_conn, 1); + conn->tg = tg; + conn->gc = gc; + conn->pa = acct; + purple_connection_set_protocol_data(gc, conn); + tg->extra = conn; + + purple_connection_set_state (conn->gc, PURPLE_CONNECTING); + telegram_network_connect(tg); +} + void on_new_message(struct message *M) { purple_debug_info(PLUGIN_ID, "New Message: %s\n", M->message); diff --git a/telegram.c b/telegram.c index d299caa..5f320f1 100755 --- a/telegram.c +++ b/telegram.c @@ -115,7 +115,9 @@ void on_state_change(struct telegram *instance, int state, void *data) } } -struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path) +struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path, + void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port), + void (*proxy_close_cb)(struct telegram *instance, int fd)) { struct telegram *this = malloc(sizeof(struct telegram)); this->protocol_data = NULL; @@ -123,6 +125,8 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf this->auth.DC_list[0] = DC; this->change_state_listeners = NULL; this->bl = talloc0 (sizeof(struct binlog)); + this->proxy_request_cb = proxy_request_cb; + this->proxy_close_cb = proxy_close_cb; this->login = g_strdup(login); this->config_path = g_strdup_printf("%s/%s", config_path, login); @@ -234,18 +238,16 @@ void on_authorized(struct mtproto_connection *c, void* data); /** * Connect to the currently active data center */ -void telegram_network_connect(struct telegram *instance, int fd) +void telegram_network_connect(struct telegram *instance) { logprintf("telegram_network_connect()\n"); if (!instance->auth.DC_list) { logprintf("telegram_network_connect(): cannot connect, restore / init a session first.\n"); assert(0); } - struct dc *DC_working = telegram_get_working_dc(instance); - instance->connection = mtproto_new(DC_working, fd, instance); - instance->connection->on_ready = on_authorized; - instance->connection->on_ready_data = instance; - mtproto_connect(instance->connection); + struct dc *DC_working = telegram_get_working_dc (instance); + assert (instance->proxy_request_cb); + instance->proxy_request_cb (instance, DC_working->ip, DC_working->port); } /** @@ -273,6 +275,13 @@ void on_authorized(struct mtproto_connection *c, void *data) void telegram_read_input (struct telegram *instance) { return try_read(instance->connection->connection); +void telegram_set_proxy(struct telegram *instance, int fd) +{ + struct dc *DC_working = telegram_get_working_dc (instance); + instance->connection = mtproto_new (DC_working, fd, instance); + instance->connection->on_ready = on_authorized; + instance->connection->on_ready_data = instance; + mtproto_connect (instance->connection); } int telegram_write_output (struct telegram *instance) diff --git a/telegram.h b/telegram.h index 66fbfd0..d9dd34e 100644 --- a/telegram.h +++ b/telegram.h @@ -124,15 +124,27 @@ struct telegram { * callbacks */ void (*on_output)(struct telegram *instance); + void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port); + void (*proxy_close_cb)(struct telegram *instance, int fd); void *extra; }; /** - * constructor + * Create a new telegram application + * + * @param DC The initial data center to use + * @param login The phone number to use as login name + * @param config_path The configuration path used to store the content + * @param proxy_request_cb A callback function that delivers a connections to the given hostname + * and port by calling telegram_set_proxy. This is useful for tunelling + * the connection through a proxy server + * @param proxy_close_cb A callback function that is called once the proxy connection is no longer + * needed. This is useful for freeing all used resources */ -struct telegram *telegram_new(struct dc *DC, const char* login, - const char* config_path); +struct telegram *telegram_new(struct dc *DC, const char* login, const char* config_path, + void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port), + void (*proxy_close_cb)(struct telegram *instance, int fd)); /** * Resume the session to @@ -194,7 +206,7 @@ void telegram_change_state(struct telegram *instance, int state, void *data); /** * Connect to the telegram network with the given configuration */ -void telegram_network_connect (struct telegram *instance, int fd); +void telegram_network_connect(struct telegram *instance); int telegram_login (struct telegram *instance); @@ -294,4 +306,11 @@ void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)); */ void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); +/** + * Set the proxy-connection to use + * + * NOTE: you may only call this function from the + */ +void telegram_set_proxy(struct telegram *instance, int fd); + #endif From c144484fd5d5549783947c94d2661c5f50fec219 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 18:36:49 +0200 Subject: [PATCH 346/465] Add memory management for mtproto_connections Mark connections for destruction on close and free all allocated memory only once all incoming queries are read, since those queries will still access data on the current mtproto_connection and cause segmentation faults. --- mtproto-client.c | 45 +++++++++++++++++++++++++++++++++++++++++---- mtproto-client.h | 5 +++++ telegram.c | 7 ++++++- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 23dd2e4..fa767de 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1855,14 +1855,18 @@ struct connection_methods mtproto_methods = { .close = rpc_close }; +// TODO: use a list or tree instead +struct mtproto_connection *Cs[100]; + /** * Create a new struct mtproto_connection connection using the giving datacenter for authorization and * session handling */ struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg) { - // init + static int cs = 0; struct mtproto_connection *mtp = talloc(sizeof(struct mtproto_connection)); + Cs[cs++] = mtp; memset(mtp, 0, sizeof(struct mtproto_connection)); mtp->packet_buffer = mtp->__packet_buffer + 16; mtp->connection = fd_create_connection(DC, fd, tg, &mtproto_methods, mtp); @@ -1888,10 +1892,43 @@ void mtproto_connect(struct mtproto_connection *c) /** * Free all used resources and close the connection */ -void mtproto_close(struct mtproto_connection *c) -{ +void mtproto_close(struct mtproto_connection *mtp) { + logprintf ("closing mtproto_connection...\n"); + mtp->destroy = 1; + // TODO: Use Pings? // stop_ping_timer (c->connection); - fd_close_connection(c->connection); + + // TODO: Set destruction timeout? + // add_destruction_timer (c, 5000) + /* + Timout: + - alle queries und acks löschen? + - was passiert wenn eine antwort auf eine query + in einer neuen instanz ankommt? + */ +} + +void mtproto_destroy (struct mtproto_connection *self) { + logprintf("destroying mtproto_connection: %p\n", self); + + // TODO: Remove all pending timers, queries, acks + // TODO: Call destruction callback + fd_close_connection(self->connection); + tfree(self->connection, sizeof(struct connection)); +} + +void mtproto_free_closed () { + int i; + for (i = 0; i < 100; i++) { + if (Cs[i] == NULL) continue; + struct mtproto_connection *c = Cs[i]; + logprintf ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", + i, c->c_state, c->destroy, c->queries_num); + if (c->destroy == 0) continue; + if (c->queries_num > 0) continue; + mtproto_destroy (c); + Cs[i] = NULL; + } } diff --git a/mtproto-client.h b/mtproto-client.h index 2214b3c..8fbbe40 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -156,6 +156,8 @@ enum dc_state { // forward-declarations struct timespec; struct telegram; +struct mtproto_connection; +void mtproto_destroy (struct mtproto_connection *self); #define DECRYPT_BUFFER_INTS 16384 #define ENCRYPT_BUFFER_INTS 16384 @@ -501,4 +503,7 @@ static inline void hexdump_out (struct mtproto_connection *self) { #endif void my_clock_gettime (int clock_id, struct timespec *T); +void mtproto_free_closed (); + #endif + diff --git a/telegram.c b/telegram.c index 5f320f1..ded02be 100755 --- a/telegram.c +++ b/telegram.c @@ -274,7 +274,12 @@ void on_authorized(struct mtproto_connection *c, void *data) void telegram_read_input (struct telegram *instance) { - return try_read(instance->connection->connection); + try_read(instance->connection->connection); + mtproto_free_closed(); + // free all mtproto_connections that may have errored through + // a received query +} + void telegram_set_proxy(struct telegram *instance, int fd) { struct dc *DC_working = telegram_get_working_dc (instance); From 5d8d170927c0401c5da24655fbf1df5bb497364b Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 18:44:23 +0200 Subject: [PATCH 347/465] Use allocation utilities from utilites.h and initiate telegram with zeroes --- mtproto-client.c | 1 + telegram.c | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index fa767de..741c205 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1706,6 +1706,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int rpc_execute (struct connection *c, int op, int len) { logprintf ("outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); struct mtproto_connection *self = c->mtconnection; + struct telegram *instance = c->instance; /* if (op < 0) { diff --git a/telegram.c b/telegram.c index ded02be..9c06e28 100755 --- a/telegram.c +++ b/telegram.c @@ -119,9 +119,8 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port), void (*proxy_close_cb)(struct telegram *instance, int fd)) { - struct telegram *this = malloc(sizeof(struct telegram)); + struct telegram *this = talloc0(sizeof(struct telegram)); this->protocol_data = NULL; - //this->curr_dc = 0; this->auth.DC_list[0] = DC; this->change_state_listeners = NULL; this->bl = talloc0 (sizeof(struct binlog)); @@ -156,8 +155,8 @@ void telegram_free(struct telegram *this) g_free(this->auth_path); g_free(this->state_path); g_free(this->secret_path); - free(this); tfree(this->bl, sizeof(struct binlog)); + tfree(this, sizeof(struct telegram)); } void assert_file_usable(const char *file) From 8ff9734077c4a8fa56578b782de1b62532a1b0b2 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 18:54:25 +0200 Subject: [PATCH 348/465] Handle the SWITCH_DC RPCError by changing the data center and creating a new mtproto_connection --- mtproto-client.c | 4 ++++ queries.c | 4 +++- telegram.c | 26 +++++++++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 741c205..f2c267c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1751,6 +1751,10 @@ int rpc_execute (struct connection *c, int op, int len) { case st_authorized: if (op < 0 && op >= -999) { logprintf ("Server error %d\n", op); + char code[12] = {0}; + snprintf (code, 12, "%d", op); + c->mtconnection->c_state = st_error; + telegram_change_state (instance, STATE_ERROR, code); } else { process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); } diff --git a/queries.c b/queries.c index 57b6c7f..811a169 100644 --- a/queries.c +++ b/queries.c @@ -583,8 +583,10 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error //check_phone_result = 1; } else { logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); + telegram_change_state(instance, STATE_ERROR, error); } - telegram_change_state(instance, STATE_DISCONNECTED_SWITCH_DC, error); + telegram_change_state(instance, + STATE_DISCONNECTED_SWITCH_DC, &instance->auth.dc_working_num); return 0; } diff --git a/telegram.c b/telegram.c index 9c06e28..cea7a32 100755 --- a/telegram.c +++ b/telegram.c @@ -73,6 +73,9 @@ void on_state_change(struct telegram *instance, int state, void *data) err = ""; } logprintf("telegram errored: %s\n", err); + + // close the connection + mtproto_close (instance->connection); } break; @@ -108,9 +111,26 @@ void on_state_change(struct telegram *instance, int state, void *data) // wait for user input ... break; - case STATE_DISCONNECTED_SWITCH_DC: - logprintf("Have to migrate to other DC"); - instance->connection + case STATE_DISCONNECTED_SWITCH_DC: { + // telegram demands that we use a different data center, which caused + // the current mtproto_connection to be disconnected + + int target_dc = *(int*) data; + logprintf ("Disconnected: Migrate to data center %d\n", target_dc); + + // close old connection and mark it for destruction + mtproto_close (instance->connection); + if (instance->proxy_request_cb) { + // tell the proxy to close all connections + instance->proxy_close_cb (instance, + instance->connection->connection->fd); + } + + // start a new connection to the demanded data center. The pointer to the + // currently working dc should have already been updated by the + // on_error function of the query + telegram_network_connect (instance); + } break; } } From c81ce16e809e22cd004371913ede05714a913c5d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 18:57:14 +0200 Subject: [PATCH 349/465] Fix coding style and add missing docstrings --- mtproto-client.c | 2 +- telegram.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index f2c267c..01618c6 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1791,7 +1791,7 @@ int tc_becomes_ready (struct connection *c) { break; case st_authorized: auth_work_start (c); - telegram_change_state(c->instance, STATE_AUTHORIZED, NULL); + telegram_change_state (c->instance, STATE_AUTHORIZED, NULL); break; default: logprintf ( "c_state = %d\n", c->mtconnection->c_state); diff --git a/telegram.c b/telegram.c index cea7a32..a6190fc 100755 --- a/telegram.c +++ b/telegram.c @@ -63,6 +63,13 @@ void telegram_change_state(struct telegram *instance, int state, void *data) } while ((curr = g_list_next(change_listeners)) != NULL); } +/** + * Handle state changes of the telegram instance + * + * Execute all actions necessary when a certain state is reached. The state machine executes + * the authorization and registration steps needed to connect the client to the telegram network, + * and will either trigger RPC queries or callbacks to the GUI to request input from the user. + */ void on_state_change(struct telegram *instance, int state, void *data) { logprintf("on_state_change: %d\n", state); @@ -259,8 +266,8 @@ void on_authorized(struct mtproto_connection *c, void* data); */ void telegram_network_connect(struct telegram *instance) { - logprintf("telegram_network_connect()\n"); - if (!instance->auth.DC_list) { + logprintf ("telegram_network_connect()\n"); + if (! instance->auth.DC_list) { logprintf("telegram_network_connect(): cannot connect, restore / init a session first.\n"); assert(0); } From f09b4c1c8756f033a445f7f49366b4539751032d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 22 Aug 2014 19:02:11 +0200 Subject: [PATCH 350/465] Move config function to avoid predeclaration --- telegram.c | 17 ++++++++++++----- telegram.h | 2 -- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/telegram.c b/telegram.c index a6190fc..e214cfc 100755 --- a/telegram.c +++ b/telegram.c @@ -63,6 +63,18 @@ void telegram_change_state(struct telegram *instance, int state, void *data) } while ((curr = g_list_next(change_listeners)) != NULL); } +/** + * Calculate the configuration path for the given config file and the given instance + * + * @returns The full path to the configuration. + * + * NOTE: the returned string must be freed manually using gfree + */ +char *telegram_get_config(struct telegram *instance, char *config) +{ + return g_strdup_printf("%s/%s", instance->config_path, config); +} + /** * Handle state changes of the telegram instance * @@ -254,11 +266,6 @@ void telegram_store_session(struct telegram *instance) write_state_file(&instance->proto, instance->state_path); } -char *telegram_get_config(struct telegram *instance, char *config) -{ - return g_strdup_printf("%s/%s", instance->config_path, config); -} - void on_authorized(struct mtproto_connection *c, void* data); /** diff --git a/telegram.h b/telegram.h index d9dd34e..59efb8f 100644 --- a/telegram.h +++ b/telegram.h @@ -151,8 +151,6 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char* conf */ void telegram_restore_session(struct telegram *instance); -char *telegram_get_config(struct telegram *instance, char *config); - /** * Store */ From a4e5449d5abe716f320853149bc014a592303081 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 02:40:10 +0200 Subject: [PATCH 351/465] Move telegram callbacks and settings into configuration struct --- mtproto-client.c | 2 +- purple-plugin/telegram-purple.c | 251 +++++++++++++++----------------- queries.c | 6 +- telegram.c | 67 ++------- telegram.h | 116 ++++++++++----- 5 files changed, 213 insertions(+), 229 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 01618c6..3bc63c1 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -890,7 +890,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { assert (M); fetch_pts (self); self->unread_messages ++; - event_update_new_message(M); + event_update_new_message (tg, M); //print_message (M); //update_prompt (); break; diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index ed651c2..c66b7cf 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -73,8 +73,10 @@ void tg_cli_log_cb(const char* format, va_list ap) purple_debug_info(PLUGIN_ID, "%s", buffer); } -void on_new_message(struct message *M); -void peer_allocated_handler(void *user); +void on_new_message (struct telegram *instance, struct message *M); +void peer_allocated_handler (struct telegram *instance, void *user); +void telegram_on_phone_registration (struct telegram *instance); +void elegram_on_client_registration (struct telegram *instance); /** * Returns the base icon name for the given buddy and account. @@ -99,26 +101,7 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info } /** - * Request a verification key, save the returned verification_hash in the account settings - * for later usage and inform the user. -static void login_request_verification(PurpleAccount *acct) -{ - // TODO: we should find a way to request the key - // only once. - purple_debug_info(PLUGIN_ID, "No code provided, requesting new authentication code.\n"); - char *new_hash = network_request_registration(); - purple_debug_info(PLUGIN_ID, "Saving verification_hash: '%s'", new_hash); - purple_account_set_string(acct, "verification_hash", new_hash); - - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Please Verify", - "You need to verify this device, please enter the code struct telegram has sent to you by SMS.", - NULL, NULL, NULL); -} - */ - -/** - * Handle a failed verification, by removing the invalid sms code and - * notifying the user + * Handle a failed verification by removing the invalid sms code and notifying the user */ static void login_verification_fail(PurpleAccount *acct) { @@ -179,89 +162,6 @@ static void tgprpl_has_input(struct telegram *tg) } } -static void tgprpl_on_state_change(struct telegram *instance, int state, void *data) -{ - telegram_conn *conn = instance->extra; - switch (state) { - case STATE_PHONE_NOT_REGISTERED: - // TODO: Request first and last name - // TODO: Fetch PurpleAccount and don't use global - purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); - const char *first_name = purple_account_get_string(conn->pa, "first_name", NULL); - const char *last_name = purple_account_get_string(conn->pa, "last_name", NULL); - const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); - const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); - purple_debug_info(PLUGIN_ID, "code: %s\n", code); - purple_debug_info(PLUGIN_ID, "verification_hash: %s\n", hash); - if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", - "Enter your first and last name to register this phone number with the telegram network.", - NULL, NULL, NULL); - return; - } - - do_send_code_result_auth (instance, code, hash, first_name, last_name); - break; - - case STATE_PHONE_CODE_NOT_ENTERED: { - char *hash = data; - const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); - do_send_code_result(instance, code, hash); - // TODO: Request SMS code - } - break; - - case STATE_CLIENT_CODE_NOT_ENTERED: { - char *hash = data; - const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); - //const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL); - do_send_code_result(instance, code, hash); - // enter SMS code - } - break; - - case STATE_READY: - // ready - purple_debug_info(PLUGIN_ID, "Logged in...\n"); - purple_connection_set_state(conn->gc, PURPLE_CONNECTED); - char const *username = purple_account_get_username(conn->pa); - purple_connection_set_display_name(conn->gc, username); - purple_blist_add_account(conn->pa); - - tggroup = purple_find_group("struct telegram"); - if (tggroup == NULL) { - purple_debug_info(PLUGIN_ID, "PurpleGroup = NULL, creating"); - tggroup = purple_group_new("struct telegram"); - purple_blist_add_group(tggroup, NULL); - } - - on_update_new_message(on_new_message); - on_peer_allocated(peer_allocated_handler); - - // get all current contacts - purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); - do_update_contact_list(instance); - - purple_debug_info(PLUGIN_ID, "Fetching all current chats...\n"); - do_get_dialog_list(instance); - - // get new messages - purple_debug_info(PLUGIN_ID, "Fetching new messages...\n"); - do_get_difference(instance); - - tgprpl_has_output(instance); - //telegram_flush_queries(instance); - break; - - case STATE_ERROR: { - const char* err = data; - logprintf("Connection errored: %s\n", err); - - } - break; - } -} - static void init_dc_settings(PurpleAccount *acc, struct dc *DC) { DC->port = purple_account_get_int(acc, "port", TELEGRAM_DEFAULT_PORT); @@ -293,6 +193,101 @@ void telegram_on_proxy_close(struct telegram *instance, int fd UU) purple_input_remove (conn->wh); } +void telegram_on_phone_registration (struct telegram *instance) +{ + telegram_conn *conn = instance->extra; + + // TODO: Request first and last name + // TODO: Fetch PurpleAccount and don't use global + purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); + const char *first_name = purple_account_get_string(conn->pa, "first_name", NULL); + const char *last_name = purple_account_get_string(conn->pa, "last_name", NULL); + const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); + + if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { + purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", + "Enter your first and last name to register this phone number with the telegram network.", + NULL, NULL, NULL); + return; + } + + do_send_code_result_auth (instance, code, first_name, last_name); +} + +void client_registration_entered (gpointer data, const gchar *code) +{ + struct telegram *tg = data; + do_send_code_result (tg, code); + tgprpl_has_output (tg); +} + +void client_registration_canceled (gpointer data) +{ + struct telegram *tg = data; + // TODO: disconnect and exit +} + +void telegram_on_client_registration (struct telegram *instance) +{ + purple_debug_info(PLUGIN_ID, "Client is not registered, registering...\n"); + telegram_conn *conn = instance->extra; + + purple_request_input( + conn->gc, // handle (the PurpleAccount) + "Telegram Code", // title + "Enter Telegram Code", // primary + "Telegram wants to verify your identity, please enter the code, that you have received via SMS.", // secondary + NULL, // default_value + FALSE, // multiline + FALSE, // masked + "code", // hint + "OK", // ok_text + G_CALLBACK(client_registration_entered), // ok_cb + "Cancel", // cancel_text + G_CALLBACK(client_registration_canceled), // cancel_cb + conn->pa, // account + NULL, // who + NULL, // conv + conn->tg // user_data + ); +} + +void telegram_on_ready (struct telegram *instance) +{ + purple_debug_info(PLUGIN_ID, "telegram_on_ready().\n"); + telegram_conn *conn = instance->extra; + + purple_connection_set_state(conn->gc, PURPLE_CONNECTED); + purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa)); + + purple_blist_add_account(conn->pa); + tggroup = purple_find_group("Telegram"); + if (tggroup == NULL) { + purple_debug_info (PLUGIN_ID, "PurpleGroup = NULL, creating"); + tggroup = purple_group_new ("struct telegram"); + purple_blist_add_group (tggroup, NULL); + } + + // get all current contacts + purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); + do_update_contact_list(instance); + + purple_debug_info(PLUGIN_ID, "Fetching all current chats...\n"); + do_get_dialog_list(instance); + + // get new messages + purple_debug_info(PLUGIN_ID, "Fetching new messages...\n"); + do_get_difference(instance); + + tgprpl_has_output(instance); +} + +void telegram_on_disconnected (struct telegram *tg) +{ + logprintf ("telegram_on_disconnected()\n"); + assert (0); +} + /** * A proxy connection was created by purple * @@ -314,31 +309,17 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg); telegram_set_proxy(tg, fd); +} - // // load all settings: the known network topology, secret keys, logs and configuration file paths - // purple_debug_info(PLUGIN_ID, "parse_config()\n"); - // parse_config (); - // purple_debug_info(PLUGIN_ID, "set_default_username()\n"); - //set_default_username (username); - - // Connect to the network - // Assure phone number registration - /* - if (!network_phone_is_registered()) { - if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { - int registered = network_verify_phone_registration(code, hash, first_name, last_name); - if (registered) { - store_config(); - } else { - login_verification_fail(acct); - return; - } - } else { - login_request_verification(acct); - return; - } - } - */ +struct telegram_config tgconf = { + "/home/dev-jessie/.telegram", + NULL, // on output + telegram_on_proxy_request, + telegram_on_proxy_close, + telegram_on_phone_registration, + telegram_on_client_registration, + telegram_on_ready, + telegram_on_disconnected, // Assure client registration /* @@ -362,7 +343,9 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa } } */ -} + on_new_message, + peer_allocated_handler +}; /** * This must be implemented. @@ -380,9 +363,7 @@ static void tgprpl_login(PurpleAccount * acct) // TODO: fetch current home directory // use this as root - struct telegram *tg = telegram_new(&DC, username, "/home/dev-jessie/.telegram", - telegram_on_proxy_request, telegram_on_proxy_close); - telegram_add_state_change_listener(tg, tgprpl_on_state_change); + struct telegram *tg = telegram_new (&DC, username, &tgconf); telegram_restore_session(tg); telegram_conn *conn = g_new0(telegram_conn, 1); @@ -396,7 +377,7 @@ static void tgprpl_login(PurpleAccount * acct) telegram_network_connect(tg); } -void on_new_message(struct message *M) +void on_new_message(struct telegram *tg, struct message *M) { purple_debug_info(PLUGIN_ID, "New Message: %s\n", M->message); // TODO: this should probably be freed again somwhere @@ -439,7 +420,7 @@ static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id) } -void peer_allocated_handler(void *usr) +void peer_allocated_handler(struct telegram *tg, void *usr) { peer_t *user = usr; gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); diff --git a/queries.c b/queries.c index 811a169..3c89ea9 100644 --- a/queries.c +++ b/queries.c @@ -75,7 +75,7 @@ extern int sync_from_start; int sync_from_start = 0; void telegram_flush_queries (struct telegram *instance) { - instance->on_output(instance); + instance->config->on_output(instance); } void out_peer_id (struct mtproto_connection *self, peer_id_t id); @@ -153,8 +153,10 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); } } + queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); - logprintf("queries_num: %d\n", ++ mtc->queries_num); + struct mtproto_connection *mtp = query_get_mtproto(q); + logprintf("queries_num: %d\n", ++ mtp->queries_num); q->ev.alarm = (void *)alarm_query; q->ev.timeout = get_double_time () + QUERY_TIMEOUT; diff --git a/telegram.c b/telegram.c index e214cfc..fda4e58 100755 --- a/telegram.c +++ b/telegram.c @@ -18,51 +18,23 @@ /* * New message received */ -void (*on_msg_handler)(struct message *M); -void on_update_new_message(void (*on_msg)(struct message *M)) +void event_update_new_message(struct telegram *instance, struct message *M) { - on_msg_handler = on_msg; -} -void event_update_new_message(struct message *M) -{ - if (on_msg_handler) { - on_msg_handler(M); + if (instance->config->on_msg_handler) { + instance->config->on_msg_handler(instance, M); } } /* * Peer allocated */ -void (*on_peer_allocated_handler)(void *peer); -void on_peer_allocated(void (*handler)(void *peer)) +void event_peer_allocated(struct telegram *instance, void *peer) { - on_peer_allocated_handler = handler; -} -void event_peer_allocated(void *peer) -{ - if (on_peer_allocated_handler) { - on_peer_allocated_handler(peer); + if (instance->config->on_peer_allocated_handler) { + instance->config->on_peer_allocated_handler(instance, peer); } } -/* - * State changed - */ -GList *change_listeners = NULL; -void telegram_add_state_change_listener(struct telegram *instance, state_listener_t listener) -{ - instance->change_state_listeners = g_list_append(instance->change_state_listeners, listener); -} -void telegram_change_state(struct telegram *instance, int state, void *data) -{ - logprintf("telegram connection state changed to: %d\n", state); - instance->session_state = state; - GList *curr = instance->change_state_listeners; - do { - ((state_listener_t)curr->data)(instance, state, data); - } while ((curr = g_list_next(change_listeners)) != NULL); -} - /** * Calculate the configuration path for the given config file and the given instance * @@ -82,8 +54,9 @@ char *telegram_get_config(struct telegram *instance, char *config) * the authorization and registration steps needed to connect the client to the telegram network, * and will either trigger RPC queries or callbacks to the GUI to request input from the user. */ -void on_state_change(struct telegram *instance, int state, void *data) +void telegram_change_state (struct telegram *instance, int state, void *data) { + instance->session_state = state; logprintf("on_state_change: %d\n", state); switch (state) { case STATE_ERROR: { @@ -139,11 +112,9 @@ void on_state_change(struct telegram *instance, int state, void *data) // close old connection and mark it for destruction mtproto_close (instance->connection); - if (instance->proxy_request_cb) { - // tell the proxy to close all connections - instance->proxy_close_cb (instance, - instance->connection->connection->fd); - } + assert (instance->config->proxy_request_cb); + // tell the proxy to close all connections + instance->config->proxy_close_cb (instance, instance->connection->connection->fd); // start a new connection to the demanded data center. The pointer to the // currently working dc should have already been updated by the @@ -154,20 +125,16 @@ void on_state_change(struct telegram *instance, int state, void *data) } } -struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path, - void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port), - void (*proxy_close_cb)(struct telegram *instance, int fd)) +struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_config *config) { struct telegram *this = talloc0(sizeof(struct telegram)); this->protocol_data = NULL; this->auth.DC_list[0] = DC; - this->change_state_listeners = NULL; this->bl = talloc0 (sizeof(struct binlog)); - this->proxy_request_cb = proxy_request_cb; - this->proxy_close_cb = proxy_close_cb; + this->config = config; this->login = g_strdup(login); - this->config_path = g_strdup_printf("%s/%s", config_path, login); + this->config_path = g_strdup_printf("%s/%s", config->base_config_path, login); this->download_path = telegram_get_config(this, "downloads"); this->auth_path = telegram_get_config(this, "auth"); this->state_path = telegram_get_config(this, "state"); @@ -180,14 +147,12 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf logprintf("%s\n", this->state_path); logprintf("%s\n", this->secret_path); - telegram_add_state_change_listener(this, on_state_change); telegram_change_state(this, STATE_INITIALISED, NULL); return this; } void telegram_free(struct telegram *this) { - g_list_free(this->change_state_listeners); g_free(this->login); g_free(this->config_path); g_free(this->download_path); @@ -279,8 +244,8 @@ void telegram_network_connect(struct telegram *instance) assert(0); } struct dc *DC_working = telegram_get_working_dc (instance); - assert (instance->proxy_request_cb); - instance->proxy_request_cb (instance, DC_working->ip, DC_working->port); + assert (instance->config->proxy_request_cb); + instance->config->proxy_request_cb (instance, DC_working->ip, DC_working->port); } /** diff --git a/telegram.h b/telegram.h index 59efb8f..8e04e0d 100644 --- a/telegram.h +++ b/telegram.h @@ -83,6 +83,75 @@ struct binlog { int s[1000]; }; +struct telegram; + +/** + * Contains all options and pointer to callback functions required by telegram + */ +struct telegram_config { + + /** + * The base path containing the telegram configuration + */ + const char* base_config_path; + + /** + * Called when there is pending network output + */ + void (*on_output)(struct telegram *instance); + + /** + * A callback function that delivers a connections to the given hostname + * and port by calling telegram_set_proxy. This is useful for tunelling + * the connection through a proxy server. + */ + void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port); + + /** + * A callback function that is called once the proxy connection is no longer + * needed. This is useful for freeing all used resources. + */ + void (*proxy_close_cb)(struct telegram *instance, int fd); + + /** + * A callback function that is called when a phone registration is required. + * + * This callback must query first name, last name and the + * authentication code from the user and call do_send_code_result_auth once done + */ + void (*on_phone_registration_required) (struct telegram *instance); + + /** + * A callback function that is called when a client registration is required. + * + * This callback must query the authentication code from the user and + * call do_send_code_result once done + */ + void (*on_client_registration_required) (struct telegram *instance); + + /** + * A callback function that is called when telegram is ready + */ + void (*on_ready) (struct telegram *instance); + + /** + * A callback function that is called when telegram is disconnected + */ + void (*on_disconnected) (struct telegram *instance); + + /** + * A callback function that is called when a new message was allocated. This is useful + * for adding new messages to the GUI. + */ + void (*on_msg_handler)(struct telegram *instance, struct message *M); + + /** + * A callback function that is called when a new peer was allocated. This is useful + * for populating the GUI with new peers. + */ + void (*on_peer_allocated_handler)(struct telegram *instance, void *peer); +}; + /** * A telegram session * @@ -101,6 +170,7 @@ struct telegram { char *secret_path; int session_state; + struct telegram_config *config; /* * protocol state @@ -108,8 +178,6 @@ struct telegram { struct protocol_state proto; struct authorization_state auth; - GList *change_state_listeners; - /* * connection */ @@ -120,12 +188,6 @@ struct telegram { */ struct binlog *bl; - /* - * callbacks - */ - void (*on_output)(struct telegram *instance); - void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port); - void (*proxy_close_cb)(struct telegram *instance, int fd); void *extra; }; @@ -133,18 +195,11 @@ struct telegram { /** * Create a new telegram application * - * @param DC The initial data center to use - * @param login The phone number to use as login name - * @param config_path The configuration path used to store the content - * @param proxy_request_cb A callback function that delivers a connections to the given hostname - * and port by calling telegram_set_proxy. This is useful for tunelling - * the connection through a proxy server - * @param proxy_close_cb A callback function that is called once the proxy connection is no longer - * needed. This is useful for freeing all used resources + * @param DC The initial data center to use + * @param login The phone number to use as login name + * @param config Contains all callbacks used for the telegram instance */ -struct telegram *telegram_new(struct dc *DC, const char* login, const char* config_path, - void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port), - void (*proxy_close_cb)(struct telegram *instance, int fd)); +struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_config *config); /** * Resume the session to @@ -175,23 +230,6 @@ struct dc *telegram_get_working_dc(struct telegram *instance); * Events */ -/** - * Handler to process a state change - * - * @param instance The telegram instance that changed its state - * @param state The changed state - * @param data Extra data that depends on switched state - */ -typedef void (*state_listener_t)(struct telegram *instance, int state, void *data); - -/** - * Execute this listener when the state has changed - * - * @param instance The telegram instance - * @param listener The listener to execute - */ -void telegram_add_state_change_listener(struct telegram *instance, state_listener_t listener); - /** * Change the state of the given telegram instance and execute all event handlers * @@ -283,14 +321,12 @@ void session_update_contact_list(); /* * Events */ -void on_update_new_message(void (*on_msg)(struct message *M)); -void event_update_new_message(struct message *M); +void event_update_new_message(struct telegram *instance, struct message *M); /* * Load known users and chats on connect */ -void on_peer_allocated(void (*handler)(void *peer)); -void event_peer_allocated(void *peer); +void event_peer_allocated(struct telegram *instance, void *peer); /** * Set a function to use as a handle to read from a network resource From d062ec44d0d76a072ff2fad9342ac9e5c1c5aa82 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 02:41:26 +0200 Subject: [PATCH 352/465] Switch to ready-state when the data center is already registered --- loop.c | 6 ------ telegram.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/loop.c b/loop.c index 90be491..9dfe044 100644 --- a/loop.c +++ b/loop.c @@ -567,12 +567,6 @@ int network_phone_is_registered() { } */ -/** - * Return whether the current client is registered. - */ -int network_client_is_registered(struct telegram *tg) { - return !(tg->auth.auth_state == 100 || !(telegram_get_working_dc(tg)->has_auth)); -} /** * Verify the phone number by providing the sms_code and the real name diff --git a/telegram.c b/telegram.c index fda4e58..ecaf2a0 100755 --- a/telegram.c +++ b/telegram.c @@ -74,6 +74,10 @@ void telegram_change_state (struct telegram *instance, int state, void *data) case STATE_AUTHORIZED: logprintf("requesting configuration\n"); telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); + if (telegram_is_registered(instance)) { + telegram_change_state (instance, STATE_READY, NULL); + return; + } do_help_get_config (instance); break; @@ -102,6 +106,12 @@ void telegram_change_state (struct telegram *instance, int state, void *data) logprintf("client authentication, user needs to enter code"); // wait for user input ... break; + + case STATE_READY: + logprintf("telegram is registered and ready.\n"); + telegram_store_session (instance); + instance->config->on_ready (instance); + break; case STATE_DISCONNECTED_SWITCH_DC: { // telegram demands that we use a different data center, which caused From 32039628a6401217cc49929091f215840e2c1c9e Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 02:44:57 +0200 Subject: [PATCH 353/465] Remove unneeded commented code --- purple-plugin/telegram-purple.c | 22 ------------------- queries.c | 39 --------------------------------- 2 files changed, 61 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index c66b7cf..f9ba248 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -321,28 +321,6 @@ struct telegram_config tgconf = { telegram_on_ready, telegram_on_disconnected, - // Assure client registration - /* - if (!network_client_is_registered()) { - purple_debug_info(PLUGIN_ID, "Client is not registered\n"); - - if (code && strlen(code) > 0 && hash && strlen(hash) > 0) { - purple_debug_info(PLUGIN_ID, "SMS code provided, trying to verify \n"); - purple_debug_info(PLUGIN_ID, "strlen - code: %lu hash: %lu\n", strlen(code), strlen(hash)); - purple_debug_info(PLUGIN_ID, "pointer - code: %p hash: %p\n", code, hash); - purple_debug_info(PLUGIN_ID, "string - code: %s hash: %s\n", code, hash); - if (verified) { - store_config(); - } else { - login_verification_fail(acct); - return; - } - } else { - login_request_verification(acct); - return; - } - } - */ on_new_message, peer_allocated_handler }; diff --git a/queries.c b/queries.c index 3c89ea9..d3a093d 100644 --- a/queries.c +++ b/queries.c @@ -476,29 +476,6 @@ void do_send_code (struct telegram *instance, const char *user) { telegram_change_state(instance, STATE_ERROR, NULL); } // TODO: Phone Code Hash - /* - net_loop (0, code_is_sent); - - if (want_dc_num == -1) { return phone_code_hash; } - bl_do_set_working_dc (dc_working_num); - - logprintf ("send_code: dc_num = %d\n", dc_working_num); - want_dc_num = 0; - clear_packet (mtp); - do_insert_header (); - out_int (CODE_auth_send_code); - out_string (user); - out_int (0); - out_int (TG_APP_ID); - out_string (TG_APP_HASH); - out_string ("en"); - - send_query (telegram_get_working_dc(instance), packet_ptr - packet_buffer, packet_buffer, &send_code_methods, 0); - net_loop (0, code_is_sent); - assert (want_dc_num == -1); - - return phone_code_hash; - */ } @@ -607,12 +584,6 @@ void do_auth_check_phone (struct telegram *instance, const char *user) { check_phone_result = -1; struct dc *DC_working = telegram_get_working_dc(instance); send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &check_phone_methods, instance); - /* - net_loop (0, cr_f); - check_phone_result = -1; - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, instance); - net_loop (0, cr_f); - */ } /* }}} */ @@ -716,11 +687,6 @@ void do_send_code_result (struct telegram *instance, const char *code, const cha out_string(mtp, sms_hash); out_string (mtp, code); send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); - /* - sign_in_ok = 0; - //net_loop (0, sign_in_is_ok); - return sign_in_ok; - */ } void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { @@ -735,11 +701,6 @@ void do_send_code_result_auth (struct telegram *instance, const char *code, cons out_string (mtp, first_name); out_string (mtp, last_name); send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); - /* - sign_in_ok = 0; - net_loop (0, sign_in_is_ok); - return sign_in_ok; - */ } /* }}} */ From 7ee334ec378d4a558e75aa87973f059f2e541a5a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 02:50:11 +0200 Subject: [PATCH 354/465] Fix user registration --- mtproto-client.h | 1 - purple-plugin/telegram-purple.c | 1 + queries.c | 79 +++++++++++++-------------------- queries.h | 4 +- structures.c | 9 ++-- telegram.c | 22 ++++++--- telegram.h | 3 ++ 7 files changed, 59 insertions(+), 60 deletions(-) diff --git a/mtproto-client.h b/mtproto-client.h index 8fbbe40..b55e7d3 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -279,7 +279,6 @@ static inline void out_ints (struct mtproto_connection *self, const int *what, i static inline void out_int (struct mtproto_connection *self, int x) { - logprintf("out_int(): packet_ptr:%p, packet_buffer:%p\n", self->packet_ptr, self->packet_buffer); assert (self->packet_ptr + 1 <= self->packet_buffer + PACKET_BUFFER_SIZE); *self->packet_ptr++ = x; } diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f9ba248..fee3973 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -42,6 +42,7 @@ #include "prefs.h" #include "util.h" #include "eventloop.h" +#include "request.h" // struct telegram Includes diff --git a/queries.c b/queries.c index d3a093d..4fc68af 100644 --- a/queries.c +++ b/queries.c @@ -392,7 +392,6 @@ void do_help_get_config (struct telegram *instance) { /* }}} */ /* {{{ Send code */ -char *phone_code_hash; int send_code_on_answer (struct query *q UU) { struct telegram *instance = q->extra; struct mtproto_connection *mtp = query_get_mtproto(q); @@ -400,19 +399,16 @@ int send_code_on_answer (struct query *q UU) { assert (fetch_int (mtp) == (int)CODE_auth_sent_code); fetch_bool (mtp); int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - if (phone_code_hash) { - tfree_str (phone_code_hash); - } - phone_code_hash = tstrndup (s, l); + char *phone_code_hash = tstrndup (fetch_str (mtp, l), l); + instance->phone_code_hash = phone_code_hash; logprintf("telegram: phone_code_hash: %s\n", phone_code_hash); fetch_int (mtp); fetch_bool (mtp); want_dc_num = -1; if (instance->session_state == STATE_PHONE_CODE_REQUESTED) { - telegram_change_state(instance, STATE_PHONE_CODE_NOT_ENTERED, phone_code_hash); + telegram_change_state(instance, STATE_PHONE_CODE_NOT_ENTERED, NULL); } else if (instance->session_state == STATE_CLIENT_CODE_REQUESTED) { - telegram_change_state(instance, STATE_CLIENT_CODE_NOT_ENTERED, phone_code_hash); + telegram_change_state(instance, STATE_CLIENT_CODE_NOT_ENTERED, NULL); } else { logprintf("send_code_on_answer(): Invalid State %d ", instance->session_state); telegram_change_state(instance, STATE_ERROR, NULL); @@ -507,7 +503,7 @@ void do_phone_call (struct telegram *instance, const char *user) { do_insert_header (mtp); out_int (mtp, CODE_auth_send_call); out_string (mtp, user); - out_string (mtp, phone_code_hash); + out_string (mtp, instance->phone_code_hash); logprintf ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); send_query (telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &phone_call_methods, 0); @@ -527,17 +523,10 @@ int check_phone_on_answer (struct query *q UU) { check_phone_result = fetch_bool (mtp); fetch_bool (mtp); - if (mtp->connection->instance->session_state != STATE_CONFIG_RECEIVED) { - logprintf("check_phone_on_answer(): invalid state: %d\n", mtp->connection->instance->session_state); - telegram_change_state(mtp->connection->instance, STATE_ERROR, NULL); - return -1; - } - logprintf("check_phone_result=%d\n", check_phone_result); - if (check_phone_result) { - telegram_change_state(mtp->connection->instance, STATE_CLIENT_NOT_REGISTERED, NULL); - } else { - telegram_change_state(mtp->connection->instance, STATE_PHONE_NOT_REGISTERED, NULL); - } + assert (mtp->connection->instance->session_state == STATE_CONFIG_RECEIVED); + logprintf ("check_phone_result=%d\n", check_phone_result); + telegram_change_state (mtp->connection->instance, + check_phone_result ? STATE_CLIENT_NOT_REGISTERED : STATE_PHONE_NOT_REGISTERED, NULL); return 0; } @@ -583,7 +572,8 @@ void do_auth_check_phone (struct telegram *instance, const char *user) { out_string (mtp, user); check_phone_result = -1; struct dc *DC_working = telegram_get_working_dc(instance); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &check_phone_methods, instance); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, + &check_phone_methods, instance); } /* }}} */ @@ -629,17 +619,14 @@ void do_get_nearest_dc (struct telegram *instance) { /* }}} */ /* {{{ Sign in / Sign up */ -int sign_in_ok; int our_id; -int sign_in_is_ok (void) { - return sign_in_ok; -} struct user User; -int sign_in_on_answer (struct query *q UU) { +int sign_in_on_answer (struct query *q) { + logprintf ("sign_in_on_answer()\n"); struct mtproto_connection *mtp = query_get_mtproto(q); - struct dc *DC_working = telegram_get_working_dc(q->extra); + struct dc *DC_working = telegram_get_working_dc(mtp->connection->instance); assert (fetch_int (mtp) == (int)CODE_auth_authorization); int expires = fetch_int (mtp); fetch_user (mtp, &User); @@ -647,28 +634,20 @@ int sign_in_on_answer (struct query *q UU) { our_id = get_peer_id (User.id); bl_do_set_our_id (mtp->bl, mtp, our_id); } - sign_in_ok = 1; - logprintf ( "telegram: authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); + logprintf ( "telegram: 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; bl_do_dc_signed (mtp->bl, mtp, DC_working->id); - + telegram_change_state (mtp->connection->instance, STATE_READY, NULL); return 0; } -char lasterror[75]; -const char *get_last_err() -{ - return lasterror; -} - int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { + logprintf ("sign_in_on_error()\n"); + struct mtproto_connection *mtp = query_get_mtproto(q); logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); - if (sizeof(lasterror) >= strlen(error)) { - int dest = memcmp(lasterror, error, strlen(error)); - logprintf("memcpy-state: %d", dest); - } - sign_in_ok = -1; + telegram_change_state (mtp->connection->instance, STATE_CLIENT_CODE_NOT_ENTERED, NULL); return 0; } @@ -677,26 +656,29 @@ struct query_methods sign_in_methods = { .on_error = sign_in_on_error }; -void do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash) { +void do_send_code_result (struct telegram *instance, const char *code) { + logprintf ("do_send_code_result()\n"); struct mtproto_connection *mtp = instance->connection; + assert (instance->session_state == STATE_CLIENT_CODE_NOT_ENTERED); struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (mtp); out_int (mtp, CODE_auth_sign_in); out_string (mtp, suser); - out_string(mtp, sms_hash); + out_string(mtp, instance->phone_code_hash); out_string (mtp, code); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, + &sign_in_methods, NULL); } -void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name) { +void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); out_int (mtp, CODE_auth_sign_up); out_string (mtp ,suser); - out_string (mtp, sms_hash); + out_string (mtp, instance->phone_code_hash); out_string (mtp, code); out_string (mtp, first_name); out_string (mtp, last_name); @@ -1760,7 +1742,7 @@ void do_rename_chat (struct telegram *instance, peer_id_t id, char *name UU) { void print_chat_info (struct chat *C) { // TODO: use peer_t - peer_t *U UU= (void *)C; + peer_t *U UU = (void *)C; //print_start (); //push_color (COLOR_YELLOW); @@ -2821,7 +2803,7 @@ int get_difference_on_answer (struct query *q UU) { unread_messages = fetch_int (mtp); //write_state_file (); for (i = 0; i < ml_pos; i++) { - event_update_new_message(ML[i]); + event_update_new_message (instance, ML[i]); ////print_message (ML[i]); } if (x == CODE_updates_difference_slice) { @@ -3115,3 +3097,4 @@ void do_update_status (struct telegram *instance, int online UU) { send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); } + diff --git a/queries.h b/queries.h index 2e5917e..516b0e2 100644 --- a/queries.h +++ b/queries.h @@ -72,7 +72,7 @@ extern struct query_methods help_get_config_methods; void do_send_code (struct telegram *instance, const char *user); void do_phone_call (struct telegram *instance, const char *user); -void do_send_code_result (struct telegram *instance, const char *code, const char *sms_hash); +void do_send_code_result (struct telegram *instance, const char *code); double get_double_time (void); void do_update_contact_list (struct telegram *instance); @@ -105,7 +105,7 @@ void do_load_document_thumb (struct telegram *instance, struct document *video, void do_help_get_config (struct telegram *instance); void do_auth_check_phone (struct telegram *instance, const char *user); void do_get_nearest_dc (struct telegram*); -void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name); +void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name); void do_import_auth (struct telegram *instance, int num); void do_export_auth (struct telegram *instance, int num); void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); diff --git a/structures.c b/structures.c index de7f5c5..16c2793 100644 --- a/structures.c +++ b/structures.c @@ -1550,7 +1550,7 @@ struct user *fetch_alloc_user (struct mtproto_connection *mtp) { } fetch_user (mtp, &U->user); if (send_event) { - event_peer_allocated(U); + event_peer_allocated(mtp->connection->instance, U); } return &U->user; } @@ -1569,7 +1569,7 @@ struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp) Peers[peer_num ++] = U; } fetch_encrypted_chat (mtp, &U->encr_chat); - event_peer_allocated(U); + event_peer_allocated(mtp->connection->instance, U); return &U->encr_chat; } @@ -1820,14 +1820,15 @@ struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct tele int data[2]; prefetch_data (mtp, data, 8); struct message *M = message_get (data[1]); - M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); M->id = data[1]; + M->instance = instance; message_insert_tree (M); messages_allocated ++; } + M->instance = instance; fetch_message (mtp, M); return M; } @@ -1926,7 +1927,7 @@ struct chat *fetch_alloc_chat (struct mtproto_connection *mtp) { Peers[peer_num ++] = U; } fetch_chat (mtp, &U->chat); - event_peer_allocated(U); + event_peer_allocated(mtp->connection->instance, U); return &U->chat; } diff --git a/telegram.c b/telegram.c index ecaf2a0..db40105 100755 --- a/telegram.c +++ b/telegram.c @@ -44,9 +44,17 @@ void event_peer_allocated(struct telegram *instance, void *peer) */ char *telegram_get_config(struct telegram *instance, char *config) { - return g_strdup_printf("%s/%s", instance->config_path, config); + return g_strdup_printf("%s/%s", instance->config->base_config_path, config); } +/** + * Return whether the current client is registered. + */ +int telegram_is_registered(struct telegram *tg) { + return telegram_get_working_dc(tg)->has_auth; +} + + /** * Handle state changes of the telegram instance * @@ -92,8 +100,10 @@ void telegram_change_state (struct telegram *instance, int state, void *data) do_send_code(instance, instance->login); break; - case STATE_PHONE_CODE_REQUESTED: + case STATE_PHONE_CODE_NOT_ENTERED: logprintf("phone authenticion, user needs to enter code, first and last name.\n"); + assert (instance->config->on_phone_registration_required); + instance->config->on_phone_registration_required (instance); // wait for user input ... break; @@ -103,7 +113,9 @@ void telegram_change_state (struct telegram *instance, int state, void *data) break; case STATE_CLIENT_CODE_NOT_ENTERED: - logprintf("client authentication, user needs to enter code"); + logprintf("client authentication, user needs to enter code.\n"); + assert (instance->config->on_client_registration_required); + instance->config->on_client_registration_required (instance); // wait for user input ... break; @@ -175,6 +187,7 @@ void telegram_free(struct telegram *this) void assert_file_usable(const char *file) { + logprintf ("assert_file_usable (%s)\n", file); assert(access(file, W_OK | R_OK | F_OK) != -1); } @@ -231,7 +244,7 @@ void telegram_restore_session(struct telegram *instance) } /** - * Load the current session state from a file + * Load the current session state */ void telegram_store_session(struct telegram *instance) { @@ -306,4 +319,3 @@ int telegram_has_output (struct telegram *instance) { return instance->connection->queries_num > 0; } - diff --git a/telegram.h b/telegram.h index 8e04e0d..fff1a45 100644 --- a/telegram.h +++ b/telegram.h @@ -188,6 +188,9 @@ struct telegram { */ struct binlog *bl; + // TODO: Bind this to the current data center, since the code hash is only + // valid in its context + char *phone_code_hash; void *extra; }; From dddbe451c1da0f77a75156ee154136ac7584f242 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 02:53:57 +0200 Subject: [PATCH 355/465] fix a bug in the configuration writer creates new configuration files readable and writable --- telegram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram.c b/telegram.c index db40105..f23b230 100755 --- a/telegram.c +++ b/telegram.c @@ -195,7 +195,7 @@ void assure_file_exists(const char *dir, const char *file) { g_mkdir_with_parents(dir, 0700); char *f = g_strdup_printf("%s/%s", dir, file); - close(open(f, O_RDWR | O_CREAT, S_IRUSR, S_IWUSR)); + close(open(f, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)); assert_file_usable(f); g_free(f); } From eec5ea50aa8ebd15b7f794c1ae656058e5b213a1 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 02:56:47 +0200 Subject: [PATCH 356/465] Remove globals containing account and connection from the purple plugin to enable multiple connections --- purple-plugin/telegram-purple.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index fee3973..4ddfa7a 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -56,9 +56,6 @@ #define BUDDYNAME_MAX_LENGTH 128 static PurplePlugin *_telegram_protocol = NULL; - -PurpleConnection *_gc; -PurpleAccount *_pa; PurpleGroup *tggroup; void tgprpl_login_on_connected(); @@ -334,8 +331,6 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); char const *username = purple_account_get_username(acct); - _gc = gc; - _pa = acct; struct dc DC; init_dc_settings(acct, &DC); @@ -358,10 +353,13 @@ static void tgprpl_login(PurpleAccount * acct) void on_new_message(struct telegram *tg, struct message *M) { + telegram_conn *conn = tg->extra; + PurpleConnection *gc = conn->gc; + purple_debug_info(PLUGIN_ID, "New Message: %s\n", M->message); // TODO: this should probably be freed again somwhere char *who = g_strdup_printf("%d", get_peer_id(M->from_id)); - serv_got_im(_gc, who, M->message, PURPLE_MESSAGE_RECV, time(NULL)); + serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time(NULL)); g_free(who); } @@ -401,6 +399,10 @@ static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id) void peer_allocated_handler(struct telegram *tg, void *usr) { + telegram_conn *conn = tg->extra; + PurpleConnection *gc = conn->gc; + PurpleAccount *pa = conn->pa; + peer_t *user = usr; gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); logprintf("Allocated peer: %s\n", name); @@ -415,10 +417,10 @@ void peer_allocated_handler(struct telegram *tg, void *usr) get_peer_id(user->id)); return; } - PurpleBuddy *buddy = purple_find_buddy(_pa, name); + PurpleBuddy *buddy = purple_find_buddy(pa, name); if (!buddy) { purple_debug_info(PLUGIN_ID, "Adding %s to buddy list\n", name); - buddy = purple_buddy_new(_pa, name, alias); + buddy = purple_buddy_new(pa, name, alias); purple_blist_add_buddy(buddy, NULL, tggroup, NULL); } purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); @@ -427,7 +429,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) break; case PEER_CHAT: { logprintf("Peer type: chat.\n"); - PurpleChat *ch = blist_find_chat_by_id(_gc, name); + PurpleChat *ch = blist_find_chat_by_id(gc, name); if (!ch) { gchar *admin = g_strdup_printf("%d", user->chat.admin_id); GHashTable *htable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); @@ -435,7 +437,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) g_hash_table_insert(htable, g_strdup("id"), name); g_hash_table_insert(htable, g_strdup("owner"), admin); logprintf("Adding chat to blist: %s (%s, %s)\n", user->chat.title, name, admin); - ch = purple_chat_new(_pa, user->chat.title, htable); + ch = purple_chat_new(pa, user->chat.title, htable); purple_blist_add_chat(ch, NULL, NULL); } @@ -443,7 +445,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) //char const *id = g_hash_table_lookup(gh, "id"); char const *owner = g_hash_table_lookup(gh, "owner"); - PurpleConversation *conv = purple_find_chat(_gc, atoi(name)); + PurpleConversation *conv = purple_find_chat(gc, atoi(name)); purple_conv_chat_clear_users(purple_conversation_get_chat_data(conv)); if (conv) { @@ -495,8 +497,10 @@ static void tgprpl_close(PurpleConnection * gc) static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) { telegram_conn *conn = purple_connection_get_protocol_data(gc); + PurpleAccount *pa = conn->pa; + purple_debug_info(PLUGIN_ID, "tgprpl_send_im()\n"); - PurpleBuddy *b = purple_find_buddy(_pa, who); + PurpleBuddy *b = purple_find_buddy(pa, who); peer_id_t *peer = purple_buddy_get_protocol_data(b); do_send_message(conn->tg, *peer, message, strlen(message)); return 1; From 832cf949f0b9291679468f5fc15fdb8f8848aa8c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 11:18:42 +0200 Subject: [PATCH 357/465] Fix message allocation --- purple-plugin/telegram-purple.c | 31 ++++++++++++++++++++----------- structures.c | 3 +++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 4ddfa7a..0931fdf 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -44,8 +44,6 @@ #include "eventloop.h" #include "request.h" -// struct telegram Includes - // telegram-purple includes #include "telegram.h" #include "telegram-purple.h" @@ -71,7 +69,7 @@ void tg_cli_log_cb(const char* format, va_list ap) purple_debug_info(PLUGIN_ID, "%s", buffer); } -void on_new_message (struct telegram *instance, struct message *M); +void message_allocated_handler (struct telegram *instance, struct message *M); void peer_allocated_handler (struct telegram *instance, void *user); void telegram_on_phone_registration (struct telegram *instance); void elegram_on_client_registration (struct telegram *instance); @@ -262,7 +260,7 @@ void telegram_on_ready (struct telegram *instance) tggroup = purple_find_group("Telegram"); if (tggroup == NULL) { purple_debug_info (PLUGIN_ID, "PurpleGroup = NULL, creating"); - tggroup = purple_group_new ("struct telegram"); + tggroup = purple_group_new ("Telegram"); purple_blist_add_group (tggroup, NULL); } @@ -319,7 +317,7 @@ struct telegram_config tgconf = { telegram_on_ready, telegram_on_disconnected, - on_new_message, + message_allocated_handler, peer_allocated_handler }; @@ -351,16 +349,27 @@ static void tgprpl_login(PurpleAccount * acct) telegram_network_connect(tg); } -void on_new_message(struct telegram *tg, struct message *M) +void message_allocated_handler(struct telegram *tg, struct message *M) { + logprintf ("message_allocated_handler\n"); telegram_conn *conn = tg->extra; PurpleConnection *gc = conn->gc; - purple_debug_info(PLUGIN_ID, "New Message: %s\n", M->message); - // TODO: this should probably be freed again somwhere - char *who = g_strdup_printf("%d", get_peer_id(M->from_id)); - serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time(NULL)); - g_free(who); + // TODO: this should probably be freed again somwhere + int id = get_peer_id(M->from_id); + logprintf ("id: %d\n", id); + char *who = g_strdup_printf("%d", id); + if (who) { + logprintf ("who: %s\n", who); + if (M->service) { + // TODO: handle service messages properly, currently adding them + // causes a segfault for an unknown reason + logprintf ("service message, skipping...\n"); + return; + } + serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time(NULL)); + g_free(who); + } } diff --git a/structures.c b/structures.c index 16c2793..a9dd465 100644 --- a/structures.c +++ b/structures.c @@ -1827,6 +1827,9 @@ struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct tele M->instance = instance; message_insert_tree (M); messages_allocated ++; + fetch_message (mtp, M); + event_update_new_message (instance, M); + return M; } M->instance = instance; fetch_message (mtp, M); From 5a425be62f0f0008cb2df6ec6726880a30802314 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 12:57:38 +0200 Subject: [PATCH 358/465] Remove unused code and build files --- App configuration.html | 177 -- Makefile.in | 2 +- ax_lua.m4 | 614 ------ binlog.c | 6 - config.h.in | 177 -- config.sample | 66 - configure | 1962 +----------------- configure.ac | 54 +- debian/changelog | 5 - debian/clean | 1 - debian/compat | 1 - debian/control | 36 - debian/copyright | 28 - debian/docs | 1 - debian/install | 1 - debian/rules | 17 - debian/source/format | 1 - debian/watch | 4 - gentoo/telegram-cli/Manifest | 1 - gentoo/telegram-cli/telegram-cli-9999.ebuild | 31 - interface.c | 1577 -------------- interface.h | 63 - loop.c | 308 --- lua-tg.c | 550 ----- lua-tg.h | 18 - main.c | 493 ----- mtproto-client.c | 55 - mtproto-client.h | 4 - net.c | 5 - net.h | 2 - queries.c | 32 - rpm/telegram-cli-Beta-2.fc20.x86_64.rpm | Bin 147652 -> 0 bytes structures.c | 4 - telegram-cli.spec | 46 - test.lua | 95 - tools.c | 32 +- 36 files changed, 73 insertions(+), 6396 deletions(-) delete mode 100644 App configuration.html delete mode 100644 ax_lua.m4 delete mode 100644 config.h.in delete mode 100644 config.sample delete mode 100644 debian/changelog delete mode 100644 debian/clean delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100644 debian/docs delete mode 100644 debian/install delete mode 100755 debian/rules delete mode 100644 debian/source/format delete mode 100644 debian/watch delete mode 100644 gentoo/telegram-cli/Manifest delete mode 100644 gentoo/telegram-cli/telegram-cli-9999.ebuild delete mode 100644 interface.c delete mode 100644 interface.h delete mode 100644 lua-tg.c delete mode 100644 lua-tg.h delete mode 100644 main.c delete mode 100644 rpm/telegram-cli-Beta-2.fc20.x86_64.rpm delete mode 100644 telegram-cli.spec delete mode 100644 test.lua diff --git a/App configuration.html b/App configuration.html deleted file mode 100644 index e416b66..0000000 --- a/App configuration.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - - App configuration - - - - - - - - - - -
-
- -
-
-
-
-

App configuration

-
- -
- 16154 -
-
-
- -
- -
- 99428c722d0ed59b9cd844e4577cb4bb -
-
-
- -
- -
- -
-
- -
- -
- -

alphanumeric, 5-32 characters

-
-
- -
-

PUSH-notifications settings

- -
- - -
-
- -
-

- APNS certificates - -  Update -  Delete - -

- - - - -
- -

Available MTProto servers

- -
- -
- 173.240.5.253:443 -

First DC

-
-
-
- -
- 173.240.5.1:443 -

First DC

-
-
- -
- -
-
-----BEGIN RSA PUBLIC KEY-----
-MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
-lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
-an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
-Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
-8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
-Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
------END RSA PUBLIC KEY-----
-
-
- - -
- - Cancel -
-
-
- -
-
-
- - - - - - - \ No newline at end of file diff --git a/Makefile.in b/Makefile.in index c0a9367..1255097 100644 --- a/Makefile.in +++ b/Makefile.in @@ -14,7 +14,7 @@ EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h INCLUDE=-I. -I${srcdir} CC=@CC@ diff --git a/ax_lua.m4 b/ax_lua.m4 deleted file mode 100644 index d9f4773..0000000 --- a/ax_lua.m4 +++ /dev/null @@ -1,614 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_lua.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# -# DESCRIPTION -# -# Detect a Lua interpreter, optionally specifying a minimum and maximum -# version number. Set up important Lua paths, such as the directories in -# which to install scripts and modules (shared libraries). -# -# Also detect Lua headers and libraries. The Lua version contained in the -# header is checked to match the Lua interpreter version exactly. When -# searching for Lua libraries, the version number is used as a suffix. -# This is done with the goal of supporting multiple Lua installs (5.1 and -# 5.2 side-by-side). -# -# A note on compatibility with previous versions: This file has been -# mostly rewritten for serial 18. Most developers should be able to use -# these macros without needing to modify configure.ac. Care has been taken -# to preserve each macro's behavior, but there are some differences: -# -# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as -# AX_PROG_LUA with no arguments. -# -# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h -# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore -# unnecessary, so it is deprecated and does not expand to anything. -# -# 3) The configure flag --with-lua-suffix no longer exists; the user -# should instead specify the LUA precious variable on the command line. -# See the AX_PROG_LUA description for details. -# -# Please read the macro descriptions below for more information. -# -# This file was inspired by Andrew Dalke's and James Henstridge's -# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 -# (serial 17). Basically, this file is a mash-up of those two files. I -# like to think it combines the best of the two! -# -# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua -# paths. Adds precious variable LUA, which may contain the path of the Lua -# interpreter. If LUA is blank, the user's path is searched for an -# suitable interpreter. -# -# If MINIMUM-VERSION is supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION will be accepted. If -# TOO-BIG- VERSION is also supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION and less than -# TOO-BIG-VERSION will be accepted. -# -# Version comparisons require the AX_COMPARE_VERSION macro, which is -# provided by ax_compare_version.m4 from the Autoconf Archive. -# -# The Lua version number, LUA_VERSION, is found from the interpreter, and -# substituted. LUA_PLATFORM is also found, but not currently supported (no -# standard representation). -# -# Finally, the macro finds four paths: -# -# luadir Directory to install Lua scripts. -# pkgluadir $luadir/$PACKAGE -# luaexecdir Directory to install Lua modules. -# pkgluaexecdir $luaexecdir/$PACKAGE -# -# These paths a found based on $prefix, $exec_prefix, Lua's package.path, -# and package.cpath. The first path of package.path beginning with $prefix -# is selected as luadir. The first path of package.cpath beginning with -# $exec_prefix is used as luaexecdir. This should work on all reasonable -# Lua installations. If a path cannot be determined, a default path is -# used. Of course, the user can override these later when invoking make. -# -# luadir Default: $prefix/share/lua/$LUA_VERSION -# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION -# -# These directories can be used by Automake as install destinations. The -# variable name minus 'dir' needs to be used as a prefix to the -# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. -# -# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- -# FOUND is blank, then it will default to printing an error. To prevent -# the default behavior, give ':' as an action. -# -# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_INCLUDE, which -# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If -# LUA_INCLUDE is blank, then this macro will attempt to find suitable -# flags. -# -# LUA_INCLUDE can be used by Automake to compile Lua modules or -# executables with embedded interpreters. The *_CPPFLAGS variables should -# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). -# -# This macro searches for the header lua.h (and others). The search is -# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. -# If the search is unsuccessful, then some common directories are tried. -# If the headers are then found, then LUA_INCLUDE is set accordingly. -# -# The paths automatically searched are: -# -# * /usr/include/luaX.Y -# * /usr/include/lua/X.Y -# * /usr/include/luaXY -# * /usr/local/include/luaX.Y -# * /usr/local/include/lua-X.Y -# * /usr/local/include/lua/X.Y -# * /usr/local/include/luaXY -# -# (Where X.Y is the Lua version number, e.g. 5.1.) -# -# The Lua version number found in the headers is always checked to match -# the Lua interpreter's version number. Lua headers with mismatched -# version numbers are not accepted. -# -# If headers are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_LIB, which may -# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, -# then this macro will attempt to find suitable flags. -# -# LUA_LIB can be used by Automake to link Lua modules or executables with -# embedded interpreters. The *_LIBADD and *_LDADD variables should be used -# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). -# -# This macro searches for the Lua library. More technically, it searches -# for a library containing the function lua_load. The search is performed -# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. -# -# If the search determines that some linker flags are missing, then those -# flags will be added to LUA_LIB. -# -# If libraries are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_READLINE: Search for readline headers and libraries. Requires the -# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the -# Autoconf Archive. -# -# If a readline compatible library is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is performed. -# -# LICENSE -# -# Copyright (c) 2013 Tim Perkins -# Copyright (c) 2013 Reuben Thomas -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 21 - -dnl ========================================================================= -dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION], -dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_PROG_LUA], -[ - dnl Make LUA a precious variable. - AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1]) - - dnl Find a Lua interpreter. - m4_define_default([_AX_LUA_INTERPRETER_LIST], - [lua lua5.2 lua52 lua5.1 lua51 lua50]) - - m4_if([$1], [], - [ dnl No version check is needed. Find any Lua interpreter. - AS_IF([test "x$LUA" = 'x'], - [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])]) - ax_display_LUA='lua' - - dnl At least check if this is a Lua interpreter. - AC_MSG_CHECKING([if $LUA is a Lua interpreter]) - _AX_LUA_CHK_IS_INTRP([$LUA], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([not a Lua interpreter]) - ]) - ], - [ dnl A version check is needed. - AS_IF([test "x$LUA" != 'x'], - [ dnl Check if this is a Lua interpreter. - AC_MSG_CHECKING([if $LUA is a Lua interpreter]) - _AX_LUA_CHK_IS_INTRP([$LUA], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([not a Lua interpreter]) - ]) - dnl Check the version. - m4_if([$2], [], - [_ax_check_text="whether $LUA version >= $1"], - [_ax_check_text="whether $LUA version >= $1, < $2"]) - AC_MSG_CHECKING([$_ax_check_text]) - _AX_LUA_CHK_VER([$LUA], [$1], [$2], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([version is out of range for specified LUA])]) - ax_display_LUA=$LUA - ], - [ dnl Try each interpreter until we find one that satisfies VERSION. - m4_if([$2], [], - [_ax_check_text="for a Lua interpreter with version >= $1"], - [_ax_check_text="for a Lua interpreter with version >= $1, < $2"]) - AC_CACHE_CHECK([$_ax_check_text], - [ax_cv_pathless_LUA], - [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do - test "x$ax_cv_pathless_LUA" = 'xnone' && break - _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue]) - _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break]) - done - ]) - dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA. - AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'], - [LUA=':'], - [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])]) - ax_display_LUA=$ax_cv_pathless_LUA - ]) - ]) - - AS_IF([test "x$LUA" = 'x:'], - [ dnl Run any user-specified action, or abort. - m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])]) - ], - [ dnl Query Lua for its version number. - AC_CACHE_CHECK([for $ax_display_LUA version], [ax_cv_lua_version], - [ ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ - sed "s|^Lua \(.*\)|\1|" | \ - grep -E -o "^@<:@0-9@:>@+\.@<:@0-9@:>@+"` - ]) - AS_IF([test "x$ax_cv_lua_version" = 'x'], - [AC_MSG_ERROR([invalid Lua version number])]) - AC_SUBST([LUA_VERSION], [$ax_cv_lua_version]) - AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | sed 's|\.||'`]) - - dnl The following check is not supported: - dnl At times (like when building shared libraries) you may want to know - dnl which OS platform Lua thinks this is. - AC_CACHE_CHECK([for $ax_display_LUA platform], [ax_cv_lua_platform], - [ax_cv_lua_platform=`$LUA -e "print('unknown')"`]) - AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform]) - - dnl Use the values of $prefix and $exec_prefix for the corresponding - dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct - dnl variables so they can be overridden if need be. However, the general - dnl consensus is that you shouldn't need this ability. - AC_SUBST([LUA_PREFIX], ['${prefix}']) - AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}']) - - dnl Lua provides no way to query the script directory, and instead - dnl provides LUA_PATH. However, we should be able to make a safe educated - dnl guess. If the built-in search path contains a directory which is - dnl prefixed by $prefix, then we can store scripts there. The first - dnl matching path will be used. - AC_CACHE_CHECK([for $ax_display_LUA script directory], - [ax_cv_lua_luadir], - [ AS_IF([test "x$prefix" = 'xNONE'], - [ax_lua_prefix=$ac_default_prefix], - [ax_lua_prefix=$prefix]) - - dnl Initialize to the default path. - ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" - - dnl Try to find a path with the prefix. - _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [package.path]) - AS_IF([test "x$ax_lua_prefixed_path" != 'x'], - [ dnl Fix the prefix. - _ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'` - ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ - sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"` - ]) - ]) - AC_SUBST([luadir], [$ax_cv_lua_luadir]) - AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE]) - - dnl Lua provides no way to query the module directory, and instead - dnl provides LUA_PATH. However, we should be able to make a safe educated - dnl guess. If the built-in search path contains a directory which is - dnl prefixed by $exec_prefix, then we can store modules there. The first - dnl matching path will be used. - AC_CACHE_CHECK([for $ax_display_LUA module directory], - [ax_cv_lua_luaexecdir], - [ AS_IF([test "x$exec_prefix" = 'xNONE'], - [ax_lua_exec_prefix=$ax_lua_prefix], - [ax_lua_exec_prefix=$exec_prefix]) - - dnl Initialize to the default path. - ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" - - dnl Try to find a path with the prefix. - _AX_LUA_FND_PRFX_PTH([$LUA], - [$ax_lua_exec_prefix], [package.cpathd]) - AS_IF([test "x$ax_lua_prefixed_path" != 'x'], - [ dnl Fix the prefix. - _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'` - ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ - sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"` - ]) - ]) - AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir]) - AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE]) - - dnl Run any user specified action. - $3 - ]) -]) - -dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA. -AC_DEFUN([AX_WITH_LUA], -[ - AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA]]) - AX_PROG_LUA -]) - - -dnl ========================================================================= -dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_CHK_IS_INTRP], -[ - dnl Just print _VERSION because all Lua interpreters have this global. - AS_IF([$1 -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null], - [$2], [$3]) -]) - - -dnl ========================================================================= -dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION], -dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_CHK_VER], -[ - _ax_test_ver=`$1 -e "print(_VERSION)" 2>/dev/null | \ - sed "s|^Lua \(.*\)|\1|" | grep -E -o "^@<:@0-9@:>@+\.@<:@0-9@:>@+"` - AS_IF([test "x$_ax_test_ver" = 'x'], - [_ax_test_ver='0']) - AX_COMPARE_VERSION([$_ax_test_ver], [ge], [$2]) - m4_if([$3], [], [], - [ AS_IF([$ax_compare_version], - [AX_COMPARE_VERSION([$_ax_test_ver], [lt], [$3])]) - ]) - AS_IF([$ax_compare_version], [$4], [$5]) -]) - - -dnl ========================================================================= -dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, LUA-PATH-VARIABLE) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_FND_PRFX_PTH], -[ - dnl Invokes the Lua interpreter PROG to print the path variable - dnl LUA-PATH-VARIABLE, usually package.path or package.cpath. Paths are - dnl then matched against PREFIX. The first path to begin with PREFIX is set - dnl to ax_lua_prefixed_path. - - ax_lua_prefixed_path='' - _ax_package_paths=`$1 -e 'print($3)' 2>/dev/null | sed 's|;|\n|g'` - dnl Try the paths in order, looking for the prefix. - for _ax_package_path in $_ax_package_paths; do - dnl Copy the path, up to the use of a Lua wildcard. - _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` - _ax_reassembled='' - for _ax_path_part in $_ax_path_parts; do - echo "$_ax_path_part" | grep '\?' >/dev/null && break - _ax_reassembled="$_ax_reassembled/$_ax_path_part" - done - dnl Check the path against the prefix. - _ax_package_path=$_ax_reassembled - if echo "$_ax_package_path" | grep "^$2" >/dev/null; then - dnl Found it. - ax_lua_prefixed_path=$_ax_package_path - break - fi - done -]) - - -dnl ========================================================================= -dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_HEADERS], -[ - dnl Check for LUA_VERSION. - AC_MSG_CHECKING([if LUA_VERSION is defined]) - AS_IF([test "x$LUA_VERSION" != 'x'], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION]) - ]) - - dnl Make LUA_INCLUDE a precious variable. - AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1]) - - dnl Some default directories to search. - LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` - m4_define_default([_AX_LUA_INCLUDE_LIST], - [ /usr/include/lua$LUA_VERSION \ - /usr/include/lua/$LUA_VERSION \ - /usr/include/lua$LUA_SHORT_VERSION \ - /usr/local/include/lua$LUA_VERSION \ - /usr/local/include/lua-$LUA_VERSION \ - /usr/local/include/lua/$LUA_VERSION \ - /usr/local/include/lua$LUA_SHORT_VERSION \ - ]) - - dnl Try to find the headers. - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) - CPPFLAGS=$_ax_lua_saved_cppflags - - dnl Try some other directories if LUA_INCLUDE was not set. - AS_IF([test "x$LUA_INCLUDE" = 'x' && - test "x$ac_cv_header_lua_h" != 'xyes'], - [ dnl Try some common include paths. - for _ax_include_path in _AX_LUA_INCLUDE_LIST; do - test ! -d "$_ax_include_path" && continue - - AC_MSG_CHECKING([for Lua headers in]) - AC_MSG_RESULT([$_ax_include_path]) - - AS_UNSET([ac_cv_header_lua_h]) - AS_UNSET([ac_cv_header_lualib_h]) - AS_UNSET([ac_cv_header_lauxlib_h]) - AS_UNSET([ac_cv_header_luaconf_h]) - - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS -I$_ax_include_path" - AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) - CPPFLAGS=$_ax_lua_saved_cppflags - - AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], - [ LUA_INCLUDE="-I$_ax_include_path" - break - ]) - done - ]) - - AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], - [ dnl Make a program to print LUA_VERSION defined in the header. - dnl TODO This probably shouldn't be a runtime test. - - AC_CACHE_CHECK([for Lua header version], - [ax_cv_lua_header_version], - [ _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - AC_RUN_IFELSE( - [ AC_LANG_SOURCE([[ -#include -#include -#include -int main(int argc, char ** argv) -{ - if(argc > 1) printf("%s", LUA_VERSION); - exit(EXIT_SUCCESS); -} -]]) - ], - [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ - sed "s|^Lua \(.*\)|\1|" | \ - grep -E -o "^@<:@0-9@:>@+\.@<:@0-9@:>@+"` - ], - [ax_cv_lua_header_version='unknown']) - CPPFLAGS=$_ax_lua_saved_cppflags - ]) - - dnl Compare this to the previously found LUA_VERSION. - AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) - AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], - [ AC_MSG_RESULT([yes]) - ax_header_version_match='yes' - ], - [ AC_MSG_RESULT([no]) - ax_header_version_match='no' - ]) - ]) - - dnl Was LUA_INCLUDE specified? - AS_IF([test "x$ax_header_version_match" != 'xyes' && - test "x$LUA_INCLUDE" != 'x'], - [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])]) - - dnl Test the final result and run user code. - AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1], - [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])]) -]) - -dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS. -AC_DEFUN([AX_LUA_HEADERS_VERSION], -[ - AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS]]) -]) - - -dnl ========================================================================= -dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_LIBS], -[ - dnl TODO Should this macro also check various -L flags? - - dnl Check for LUA_VERSION. - AC_MSG_CHECKING([if LUA_VERSION is defined]) - AS_IF([test "x$LUA_VERSION" != 'x'], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION]) - ]) - - dnl Make LUA_LIB a precious variable. - AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1]) - - AS_IF([test "x$LUA_LIB" != 'x'], - [ dnl Check that LUA_LIBS works. - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - AC_SEARCH_LIBS([lua_load], [], - [_ax_found_lua_libs='yes'], - [_ax_found_lua_libs='no']) - LIBS=$_ax_lua_saved_libs - - dnl Check the result. - AS_IF([test "x$_ax_found_lua_libs" != 'xyes'], - [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])]) - ], - [ dnl First search for extra libs. - _ax_lua_extra_libs='' - - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - AC_SEARCH_LIBS([exp], [m]) - AC_SEARCH_LIBS([dlopen], [dl]) - LIBS=$_ax_lua_saved_libs - - AS_IF([test "x$ac_cv_search_exp" != 'xno' && - test "x$ac_cv_search_exp" != 'xnone required'], - [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"]) - - AS_IF([test "x$ac_cv_search_dlopen" != 'xno' && - test "x$ac_cv_search_dlopen" != 'xnone required'], - [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"]) - - dnl Try to find the Lua libs. - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - AC_SEARCH_LIBS([lua_load], - [ lua$LUA_VERSION \ - lua$LUA_SHORT_VERSION \ - lua-$LUA_VERSION \ - lua-$LUA_SHORT_VERSION \ - lua], - [_ax_found_lua_libs='yes'], - [_ax_found_lua_libs='no'], - [$_ax_lua_extra_libs]) - LIBS=$_ax_lua_saved_libs - - AS_IF([test "x$ac_cv_search_lua_load" != 'xno' && - test "x$ac_cv_search_lua_load" != 'xnone required'], - [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"]) - ]) - - dnl Test the result and run user code. - AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1], - [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])]) -]) - - -dnl ========================================================================= -dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_READLINE], -[ - AX_LIB_READLINE - AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' && - test "x$ac_cv_header_readline_history_h" != 'x'], - [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS" - $1 - ], - [$2]) -]) diff --git a/binlog.c b/binlog.c index d8b7421..84915e6 100644 --- a/binlog.c +++ b/binlog.c @@ -17,10 +17,6 @@ Copyright Vitaly Valtman 2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include #include #include @@ -55,8 +51,6 @@ char *get_binlog_file_name() return "/home/dev-jessie/.telegram/binlog"; } -//extern struct dc *DC_list[]; -//extern int dc_working_num; extern int our_id; int binlog_enabled = 0; extern int encr_root; diff --git a/config.h.in b/config.h.in deleted file mode 100644 index 1a20b5b..0000000 --- a/config.h.in +++ /dev/null @@ -1,177 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the `alarm' function. */ -#undef HAVE_ALARM - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define to 1 if you have the `endpwent' function. */ -#undef HAVE_ENDPWENT - -/* Define to 1 if you have the header file. */ -#undef HAVE_EXECINFO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LAUXLIB_H - -/* Define to 1 if you have the `config' library (-lconfig). */ -#undef HAVE_LIBCONFIG - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -#undef HAVE_LIBCRYPTO - -/* Define to 1 if you have the `edit' library (-ledit). */ -#undef HAVE_LIBEDIT - -/* Define to 1 if you have the `m' library (-lm). */ -#undef HAVE_LIBM - -/* Define to 1 if you have the `z' library (-lz). */ -#undef HAVE_LIBZ - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUACONF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUALIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LUA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MACH_MACH_H - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#undef HAVE_MALLOC - -/* Define to 1 if you have the header file. */ -#undef HAVE_MALLOC_H - -/* Define to 1 if you have the `memmove' function. */ -#undef HAVE_MEMMOVE - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET - -/* Define to 1 if you have the `mkdir' function. */ -#undef HAVE_MKDIR - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#undef HAVE_REALLOC - -/* Define to 1 if you have the `select' function. */ -#undef HAVE_SELECT - -/* Define to 1 if you have the `socket' function. */ -#undef HAVE_SOCKET - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strdup' function. */ -#undef HAVE_STRDUP - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strndup' function. */ -#undef HAVE_STRNDUP - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_FILE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_TERMIOS_H - -/* Define to 1 if you have the `uname' function. */ -#undef HAVE_UNAME - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Use custom prog name */ -#undef PROG_NAME - -/* Use libedit */ -#undef READLINE_EDIT - -/* Use gnu libreadline */ -#undef READLINE_GNU - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* use lua */ -#undef USE_LUA - -/* Define to `int' if doesn't define. */ -#undef gid_t - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -/* Define to rpl_malloc if the replacement function should be used. */ -#undef malloc - -/* Define to rpl_realloc if the replacement function should be used. */ -#undef realloc - -/* Define to `unsigned int' if does not define. */ -#undef size_t - -/* Define to `int' if doesn't define. */ -#undef uid_t diff --git a/config.sample b/config.sample deleted file mode 100644 index dffcc44..0000000 --- a/config.sample +++ /dev/null @@ -1,66 +0,0 @@ -# This is an empty config file -# Feel free to put something here - -default_profile = "binlog"; - -test_dc1 = { - config_directory = ".telegram/test_dc1"; - test = true; - msg_num = true; - binlog_enabled = true; -}; - -binlog = { - config_directory = ".telegram/binlog"; - test = false; - msg_num = true; - binlog_enabled = true; - log_level = 2; -}; - -binlog_mts = { - config_directory = ".telegram/binlog_mts"; - test = false; - msg_num = true; - binlog_enabled = true; - log_level = 2; -}; - -mega = { - config_directory = ".telegram/mega"; - test = false; - msg_num = true; - binlog_enabled = true; - log_level = 2; -}; - -new = { - config_directory = ".telegram/new"; - test = false; - msg_num = true; -}; - -production = { - config_directory = ".telegram/production"; - test = false; - msg_num = true; -}; - -test = { - config_directory = ".telegram/test"; - test = true; - msg_num = true; -}; - -test1 = { - config_directory = ".telegram/test1"; - msg_num = true; - binlog_enabled = true; -}; - -test2 = { - config_directory = ".telegram/test2"; - msg_num = true; - binlog_enabled = true; -}; - diff --git a/configure b/configure index 0a54e9f..ea2640d 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for telegram 0.1. +# Generated by GNU Autoconf 2.69 for telegram-purple 0.1. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -575,14 +575,13 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME='telegram' -PACKAGE_TARNAME='telegram' +PACKAGE_NAME='telegram-purple' +PACKAGE_TARNAME='telegram-purple' PACKAGE_VERSION='0.1' -PACKAGE_STRING='telegram 0.1' +PACKAGE_STRING='telegram-purple 0.1' PACKAGE_BUGREPORT='' PACKAGE_URL='' -ac_unique_file="config.h.in" # Factoring default headers for most tests. ac_includes_default="\ #include @@ -622,21 +621,9 @@ ac_includes_default="\ ac_subst_vars='LTLIBOBJS EXTRA_LIBS LIBOBJS -LUA_LIB EGREP GREP CPP -LUA_INCLUDE -pkgluaexecdir -luaexecdir -pkgluadir -luadir -LUA_EXEC_PREFIX -LUA_PREFIX -LUA_PLATFORM -LUA_SHORT_VERSION -LUA_VERSION -LUA OBJEXT EXEEXT ac_ct_CC @@ -685,8 +672,6 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking -enable_libconfig -enable_liblua with_progname ' ac_precious_vars='build_alias @@ -697,10 +682,7 @@ CFLAGS LDFLAGS LIBS CPPFLAGS -LUA -LUA_INCLUDE -CPP -LUA_LIB' +CPP' # Initialize some variables set by options. @@ -1241,7 +1223,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures telegram 0.1 to adapt to many kinds of systems. +\`configure' configures telegram-purple 0.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1289,7 +1271,7 @@ Fine tuning of the installation directories: --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/telegram] + --docdir=DIR documentation root [DATAROOTDIR/doc/telegram-purple] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] @@ -1302,17 +1284,10 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of telegram 0.1:";; + short | recursive ) echo "Configuration of telegram-purple 0.1:";; esac cat <<\_ACEOF -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] ---enable-libconfig/--disable-libconfig ---enable-liblua/--disable-liblua - Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) @@ -1326,10 +1301,7 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory - LUA The Lua interpreter, e.g. /usr/bin/lua5.1 - LUA_INCLUDE The Lua includes, e.g. -I/usr/include/lua5.1 CPP C preprocessor - LUA_LIB The Lua library, e.g. -llua5.1 Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1397,7 +1369,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -telegram configure 0.1 +telegram-purple configure 0.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1816,7 +1788,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by telegram $as_me 0.1, which was +It was created by telegram-purple $as_me 0.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2162,221 +2134,6 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - - -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_lua.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# -# DESCRIPTION -# -# Detect a Lua interpreter, optionally specifying a minimum and maximum -# version number. Set up important Lua paths, such as the directories in -# which to install scripts and modules (shared libraries). -# -# Also detect Lua headers and libraries. The Lua version contained in the -# header is checked to match the Lua interpreter version exactly. When -# searching for Lua libraries, the version number is used as a suffix. -# This is done with the goal of supporting multiple Lua installs (5.1 and -# 5.2 side-by-side). -# -# A note on compatibility with previous versions: This file has been -# mostly rewritten for serial 18. Most developers should be able to use -# these macros without needing to modify configure.ac. Care has been taken -# to preserve each macro's behavior, but there are some differences: -# -# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as -# AX_PROG_LUA with no arguments. -# -# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h -# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore -# unnecessary, so it is deprecated and does not expand to anything. -# -# 3) The configure flag --with-lua-suffix no longer exists; the user -# should instead specify the LUA precious variable on the command line. -# See the AX_PROG_LUA description for details. -# -# Please read the macro descriptions below for more information. -# -# This file was inspired by Andrew Dalke's and James Henstridge's -# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 -# (serial 17). Basically, this file is a mash-up of those two files. I -# like to think it combines the best of the two! -# -# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua -# paths. Adds precious variable LUA, which may contain the path of the Lua -# interpreter. If LUA is blank, the user's path is searched for an -# suitable interpreter. -# -# If MINIMUM-VERSION is supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION will be accepted. If -# TOO-BIG- VERSION is also supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION and less than -# TOO-BIG-VERSION will be accepted. -# -# Version comparisons require the AX_COMPARE_VERSION macro, which is -# provided by ax_compare_version.m4 from the Autoconf Archive. -# -# The Lua version number, LUA_VERSION, is found from the interpreter, and -# substituted. LUA_PLATFORM is also found, but not currently supported (no -# standard representation). -# -# Finally, the macro finds four paths: -# -# luadir Directory to install Lua scripts. -# pkgluadir $luadir/$PACKAGE -# luaexecdir Directory to install Lua modules. -# pkgluaexecdir $luaexecdir/$PACKAGE -# -# These paths a found based on $prefix, $exec_prefix, Lua's package.path, -# and package.cpath. The first path of package.path beginning with $prefix -# is selected as luadir. The first path of package.cpath beginning with -# $exec_prefix is used as luaexecdir. This should work on all reasonable -# Lua installations. If a path cannot be determined, a default path is -# used. Of course, the user can override these later when invoking make. -# -# luadir Default: $prefix/share/lua/$LUA_VERSION -# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION -# -# These directories can be used by Automake as install destinations. The -# variable name minus 'dir' needs to be used as a prefix to the -# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. -# -# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- -# FOUND is blank, then it will default to printing an error. To prevent -# the default behavior, give ':' as an action. -# -# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_INCLUDE, which -# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If -# LUA_INCLUDE is blank, then this macro will attempt to find suitable -# flags. -# -# LUA_INCLUDE can be used by Automake to compile Lua modules or -# executables with embedded interpreters. The *_CPPFLAGS variables should -# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). -# -# This macro searches for the header lua.h (and others). The search is -# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. -# If the search is unsuccessful, then some common directories are tried. -# If the headers are then found, then LUA_INCLUDE is set accordingly. -# -# The paths automatically searched are: -# -# * /usr/include/luaX.Y -# * /usr/include/lua/X.Y -# * /usr/include/luaXY -# * /usr/local/include/luaX.Y -# * /usr/local/include/lua-X.Y -# * /usr/local/include/lua/X.Y -# * /usr/local/include/luaXY -# -# (Where X.Y is the Lua version number, e.g. 5.1.) -# -# The Lua version number found in the headers is always checked to match -# the Lua interpreter's version number. Lua headers with mismatched -# version numbers are not accepted. -# -# If headers are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_LIB, which may -# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, -# then this macro will attempt to find suitable flags. -# -# LUA_LIB can be used by Automake to link Lua modules or executables with -# embedded interpreters. The *_LIBADD and *_LDADD variables should be used -# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). -# -# This macro searches for the Lua library. More technically, it searches -# for a library containing the function lua_load. The search is performed -# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. -# -# If the search determines that some linker flags are missing, then those -# flags will be added to LUA_LIB. -# -# If libraries are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_READLINE: Search for readline headers and libraries. Requires the -# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the -# Autoconf Archive. -# -# If a readline compatible library is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is performed. -# -# LICENSE -# -# Copyright (c) 2013 Tim Perkins -# Copyright (c) 2013 Reuben Thomas -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 21 - - - - - - - - - - - - - - - - - - - - - - - @@ -3581,123 +3338,36 @@ $as_echo "#define READLINE_EDIT 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libconfig" >&5 -$as_echo_n "checking for libconfig... " >&6; } -# Check whether --enable-libconfig was given. -if test "${enable_libconfig+set}" = set; then : - enableval=$enable_libconfig; - if test "x$enableval" = "xno" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 -$as_echo "disabled" >&6; } +#check for custom prog name + +# Check whether --with-progname was given. +if test "${with_progname+set}" = set; then : + withval=$with_progname; + if test "x$with_progname" = "xno" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 +$as_echo "default" >&6; } + elif test "x$with_progname" = "xyes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 +$as_echo "default" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 -$as_echo "enabled" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for config_init in -lconfig" >&5 -$as_echo_n "checking for config_init in -lconfig... " >&6; } -if ${ac_cv_lib_config_config_init+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lconfig $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_progname\"" >&5 +$as_echo "\"$with_progname\"" >&6; } -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char config_init (); -int -main () -{ -return config_init (); - ; - return 0; -} +cat >>confdefs.h <<_ACEOF +#define PROG_NAME "$with_progname" _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_config_config_init=yes -else - ac_cv_lib_config_config_init=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_config_config_init" >&5 -$as_echo "$ac_cv_lib_config_config_init" >&6; } -if test "x$ac_cv_lib_config_config_init" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBCONFIG 1 -_ACEOF - - LIBS="-lconfig $LIBS" - -else - as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 -fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 -$as_echo "enabled" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for config_init in -lconfig" >&5 -$as_echo_n "checking for config_init in -lconfig... " >&6; } -if ${ac_cv_lib_config_config_init+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lconfig $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char config_init (); -int -main () -{ -return config_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_config_config_init=yes -else - ac_cv_lib_config_config_init=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_config_config_init" >&5 -$as_echo "$ac_cv_lib_config_config_init" >&6; } -if test "x$ac_cv_lib_config_config_init" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBCONFIG 1 -_ACEOF - - LIBS="-lconfig $LIBS" - -else - as_fn_error $? "No libconfig found. Try --disable-libconfig" "$LINENO" 5 -fi - + { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 +$as_echo "default" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for liblua" >&5 -$as_echo_n "checking for liblua... " >&6; } +# Checks for header files. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4095,1381 +3765,6 @@ fi done -# Check whether --enable-liblua was given. -if test "${enable_liblua+set}" = set; then : - enableval=$enable_liblua; - if test "x$enableval" = "xno" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 -$as_echo "disabled" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 -$as_echo "enabled" >&6; } - - - - - - if test "x$LUA" = 'x'; then : - for ac_prog in lua lua5.2 lua52 lua5.1 lua51 lua50 -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_LUA+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $LUA in - [\\/]* | ?:[\\/]*) - ac_cv_path_LUA="$LUA" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_LUA="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -LUA=$ac_cv_path_LUA -if test -n "$LUA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LUA" >&5 -$as_echo "$LUA" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$LUA" && break -done -test -n "$LUA" || LUA=":" - -fi - ax_display_LUA='lua' - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LUA is a Lua interpreter" >&5 -$as_echo_n "checking if $LUA is a Lua interpreter... " >&6; } - - if $LUA -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - as_fn_error $? "not a Lua interpreter" "$LINENO" 5 - -fi - - - - if test "x$LUA" = 'x:'; then : - - as_fn_error $? "No lua found. Try --disable-liblua" "$LINENO" 5 - - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA version" >&5 -$as_echo_n "checking for $ax_display_LUA version... " >&6; } -if ${ax_cv_lua_version+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ - sed "s|^Lua \(.*\)|\1|" | \ - grep -E -o "^[0-9]+\.[0-9]+"` - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_version" >&5 -$as_echo "$ax_cv_lua_version" >&6; } - if test "x$ax_cv_lua_version" = 'x'; then : - as_fn_error $? "invalid Lua version number" "$LINENO" 5 -fi - LUA_VERSION=$ax_cv_lua_version - - LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA platform" >&5 -$as_echo_n "checking for $ax_display_LUA platform... " >&6; } -if ${ax_cv_lua_platform+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_lua_platform=`$LUA -e "print('unknown')"` -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_platform" >&5 -$as_echo "$ax_cv_lua_platform" >&6; } - LUA_PLATFORM=$ax_cv_lua_platform - - - LUA_PREFIX='${prefix}' - - LUA_EXEC_PREFIX='${exec_prefix}' - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA script directory" >&5 -$as_echo_n "checking for $ax_display_LUA script directory... " >&6; } -if ${ax_cv_lua_luadir+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$prefix" = 'xNONE'; then : - ax_lua_prefix=$ac_default_prefix -else - ax_lua_prefix=$prefix -fi - - ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" - - - - ax_lua_prefixed_path='' - _ax_package_paths=`$LUA -e 'print(package.path)' 2>/dev/null | sed 's|;|\n|g'` - for _ax_package_path in $_ax_package_paths; do - _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` - _ax_reassembled='' - for _ax_path_part in $_ax_path_parts; do - echo "$_ax_path_part" | grep '\?' >/dev/null && break - _ax_reassembled="$_ax_reassembled/$_ax_path_part" - done - _ax_package_path=$_ax_reassembled - if echo "$_ax_package_path" | grep "^$ax_lua_prefix" >/dev/null; then - ax_lua_prefixed_path=$_ax_package_path - break - fi - done - - if test "x$ax_lua_prefixed_path" != 'x'; then : - _ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'` - ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ - sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"` - -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luadir" >&5 -$as_echo "$ax_cv_lua_luadir" >&6; } - luadir=$ax_cv_lua_luadir - - pkgluadir=\${luadir}/$PACKAGE - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA module directory" >&5 -$as_echo_n "checking for $ax_display_LUA module directory... " >&6; } -if ${ax_cv_lua_luaexecdir+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$exec_prefix" = 'xNONE'; then : - ax_lua_exec_prefix=$ax_lua_prefix -else - ax_lua_exec_prefix=$exec_prefix -fi - - ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" - - - - ax_lua_prefixed_path='' - _ax_package_paths=`$LUA -e 'print(package.cpathd)' 2>/dev/null | sed 's|;|\n|g'` - for _ax_package_path in $_ax_package_paths; do - _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` - _ax_reassembled='' - for _ax_path_part in $_ax_path_parts; do - echo "$_ax_path_part" | grep '\?' >/dev/null && break - _ax_reassembled="$_ax_reassembled/$_ax_path_part" - done - _ax_package_path=$_ax_reassembled - if echo "$_ax_package_path" | grep "^$ax_lua_exec_prefix" >/dev/null; then - ax_lua_prefixed_path=$_ax_package_path - break - fi - done - - if test "x$ax_lua_prefixed_path" != 'x'; then : - _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'` - ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ - sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"` - -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luaexecdir" >&5 -$as_echo "$ax_cv_lua_luaexecdir" >&6; } - luaexecdir=$ax_cv_lua_luaexecdir - - pkgluaexecdir=\${luaexecdir}/$PACKAGE - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 -$as_echo_n "checking if LUA_VERSION is defined... " >&6; } - if test "x$LUA_VERSION" != 'x'; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - as_fn_error $? "cannot check Lua headers without knowing LUA_VERSION" "$LINENO" 5 - -fi - - - - LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` - - - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - for ac_header in lua.h lualib.h lauxlib.h luaconf.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - CPPFLAGS=$_ax_lua_saved_cppflags - - if test "x$LUA_INCLUDE" = 'x' && - test "x$ac_cv_header_lua_h" != 'xyes'; then : - for _ax_include_path in /usr/include/lua$LUA_VERSION \ - /usr/include/lua/$LUA_VERSION \ - /usr/include/lua$LUA_SHORT_VERSION \ - /usr/local/include/lua$LUA_VERSION \ - /usr/local/include/lua-$LUA_VERSION \ - /usr/local/include/lua/$LUA_VERSION \ - /usr/local/include/lua$LUA_SHORT_VERSION \ - ; do - test ! -d "$_ax_include_path" && continue - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua headers in" >&5 -$as_echo_n "checking for Lua headers in... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_ax_include_path" >&5 -$as_echo "$_ax_include_path" >&6; } - - { ac_cv_header_lua_h=; unset ac_cv_header_lua_h;} - { ac_cv_header_lualib_h=; unset ac_cv_header_lualib_h;} - { ac_cv_header_lauxlib_h=; unset ac_cv_header_lauxlib_h;} - { ac_cv_header_luaconf_h=; unset ac_cv_header_luaconf_h;} - - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS -I$_ax_include_path" - for ac_header in lua.h lualib.h lauxlib.h luaconf.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - CPPFLAGS=$_ax_lua_saved_cppflags - - if test "x$ac_cv_header_lua_h" = 'xyes'; then : - LUA_INCLUDE="-I$_ax_include_path" - break - -fi - done - -fi - - if test "x$ac_cv_header_lua_h" = 'xyes'; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua header version" >&5 -$as_echo_n "checking for Lua header version... " >&6; } -if ${ax_cv_lua_header_version+:} false; then : - $as_echo_n "(cached) " >&6 -else - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -int main(int argc, char ** argv) -{ - if(argc > 1) printf("%s", LUA_VERSION); - exit(EXIT_SUCCESS); -} - - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ax_cv_lua_header_version=`./conftest$EXEEXT p | \ - sed "s|^Lua \(.*\)|\1|" | \ - grep -E -o "^[0-9]+\.[0-9]+"` - -else - ax_cv_lua_header_version='unknown' -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - CPPFLAGS=$_ax_lua_saved_cppflags - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_header_version" >&5 -$as_echo "$ax_cv_lua_header_version" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Lua header version matches $LUA_VERSION" >&5 -$as_echo_n "checking if Lua header version matches $LUA_VERSION... " >&6; } - if test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ax_header_version_match='yes' - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - ax_header_version_match='no' - -fi - -fi - - if test "x$ax_header_version_match" != 'xyes' && - test "x$LUA_INCLUDE" != 'x'; then : - as_fn_error $? "cannot find headers for specified LUA_INCLUDE" "$LINENO" 5 -fi - - if test "x$ax_header_version_match" = 'xyes'; then : - -else - as_fn_error $? "No lua headers found. Try --disable-liblua" "$LINENO" 5 -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 -$as_echo_n "checking if LUA_VERSION is defined... " >&6; } - if test "x$LUA_VERSION" != 'x'; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - as_fn_error $? "cannot check Lua libs without knowing LUA_VERSION" "$LINENO" 5 - -fi - - - - if test "x$LUA_LIB" != 'x'; then : - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 -$as_echo_n "checking for library containing lua_load... " >&6; } -if ${ac_cv_search_lua_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char lua_load (); -int -main () -{ -return lua_load (); - ; - return 0; -} -_ACEOF -for ac_lib in '' ; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_lua_load=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_lua_load+:} false; then : - break -fi -done -if ${ac_cv_search_lua_load+:} false; then : - -else - ac_cv_search_lua_load=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 -$as_echo "$ac_cv_search_lua_load" >&6; } -ac_res=$ac_cv_search_lua_load -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - _ax_found_lua_libs='yes' -else - _ax_found_lua_libs='no' -fi - - LIBS=$_ax_lua_saved_libs - - if test "x$_ax_found_lua_libs" != 'xyes'; then : - as_fn_error $? "cannot find libs for specified LUA_LIB" "$LINENO" 5 -fi - -else - _ax_lua_extra_libs='' - - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing exp" >&5 -$as_echo_n "checking for library containing exp... " >&6; } -if ${ac_cv_search_exp+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char exp (); -int -main () -{ -return exp (); - ; - return 0; -} -_ACEOF -for ac_lib in '' m; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_exp=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_exp+:} false; then : - break -fi -done -if ${ac_cv_search_exp+:} false; then : - -else - ac_cv_search_exp=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_exp" >&5 -$as_echo "$ac_cv_search_exp" >&6; } -ac_res=$ac_cv_search_exp -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 -$as_echo_n "checking for library containing dlopen... " >&6; } -if ${ac_cv_search_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dl; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_dlopen=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_dlopen+:} false; then : - break -fi -done -if ${ac_cv_search_dlopen+:} false; then : - -else - ac_cv_search_dlopen=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 -$as_echo "$ac_cv_search_dlopen" >&6; } -ac_res=$ac_cv_search_dlopen -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - LIBS=$_ax_lua_saved_libs - - if test "x$ac_cv_search_exp" != 'xno' && - test "x$ac_cv_search_exp" != 'xnone required'; then : - _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp" -fi - - if test "x$ac_cv_search_dlopen" != 'xno' && - test "x$ac_cv_search_dlopen" != 'xnone required'; then : - _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen" -fi - - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 -$as_echo_n "checking for library containing lua_load... " >&6; } -if ${ac_cv_search_lua_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char lua_load (); -int -main () -{ -return lua_load (); - ; - return 0; -} -_ACEOF -for ac_lib in '' lua$LUA_VERSION \ - lua$LUA_SHORT_VERSION \ - lua-$LUA_VERSION \ - lua-$LUA_SHORT_VERSION \ - lua; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $_ax_lua_extra_libs $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_lua_load=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_lua_load+:} false; then : - break -fi -done -if ${ac_cv_search_lua_load+:} false; then : - -else - ac_cv_search_lua_load=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 -$as_echo "$ac_cv_search_lua_load" >&6; } -ac_res=$ac_cv_search_lua_load -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - _ax_found_lua_libs='yes' -else - _ax_found_lua_libs='no' -fi - - LIBS=$_ax_lua_saved_libs - - if test "x$ac_cv_search_lua_load" != 'xno' && - test "x$ac_cv_search_lua_load" != 'xnone required'; then : - LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs" -fi - -fi - - if test "x$_ax_found_lua_libs" = 'xyes'; then : - -else - as_fn_error $? "No lua libs found. Try --disable-liblua" "$LINENO" 5 -fi - - EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; - CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; - -$as_echo "#define USE_LUA 1" >>confdefs.h - - - -fi - - fi - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 -$as_echo "enabled" >&6; } - - - - - - if test "x$LUA" = 'x'; then : - for ac_prog in lua lua5.2 lua52 lua5.1 lua51 lua50 -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_LUA+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $LUA in - [\\/]* | ?:[\\/]*) - ac_cv_path_LUA="$LUA" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_LUA="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -LUA=$ac_cv_path_LUA -if test -n "$LUA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LUA" >&5 -$as_echo "$LUA" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$LUA" && break -done -test -n "$LUA" || LUA=":" - -fi - ax_display_LUA='lua' - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LUA is a Lua interpreter" >&5 -$as_echo_n "checking if $LUA is a Lua interpreter... " >&6; } - - if $LUA -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - as_fn_error $? "not a Lua interpreter" "$LINENO" 5 - -fi - - - - if test "x$LUA" = 'x:'; then : - - as_fn_error $? "No lua found. Try --disable-liblua" "$LINENO" 5 - - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA version" >&5 -$as_echo_n "checking for $ax_display_LUA version... " >&6; } -if ${ax_cv_lua_version+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_lua_version=`$LUA -e "print(_VERSION)" | \ - sed "s|^Lua \(.*\)|\1|" | \ - grep -E -o "^[0-9]+\.[0-9]+"` - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_version" >&5 -$as_echo "$ax_cv_lua_version" >&6; } - if test "x$ax_cv_lua_version" = 'x'; then : - as_fn_error $? "invalid Lua version number" "$LINENO" 5 -fi - LUA_VERSION=$ax_cv_lua_version - - LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA platform" >&5 -$as_echo_n "checking for $ax_display_LUA platform... " >&6; } -if ${ax_cv_lua_platform+:} false; then : - $as_echo_n "(cached) " >&6 -else - ax_cv_lua_platform=`$LUA -e "print('unknown')"` -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_platform" >&5 -$as_echo "$ax_cv_lua_platform" >&6; } - LUA_PLATFORM=$ax_cv_lua_platform - - - LUA_PREFIX='${prefix}' - - LUA_EXEC_PREFIX='${exec_prefix}' - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA script directory" >&5 -$as_echo_n "checking for $ax_display_LUA script directory... " >&6; } -if ${ax_cv_lua_luadir+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$prefix" = 'xNONE'; then : - ax_lua_prefix=$ac_default_prefix -else - ax_lua_prefix=$prefix -fi - - ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" - - - - ax_lua_prefixed_path='' - _ax_package_paths=`$LUA -e 'print(package.path)' 2>/dev/null | sed 's|;|\n|g'` - for _ax_package_path in $_ax_package_paths; do - _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` - _ax_reassembled='' - for _ax_path_part in $_ax_path_parts; do - echo "$_ax_path_part" | grep '\?' >/dev/null && break - _ax_reassembled="$_ax_reassembled/$_ax_path_part" - done - _ax_package_path=$_ax_reassembled - if echo "$_ax_package_path" | grep "^$ax_lua_prefix" >/dev/null; then - ax_lua_prefixed_path=$_ax_package_path - break - fi - done - - if test "x$ax_lua_prefixed_path" != 'x'; then : - _ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'` - ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ - sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"` - -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luadir" >&5 -$as_echo "$ax_cv_lua_luadir" >&6; } - luadir=$ax_cv_lua_luadir - - pkgluadir=\${luadir}/$PACKAGE - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ax_display_LUA module directory" >&5 -$as_echo_n "checking for $ax_display_LUA module directory... " >&6; } -if ${ax_cv_lua_luaexecdir+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$exec_prefix" = 'xNONE'; then : - ax_lua_exec_prefix=$ax_lua_prefix -else - ax_lua_exec_prefix=$exec_prefix -fi - - ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" - - - - ax_lua_prefixed_path='' - _ax_package_paths=`$LUA -e 'print(package.cpathd)' 2>/dev/null | sed 's|;|\n|g'` - for _ax_package_path in $_ax_package_paths; do - _ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'` - _ax_reassembled='' - for _ax_path_part in $_ax_path_parts; do - echo "$_ax_path_part" | grep '\?' >/dev/null && break - _ax_reassembled="$_ax_reassembled/$_ax_path_part" - done - _ax_package_path=$_ax_reassembled - if echo "$_ax_package_path" | grep "^$ax_lua_exec_prefix" >/dev/null; then - ax_lua_prefixed_path=$_ax_package_path - break - fi - done - - if test "x$ax_lua_prefixed_path" != 'x'; then : - _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'` - ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ - sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"` - -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_luaexecdir" >&5 -$as_echo "$ax_cv_lua_luaexecdir" >&6; } - luaexecdir=$ax_cv_lua_luaexecdir - - pkgluaexecdir=\${luaexecdir}/$PACKAGE - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 -$as_echo_n "checking if LUA_VERSION is defined... " >&6; } - if test "x$LUA_VERSION" != 'x'; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - as_fn_error $? "cannot check Lua headers without knowing LUA_VERSION" "$LINENO" 5 - -fi - - - - LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'` - - - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - for ac_header in lua.h lualib.h lauxlib.h luaconf.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - CPPFLAGS=$_ax_lua_saved_cppflags - - if test "x$LUA_INCLUDE" = 'x' && - test "x$ac_cv_header_lua_h" != 'xyes'; then : - for _ax_include_path in /usr/include/lua$LUA_VERSION \ - /usr/include/lua/$LUA_VERSION \ - /usr/include/lua$LUA_SHORT_VERSION \ - /usr/local/include/lua$LUA_VERSION \ - /usr/local/include/lua-$LUA_VERSION \ - /usr/local/include/lua/$LUA_VERSION \ - /usr/local/include/lua$LUA_SHORT_VERSION \ - ; do - test ! -d "$_ax_include_path" && continue - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua headers in" >&5 -$as_echo_n "checking for Lua headers in... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_ax_include_path" >&5 -$as_echo "$_ax_include_path" >&6; } - - { ac_cv_header_lua_h=; unset ac_cv_header_lua_h;} - { ac_cv_header_lualib_h=; unset ac_cv_header_lualib_h;} - { ac_cv_header_lauxlib_h=; unset ac_cv_header_lauxlib_h;} - { ac_cv_header_luaconf_h=; unset ac_cv_header_luaconf_h;} - - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS -I$_ax_include_path" - for ac_header in lua.h lualib.h lauxlib.h luaconf.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - CPPFLAGS=$_ax_lua_saved_cppflags - - if test "x$ac_cv_header_lua_h" = 'xyes'; then : - LUA_INCLUDE="-I$_ax_include_path" - break - -fi - done - -fi - - if test "x$ac_cv_header_lua_h" = 'xyes'; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Lua header version" >&5 -$as_echo_n "checking for Lua header version... " >&6; } -if ${ax_cv_lua_header_version+:} false; then : - $as_echo_n "(cached) " >&6 -else - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -#include -int main(int argc, char ** argv) -{ - if(argc > 1) printf("%s", LUA_VERSION); - exit(EXIT_SUCCESS); -} - - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ax_cv_lua_header_version=`./conftest$EXEEXT p | \ - sed "s|^Lua \(.*\)|\1|" | \ - grep -E -o "^[0-9]+\.[0-9]+"` - -else - ax_cv_lua_header_version='unknown' -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - CPPFLAGS=$_ax_lua_saved_cppflags - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_lua_header_version" >&5 -$as_echo "$ax_cv_lua_header_version" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Lua header version matches $LUA_VERSION" >&5 -$as_echo_n "checking if Lua header version matches $LUA_VERSION... " >&6; } - if test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ax_header_version_match='yes' - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - ax_header_version_match='no' - -fi - -fi - - if test "x$ax_header_version_match" != 'xyes' && - test "x$LUA_INCLUDE" != 'x'; then : - as_fn_error $? "cannot find headers for specified LUA_INCLUDE" "$LINENO" 5 -fi - - if test "x$ax_header_version_match" = 'xyes'; then : - -else - as_fn_error $? "No lua headers found. Try --disable-liblua" "$LINENO" 5 -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LUA_VERSION is defined" >&5 -$as_echo_n "checking if LUA_VERSION is defined... " >&6; } - if test "x$LUA_VERSION" != 'x'; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - as_fn_error $? "cannot check Lua libs without knowing LUA_VERSION" "$LINENO" 5 - -fi - - - - if test "x$LUA_LIB" != 'x'; then : - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 -$as_echo_n "checking for library containing lua_load... " >&6; } -if ${ac_cv_search_lua_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char lua_load (); -int -main () -{ -return lua_load (); - ; - return 0; -} -_ACEOF -for ac_lib in '' ; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_lua_load=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_lua_load+:} false; then : - break -fi -done -if ${ac_cv_search_lua_load+:} false; then : - -else - ac_cv_search_lua_load=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 -$as_echo "$ac_cv_search_lua_load" >&6; } -ac_res=$ac_cv_search_lua_load -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - _ax_found_lua_libs='yes' -else - _ax_found_lua_libs='no' -fi - - LIBS=$_ax_lua_saved_libs - - if test "x$_ax_found_lua_libs" != 'xyes'; then : - as_fn_error $? "cannot find libs for specified LUA_LIB" "$LINENO" 5 -fi - -else - _ax_lua_extra_libs='' - - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing exp" >&5 -$as_echo_n "checking for library containing exp... " >&6; } -if ${ac_cv_search_exp+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char exp (); -int -main () -{ -return exp (); - ; - return 0; -} -_ACEOF -for ac_lib in '' m; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_exp=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_exp+:} false; then : - break -fi -done -if ${ac_cv_search_exp+:} false; then : - -else - ac_cv_search_exp=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_exp" >&5 -$as_echo "$ac_cv_search_exp" >&6; } -ac_res=$ac_cv_search_exp -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 -$as_echo_n "checking for library containing dlopen... " >&6; } -if ${ac_cv_search_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dl; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_dlopen=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_dlopen+:} false; then : - break -fi -done -if ${ac_cv_search_dlopen+:} false; then : - -else - ac_cv_search_dlopen=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 -$as_echo "$ac_cv_search_dlopen" >&6; } -ac_res=$ac_cv_search_dlopen -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - LIBS=$_ax_lua_saved_libs - - if test "x$ac_cv_search_exp" != 'xno' && - test "x$ac_cv_search_exp" != 'xnone required'; then : - _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp" -fi - - if test "x$ac_cv_search_dlopen" != 'xno' && - test "x$ac_cv_search_dlopen" != 'xnone required'; then : - _ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen" -fi - - _ax_lua_saved_libs=$LIBS - LIBS="$LIBS $LUA_LIB" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing lua_load" >&5 -$as_echo_n "checking for library containing lua_load... " >&6; } -if ${ac_cv_search_lua_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char lua_load (); -int -main () -{ -return lua_load (); - ; - return 0; -} -_ACEOF -for ac_lib in '' lua$LUA_VERSION \ - lua$LUA_SHORT_VERSION \ - lua-$LUA_VERSION \ - lua-$LUA_SHORT_VERSION \ - lua; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $_ax_lua_extra_libs $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_lua_load=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_lua_load+:} false; then : - break -fi -done -if ${ac_cv_search_lua_load+:} false; then : - -else - ac_cv_search_lua_load=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_lua_load" >&5 -$as_echo "$ac_cv_search_lua_load" >&6; } -ac_res=$ac_cv_search_lua_load -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - _ax_found_lua_libs='yes' -else - _ax_found_lua_libs='no' -fi - - LIBS=$_ax_lua_saved_libs - - if test "x$ac_cv_search_lua_load" != 'xno' && - test "x$ac_cv_search_lua_load" != 'xnone required'; then : - LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs" -fi - -fi - - if test "x$_ax_found_lua_libs" = 'xyes'; then : - -else - as_fn_error $? "No lua libs found. Try --disable-liblua" "$LINENO" 5 -fi - - EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; - CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; - -$as_echo "#define USE_LUA 1" >>confdefs.h - - - -fi - - -fi - - -#check for custom prog name - -# Check whether --with-progname was given. -if test "${with_progname+set}" = set; then : - withval=$with_progname; - if test "x$with_progname" = "xno" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 -$as_echo "default" >&6; } - elif test "x$with_progname" = "xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 -$as_echo "default" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_progname\"" >&5 -$as_echo "\"$with_progname\"" >&6; } - -cat >>confdefs.h <<_ACEOF -#define PROG_NAME "$with_progname" -_ACEOF - - fi - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 -$as_echo "default" >&6; } - -fi - - -# Checks for header files. for ac_header in execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` @@ -5810,7 +4105,43 @@ test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' -DEFS=-DHAVE_CONFIG_H +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + ac_libobjs= ac_ltlibobjs= @@ -6226,7 +4557,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by telegram $as_me 0.1, which was +This file was extended by telegram-purple $as_me 0.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6244,15 +4575,11 @@ case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" -config_headers="$ac_config_headers" _ACEOF @@ -6273,22 +4600,17 @@ Usage: $0 [OPTION]... [TAG]... --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE Configuration files: $config_files -Configuration headers: -$config_headers - Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -telegram config.status 0.1 +telegram-purple config.status 0.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -6342,18 +4664,7 @@ do esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) + --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) @@ -6409,7 +4720,6 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 for ac_config_target in $ac_config_targets do case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; @@ -6423,7 +4733,6 @@ done # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree @@ -6611,116 +4920,8 @@ fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +eval set X " :F $CONFIG_FILES " shift for ac_tag do @@ -6928,30 +5129,7 @@ which seems to be undefined. Please make sure it is defined" >&2;} esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi - ;; + esac diff --git a/configure.ac b/configure.ac index 6b0f5d7..fbdb867 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,5 @@ AC_PREREQ([2.68]) -AC_INIT([telegram], [0.1]) -AC_CONFIG_SRCDIR([config.h.in]) -AC_CONFIG_HEADERS([config.h]) - -m4_include([ax_lua.m4]) +AC_INIT([telegram-purple], [0.1]) # Checks for programs. AC_PROG_CC @@ -33,54 +29,6 @@ AC_CHECK_LIB([readline], [rl_save_prompt], ] ) -AC_MSG_CHECKING([for libconfig]) -AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], - [ - if test "x$enableval" = "xno" ; then - AC_MSG_RESULT([disabled]) - else - AC_MSG_RESULT([enabled]) - AC_CHECK_LIB([config],[config_init],[],AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) - fi - ],[ - AC_MSG_RESULT([enabled]) - AC_CHECK_LIB([config],[config_init],[],AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) - ]) - -AC_MSG_CHECKING([for liblua]) -AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], - [ - if test "x$enableval" = "xno" ; then - AC_MSG_RESULT([disabled]) - else - AC_MSG_RESULT([enabled]) - AX_PROG_LUA([],[], - [ - AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) - AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) - [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] - [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] - AC_DEFINE(USE_LUA,1,[use lua]) - ], - [ - AC_MSG_ERROR([No lua found. Try --disable-liblua]) - ]) - fi - ],[ - AC_MSG_RESULT([enabled]) - AX_PROG_LUA([],[], - [ - AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) - AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) - [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] - [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] - AC_DEFINE(USE_LUA,1,[use lua]) - ], - [ - AC_MSG_ERROR([No lua found. Try --disable-liblua]) - ]) - ]) - #check for custom prog name AC_ARG_WITH(progname,[--with-progname=], [ diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index c83e5f7..0000000 --- a/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -telegram-cli (0.1-1) unstable; urgency=low - - * Initial release (Closes #737563) - - -- Cleto Martín Mon, 03 Feb 2014 20:00:03 +0000 diff --git a/debian/clean b/debian/clean deleted file mode 100644 index 33ceb8f..0000000 --- a/debian/clean +++ /dev/null @@ -1 +0,0 @@ -Makefile \ No newline at end of file diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control deleted file mode 100644 index 5e7e1f0..0000000 --- a/debian/control +++ /dev/null @@ -1,36 +0,0 @@ -Source: telegram-cli -Section: net -Priority: optional -Maintainer: Cleto Martín -Build-Depends: debhelper (>= 8.0.0), - autotools-dev, - autoconf-archive, - libreadline-dev, - libconfig-dev, - libssl-dev, - lua5.2, - liblua5.2-dev -Standards-Version: 3.9.4 -Homepage: https://github.com/vysheng/tg -Vcs-Git: git://github.com/vysheng/tg.git -Vcs-Browser: https://github.com/vysheng/tg - -Package: telegram-cli -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: Command-line interface for Telegram messenger - Telegram messenger is a cloud-based instant messaging designed for - smart phones and similar to Whatsapp but more flexible, and - powerful. You can send messages, photos, videos and documents to - people who are in your phone contacts (and have Telegram). Telegram - also supports secret chats whose provide a private (encrypted) way of - communication. - . - This package contains a command-line based client for Telegram with - the following features: - * Colored terminal messages. - * Message management: history, stats, etc. - * Group chat: create and manage groups. - * Secret chat: secured and encrypted conversations. - * Contact management: add/edit/remove contacts. - * Multimedia support: send/load photos and videos. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 2e46990..0000000 --- a/debian/copyright +++ /dev/null @@ -1,28 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: telegram-cli -Source: https://github.com/vysheng/tg - -Files: * -Copyright: 2013 Vitaly Valtman -License: GPL-2.0+ - -Files: debian/* -Copyright: 2014 Cleto Martín -License: GPL-2.0+ - -License: GPL-2.0+ - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see - . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". diff --git a/debian/docs b/debian/docs deleted file mode 100644 index b43bf86..0000000 --- a/debian/docs +++ /dev/null @@ -1 +0,0 @@ -README.md diff --git a/debian/install b/debian/install deleted file mode 100644 index f0f94de..0000000 --- a/debian/install +++ /dev/null @@ -1 +0,0 @@ -telegram usr/bin diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 0f41aca..0000000 --- a/debian/rules +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') -PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') - -%: - dh $@ --with autotools-dev - -build-orig: - mkdir -p $(PACKAGE_NAME)-$(VERSION) - tar --exclude=ax_lua.m4 --exclude=debian --exclude=\.pc \ - --exclude=$(PACKAGE_NAME)-$(VERSION) -cf - . \ - | ( cd $(PACKAGE_NAME)-$(VERSION) && tar xf - ) - tar -cf ../$(PACKAGE_NAME)_$(VERSION).orig.tar $(PACKAGE_NAME)-$(VERSION) - $(RM) -r $(PACKAGE_NAME)-$(VERSION) - xz ../$(PACKAGE_NAME)_$(VERSION).orig.tar diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 163aaf8..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debian/watch b/debian/watch deleted file mode 100644 index 2148331..0000000 --- a/debian/watch +++ /dev/null @@ -1,4 +0,0 @@ -version=3 - -opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/tg-$1\.tar\.gz/ \ - https://github.com/vysheng/tg/tags .*/v?(\d\S*)\.tar\.gz diff --git a/gentoo/telegram-cli/Manifest b/gentoo/telegram-cli/Manifest deleted file mode 100644 index f39008c..0000000 --- a/gentoo/telegram-cli/Manifest +++ /dev/null @@ -1 +0,0 @@ -EBUILD telegram-cli-9999.ebuild 641 SHA256 4597e2f84c36b1ee02ecc415c399408bb8536b456e94370e996d57477db621be SHA512 287da263c9a4ba2058bf2f5844599432619053abc9249fd5725ed7b5e920c5c02e2493ad7b07f89177933b2c15394d939e7dc7dbf05d5873c32e55c9ec614d4c WHIRLPOOL 73dee37f91f1d4b747afc35c0a0cb2efb141d37702c71a7a9d188d2e1d727375c0ee3e7a1192e6c4c34f17ba1303f3a0be47b24272b5378ff255bce1a4a281be diff --git a/gentoo/telegram-cli/telegram-cli-9999.ebuild b/gentoo/telegram-cli/telegram-cli-9999.ebuild deleted file mode 100644 index 17e3288..0000000 --- a/gentoo/telegram-cli/telegram-cli-9999.ebuild +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 1999-2013 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Header: $ - -EAPI=5 - -EGIT_REPO_URI="https://github.com/vysheng/tg.git" -inherit git-2 -IUSE="lua" -DESCRIPTION="Command line interface client for Telegram" -HOMEPAGE="https://github.com/vysheng/tg" -LICENSE="GPL-2" -SLOT="0" -KEYWORDS="~amd64 ~x86" - -DEPEND="sys-libs/zlib - sys-libs/readline - dev-libs/libconfig - dev-libs/openssl - lua? ( dev-lang/lua )" - -src_configure() { - econf $(use_enable lua liblua ) --with-progname=telegram-cli -} - -src_install() { - newbin telegram telegram-cli - - insinto /etc/telegram-cli/ - newins tg-server.pub server.pub -} diff --git a/interface.c b/interface.c deleted file mode 100644 index 79a7a96..0000000 --- a/interface.c +++ /dev/null @@ -1,1577 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include - -#ifdef READLINE_GNU -#include -#include -#else -#include -#include -#endif - -#include "include.h" -#include "queries.h" - -#include "telegram.h" -#include "structures.h" - - -// libpurple debugging-messages -#include "debug.h" -#include "purple-plugin/telegram-purple.h" -#include "msglog.h" - -#define ALLOW_MULT 1 -char *default_prompt = "> "; - -int unread_messages; -int msg_num_mode; -int alert_sound; - -int safe_quit; - -int in_readline; -int readline_active; - -int log_level = 1; - -long long cur_uploading_bytes; -long long cur_uploaded_bytes; -long long cur_downloading_bytes; -long long cur_downloaded_bytes; - -char *line_ptr; -extern peer_t *Peers[]; -extern int peer_num; - -int in_chat_mode; -peer_id_t chat_mode_id; - - -int is_same_word (const char *s, size_t l, const char *word) { - return s && word && strlen (word) == l && !memcmp (s, word, l); -} - -char *next_token (int *l) { - while (*line_ptr == ' ') { line_ptr ++; } - if (!*line_ptr) { - *l = 0; - return 0; - } - int neg = 0; - char *s = line_ptr; - int in_str = 0; - while (*line_ptr && (*line_ptr != ' ' || neg || in_str)) { -/* if (*line_ptr == '\\') { - neg = 1 - neg; - } else { - if (*line_ptr == '"' && !neg) { - in_str = !in_str; - } - neg = 0; - }*/ - line_ptr++; - } - *l = line_ptr - s; - return s; -} - -#define NOT_FOUND (int)0x80000000 -peer_id_t PEER_NOT_FOUND = {.id = NOT_FOUND}; - -long long next_token_int (void) { - int l; - char *s = next_token (&l); - if (!s) { return NOT_FOUND; } - char *r; - long long x = strtoll (s, &r, 10); - if (r == s + l) { - return x; - } else { - return NOT_FOUND; - } -} - -peer_id_t next_token_user (void) { - int l; - char *s = next_token (&l); - if (!s) { return PEER_NOT_FOUND; } - - if (l >= 6 && !memcmp (s, "user#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - if (r >= 0) { return set_peer_id (PEER_USER, r); } - else { return PEER_NOT_FOUND; } - } - - int index = 0; - while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) { - index ++; - } - if (index < peer_num) { - return Peers[index]->id; - } else { - return PEER_NOT_FOUND; - } -} - -peer_id_t next_token_chat (void) { - int l; - char *s = next_token (&l); - if (!s) { return PEER_NOT_FOUND; } - - if (l >= 6 && !memcmp (s, "chat#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - if (r >= 0) { return set_peer_id (PEER_CHAT, r); } - else { return PEER_NOT_FOUND; } - } - - int index = 0; - while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { - index ++; - } - if (index < peer_num) { - return Peers[index]->id; - } else { - return PEER_NOT_FOUND; - } -} - -peer_id_t next_token_encr_chat (void) { - int l; - char *s = next_token (&l); - if (!s) { return PEER_NOT_FOUND; } - - int index = 0; - while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) { - index ++; - } - if (index < peer_num) { - return Peers[index]->id; - } else { - return PEER_NOT_FOUND; - } -} - -peer_id_t next_token_peer (void) { - int l; - char *s = next_token (&l); - if (!s) { return PEER_NOT_FOUND; } - - if (l >= 6 && !memcmp (s, "user#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - if (r >= 0) { return set_peer_id (PEER_USER, r); } - else { return PEER_NOT_FOUND; } - } - if (l >= 6 && !memcmp (s, "chat#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - if (r >= 0) { return set_peer_id (PEER_CHAT, r); } - else { return PEER_NOT_FOUND; } - } - - int index = 0; - while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name))) { - index ++; - } - if (index < peer_num) { - return Peers[index]->id; - } else { - return PEER_NOT_FOUND; - } -} - -char *get_default_prompt (void) { - static char buf[1000]; - int l = 0; - if (in_chat_mode) { - peer_t *U = user_chat_get (chat_mode_id); - assert (U && U->print_name); - l += tsnprintf (buf + l, 999 - l, COLOR_RED "%.*s " COLOR_NORMAL, 100, U->print_name); - } - if (unread_messages || cur_uploading_bytes || cur_downloading_bytes) { - l += tsnprintf (buf + l, 999 - l, COLOR_RED "["); - int ok = 0; - if (unread_messages) { - l += tsnprintf (buf + l, 999 - l, "%d unread", unread_messages); - ok = 1; - } - if (cur_uploading_bytes) { - if (ok) { *(buf + l) = ' '; l ++; } - ok = 1; - l += tsnprintf (buf + l, 999 - l, "%lld%%Up", 100 * cur_uploaded_bytes / cur_uploading_bytes); - } - if (cur_downloading_bytes) { - if (ok) { *(buf + l) = ' '; l ++; } - ok = 1; - l += tsnprintf (buf + l, 999 - l, "%lld%%Down", 100 * cur_downloaded_bytes / cur_downloading_bytes); - } - l += tsnprintf (buf + l, 999 - l, "]" COLOR_NORMAL); - return buf; - } - l += tsnprintf (buf + l, 999 - l, "%s", default_prompt); - return buf; -} - -char *complete_none (const char *text UU, int state UU) { - return 0; -} - - -void set_prompt (const char *s) { - rl_set_prompt (s); -} - -void update_prompt (void) { - print_start (); - set_prompt (get_default_prompt ()); - if (readline_active) { - rl_redisplay (); - } - print_end (); -} - -char *modifiers[] = { - "[offline]", - 0 -}; - -char *in_chat_commands[] = { - "/exit", - "/quit", - "/history", - "/read", - 0 -}; - -char *commands[] = { - "help", - "msg", - "contact_list", - "stats", - "history", - "dialog_list", - "send_photo", - "send_video", - "send_text", - "chat_info", - "user_info", - "fwd", - "rename_chat", - "load_photo", - "view_photo", - "load_video_thumb", - "view_video_thumb", - "load_video", - "view_video", - "add_contact", - "rename_contact", - "show_license", - "search", - "mark_read", - "visualize_key", - "create_secret_chat", - "suggested_contacts", - "global_search", - "chat_add_user", - "chat_del_user", - "status_online", - "status_offline", - "contacts_search", - "quit", - "safe_quit", - "send_audio", - "load_audio", - "view_audio", - "send_document", - "load_document_thumb", - "view_document_thumb", - "load_document", - "view_document", - "set", - "chat_with_peer", - "delete_msg", - "restore_msg", - "create_group_chat", - 0 }; - -int commands_flags[] = { - 070, - 072, - 07, - 07, - 072, - 07, - 0732, - 0732, - 0732, - 074, - 071, - 072, - 074, - 07, - 07, - 07, - 07, - 07, - 07, - 07, - 071, - 07, - 072, - 072, - 075, - 071, - 07, - 07, - 0724, - 0724, - 07, - 07, - 07, - 07, - 07, - 0732, - 07, - 07, - 0732, - 07, - 07, - 07, - 07, - 07, - 072, - 07, - 072, - 07 -}; - - - -int get_complete_mode (void) { - line_ptr = rl_line_buffer; - int l = 0; - char *r = next_token (&l); - if (!r) { return 0; } - while (r && r[0] == '[' && r[l - 1] == ']') { - r = next_token (&l); - if (!r) { return 0; } - } - if (*r == '[' && !r[l]) { - return 6; - } - - if (!*line_ptr) { return 0; } - char **command = commands; - int n = 0; - int flags = -1; - while (*command) { - if (is_same_word (r, l, *command)) { - flags = commands_flags[n]; - break; - } - n ++; - command ++; - } - if (flags == -1) { - return 7; - } - int s = 0; - while (1) { - if (!next_token (&l) || !*line_ptr) { - return flags ? flags & 7 : 7; - } - s ++; - if (s <= 4) { flags >>= 3; } - } -} - -int complete_user_list (int index, const char *text, int len, char **R) { - index ++; - while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) { - index ++; - } - if (index < peer_num) { - *R = strdup (Peers[index]->print_name); - return index; - } else { - return -1; - } -} - -int complete_chat_list (int index, const char *text, int len, char **R) { - index ++; - while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) { - index ++; - } - if (index < peer_num) { - *R = strdup (Peers[index]->print_name); - return index; - } else { - return -1; - } -} - -int complete_encr_chat_list (int index, const char *text, int len, char **R) { - index ++; - while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) { - index ++; - } - if (index < peer_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 < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { - index ++; - } - if (index < peer_num) { - *R = strdup (Peers[index]->print_name); - return index; - } else { - return -1; - } -} - -int complete_string_list (char **list, int index, const char *text, int len, char **R) { - index ++; - while (list[index] && strncmp (list[index], text, len)) { - index ++; - } - if (list[index]) { - *R = strdup (list[index]); - return index; - } else { - *R = 0; - return -1; - } -} -char *command_generator (const char *text, int state) { - static int len, index, mode; - - if (in_chat_mode) { - char *R = 0; - index = complete_string_list (in_chat_commands, index, text, rl_point, &R); - return R; - } - - char c = 0; - if (!state) { - len = strlen (text); - index = -1; - - c = rl_line_buffer[rl_point]; - rl_line_buffer[rl_point] = 0; - mode = get_complete_mode (); - } else { - if (index == -1) { return 0; } - } - - if (mode == -1) { - if (c) { rl_line_buffer[rl_point] = c; } - return 0; - } - - char *R = 0; - switch (mode & 7) { - case 0: - index = complete_string_list (commands, index, text, len, &R); - if (c) { rl_line_buffer[rl_point] = c; } - return R; - case 1: - index = complete_user_list (index, text, len, &R); - if (c) { rl_line_buffer[rl_point] = c; } - return R; - case 2: - index = complete_user_chat_list (index, text, len, &R); - if (c) { rl_line_buffer[rl_point] = c; } - return R; - case 3: - R = rl_filename_completion_function(text,state); - if (c) { rl_line_buffer[rl_point] = c; } - return R; - case 4: - index = complete_chat_list (index, text, len, &R); - if (c) { rl_line_buffer[rl_point] = c; } - return R; - case 5: - index = complete_encr_chat_list (index, text, len, &R); - if (c) { rl_line_buffer[rl_point] = c; } - return R; - case 6: - index = complete_string_list (modifiers, index, text, len, &R); - if (c) { rl_line_buffer[rl_point] = c; } - return R; - default: - if (c) { rl_line_buffer[rl_point] = c; } - return 0; - } -} - -char **complete_text (char *text, int start UU, int end UU) { - return (char **) rl_completion_matches (text, command_generator); -} - -int offline_mode; -int count = 1; -void work_modifier (const char *s, int l) { - if (is_same_word (s, l, "[offline]")) { - offline_mode = 1; - } -#ifdef ALLOW_MULT - if (sscanf (s, "[x%d]", &count) >= 1) { - } -#endif -} - - - -void interpreter_chat_mode (char *line) { - if (line == NULL || /* EOF received */ - !strncmp (line, "/exit", 5) || !strncmp (line, "/quit", 5)) { - in_chat_mode = 0; - update_prompt (); - return; - } - if (!strncmp (line, "/history", 8)) { - int limit = 40; - sscanf (line, "/history %99d", &limit); - if (limit < 0 || limit > 1000) { limit = 40; } - do_get_history (chat_mode_id, limit); - return; - } - if (!strncmp (line, "/read", 5)) { - do_mark_read (chat_mode_id); - return; - } - if (strlen (line)>0) { - do_send_message (chat_mode_id, line, strlen (line)); - } -} - -void interpreter (char *line UU) { - assert (!in_readline); - in_readline = 1; - if (in_chat_mode) { - interpreter_chat_mode (line); - in_readline = 0; - return; - } - - line_ptr = line; - offline_mode = 0; - count = 1; - if (!line) { - in_readline = 0; - return; - } - if (line && *line) { - add_history (line); - } - - int l; - char *command; - while (1) { - command = next_token (&l); - if (!command) { in_readline = 0; return; } - if (*command == '[' && command[l - 1] == ']') { - work_modifier (command, l); - } else { - break; - } - } - - int _; - char *save = line_ptr; - int ll = l; - char *cs = command; - for (_ = 0; _ < count; _ ++) { - line_ptr = save; - l = ll; - command = cs; -#define IS_WORD(s) is_same_word (command, l, (s)) -#define RET in_readline = 0; return; - - peer_id_t id; -#define GET_PEER \ - id = next_token_peer (); \ - if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ - printf ("Bad user/chat id\n"); \ - RET; \ - } -#define GET_PEER_USER \ - id = next_token_user (); \ - if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ - printf ("Bad user id\n"); \ - RET; \ - } -#define GET_PEER_CHAT \ - id = next_token_chat (); \ - if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ - printf ("Bad chat id\n"); \ - RET; \ - } -#define GET_PEER_ENCR_CHAT \ - id = next_token_encr_chat (); \ - if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ - printf ("Bad encr_chat id\n"); \ - RET; \ - } - - if (IS_WORD ("contact_list")) { - do_update_contact_list (); - } else if (IS_WORD ("dialog_list")) { - do_get_dialog_list (); - } else if (IS_WORD ("stats")) { - static char stat_buf[1 << 15]; - print_stat (stat_buf, (1 << 15) - 1); - printf ("%s\n", stat_buf); - } else if (IS_WORD ("msg")) { - GET_PEER; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty message\n"); - RET; - } - do_send_message (id, s, strlen (s)); - } else if (IS_WORD ("rename_chat")) { - GET_PEER_CHAT; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty new name\n"); - RET; - } - do_rename_chat (id, s); - } else if (IS_WORD ("send_photo")) { - GET_PEER; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty file name\n"); - RET; - } - do_send_photo (CODE_input_media_uploaded_photo, id, tstrndup (s, t)); - } else if (IS_WORD("send_video")) { - GET_PEER; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty file name\n"); - RET; - } - do_send_photo (CODE_input_media_uploaded_video, id, tstrndup (s, t)); - } else if (IS_WORD ("send_text")) { - GET_PEER; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty file name\n"); - RET; - } - do_send_text (id, tstrndup (s, t)); - } else if (IS_WORD ("fwd")) { - GET_PEER; - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { - printf ("Bad msg id\n"); - RET; - } - do_forward_message (id, num); - } else if (IS_WORD ("load_photo")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_photo) { - do_load_photo (&M->media.photo, 1); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_photo) { - do_load_encr_video (&M->media.encr_video, 1); // this is not a bug. - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("view_photo")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_photo) { - do_load_photo (&M->media.photo, 2); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_photo) { - do_load_encr_video (&M->media.encr_video, 2); // this is not a bug. - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("load_video_thumb")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_video) { - do_load_video_thumb (&M->media.video, 1); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("view_video_thumb")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_video) { - do_load_video_thumb (&M->media.video, 2); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("load_video")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_video) { - do_load_video (&M->media.video, 1); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_video) { - do_load_encr_video (&M->media.encr_video, 1); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("view_video")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_video) { - do_load_video (&M->media.video, 2); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_video) { - do_load_encr_video (&M->media.encr_video, 2); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("chat_info")) { - GET_PEER_CHAT; - do_get_chat_info (id); - } else if (IS_WORD ("user_info")) { - GET_PEER_USER; - do_get_user_info (id); - } else if (IS_WORD ("history")) { - GET_PEER; - int limit = next_token_int (); - do_get_history (id, limit > 0 ? limit : 40); - } else if (IS_WORD ("chat_add_user")) { - GET_PEER_CHAT; - peer_id_t chat_id = id; - GET_PEER_USER; - do_add_user_to_chat (chat_id, id, 100); - } else if (IS_WORD ("chat_del_user")) { - GET_PEER_CHAT; - peer_id_t chat_id = id; - GET_PEER_USER; - do_del_user_from_chat (chat_id, id); - } else if (IS_WORD ("add_contact")) { - int phone_len, first_name_len, last_name_len; - char *phone, *first_name, *last_name; - phone = next_token (&phone_len); - if (!phone) { - printf ("No phone number found\n"); - RET; - } - first_name = next_token (&first_name_len); - if (!first_name_len) { - printf ("No first name found\n"); - RET; - } - last_name = next_token (&last_name_len); - if (!last_name_len) { - printf ("No last name found\n"); - RET; - } - do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 0); - } else if (IS_WORD ("rename_contact")) { - GET_PEER_USER; - peer_t *U = user_chat_get (id); - if (!U) { - printf ("No such user\n"); - RET; - } - if (!U->user.phone || !strlen (U->user.phone)) { - printf ("User has no phone. Can not rename\n"); - RET; - } - int phone_len, first_name_len, last_name_len; - char *phone, *first_name, *last_name; - phone_len = strlen (U->user.phone); - phone = U->user.phone; - first_name = next_token (&first_name_len); - if (!first_name_len) { - printf ("No first name found\n"); - RET; - } - last_name = next_token (&last_name_len); - if (!last_name_len) { - printf ("No last name found\n"); - RET; - } - do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 1); - } else if (IS_WORD ("help")) { - //print_start (); - push_color (COLOR_YELLOW); - printf ( - "help - prints this help\n" - "msg Text - sends message to this peer\n" - "contact_list - prints info about users in your contact list\n" - "stats - just for debugging \n" - "history [limit] - prints history (and marks it as read). Default limit = 40\n" - "dialog_list - prints info about your dialogs\n" - "send_photo - sends photo to peer\n" - "send_video - sends video to peer\n" - "send_text - sends text file as plain messages\n" - "chat_info - prints info about chat\n" - "user_info - prints info about user\n" - "fwd - forward message to user. You can see message numbers starting client with -N\n" - "rename_chat \n" - "load_photo/load_video/load_video_thumb - loads photo/video to download dir. You can see message numbers starting client with -N\n" - "view_photo/view_video/view_video_thumb - loads photo/video to download dir and starts system default viewer. You can see message numbers starting client with -N\n" - "show_license - prints contents of GPLv2\n" - "search pattern - searches pattern in messages with peer\n" - "global_search pattern - searches pattern in all messages\n" - "mark_read - mark read all received messages with peer\n" - "add_contact - tries to add contact to contact-list by phone\n" - "create_secret_chat - creates secret chat with this user\n" - "create_group_chat - creates group chat with this user, add more users with chat_add_user \n" - "rename_contact - tries to rename contact. If you have another device it will be a fight\n" - "suggested_contacts - print info about contacts, you have max common friends\n" - "visualize_key - prints visualization of encryption key. You should compare it to your partner's one\n" - "set . Possible values are:\n" - "\tdebug_verbosity - just as it sounds. Debug verbosity\n" - "\tlog_level - level of logging of new events. Lower is less verbose:\n" - "\t\tLevel 1: prints info about read messages\n" - "\t\tLevel 2: prints line, when somebody is typing in chat\n" - "\t\tLevel 3: prints line, when somebody changes online status\n" - "\tmsg_num - enables/disables numeration of messages\n" - "\talert - enables/disables alert sound notifications\n" - "chat_with_peer - starts chat with this peer. Every command after is message to this peer. Type /exit or /quit to end this mode\n" - ); - pop_color (); - } else if (IS_WORD ("show_license")) { - char *b = -#include "LICENSE.h" - ; - printf ("%s", b); - } else if (IS_WORD ("search")) { - GET_PEER; - int from = 0; - int to = 0; - int limit = 40; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty message\n"); - RET; - } - do_msg_search (id, from, to, limit, s); - } else if (IS_WORD ("global_search")) { - int from = 0; - int to = 0; - int limit = 40; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty message\n"); - RET; - } - do_msg_search (PEER_NOT_FOUND, from, to, limit, s); - } else if (IS_WORD ("mark_read")) { - GET_PEER; - do_mark_read (id); - } else if (IS_WORD ("visualize_key")) { - GET_PEER_ENCR_CHAT; - do_visualize_key (id); - } else if (IS_WORD ("create_secret_chat")) { - GET_PEER; - do_create_secret_chat (id); - } else if (IS_WORD ("create_group_chat")) { - GET_PEER; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty chat topic\n"); - RET; - } - do_create_group_chat (id, s); - } else if (IS_WORD ("suggested_contacts")) { - do_get_suggested (); - } else if (IS_WORD ("status_online")) { - do_update_status (1); - } else if (IS_WORD ("status_offline")) { - do_update_status (0); - } else if (IS_WORD ("contacts_search")) { - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty search query\n"); - RET; - } - do_contacts_search (100, s); - } else if (IS_WORD("send_audio")) { - GET_PEER; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty file name\n"); - RET; - } - do_send_photo (CODE_input_media_uploaded_audio, id, tstrndup (s, t)); - } else if (IS_WORD("send_document")) { - GET_PEER; - int t; - char *s = next_token (&t); - if (!s) { - printf ("Empty file name\n"); - RET; - } - do_send_photo (CODE_input_media_uploaded_document, id, tstrndup (s, t)); - } else if (IS_WORD ("load_audio")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_audio) { - do_load_audio (&M->media.video, 1); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_audio) { - do_load_encr_video (&M->media.encr_video, 1); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("view_audio")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_audio) { - do_load_audio (&M->media.video, 2); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_audio) { - do_load_encr_video (&M->media.encr_video, 2); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("load_document_thumb")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_document) { - do_load_document_thumb (&M->media.document, 1); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("view_document_thumb")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == (int)CODE_message_media_document) { - do_load_document_thumb (&M->media.document, 2); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("load_document")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_document) { - do_load_document (&M->media.document, 1); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_document) { - do_load_encr_video (&M->media.encr_video, 1); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("view_document")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - struct message *M = message_get (num); - if (M && !M->service && M->media.type == CODE_message_media_document) { - do_load_document (&M->media.document, 2); - } else if (M && !M->service && M->media.type == CODE_decrypted_message_media_document) { - do_load_encr_video (&M->media.encr_video, 2); - } else { - printf ("Bad msg id\n"); - RET; - } - } else if (IS_WORD ("set")) { - command = next_token (&l); - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - if (IS_WORD ("debug_verbosity")) { - verbosity = num; - } else if (IS_WORD ("log_level")) { - log_level = num; - } else if (IS_WORD ("msg_num")) { - msg_num_mode = num; - } else if (IS_WORD ("alert")) { - alert_sound = num; - } - } else if (IS_WORD ("chat_with_peer")) { - GET_PEER; - in_chat_mode = 1; - chat_mode_id = id; - } else if (IS_WORD ("delete_msg")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - do_delete_msg (num); - } else if (IS_WORD ("restore_msg")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - do_restore_msg (num); - } else if (IS_WORD ("delete_restore_msg")) { - long long num = next_token_int (); - if (num == NOT_FOUND) { - printf ("Bad msg id\n"); - RET; - } - do_delete_msg (num); - do_restore_msg (num); - } else if (IS_WORD ("quit")) { - exit (0); - } else if (IS_WORD ("safe_quit")) { - safe_quit = 1; - } - } -#undef IS_WORD -#undef RET - update_prompt (); - in_readline = 0; -} - -int readline_active; -void rprintf (const char *format, ...) { - print_start (); - va_list ap; - va_start (ap, format); - vfprintf (stdout, format, ap); - va_end (ap); - print_end(); -} - -int saved_point; -char *saved_line; -int prompt_was; -void print_start (void) { - if (in_readline) { return; } - assert (!prompt_was); - if (readline_active) { - saved_point = rl_point; -#ifdef READLINE_GNU - saved_line = talloc (rl_end + 1); - saved_line[rl_end] = 0; - memcpy (saved_line, rl_line_buffer, rl_end); - - rl_save_prompt(); - rl_replace_line("", 0); -#else - assert (rl_end >= 0); - saved_line = talloc (rl_end + 1); - memcpy (saved_line, rl_line_buffer, rl_end + 1); - rl_line_buffer[0] = 0; - set_prompt (""); -#endif - rl_redisplay(); - } - prompt_was = 1; -} - -void print_end (void) { - if (in_readline) { return; } - assert (prompt_was); - if (readline_active) { - set_prompt (get_default_prompt ()); -#if READLINE_GNU - rl_replace_line(saved_line, 0); -#else - memcpy (rl_line_buffer, saved_line, rl_end + 1); // not safe, but I hope this would work. -#endif - rl_point = saved_point; - rl_redisplay(); - tfree_str (saved_line); - } - prompt_was = 0; -} - - -/* -void logprintf (const char *format, ...) { - va_list ap; - va_start (ap, format); - log_message(format, ap); - va_end (ap); - //int x = 0; - //if (!prompt_was) { - // x = 1; - // print_start (); - //} - //printf (COLOR_GREY " *** "); - //printf (COLOR_NORMAL); - //if (x) { - // print_end (); - //} -} -*/ - -int color_stack_pos; -const char *color_stack[10]; - -void push_color (const char *color) { - assert (color_stack_pos < 10); - color_stack[color_stack_pos ++] = color; - printf ("%s", color); -} - -void pop_color (void) { - assert (color_stack_pos > 0); - color_stack_pos --; - if (color_stack_pos >= 1) { - printf ("%s", color_stack[color_stack_pos - 1]); - } else { - printf ("%s", COLOR_NORMAL); - } -} - -void print_media (struct message_media *M) { - assert (M); - switch (M->type) { - case CODE_message_media_empty: - case CODE_decrypted_message_media_empty: - return; - case CODE_message_media_photo: - if (M->photo.caption && strlen (M->photo.caption)) { - printf ("[photo %s]", M->photo.caption); - } else { - printf ("[photo]"); - } - return; - case CODE_message_media_video: - printf ("[video]"); - return; - case CODE_message_media_audio: - printf ("[audio]"); - return; - case CODE_message_media_document: - if (M->document.mime_type && M->document.caption) { - printf ("[document %s: type %s]", M->document.caption, M->document.mime_type); - } else { - printf ("[document]"); - } - return; - case CODE_decrypted_message_media_photo: - printf ("[photo]"); - return; - case CODE_decrypted_message_media_video: - printf ("[video]"); - return; - case CODE_decrypted_message_media_audio: - printf ("[audio]"); - return; - case CODE_decrypted_message_media_document: - printf ("[document]"); - return; - case CODE_message_media_geo: - printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude); - return; - case CODE_message_media_contact: - printf ("[contact] "); - push_color (COLOR_RED); - printf ("%s %s ", M->first_name, M->last_name); - pop_color (); - printf ("%s", M->phone); - return; - case CODE_message_media_unsupported: - printf ("[unsupported]"); - return; - default: - assert (0); - } -} - -int unknown_user_list_pos; -int unknown_user_list[1000]; - -void print_user_name (peer_id_t id, peer_t *U) { - assert (get_peer_type (id) == PEER_USER); - push_color (COLOR_RED); - if (!U) { - printf ("user#%d", get_peer_id (id)); - int i; - int ok = 1; - for (i = 0; i < unknown_user_list_pos; i++) { - if (unknown_user_list[i] == get_peer_id (id)) { - ok = 0; - break; - } - } - if (ok) { - assert (unknown_user_list_pos < 1000); - unknown_user_list[unknown_user_list_pos ++] = get_peer_id (id); - } - } else { - if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { - push_color (COLOR_REDB); - } - if ((U->flags & FLAG_DELETED)) { - printf ("deleted user#%d", get_peer_id (id)); - } else if (!(U->flags & FLAG_CREATED)) { - printf ("empty user#%d", get_peer_id (id)); - } else if (!U->user.first_name || !strlen (U->user.first_name)) { - printf ("%s", U->user.last_name); - } else if (!U->user.last_name || !strlen (U->user.last_name)) { - printf ("%s", U->user.first_name); - } else { - printf ("%s %s", U->user.first_name, U->user.last_name); - } - if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) { - pop_color (); - } - } - pop_color (); -} - -void print_chat_name (peer_id_t id, peer_t *C) { - assert (get_peer_type (id) == PEER_CHAT); - push_color (COLOR_MAGENTA); - if (!C) { - printf ("chat#%d", get_peer_id (id)); - } else { - printf ("%s", C->chat.title); - } - pop_color (); -} - -void print_encr_chat_name (peer_id_t id, peer_t *C) { - assert (get_peer_type (id) == PEER_ENCR_CHAT); - push_color (COLOR_MAGENTA); - if (!C) { - printf ("encr_chat#%d", get_peer_id (id)); - } else { - printf ("%s", C->print_name); - } - pop_color (); -} - -void print_encr_chat_name_full (peer_id_t id, peer_t *C) { - assert (get_peer_type (id) == PEER_ENCR_CHAT); - push_color (COLOR_MAGENTA); - if (!C) { - printf ("encr_chat#%d", get_peer_id (id)); - } else { - printf ("%s", C->print_name); - } - pop_color (); -} - -static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -void print_date (long t) { - struct tm *tm = localtime ((void *)&t); - if (time (0) - t < 12 * 60 * 60) { - printf ("[%02d:%02d] ", tm->tm_hour, tm->tm_min); - } else { - printf ("[%02d %s]", tm->tm_mday, monthes[tm->tm_mon]); - } -} - -void print_date_full (long t) { - struct tm *tm = localtime ((void *)&t); - printf ("[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); -} - -int our_id; - -void print_service_message (struct message *M) { - assert (M); - print_start (); - push_color (COLOR_GREY); - - push_color (COLOR_MAGENTA); - if (msg_num_mode) { - printf ("%lld ", M->id); - } - print_date (M->date); - pop_color (); - printf (" "); - if (get_peer_type (M->to_id) == PEER_CHAT) { - print_chat_name (M->to_id, user_chat_get (M->to_id)); - } else { - assert (get_peer_type (M->to_id) == PEER_ENCR_CHAT); - print_encr_chat_name (M->to_id, user_chat_get (M->to_id)); - } - printf (" "); - print_user_name (M->from_id, user_chat_get (M->from_id)); - - switch (M->action.type) { - 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; - case CODE_message_action_chat_edit_title: - printf (" changed title to %s\n", - M->action.new_title); - break; - case CODE_message_action_chat_edit_photo: - printf (" changed photo\n"); - break; - case CODE_message_action_chat_delete_photo: - printf (" deleted photo\n"); - break; - case CODE_message_action_chat_add_user: - printf (" added user "); - print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); - printf ("\n"); - break; - case CODE_message_action_chat_delete_user: - printf (" deleted user "); - print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); - printf ("\n"); - break; - case CODE_decrypted_message_action_set_message_t_t_l: - printf (" set ttl to %d seconds. Unsupported yet\n", M->action.ttl); - break; - default: - assert (0); - } - pop_color (); - print_end (); -} - -peer_id_t last_from_id; -peer_id_t last_to_id; - -void print_message (struct message *M) { - assert (M); - if (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED)) { - return; - } - if (!(M->flags & FLAG_CREATED)) { return; } - if (M->service) { - print_service_message (M); - return; - } - if (!get_peer_type (M->to_id)) { - logprintf ("Bad msg\n"); - return; - } - - last_from_id = M->from_id; - last_to_id = M->to_id; - - print_start (); - if (get_peer_type (M->to_id) == PEER_USER) { - if (M->out) { - push_color (COLOR_GREEN); - if (msg_num_mode) { - logprintf ("%lld ", M->id); - } - print_date (M->date); - pop_color (); - logprintf (" "); - print_user_name (M->to_id, user_chat_get (M->to_id)); - push_color (COLOR_GREEN); - if (M->unread) { - logprintf (" <<< "); - } else { - logprintf (" ««« "); - } - } else { - push_color (COLOR_BLUE); - if (msg_num_mode) { - logprintf ("%lld ", M->id); - } - print_date (M->date); - pop_color (); - logprintf (" "); - print_user_name (M->from_id, user_chat_get (M->from_id)); - push_color (COLOR_BLUE); - if (M->unread) { - logprintf (" >>> "); - } else { - logprintf (" »»» "); - } - if (alert_sound) { - play_sound(); - } - } - } else if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { - peer_t *P = user_chat_get (M->to_id); - assert (P); - if (M->out) { - push_color (COLOR_GREEN); - if (msg_num_mode) { - logprintf ("%lld ", M->id); - } - print_date (M->date); - logprintf (" "); - push_color (COLOR_CYAN); - logprintf (" %s", P->print_name); - pop_color (); - if (M->unread) { - logprintf (" <<< "); - } else { - logprintf (" ««« "); - } - } else { - push_color (COLOR_BLUE); - if (msg_num_mode) { - logprintf ("%lld ", M->id); - } - print_date (M->date); - push_color (COLOR_CYAN); - logprintf (" %s", P->print_name); - pop_color (); - if (M->unread) { - logprintf (" >>> "); - } else { - logprintf (" »»» "); - } - if (alert_sound) { - play_sound(); - } - } - } else { - assert (get_peer_type (M->to_id) == PEER_CHAT); - push_color (COLOR_MAGENTA); - if (msg_num_mode) { - logprintf ("%lld ", M->id); - } - print_date (M->date); - pop_color (); - logprintf (" "); - print_chat_name (M->to_id, user_chat_get (M->to_id)); - logprintf (" "); - print_user_name (M->from_id, user_chat_get (M->from_id)); - if ((get_peer_type (M->from_id) == PEER_USER) && (get_peer_id (M->from_id) == our_id)) { - push_color (COLOR_GREEN); - } else { - push_color (COLOR_BLUE); - } - if (M->unread) { - logprintf (" >>> "); - } else { - logprintf (" »»» "); - } - } - if (get_peer_type (M->fwd_from_id) == PEER_USER) { - logprintf ("[fwd from "); - print_user_name (M->fwd_from_id, user_chat_get (M->fwd_from_id)); - logprintf ("] "); - } - if (M->message && strlen (M->message)) { - logprintf ("%s", M->message); - } - if (M->media.type != CODE_message_media_empty) { - print_media (&M->media); - } - pop_color (); - assert (!color_stack_pos); - logprintf ("\n"); - print_end(); -} - -void play_sound (void) { - printf ("\a"); -} - -void set_interface_callbacks (void) { - readline_active = 1; - rl_callback_handler_install (get_default_prompt (), interpreter); - rl_attempted_completion_function = (void *) complete_text; - rl_completion_entry_function = (void *)complete_none; -} diff --git a/interface.h b/interface.h deleted file mode 100644 index 99f0319..0000000 --- a/interface.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __INTERFACE_H__ -#define __INTERFACE_H__ -#include "structures.h" - -#define COLOR_RED "\033[0;31m" -#define COLOR_REDB "\033[1;31m" -#define COLOR_NORMAL "\033[0m" -#define COLOR_GREEN "\033[32;1m" -#define COLOR_GREY "\033[37;1m" -#define COLOR_YELLOW "\033[33;1m" -#define COLOR_BLUE "\033[34;1m" -#define COLOR_MAGENTA "\033[35;1m" -#define COLOR_CYAN "\033[36;1m" -#define COLOR_LCYAN "\033[0;36m" - -#define COLOR_INVERSE "\033[7m" - -char *get_default_prompt (void); -char *complete_none (const char *text, int state); -char **complete_text (char *text, int start, int end); -void interpreter (char *line); - -void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void hexdump (int *in_ptr, int *in_end); - -struct message; -union peer; -void print_message (struct message *M); -void print_chat_name (peer_id_t id, union peer *C); -void print_user_name (peer_id_t id, union peer *U); -void print_encr_chat_name_full (peer_id_t id, peer_t *C); -void print_encr_chat_name (peer_id_t id, peer_t *C); -//void print_media (struct message_media *M); -void pop_color (void); -void push_color (const char *color); -void print_start (void); -void print_end (void); -void print_date_full (long t); -void print_date (long t); - -void play_sound (void); -void update_prompt (void); -void set_interface_callbacks (void); -#endif diff --git a/loop.c b/loop.c index 9dfe044..c2a72bf 100644 --- a/loop.c +++ b/loop.c @@ -17,10 +17,6 @@ Copyright Vitaly Valtman 2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #define _GNU_SOURCE #define READLINE_CALLBACKS @@ -28,13 +24,8 @@ #include #include #include -#ifdef READLINE_GNU #include #include -#else -#include -#include -#endif #include #include @@ -49,7 +40,6 @@ #include "telegram.h" #include "loop.h" #include "binlog.h" -#include "lua-tg.h" // @@ -70,65 +60,6 @@ extern int safe_quit; int unread_messages; void got_it (char *line, int len); -/* -void net_loop (int flags, int (*is_end)(void)) { - logprintf("starting net_loop()\n"); - while (!is_end ()) { - struct pollfd fds[101]; - int cc = 0; - if (flags & 3) { - fds[0].fd = 0; - fds[0].events = POLLIN; - cc ++; - } - - logprintf("writing_state_file()\n"); - write_state_file (); - // Ensure that all connections are active? - int x = connections_make_poll_array (fds + cc, 101 - cc) + cc; - double timer = next_timer_in (); - - // Wait until file descriptors are ready - if (timer > 1000) { timer = 1000; } - if (poll (fds, x, timer) < 0) { - logprintf("poll returned -1, wait a little bit.\n"); - work_timers (); - continue; - } - - // Execute all timers that are currently due - work_timers (); - - // ? - if ((flags & 3) && (fds[0].revents & POLLIN)) { - unread_messages = 0; - if (flags & 1) { - rl_callback_read_char (); - } else { - char *line = 0; - size_t len = 0; - assert (getline (&line, &len, stdin) >= 0); - got_it (line, strlen (line)); - } - } - - // - connections_poll_result (fds + cc, x - cc); - #ifdef USE_LUA - lua_do_all (); - #endif - if (safe_quit && !queries_num) { - logprintf ("All done. Exit\n"); - rl_callback_handler_remove (); - exit (0); - } - if (unknown_user_list_pos) { - do_get_user_list_info_silent (unknown_user_list_pos, unknown_user_list); - unknown_user_list_pos = 0; - } - } -} -*/ char **_s; size_t *_l; @@ -146,33 +77,8 @@ int is_got_it (void) { return got_it_ok; } -/* -int net_getline (char **s, size_t *l) { - fflush (stdout); -// rl_already_prompted = 1; - got_it_ok = 0; - _s = s; - _l = l; -// rl_callback_handler_install (0, got_it); - //net_loop (2, is_got_it); - return 0; -} -*/ - int ret1 (void) { return 0; } -/* -int main_loop (void) { - net_loop (1, ret1); - return 0; -} -*/ - - -//struct dc *DC_list[MAX_DC_ID + 1]; -//struct dc *DC_working; -//int dc_working_num; -//int auth_state; char *get_auth_key_filename (void); char *get_state_filename (void); int zero[512]; @@ -513,217 +419,3 @@ int readline_active; int new_dc_num; int wait_dialog_list; - -/** - * Discover the network and authorise with all data centers -void network_connect (struct telegram *instance) { - verbosity = 0; - on_start (); - // will return empty default values on empty files - instance->auth = read_auth_file ("/home/dev-jessie/.telegram/auth_file"); - instance->proto = read_state_file ("/home/dev-jessie/.telegram/auth_file"); - - struct dc *DC_list = (struct dc*)instance->auth.DC_list; - struct dc *DC_working = NULL; - - assert (DC_list[dc_working_num]); - if (!DC_working || !DC_working->auth_key_id) { -// if (auth_state == 0) { - logprintf("No working DC or not start_loopd.\n"); - DC_working = &DC_list[instance->auth.dc_working_num]; - assert (!DC_working->auth_key_id); - dc_authorize (DC_working); - assert (DC_working->auth_key_id); - auth_state = 100; - write_auth_file (instance->auth); - logprintf("Authorized DataCentre: auth_key_id: %lld \n", DC_working->auth_key_id); - } else { - } - - if (verbosity) { - logprintf ("Requesting info about DC...\n"); - } - do_help_get_config (); - logprintf("net_loop\n"); - net_loop (0, mcs); - logprintf("net_loop done...\n"); - if (verbosity) { - logprintf ("DC_info: %d new DC got\n", new_dc_num); - } - // read saved connection state - //read_state_file (); - read_secret_chat_file (); -} - */ - -/** - * Return if the given phone is registered - */ - /* -int network_phone_is_registered() { - int res = do_auth_check_phone (default_username); - assert(res >= 0); - return res; -} -*/ - - -/** - * Verify the phone number by providing the sms_code and the real name - * - * NOTE: This should be called when the phone number was previously - * unknown to the telegram network. - */ - /* -int network_verify_phone_registration(const char* code, const char *sms_hash, - const char *first ,const char *last) -{ - logprintf("Registering with code:%s, hash:%s, first:%s, last:%s\n", code, sms_hash, - first, last); - return 0; -} -*/ - -/** - * Export current authentication state to all known data centers. - */ -//void network_export_registration() -//{ -// 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); -// bl_do_dc_signed (i); -// write_auth_file (); -// } -// write_auth_file (); -// fflush (stdout); -// fflush (stderr); -//} - -//int start_loop (char* code, char* auth_mode) { -// logprintf("Calling start_loop()\n"); -// logprintf("auth_state %i\n", auth_state); -// if (auth_state == 100 || !(DC_working->has_auth)) { -// logprintf("auth_state == 100 || !(DC_working->has_auth)"); -// int res = do_auth_check_phone (default_username); -// assert (res >= 0); -// logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered"); -// if (res > 0 && !register_mode) { -// // Register Mode 1 -// logprintf ("Register Mode 1\n"); -// if (code) { -// /* -// if (do_send_code_result (code) >= 0) { -// logprintf ("Authentication successfull, state = 300\n"); -// auth_state = 300; -// } -// */ -// } else { -// logprintf("No code given, attempting to register\n"); -// // Send Code -// logprintf ("auth mode %s\n", auth_mode); -// /* -// if (strcmp(TELEGRAM_AUTH_MODE_SMS"sms", auth_mode)) { -// */ -// do_send_code (default_username); -// logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); -// logprintf("storing current state in auth file...\n"); -// write_auth_file (); -// logprintf("exitting...\n"); -// return 0; -// /* -// } else { -// logprintf ("You typed \"call\", switching to phone system.\n"); -// do_phone_call (default_username); -// logprintf ("Calling you!"); -// } -// */ -// } -// } else { -// logprintf ("User is not registered. Do you want to register? [Y/n] "); -// logprintf ("ERROR THIS IS NOT POSSIBLE!\n"); -// return 1; -// // Register Mode 2 -// // TODO: Requires first and last name, decide how to handle this. -// // - We need some sort of switch between registration modes -// // - When this mode is selected First and Last name should be added to the form -// // Currently Requires Manuel Entry in Terminal. -// size_t size; -// char *first_name; -// logprintf ("First name: "); -// if (net_getline (&first_name, &size) == -1) { -// perror ("getline()"); -// exit (EXIT_FAILURE); -// } -// char *last_name; -// logprintf ("Last 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]; -// -// if (*code) { -// if (do_send_code_result_auth (code, "-", first_name, last_name) >= 0) { -// auth_state = 300; -// } -// } else { -// if (strcmp(TELEGRAM_AUTH_MODE_SMS, auth_mode)) { -// do_send_code (default_username); -// logprintf ("Code from sms (if you did not receive an SMS and want to be called, type \"call\"): "); -// } else { -// logprintf ("You typed \"call\", switching to phone system.\n"); -// do_phone_call (default_username); -// logprintf ("Calling you! Code: "); -// } -// } -// } -// } -// logprintf("Authentication done\n"); -// -// 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); -// bl_do_dc_signed (i); -// write_auth_file (); -// } -// write_auth_file (); -// -// fflush (stdout); -// fflush (stderr); -// -// // read saved connection state -// read_state_file (); -// read_secret_chat_file (); -// -// // callbacks for interface functions -// set_interface_callbacks (); -// -// do_get_difference (); -// net_loop (0, dgot); -// #ifdef USE_LUA -// lua_diff_end (); -// #endif -// send_all_unsent (); -// -// do_get_dialog_list (); -// if (wait_dialog_list) { -// dialog_list_got = 0; -// net_loop (0, dlgot); -// } -// -// return 0; //main_loop (); -//} - -/* -int loop (void) { - network_connect(); - return start_loop(NULL, NULL); -} -*/ diff --git a/lua-tg.c b/lua-tg.c deleted file mode 100644 index 6ff996b..0000000 --- a/lua-tg.c +++ /dev/null @@ -1,550 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef USE_LUA -/* -#include "lua-tg.h" - -#include "include.h" -#include -#include - - -#include -#include -#include -lua_State *luaState; - -#include "structures.h" -#include "constants.h" -#include "tools.h" -#include "queries.h" -#include "net.h" - -extern int verbosity; - -static int have_file; - -#define my_lua_checkstack(L,x) assert (lua_checkstack (L, x)) -void push_user (peer_t *P UU); -void push_peer (peer_id_t id, peer_t *P); - -void lua_add_string_field (const char *name, const char *value) { - assert (name && strlen (name)); - if (!value || !strlen (value)) { return; } - my_lua_checkstack (luaState, 3); - lua_pushstring (luaState, name); - lua_pushstring (luaState, value); - lua_settable (luaState, -3); -} - -void lua_add_num_field (const char *name, double value) { - assert (name && strlen (name)); - my_lua_checkstack (luaState, 3); - lua_pushstring (luaState, name); - lua_pushnumber (luaState, value); - lua_settable (luaState, -3); -} - -void push_peer_type (int x) { - switch (x) { - case PEER_USER: - lua_pushstring (luaState, "user"); - break; - case PEER_CHAT: - lua_pushstring (luaState, "chat"); - break; - case PEER_ENCR_CHAT: - lua_pushstring (luaState, "encr_chat"); - break; - default: - assert (0); - } -} - -void push_user (peer_t *P UU) { - my_lua_checkstack (luaState, 4); - lua_add_string_field ("first_name", P->user.first_name); - lua_add_string_field ("last_name", P->user.last_name); - lua_add_string_field ("real_first_name", P->user.real_first_name); - lua_add_string_field ("real_last_name", P->user.real_last_name); - lua_add_string_field ("phone", P->user.phone); -} - -void push_chat (peer_t *P) { - my_lua_checkstack (luaState, 4); - assert (P->chat.title); - lua_add_string_field ("title", P->chat.title); - lua_add_num_field ("members_num", P->chat.users_num); -} - -void push_encr_chat (peer_t *P) { - my_lua_checkstack (luaState, 4); - lua_pushstring (luaState, "user"); - push_peer (MK_USER (P->encr_chat.user_id), user_chat_get (MK_USER (P->encr_chat.user_id))); - lua_settable (luaState, -3); -} - -void push_peer (peer_id_t id, peer_t *P) { - lua_newtable (luaState); - - lua_add_num_field ("id", get_peer_id (id)); - lua_pushstring (luaState, "type"); - push_peer_type (get_peer_type (id)); - lua_settable (luaState, -3); - - - if (!P || !(P->flags & FLAG_CREATED)) { - lua_pushstring (luaState, "print_name"); - static char s[100]; - switch (get_peer_type (id)) { - case PEER_USER: - sprintf (s, "user#%d", get_peer_id (id)); - break; - case PEER_CHAT: - sprintf (s, "chat#%d", get_peer_id (id)); - break; - case PEER_ENCR_CHAT: - sprintf (s, "encr_chat#%d", get_peer_id (id)); - break; - default: - assert (0); - } - lua_pushstring (luaState, s); - lua_settable (luaState, -3); // flags - - return; - } - - lua_add_string_field ("print_name", P->print_name); - lua_add_num_field ("flags", P->flags); - - switch (get_peer_type (id)) { - case PEER_USER: - push_user (P); - break; - case PEER_CHAT: - push_chat (P); - break; - case PEER_ENCR_CHAT: - push_encr_chat (P); - break; - default: - assert (0); - } -} - -void push_media (struct message_media *M) { - my_lua_checkstack (luaState, 4); - - switch (M->type) { - case CODE_message_media_photo: - case CODE_decrypted_message_media_photo: - lua_pushstring (luaState, "photo"); - break; - case CODE_message_media_video: - case CODE_decrypted_message_media_video: - lua_pushstring (luaState, "video"); - break; - case CODE_message_media_audio: - case CODE_decrypted_message_media_audio: - lua_pushstring (luaState, "audio"); - break; - case CODE_message_media_document: - case CODE_decrypted_message_media_document: - lua_pushstring (luaState, "document"); - break; - case CODE_message_media_unsupported: - lua_pushstring (luaState, "unsupported"); - break; - case CODE_message_media_geo: - lua_newtable (luaState); - lua_add_num_field ("longitude", M->geo.longitude); - lua_add_num_field ("latitude", M->geo.latitude); - break; - case CODE_message_media_contact: - case CODE_decrypted_message_media_contact: - lua_newtable (luaState); - lua_add_string_field ("phone", M->phone); - lua_add_string_field ("first_name", M->first_name); - lua_add_string_field ("last_name", M->last_name); - lua_add_num_field ("user_id", M->user_id); - break; - default: - lua_pushstring (luaState, "???"); - } -} - -void push_message (struct message *M) { - assert (M); - my_lua_checkstack (luaState, 10); - lua_newtable (luaState); - - static char s[30]; - tsnprintf (s, 30, "%lld", M->id); - lua_add_string_field ("id", s); - lua_add_num_field ("flags", M->flags); - - if (get_peer_type (M->fwd_from_id)) { - lua_pushstring (luaState, "fwd_from"); - push_peer (M->fwd_from_id, user_chat_get (M->fwd_from_id)); - lua_settable (luaState, -3); // fwd_from - - lua_add_num_field ("fwd_date", M->fwd_date); - } - - lua_pushstring (luaState, "from"); - push_peer (M->from_id, user_chat_get (M->from_id)); - lua_settable (luaState, -3); - - lua_pushstring (luaState, "to"); - push_peer (M->to_id, user_chat_get (M->to_id)); - lua_settable (luaState, -3); - - lua_pushstring (luaState, "out"); - lua_pushboolean (luaState, M->out); - lua_settable (luaState, -3); - - lua_pushstring (luaState, "unread"); - lua_pushboolean (luaState, M->unread); - lua_settable (luaState, -3); - - lua_pushstring (luaState, "date"); - lua_pushnumber (luaState, M->date); - lua_settable (luaState, -3); - - lua_pushstring (luaState, "service"); - lua_pushboolean (luaState, M->service); - lua_settable (luaState, -3); - - if (!M->service) { - if (M->message_len && M->message) { - lua_pushstring (luaState, "text"); - lua_pushlstring (luaState, M->message, M->message_len); - lua_settable (luaState, -3); - } - if (M->media.type && M->media.type != CODE_message_media_empty && M->media.type != CODE_decrypted_message_media_empty) { - lua_pushstring (luaState, "media"); - push_media (&M->media); - lua_settable (luaState, -3); - } - } -} - -void lua_binlog_end (void) { - if (!have_file) { return; } - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - lua_getglobal (luaState, "on_binlog_replay_end"); - assert (lua_gettop (luaState) == 1); - - int r = lua_pcall (luaState, 0, 0, 0); - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } -} - -void lua_diff_end (void) { - if (!have_file) { return; } - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - lua_getglobal (luaState, "on_get_difference_end"); - assert (lua_gettop (luaState) == 1); - - int r = lua_pcall (luaState, 0, 0, 0); - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } -} - -void lua_our_id (int id) { - if (!have_file) { return; } - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - lua_getglobal (luaState, "on_our_id"); - lua_pushnumber (luaState, id); - assert (lua_gettop (luaState) == 2); - - int r = lua_pcall (luaState, 1, 0, 0); - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } -} - -void lua_new_msg (struct message *M UU) { - if (!have_file) { return; } - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - lua_getglobal (luaState, "on_msg_receive"); - push_message (M); - assert (lua_gettop (luaState) == 2); - - int r = lua_pcall (luaState, 1, 0, 0); - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } -} - -void lua_secret_chat_created (struct secret_chat *C) { - if (!have_file) { return; } - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - lua_getglobal (luaState, "on_secret_chat_created"); - push_peer (C->id, (void *)C); - assert (lua_gettop (luaState) == 2); - - int r = lua_pcall (luaState, 1, 0, 0); - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } -} - -void lua_user_update (struct user *U) { - if (!have_file) { return; } - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - lua_getglobal (luaState, "on_user_update"); - push_peer (U->id, (void *)U); - assert (lua_gettop (luaState) == 2); - - int r = lua_pcall (luaState, 1, 0, 0); - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } -} - -void lua_chat_update (struct chat *C) { - if (!have_file) { return; } - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - lua_getglobal (luaState, "on_chat_update"); - push_peer (C->id, (void *)C); - assert (lua_gettop (luaState) == 2); - - int r = lua_pcall (luaState, 1, 0, 0); - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } -} - -extern peer_t *Peers[]; -extern int peer_num; - -#define MAX_LUA_COMMANDS 1000 -void *lua_ptr[MAX_LUA_COMMANDS]; -static int pos; - -static peer_t *get_peer (const char *s) { - int index = 0; - while (index < peer_num && (!Peers[index]->print_name || strcmp (Peers[index]->print_name, s))) { - index ++; - } - return index == peer_num ? 0 : Peers[index]; -} - -void lua_do_all (void) { - int p = 0; - while (p < pos) { - int l = (long)lua_ptr[p ++]; - assert (p + l + 1 <= pos); - int f = (long)lua_ptr[p ++]; - switch (f) { - case 0: - do_send_message (((peer_t *)lua_ptr[p])->id, lua_ptr[p + 1], strlen (lua_ptr[p + 1])); - tfree_str (lua_ptr[p + 1]); - p += 2; - break; - case 1: - do_forward_message (((peer_t *)lua_ptr[p])->id, (long)lua_ptr[p + 1]); - p += 2; - break; - case 2: - #ifdef DEBUG - texists (lua_ptr[p], sizeof (peer_t)); - #endif - do_mark_read (((peer_t *)lua_ptr[p])->id); - p += 1; - break; - default: - assert (0); - } - } - pos = 0; -} - - -static int send_msg_from_lua (lua_State *L) { - if (MAX_LUA_COMMANDS - pos < 4) { - lua_pushboolean (L, 0); - return 1; - } - int n = lua_gettop (L); - if (n != 2) { - lua_pushboolean (L, 0); - return 1; - } - const char *s = lua_tostring (L, -2); - if (!s) { - lua_pushboolean (L, 0); - return 1; - } - const char *msg = lua_tostring (L, -1); - - peer_t *P = get_peer (s); - if (!P) { - lua_pushboolean (L, 0); - return 1; - } - - lua_ptr[pos ++] = (void *)2l; - lua_ptr[pos ++] = (void *)0l; - lua_ptr[pos ++] = P; - lua_ptr[pos ++] = tstrdup (msg); - logprintf ("msg = %s\n", msg); - - lua_pushboolean (L, 1); - return 1; -} - -static int fwd_msg_from_lua (lua_State *L) { - if (MAX_LUA_COMMANDS - pos < 4) { - lua_pushboolean (L, 0); - return 1; - } - int n = lua_gettop (L); - if (n != 2) { - lua_pushboolean (L, 0); - return 1; - } - const char *s = lua_tostring (L, -2); - long long num = atoll (lua_tostring (L, -1)); - if (!s) { - lua_pushboolean (L, 0); - return 1; - } - peer_t *P = get_peer (s); - if (!P) { - lua_pushboolean (L, 0); - return 1; - } - - lua_ptr[pos ++] = (void *)2l; - lua_ptr[pos ++] = (void *)1l; - lua_ptr[pos ++] = P; - lua_ptr[pos ++] = (void *)(long)num; - lua_pushboolean (L, 1); - return 1; -} - -static int mark_read_from_lua (lua_State *L) { - if (MAX_LUA_COMMANDS - pos < 4) { - lua_pushboolean (L, 0); - return 1; - } - int n = lua_gettop (L); - if (n != 1) { - lua_pushboolean (L, 0); - return 1; - } - const char *s = lua_tostring (L, -1); - if (!s) { - lua_pushboolean (L, 0); - return 1; - } - peer_t *P = get_peer (s); - if (!P) { - lua_pushboolean (L, 0); - return 1; - } - - lua_ptr[pos ++] = (void *)1l; - lua_ptr[pos ++] = (void *)2l; - lua_ptr[pos ++] = P; - lua_pushboolean (L, 1); - return 1; -} - -int lua_postpone_alarm (void *self) { - int *t = self; - - lua_settop (luaState, 0); - //lua_checkstack (luaState, 20); - my_lua_checkstack (luaState, 20); - - lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[1]); - lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[0]); - assert (lua_gettop (luaState) == 2); - - int r = lua_pcall (luaState, 1, 0, 0); - - luaL_unref (luaState, LUA_REGISTRYINDEX, t[0]); - luaL_unref (luaState, LUA_REGISTRYINDEX, t[1]); - - if (r) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - } - tfree (*(void **)(t + 2), sizeof (struct event_timer)); - tfree (t, 16); - return 0; -} - -static int postpone_from_lua (lua_State *L) { - int n = lua_gettop (L); - if (n != 3) { - lua_pushboolean (L, 0); - return 1; - } - - double timeout = lua_tonumber (L, -1); - if (timeout < 0) { - lua_pushboolean (L, 0); - return 1; - } - - lua_pop (L, 1); - int a1 = luaL_ref (L, LUA_REGISTRYINDEX); - int a2 = luaL_ref (L, LUA_REGISTRYINDEX); - - struct event_timer *ev = talloc (sizeof (*ev)); - int *t = talloc (16); - t[0] = a1; - t[1] = a2; - *(void **)(t + 2) = ev; - - ev->timeout = get_double_time () + timeout; - ev->alarm = (void *)lua_postpone_alarm; - ev->self = t; - insert_event_timer (ev); - - lua_pushboolean (L, 1); - return 1; -} - -void lua_init (const char *file) { - if (!file) { return; } - have_file = 1; - luaState = luaL_newstate (); - luaL_openlibs (luaState); - - lua_register (luaState, "send_msg", send_msg_from_lua); - lua_register (luaState, "fwd_msg", fwd_msg_from_lua); - lua_register (luaState, "mark_read", mark_read_from_lua); - lua_register (luaState, "postpone", postpone_from_lua); - - int ret = luaL_dofile (luaState, file); - if (ret) { - logprintf ("lua: %s\n", lua_tostring (luaState, -1)); - exit (1); - } -} -*/ - -#endif diff --git a/lua-tg.h b/lua-tg.h deleted file mode 100644 index 6ea8faa..0000000 --- a/lua-tg.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __LUA_TG_H__ -#define __LUA_TG_H__ - -#include -#include "structures.h" - -/* -void lua_init (const char *file); -void lua_new_msg (struct message *M); -void lua_our_id (int id); -void lua_secret_chat_created (struct secret_chat *U); -void lua_user_update (struct user *U); -void lua_chat_update (struct chat *C); -void lua_binlog_end (void); -void lua_diff_end (void); -void lua_do_all (void); -*/ -#endif diff --git a/main.c b/main.c deleted file mode 100644 index 0894f86..0000000 --- a/main.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#if (READLINE == GNU) -#include -#else -#include -#endif - -#include -#include -#include - -#ifdef HAVE_EXECINFO_H -#include -#endif -#include -#ifdef HAVE_LIBCONFIG -#include -#endif - -#include "telegram.h" -#include "loop.h" -#include "mtproto-client.h" -#include "tools.h" - -#ifdef USE_LUA -# include "lua-tg.h" -#endif - -// TODO: Delete this shit -#include -#define BREAK raise(SIGINT); - -#define PROGNAME "telegram-client" -#define VERSION "0.01" - -#define CONFIG_DIRECTORY "." PROG_NAME -#define CONFIG_FILE "config" -#define AUTH_KEY_FILE "auth" -#define STATE_FILE "state" -#define SECRET_CHAT_FILE "secret" -#define DOWNLOADS_DIRECTORY "downloads" -#define BINLOG_FILE "binlog" - -#define CONFIG_DIRECTORY_MODE 0700 - -#define DEFAULT_CONFIG_CONTENTS \ - "# This is an empty config file\n" \ - "# Feel free to put something here\n" - -char *default_username; -char *auth_token; -int msg_num_mode; -char *config_filename; -char *prefix; -int test_dc; -char *auth_file_name; -char *state_file_name; -char *secret_chat_file_name; -char *downloads_directory; -char *config_directory; -char *binlog_file_name; -extern int binlog_enabled; -extern int log_level; -int log_level = 1; -int sync_from_start; -int allow_weak_random; - -void set_default_username (const char *s) { - if (default_username) { - tfree_str (default_username); - } - default_username = tstrdup (s); -} - - -/* {{{ TERMINAL */ -static struct termios term_in, term_out; -static int term_set_in; -static int term_set_out; - -void get_terminal_attributes (void) { - if (tcgetattr (STDIN_FILENO, &term_in) < 0) { - } else { - term_set_in = 1; - } - if (tcgetattr (STDOUT_FILENO, &term_out) < 0) { - } else { - term_set_out = 1; - } -} - -void set_terminal_attributes (void) { - if (term_set_in) { - if (tcsetattr (STDIN_FILENO, 0, &term_in) < 0) { - perror ("tcsetattr()"); - } - } - if (term_set_out) { - if (tcsetattr (STDOUT_FILENO, 0, &term_out) < 0) { - perror ("tcsetattr()"); - } - } -} -/* }}} */ - -char *get_home_directory (void) { - static char *home_directory = NULL; - if (home_directory != NULL) { - return home_directory; - } - struct passwd *current_passwd; - uid_t user_id; - setpwent (); - user_id = getuid (); - while ((current_passwd = getpwent ())) { - if (current_passwd->pw_uid == user_id) { - home_directory = tstrdup (current_passwd->pw_dir); - break; - } - } - endpwent (); - if (home_directory == NULL) { - home_directory = tstrdup ("."); - } - return home_directory; -} - -char *get_config_directory (void) { - char *config_directory; - tasprintf (&config_directory, "%s/" CONFIG_DIRECTORY, get_home_directory ()); - return config_directory; -} - -char *get_config_filename (void) { - return config_filename; -} - -char *get_auth_key_filename (void) { - return auth_file_name; -} - -char *get_state_filename (void) { - return state_file_name; -} - -char *get_secret_chat_filename (void) { - return secret_chat_file_name; -} - -char *get_downloads_directory (void) { - return downloads_directory; -} - -char *get_binlog_file_name (void) { - return binlog_file_name; -} - -char *make_full_path (char *s) { - if (*s != '/') { - char *t = s; - tasprintf (&s, "%s/%s", get_home_directory (), s); - tfree_str (t); - } - return s; -} - -void check_type_sizes (void) { - if (sizeof (int) != 4u) { - logprintf ("sizeof (int) isn't equal 4.\n"); - exit (1); - } - if (sizeof (char) != 1u) { - logprintf ("sizeof (char) isn't equal 1.\n"); - exit (1); - } -} - -void running_for_first_time (void) { - check_type_sizes (); - if (config_filename) { - return; // Do not create custom config file - } - tasprintf (&config_filename, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, CONFIG_FILE); - config_filename = make_full_path (config_filename); - - int config_file_fd; - char *config_directory = get_config_directory (); - //char *downloads_directory = get_downloads_directory (); - - if (!mkdir (config_directory, CONFIG_DIRECTORY_MODE)) { - printf ("[%s] created\n", config_directory); - } - - tfree_str (config_directory); - config_directory = NULL; - // see if config file is there - if (access (config_filename, R_OK) != 0) { - // config file missing, so touch it - config_file_fd = open (config_filename, O_CREAT | O_RDWR, 0600); - if (config_file_fd == -1) { - perror ("open[config_file]"); - exit (EXIT_FAILURE); - } - if (write (config_file_fd, DEFAULT_CONFIG_CONTENTS, strlen (DEFAULT_CONFIG_CONTENTS)) <= 0) { - perror ("write[config_file]"); - exit (EXIT_FAILURE); - } - close (config_file_fd); - } -} - -#ifdef HAVE_LIBCONFIG -void parse_config_val (config_t *conf, char **s, char *param_name, const char *default_name, const char *path) { - static char buf[1000]; - int l = 0; - if (prefix) { - l = strlen (prefix); - memcpy (buf, prefix, l); - buf[l ++] = '.'; - } - *s = 0; - const char *r = 0; - strcpy (buf + l, param_name); - config_lookup_string (conf, buf, &r); - if (r) { - if (path) { - tasprintf (s, "%s/%s", path, r); - } else { - *s = tstrdup (r); - } - } else { - if (path) { - tasprintf (s, "%s/%s", path, default_name); - } else { - *s = tstrdup (default_name); - } - } -} - -void parse_config (void) { - config_filename = make_full_path (config_filename); - - config_t conf; - config_init (&conf); - if (config_read_file (&conf, config_filename) != CONFIG_TRUE) { - fprintf (stderr, "Can not read config '%s': error '%s' on the line %d\n", config_filename, config_error_text (&conf), config_error_line (&conf)); - exit (2); - } - - if (!prefix) { - config_lookup_string (&conf, "default_profile", (void *)&prefix); - } - - static char buf[1000]; - int l = 0; - if (prefix) { - l = strlen (prefix); - memcpy (buf, prefix, l); - buf[l ++] = '.'; - } - test_dc = 0; - strcpy (buf + l, "test"); - config_lookup_bool (&conf, buf, &test_dc); - - strcpy (buf + l, "log_lev el"); - long long t = log_level; - config_lookup_int (&conf, buf, (void *)&t); - log_level = t; - - if (!msg_num_mode) { - strcpy (buf + l, "msg_num"); - config_lookup_bool (&conf, buf, &msg_num_mode); - } - - parse_config_val (&conf, &config_directory, "config_directory", CONFIG_DIRECTORY, 0); - config_directory = make_full_path (config_directory); - - parse_config_val (&conf, &auth_file_name, "auth_file", AUTH_KEY_FILE, config_directory); - parse_config_val (&conf, &state_file_name, "state_file", STATE_FILE, config_directory); - parse_config_val (&conf, &secret_chat_file_name, "secret", SECRET_CHAT_FILE, config_directory); - parse_config_val (&conf, &downloads_directory, "downloads", DOWNLOADS_DIRECTORY, config_directory); - parse_config_val (&conf, &binlog_file_name, "binlog", BINLOG_FILE, config_directory); - - strcpy (buf + l, "binlog_enabled"); - config_lookup_bool (&conf, buf, &binlog_enabled); - - if (!mkdir (config_directory, CONFIG_DIRECTORY_MODE)) { - printf ("[%s] created\n", config_directory); - } - if (!mkdir (downloads_directory, CONFIG_DIRECTORY_MODE)) { - printf ("[%s] created\n", downloads_directory); - } -} -#else -void parse_config (void) { - printf ("libconfig not enabled\n"); - tasprintf (&auth_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, AUTH_KEY_FILE); - tasprintf (&state_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, STATE_FILE); - tasprintf (&secret_chat_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, SECRET_CHAT_FILE); - tasprintf (&downloads_directory, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, DOWNLOADS_DIRECTORY); - tasprintf (&binlog_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, BINLOG_FILE); -} -#endif - -void inner_main (void) { - loop (); -} - -void usage (void) { - printf ("%s Usage\n", PROGNAME); - - printf (" -h this help list\n"); - printf (" -u username specify username\n"); - printf (" -k public-key specify server public key\n"); - printf (" -v verbose\n"); - printf (" -l [1-3] log level\n"); - printf (" -L log-file log net file\n"); - printf (" -N message num mode\n"); - printf (" -c config-file specify config file\n"); - printf (" -p prefix specify prefix\n"); - printf (" -R register mode\n"); - printf (" -f sync from start\n"); - printf (" -B enable binlog\n"); - printf (" -E disable auto accept\n"); - printf (" -w allow weak random\n"); - printf (" -s specify lua script\n"); - printf (" -W wait dialog list\n"); - printf ("\n"); - - exit (1); -} - -extern char *rsa_public_key_name; -extern int verbosity; -extern int default_dc_num; - -char *log_net_file; -FILE *log_net_f; - -int register_mode; -int disable_auto_accept; -int wait_dialog_list; - -char *lua_file; - -void args_parse (int argc, char **argv) { - verbosity = 2; - int opt = 0; - while ((opt = getopt (argc, argv, "u:hk:vn:Nc:p:l:RfBL:Es:wW")) != -1) { - switch (opt) { - case 'u': - set_default_username (optarg); - break; - case 'k': - rsa_public_key_name = tstrdup (optarg); - break; - case 'v': - verbosity ++; - break; - case 'N': - msg_num_mode ++; - break; - case 'c': - config_filename = tstrdup (optarg); - break; - case 'p': - prefix = tstrdup (optarg); - assert (strlen (prefix) <= 100); - break; - case 'l': - log_level = atoi (optarg); - break; - case 'R': - register_mode = 1; - break; - case 'f': - sync_from_start = 1; - break; - case 'B': - binlog_enabled = 1; - break; - case 'L': - if (log_net_file) { - usage (); - } - log_net_file = tstrdup (optarg); - log_net_f = fopen (log_net_file, "a"); - assert (log_net_f); - break; - case 'E': - disable_auto_accept = 1; - break; - case 'w': - allow_weak_random = 1; - break; - case 's': - lua_file = tstrdup (optarg); - break; - case 'W': - wait_dialog_list = 1; - break; - case 'h': - default: - usage (); - break; - } - } -} - -#ifdef HAVE_EXECINFO_H -void print_backtrace (void) { - void *buffer[255]; - const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); - backtrace_symbols_fd (buffer, calls, 1); -} -#else -void print_backtrace (void) { - if (write (1, "No libexec. Backtrace disabled\n", 32) < 0) { - // Sad thing - } -} -#endif - -void sig_segv_handler (int signum __attribute__ ((unused))) { - set_terminal_attributes (); - if (write (1, "SIGSEGV received\n", 18) < 0) { - // Sad thing - } - print_backtrace (); - exit (EXIT_FAILURE); -} - -void sig_abrt_handler (int signum __attribute__ ((unused))) { - set_terminal_attributes (); - if (write (1, "SIGABRT received\n", 18) < 0) { - // Sad thing - } - print_backtrace (); - exit (EXIT_FAILURE); -} - -int tgmain (int argc, char **argv) { - signal (SIGSEGV, sig_segv_handler); - signal (SIGABRT, sig_abrt_handler); - - log_level = 10; - - args_parse (argc, argv); - running_for_first_time (); - parse_config (); - - get_terminal_attributes (); - - #ifdef USE_LUA - if (lua_file) { - lua_init (lua_file); - } - #endif - - inner_main (); - - return 0; -} diff --git a/mtproto-client.c b/mtproto-client.c index 3bc63c1..b7fcfee 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -18,10 +18,6 @@ Copyright Vitaly Valtman 2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #define _FILE_OFFSET_BITS 64 #include @@ -73,20 +69,6 @@ int verbosity = 0; int allow_weak_random = 0; int disable_auto_accept = 0; -/* -enum dc_state c_state; -char nonce[256]; -char new_nonce[256]; -char server_nonce[256]; -extern int binlog_enabled; -extern int disable_auto_accept; -extern int allow_weak_random; - -int total_packets_sent; -long long total_data_sent; -*/ - - int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); int rpc_close (struct connection *c); @@ -1467,23 +1449,6 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { fetch_long (c->mtconnection); // unique_id GET_DC(c)->server_salt = fetch_long (c->mtconnection); logprintf ("new server_salt = %lld\n", GET_DC(c)->server_salt); - - - /* - // create a new empty session - assert (DC->working_sess + 1 < 3); - assert (!DC->sessions[++ DC->working_sess]); - struct session *s = DC->sessions[DC->working_sess] = alloc_session(); - - // DC->session_id = fetch_long (); - // long las_id = fetch_long (c->mtconnection); - long ses_id = fetch_long (c->mtconnection); - //s->session_id = ses_id; - logprintf ("new sess_id = %ld\n", ses_id); - - // fetch_long (c->mtconnection); // unique_id - DC->server_salt = fetch_long (c->mtconnection); - */ } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { @@ -1833,26 +1798,6 @@ void on_start (struct mtproto_connection *self) { pk_fingerprint = compute_rsa_key_fingerprint (pubKey); } -/* -int auth_ok (void) { - return auth_success; -} -*/ - -/* -void dc_authorize (struct dc *DC) { - c_state = 0; - auth_success = 0; - if (!DC->sessions[0]) { - dc_create_session (DC); - } - if (verbosity) { - logprintf ( "Starting authorization for DC #%d: %s:%d\n", DC->id, DC->ip, DC->port); - } - net_loop (0, auth_ok); -} -*/ - struct connection_methods mtproto_methods = { .execute = rpc_execute, diff --git a/mtproto-client.h b/mtproto-client.h index b55e7d3..2130ec5 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -26,10 +26,6 @@ Copyright Nikolay Durov, Andrey Lopatin 2012-2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include #include #include diff --git a/net.c b/net.c index c0c76c7..fad9eb5 100644 --- a/net.c +++ b/net.c @@ -17,10 +17,6 @@ Copyright Vitaly Valtman 2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #define _GNU_SOURCE #include #include @@ -42,7 +38,6 @@ #include "include.h" #include "mtproto-client.h" #include "tree.h" -#include "interface.h" #ifndef POLLRDHUP #define POLLRDHUP 0 diff --git a/net.h b/net.h index eccac14..3152fe6 100644 --- a/net.h +++ b/net.h @@ -129,8 +129,6 @@ struct connection { void *extra; struct event_timer ev; double last_receive_time; - - // backreference to corrent telegram instance struct telegram *instance; struct mtproto_connection *mtconnection; }; diff --git a/queries.c b/queries.c index 4fc68af..1cd8bee 100644 --- a/queries.c +++ b/queries.c @@ -17,10 +17,6 @@ Copyright Vitaly Valtman 2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #define _FILE_OFFSET_BITS 64 #include #include @@ -705,34 +701,6 @@ int get_contacts_on_answer (struct query *q UU) { n = fetch_int (mtp); for (i = 0; i < n; i++) { fetch_alloc_user (mtp); - /* - //print_start (); - //push_color (COLOR_YELLOW); - logprintf ("User #%d: ", get_peer_id (U->id)); - //print_user_name (U->id, (peer_t *)U); - //push_color (COLOR_GREEN); - logprintf (" ("); - logprintf ("%s", U->print_name); - if (U->phone) { - logprintf (" "); - logprintf ("%s", U->phone); - } - logprintf (") "); - //pop_color (); - if (U->status.online > 0) { - logprintf ("online\n"); - } else { - if (U->status.online < 0) { - logprintf ("offline. Was online "); - //print_date_full (U->status.when); - } else { - logprintf ("offline permanent"); - } - logprintf ("\n"); - } - //pop_color (); - //print_end (); - */ } contacts_got = 1; return 0; diff --git a/rpm/telegram-cli-Beta-2.fc20.x86_64.rpm b/rpm/telegram-cli-Beta-2.fc20.x86_64.rpm deleted file mode 100644 index 0deaace0e3bfbd1184e064b665486bb52dc9ac2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147652 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

_Vt8K7?mvk= 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�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 O|(7c4`>_!C^ri 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 a0mE9dz000003RzmU%@`8^ diff --git a/structures.c b/structures.c index a9dd465..cf7ad1c 100644 --- a/structures.c +++ b/structures.c @@ -17,10 +17,6 @@ Copyright Vitaly Valtman 2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include #include #include "constants.h" diff --git a/telegram-cli.spec b/telegram-cli.spec deleted file mode 100644 index c187dc3..0000000 --- a/telegram-cli.spec +++ /dev/null @@ -1,46 +0,0 @@ -Name: telegram-cli -Version: Beta -Release: 2%{?dist} -Summary: Private fast and open platform for instant messaging - -Packager: Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) -Group: Internet/Messaging -License: GPL -URL: https://github.com/vysheng/tg -Source: master.zip - -BuildRequires: lua-devel, openssl-devel, libconfig-devel, readline-devel, wget -#Requires: wget - -%description -Telegram is an Open Source messaging platform for mobile, desktop focused on privacy. - - - - -%prep -[ -d %{name} ] && rm -Rfv %{name} -mkdir %{name} -cd %{name} -wget -O master.zip https://github.com/vysheng/tg/archive/master.zip -unzip master.zip -cd tg-master -./configure -make %{?_smp_mflags} - - -%install -cd %{name} -cd tg-master -%{__install} -D -m0755 telegram %{buildroot}/usr/bin/telegram -%{__install} -D -m0644 tg-server.pub %{buildroot}/etc/telegram/server.pub - -%files -/usr/bin/telegram -/etc/telegram/server.pub - -%changelog -* Tue Feb 4 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) -- Add server key to /etc/telegram/ -* Sat Feb 1 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) -- Initial SPEC file diff --git a/test.lua b/test.lua deleted file mode 100644 index 90a3de5..0000000 --- a/test.lua +++ /dev/null @@ -1,95 +0,0 @@ -started = 0 -our_id = 0 - -function vardump(value, depth, key) - local linePrefix = "" - local spaces = "" - - if key ~= nil then - linePrefix = "["..key.."] = " - end - - if depth == nil then - depth = 0 - else - depth = depth + 1 - for i=1, depth do spaces = spaces .. " " end - end - - if type(value) == 'table' then - mTable = getmetatable(value) - if mTable == nil then - print(spaces ..linePrefix.."(table) ") - else - print(spaces .."(metatable) ") - value = mTable - end - for tableKey, tableValue in pairs(value) do - vardump(tableValue, depth, tableKey) - end - elseif type(value) == 'function' or - type(value) == 'thread' or - type(value) == 'userdata' or - value == nil - then - print(spaces..tostring(value)) - else - print(spaces..linePrefix.."("..type(value)..") "..tostring(value)) - end -end - -print ("HI, this is lua script") - - - -function on_msg_receive (msg) - if started == 0 then - return - end - if msg.out then - return - end - if (msg.text == 'ping') then - if (msg.to.id == our_id) then - print ('sending pong to ' .. tostring (msg.from.print_name)) - send_msg (msg.from.print_name, 'pong') - else - print ('sending pong to ' .. tostring (msg.to.print_name)) - send_msg (msg.to.print_name, 'pong') - end - return - end - if (msg.text == 'PING') then - if (msg.to.id == our_id) then - fwd_msg (msg.from.print_name, msg.id) - else - fwd_msg (msg.to.print_name, msg.id) - end - return - end - --vardump (msg) - --print ( "Message # " .. msg.id .. " (flags " .. msg.flags .. ")") -end - -function on_our_id (id) - our_id = id -end - -function on_secret_chat_created (peer) - --vardump (peer) -end - -function on_user_update (user) - --vardump (user) -end - -function on_chat_update (user) - --vardump (user) -end - -function on_get_difference_end () -end - -function on_binlog_replay_end () - started = 1 -end diff --git a/tools.c b/tools.c index 888e8c4..5291d4f 100644 --- a/tools.c +++ b/tools.c @@ -17,10 +17,6 @@ Copyright Vitaly Valtman 2013 */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #define _GNU_SOURCE #include @@ -30,8 +26,8 @@ #include #include -#include "interface.h" #include "tools.h" +#include "msglog.h" #ifdef DEBUG #define RES_PRE 8 @@ -105,32 +101,6 @@ void tfree (void *ptr, int size __attribute__ ((unused))) { #endif } -/** - * Add a variable amount of strings together - */ -//char *stradd(const char *strs, ...) -//{ -// va_list args; -// size_t size = 0; -// char *result; -// -// // count strlen -// va_start(args, strs); -// for (int i = 0; strs[i] != '\0'; i++) { -// size += strlen(va_arg(args, char*)); -// } -// va_end(args); -// -// // create the new string -// result = talloc0(size + 1); -// va_start(args, strs); -// for (int i = 0; strs[i] != '\0'; i++) { -// strcat(result, va_arg(args, char*)); -// } -// va_end(args); -// return result; -//} - void tfree_str (void *ptr) { if (!ptr) { return; } tfree (ptr, strlen (ptr) + 1); From fa9d45bd208b3a8f8c703031f2e48a6dfbafda52 Mon Sep 17 00:00:00 2001 From: Christopher Althaus Date: Sun, 17 Aug 2014 22:01:04 +0200 Subject: [PATCH 359/465] User State/Typing implemented Send Messages activated --- Makefile.in | 2 +- mtproto-client.c | 4 ++ purple-plugin/telegram-purple.c | 100 ++++++++++++++++++++++++++++---- purple-plugin/telegram-purple.h | 2 + queries.c | 28 ++++++++- queries.h | 1 + structures.c | 10 ++-- telegram.c | 27 ++++++++- telegram.h | 12 ++++ 9 files changed, 165 insertions(+), 21 deletions(-) diff --git a/Makefile.in b/Makefile.in index 1255097..9e0183a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,7 +108,7 @@ run: install .PHONY: debug debug: install - gdb -tui -ex "$(shell echo $$GDB_BPOINTS )" pidgin + ddd pidgin clean: rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean" diff --git a/mtproto-client.c b/mtproto-client.c index b7fcfee..e787362 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -914,6 +914,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { peer_id_t id = MK_USER (fetch_int (self)); peer_t *U UU = user_chat_get (id); + event_update_user_typing (tg, U); if (log_level >= 2) { //print_start (); //push_color (COLOR_YELLOW); @@ -932,6 +933,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_id_t id = MK_USER (fetch_int (self)); peer_t *C UU = user_chat_get (chat_id); peer_t *U UU = user_chat_get (id); + event_update_user_typing(tg, U); if (log_level >= 2) { //print_start (); //push_color (COLOR_YELLOW); @@ -952,6 +954,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_t *U = user_chat_get (user_id); if (U) { fetch_user_status (self, &U->user.status); + event_update_user_status(tg, U); if (log_level >= 3) { //print_start (); //push_color (COLOR_YELLOW); @@ -1252,6 +1255,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); + event_update_user_typing(tg, P); if (P) { printf (" User "); peer_id_t user_id UU = MK_USER (P->encr_chat.user_id); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 0931fdf..f545aae 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -73,6 +73,8 @@ void message_allocated_handler (struct telegram *instance, struct message *M); void peer_allocated_handler (struct telegram *instance, void *user); void telegram_on_phone_registration (struct telegram *instance); void elegram_on_client_registration (struct telegram *instance); +void on_new_user_status(struct telegram *instance, void *user); +void on_user_typing(struct telegram *instance, void *user); /** * Returns the base icon name for the given buddy and account. @@ -94,8 +96,24 @@ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); + const char *status; + peer_id_t *peer = purple_buddy_get_protocol_data(buddy); + peer_t *P = user_chat_get (*peer); + + if (P->user.status.online == 1) + status = "Online"; + else + status = "Offline"; + + purple_notify_user_info_add_pair_plaintext(info, "Status", status); + + struct tm *tm = localtime ((void *)&P->user.status.when); + char buffer [21]; + sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); } + /** * Handle a failed verification by removing the invalid sms code and notifying the user */ @@ -318,9 +336,26 @@ struct telegram_config tgconf = { telegram_on_disconnected, message_allocated_handler, - peer_allocated_handler + peer_allocated_handler, + on_new_user_status, + on_user_typing }; +gboolean queries_timerfunc (gpointer data) { + logprintf ("queries_timerfunc()\n"); + telegram_conn *conn = data; + work_timers (); + // TODO: work pending timers + + if (conn->updated) { + logprintf ("State updated, storing current session...\n"); + conn->updated = 0; + telegram_store_session (conn->tg); + } + return 1; +} + + /** * This must be implemented. */ @@ -346,7 +381,9 @@ static void tgprpl_login(PurpleAccount * acct) tg->extra = conn; purple_connection_set_state (conn->gc, PURPLE_CONNECTING); - telegram_network_connect(tg); + telegram_network_connect (tg); + + purple_timeout_add (2000, queries_timerfunc, conn); } void message_allocated_handler(struct telegram *tg, struct message *M) @@ -367,11 +404,40 @@ void message_allocated_handler(struct telegram *tg, struct message *M) logprintf ("service message, skipping...\n"); return; } - serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time(NULL)); + logprintf ("fwd_date: %d\n", M->date); + serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time((time_t *) &M->date)); g_free(who); } + + conn->updated = 1; } +void on_new_user_status(struct telegram *tg, void *peer) +{ + telegram_conn *conn = tg->extra; + peer_t *p = peer; + + // purple_debug_info(PLUGIN_ID, "New User Status: %s\n", peer->user.status.online); + // TODO: this should probably be freed again somwhere + char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + + PurpleAccount *account = purple_connection_get_account(conn->gc); + if (p->user.status.online == 1) + purple_prpl_got_user_status(account, who, "available", "message", "", NULL); + else + purple_prpl_got_user_status(account, who, "unavailable", "message", "", NULL); + g_free(who); +} + +void on_user_typing(struct telegram *tg, void *peer) +{ + telegram_conn *conn = tg->extra; + peer_t *p = peer; + + char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + serv_got_typing(conn->gc, who, 2, PURPLE_TYPING); + g_free(who); +} /* * Search chats in hash table @@ -415,7 +481,6 @@ void peer_allocated_handler(struct telegram *tg, void *usr) peer_t *user = usr; gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); logprintf("Allocated peer: %s\n", name); - switch (user->id.type) { case PEER_USER: { logprintf("Peer type: user.\n"); @@ -433,6 +498,13 @@ void peer_allocated_handler(struct telegram *tg, void *usr) purple_blist_add_buddy(buddy, NULL, tggroup, NULL); } purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); + + PurpleAccount *account = purple_connection_get_account(gc); + if (user->user.status.online == 1) + purple_prpl_got_user_status(account, name, "available", "message", "", NULL); + else + purple_prpl_got_user_status(account, name, "unavailable", "message", "", NULL); + g_free(name); } break; @@ -508,10 +580,11 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me telegram_conn *conn = purple_connection_get_protocol_data(gc); PurpleAccount *pa = conn->pa; - purple_debug_info(PLUGIN_ID, "tgprpl_send_im()\n"); - PurpleBuddy *b = purple_find_buddy(pa, who); - peer_id_t *peer = purple_buddy_get_protocol_data(b); - do_send_message(conn->tg, *peer, message, strlen(message)); + purple_debug_info (PLUGIN_ID, "tgprpl_send_im()\n"); + PurpleBuddy *b = purple_find_buddy (pa, who); + peer_id_t *peer = purple_buddy_get_protocol_data (b); + do_send_message (conn->tg, *peer, message, strlen(message)); + tgprpl_has_output (conn->tg); return 1; } @@ -596,7 +669,14 @@ static void tgprpl_rem_deny(PurpleConnection * gc, const char *name) */ static unsigned int tgprpl_send_typing(PurpleConnection * gc, const char *who, PurpleTypingState typing) { + telegram_conn *conn = purple_connection_get_protocol_data(gc); + purple_debug_info(PLUGIN_ID, "tgprpl_send_typing()\n"); + PurpleBuddy *b = purple_find_buddy(conn->pa, who); + if (b) { + peer_id_t *peer = purple_buddy_get_protocol_data(b); + do_update_typing (conn->tg, *peer); + } return 0; } @@ -932,8 +1012,8 @@ static PurplePluginInfo info = { "Adds support for the telegram protocol to libpurple.", "Christopher Althaus , Markus Endres , Matthias Jentsch ", "https://bitbucket.org/telegrampurple/telegram-purple", - NULL, // on load - NULL, // on unload + NULL, // on load + NULL, // on unload NULL, // on destroy NULL, // ui specific struct &prpl_info, // plugin info struct diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 3df5749..761377c 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -40,6 +40,8 @@ typedef struct { PurpleAccount *pa; PurpleConnection *gc; + int updated; + /** * Write handler returned by purple_input_add */ diff --git a/queries.c b/queries.c index 1cd8bee..6389dac 100644 --- a/queries.c +++ b/queries.c @@ -276,6 +276,7 @@ double next_timer_in (void) { } void work_timers (void) { + logprintf ("work_timers ()\n"); double t = get_double_time (); while (timer_tree) { struct event_timer *ev = tree_get_min_timer (timer_tree); @@ -710,7 +711,6 @@ struct query_methods get_contacts_methods = { .on_answer = get_contacts_on_answer, }; - void do_update_contact_list (struct telegram *instance) { struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); @@ -2699,6 +2699,7 @@ int difference_got; int seq, pts, qts, last_date; int get_state_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); + struct telegram *instance = q->extra; logprintf("get_state_on_answer()\n"); assert (fetch_int (mtp) == (int)CODE_updates_state); @@ -2709,6 +2710,7 @@ int get_state_on_answer (struct query *q UU) { unread_messages = fetch_int (mtp); //write_state_file (); difference_got = 1; + telegram_store_session (instance); return 0; } @@ -2771,7 +2773,7 @@ int get_difference_on_answer (struct query *q UU) { unread_messages = fetch_int (mtp); //write_state_file (); for (i = 0; i < ml_pos; i++) { - event_update_new_message (instance, ML[i]); + event_update_new_message (instance, ML[i]); ////print_message (ML[i]); } if (x == CODE_updates_difference_slice) { @@ -2782,6 +2784,7 @@ int get_difference_on_answer (struct query *q UU) { } else { assert (0); } + telegram_store_session (instance); return 0; } @@ -2813,7 +2816,7 @@ void do_get_difference (struct telegram *instance) { send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); } else { out_int (mtp, CODE_updates_get_state); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, 0); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, instance); } } /* }}} */ @@ -3065,4 +3068,23 @@ void do_update_status (struct telegram *instance, int online UU) { send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); } +int update_typing_on_answer (struct query *q UU) { + fetch_bool (query_get_mtproto (q)); + return 0; +} + +struct query_methods update_typing_methods = { + .on_answer = update_typing_on_answer +}; + +void do_update_typing (struct telegram *instance, peer_id_t id) { + struct dc *DC_working = telegram_get_working_dc(instance); + struct mtproto_connection *mtp = instance->connection; + + clear_packet (mtp); + out_int (mtp, CODE_messages_set_typing); + out_peer_id (mtp, id); + out_int (mtp, CODE_bool_true); + send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_typing_methods, 0); +} diff --git a/queries.h b/queries.h index 516b0e2..8587d67 100644 --- a/queries.h +++ b/queries.h @@ -115,6 +115,7 @@ void do_get_difference (struct telegram*); void do_mark_read (struct telegram *instance, peer_id_t id); void do_visualize_key (peer_id_t id); void do_create_keys_end (struct secret_chat *U); + void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit); void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id); void do_update_status (struct telegram *instance, int online); diff --git a/structures.c b/structures.c index cf7ad1c..8b36ab1 100644 --- a/structures.c +++ b/structures.c @@ -1531,22 +1531,22 @@ static int id_cmp (struct message *M1, struct message *M2) { struct user *fetch_alloc_user (struct mtproto_connection *mtp) { logprintf("fetch_alloc_user()\n"); - int send_event = 0; int data[2]; prefetch_data (mtp, data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); if (!U) { - send_event = 1; users_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_USER (data[1]); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); assert (peer_num < MAX_PEER_NUM); Peers[peer_num ++] = U; - } - fetch_user (mtp, &U->user); - if (send_event) { + fetch_user (mtp, &U->user); + event_update_user_status(mtp->connection->instance, U); event_peer_allocated(mtp->connection->instance, U); + } else { + fetch_user (mtp, &U->user); + event_update_user_status(mtp->connection->instance, U); } return &U->user; } diff --git a/telegram.c b/telegram.c index f23b230..40332ff 100755 --- a/telegram.c +++ b/telegram.c @@ -21,7 +21,7 @@ void event_update_new_message(struct telegram *instance, struct message *M) { if (instance->config->on_msg_handler) { - instance->config->on_msg_handler(instance, M); + instance->config->on_msg_handler (instance, M); } } @@ -31,10 +31,32 @@ void event_update_new_message(struct telegram *instance, struct message *M) void event_peer_allocated(struct telegram *instance, void *peer) { if (instance->config->on_peer_allocated_handler) { - instance->config->on_peer_allocated_handler(instance, peer); + instance->config->on_peer_allocated_handler (instance, peer); } } +/* + * User status changed + */ +void event_update_user_status (struct telegram *instance, void *peer) +{ + if (instance->config->on_update_user_status_handler) { + instance->config->on_update_user_status_handler (instance, peer); + } +} + +/* + * User typing changed + */ +void event_update_user_typing (struct telegram *instance, void *peer) +{ + if (instance->config->on_update_uesr_typing_handler) { + instance->config->on_update_uesr_typing_handler (instance, peer); + } +} + + + /** * Calculate the configuration path for the given config file and the given instance * @@ -319,3 +341,4 @@ int telegram_has_output (struct telegram *instance) { return instance->connection->queries_num > 0; } + diff --git a/telegram.h b/telegram.h index fff1a45..f1b85b9 100644 --- a/telegram.h +++ b/telegram.h @@ -150,6 +150,16 @@ struct telegram_config { * for populating the GUI with new peers. */ void (*on_peer_allocated_handler)(struct telegram *instance, void *peer); + + /** + * A callback function that is called when a user's status has changed + */ + void (*on_update_user_status_handler) (struct telegram *instance, void *peer); + + /** + * A callback function that is called when a user starts or stops typing + */ + void (*on_update_uesr_typing_handler) (struct telegram *instance, void *peer); }; /** @@ -325,6 +335,8 @@ void session_update_contact_list(); * Events */ void event_update_new_message(struct telegram *instance, struct message *M); +void event_update_user_status(struct telegram *instance, void *peer); +void event_update_user_typing(struct telegram *instance, void *peer); /* * Load known users and chats on connect From 6441c6be4b86d388487053bc3679167c0447a753 Mon Sep 17 00:00:00 2001 From: Christopher Althaus Date: Thu, 21 Aug 2014 20:25:35 +0200 Subject: [PATCH 360/465] Fixed telegram notification client bug --- purple-plugin/telegram-purple.c | 57 ++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f545aae..b6f0b2a 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -96,21 +96,6 @@ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); - const char *status; - peer_id_t *peer = purple_buddy_get_protocol_data(buddy); - peer_t *P = user_chat_get (*peer); - - if (P->user.status.online == 1) - status = "Online"; - else - status = "Offline"; - - purple_notify_user_info_add_pair_plaintext(info, "Status", status); - - struct tm *tm = localtime ((void *)&P->user.status.when); - char buffer [21]; - sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); } @@ -174,6 +159,7 @@ static void tgprpl_has_input(struct telegram *tg) tgprpl_input_cb, tg); logprintf("Attached read handle: %u ", conn->rh); } + } static void init_dc_settings(PurpleAccount *acc, struct dc *DC) @@ -344,7 +330,7 @@ struct telegram_config tgconf = { gboolean queries_timerfunc (gpointer data) { logprintf ("queries_timerfunc()\n"); telegram_conn *conn = data; - work_timers (); + // work_timers (); // TODO: work pending timers if (conn->updated) { @@ -427,6 +413,44 @@ void on_new_user_status(struct telegram *tg, void *peer) else purple_prpl_got_user_status(account, who, "unavailable", "message", "", NULL); g_free(who); + +/* +<<<<<<< HEAD + const char *status; + peer_id_t *peer = purple_buddy_get_protocol_data(buddy); + peer_t *P = user_chat_get (*peer); + + if (P->user.status.online == 1) + status = "Online"; + else + status = "Offline"; + + purple_notify_user_info_add_pair_plaintext(info, "Status", status); + + struct tm *tm = localtime ((void *)&P->user.status.when); + char buffer [21]; + sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); + const char *status; + peer_id_t *peer = purple_buddy_get_protocol_data(buddy); + if(peer == NULL) + { + purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline"); + return; + } + peer_t *P = user_chat_get (*peer); + + if (P->user.status.online == 1) + status = "Online"; + else + status = "Offline"; + + purple_notify_user_info_add_pair_plaintext(info, "Status", status); + struct tm *tm = localtime ((void *)&P->user.status.when); + char buffer [21]; + sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); + */ } void on_user_typing(struct telegram *tg, void *peer) @@ -739,6 +763,7 @@ static GList *tgprpl_status_types(PurpleAccount * acct) static void tgprpl_set_status(PurpleAccount * acct, PurpleStatus * status) { purple_debug_info(PLUGIN_ID, "tgprpl_set_status()\n"); + } /** From 2e50ec47b7307e58cd2d8304fc34ba2fac071157 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 23 Aug 2014 17:36:52 +0200 Subject: [PATCH 361/465] Merge user-status --- purple-plugin/telegram-purple.c | 51 +++++++++------------------------ 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index b6f0b2a..7fbd13c 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -96,6 +96,19 @@ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); + peer_id_t *peer = purple_buddy_get_protocol_data(buddy); + if(peer == NULL) + { + purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline"); + return; + } + peer_t *P = user_chat_get (*peer); + + purple_notify_user_info_add_pair_plaintext(info, "Status", P->user.status.online == 1 ? "Online" : "Offline"); + struct tm *tm = localtime ((void *)&P->user.status.when); + char buffer [21]; + sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); } @@ -413,44 +426,6 @@ void on_new_user_status(struct telegram *tg, void *peer) else purple_prpl_got_user_status(account, who, "unavailable", "message", "", NULL); g_free(who); - -/* -<<<<<<< HEAD - const char *status; - peer_id_t *peer = purple_buddy_get_protocol_data(buddy); - peer_t *P = user_chat_get (*peer); - - if (P->user.status.online == 1) - status = "Online"; - else - status = "Offline"; - - purple_notify_user_info_add_pair_plaintext(info, "Status", status); - - struct tm *tm = localtime ((void *)&P->user.status.when); - char buffer [21]; - sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); - const char *status; - peer_id_t *peer = purple_buddy_get_protocol_data(buddy); - if(peer == NULL) - { - purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline"); - return; - } - peer_t *P = user_chat_get (*peer); - - if (P->user.status.online == 1) - status = "Online"; - else - status = "Offline"; - - purple_notify_user_info_add_pair_plaintext(info, "Status", status); - struct tm *tm = localtime ((void *)&P->user.status.when); - char buffer [21]; - sprintf (buffer, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); - */ } void on_user_typing(struct telegram *tg, void *peer) From d94dc52df0a880cf74d22cee4e14a6d8ea1bbb3e Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 21:25:41 +0200 Subject: [PATCH 362/465] Remove remaining global variables --- binlog.c | 226 ++++++++++----------- loop.c | 86 ++++---- mtproto-client.c | 85 ++++---- mtproto-client.h | 9 +- net.c | 11 +- queries.c | 498 ++++++++++++++++++++++------------------------- queries.h | 27 +-- structures.c | 284 +++++++++++++++------------ structures.h | 24 +-- telegram.h | 73 ++++++- 10 files changed, 687 insertions(+), 636 deletions(-) diff --git a/binlog.c b/binlog.c index 84915e6..11b5a3f 100644 --- a/binlog.c +++ b/binlog.c @@ -37,11 +37,6 @@ #include -extern int pts; -extern int qts; -extern int last_date; -extern int seq; - #define MAX_LOG_EVENT_SIZE (1 << 17) // TODO: remove this completely @@ -51,12 +46,7 @@ char *get_binlog_file_name() return "/home/dev-jessie/.telegram/binlog"; } -extern int our_id; int binlog_enabled = 0; -extern int encr_root; -extern unsigned char *encr_prime; -extern int encr_param_version; -extern int messages_allocated; void *alloc_log_event (struct binlog *bl, int l UU) { return bl->binlog_buffer; @@ -119,7 +109,7 @@ void replay_log_event (struct telegram *instance) { case LOG_OUR_ID: bl->rptr ++; { - our_id = *(bl->rptr ++); + instance->our_id = *(bl->rptr ++); } break; case LOG_DC_SIGNED: @@ -158,7 +148,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (id); + struct secret_chat *U = (void *)user_chat_get (bl, id); assert (U); U->key_fingerprint = *(long long *)bl->rptr; bl->rptr += 2; @@ -170,7 +160,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (id); + struct secret_chat *U = (void *)user_chat_get (bl, id); assert (U); U->key_fingerprint = *(long long *)bl->rptr; bl->rptr += 2; @@ -187,27 +177,27 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (id); + struct secret_chat *U = (void *)user_chat_get (bl, id); assert (!U || !(U->flags & FLAG_CREATED)); if (!U) { U = talloc0 (sizeof (peer_t)); U->id = id; - insert_encrypted_chat ((void *)U); + insert_encrypted_chat (bl, (void *)U); } U->flags |= FLAG_CREATED; U->user_id = *(bl->rptr ++); memcpy (U->key, bl->rptr, 256); bl->rptr += 64; if (!U->print_name) { - peer_t *P = user_chat_get (MK_USER (U->user_id)); + peer_t *P = user_chat_get (bl, MK_USER (U->user_id)); if (P) { - U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + U->print_name = create_print_name (bl, U->id, "!", P->user.first_name, P->user.last_name, 0); } else { static char buf[100]; tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (U->id, "!", buf, 0, 0); + U->print_name = create_print_name (bl, U->id, "!", buf, 0, 0); } - peer_insert_name ((void *)U); + peer_insert_name (bl, (void *)U); } }; break; @@ -215,11 +205,11 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (id); + struct secret_chat *U = (void *)user_chat_get (bl, id); if (!U) { U = talloc0 (sizeof (peer_t)); U->id = id; - insert_encrypted_chat ((void *)U); + insert_encrypted_chat (bl, (void *)U); } U->flags |= FLAG_CREATED; U->state = sc_deleted; @@ -229,7 +219,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (id); + struct secret_chat *U = (void *)user_chat_get (bl, id); assert (U); U->state = sc_waiting; U->date = *(bl->rptr ++); @@ -243,11 +233,11 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (id); + struct secret_chat *U = (void *)user_chat_get (bl, id); if (!U) { U = talloc0 (sizeof (peer_t)); U->id = id; - insert_encrypted_chat ((void *)U); + insert_encrypted_chat (bl, (void *)U); } U->flags |= FLAG_CREATED; U->state = sc_request; @@ -256,15 +246,15 @@ void replay_log_event (struct telegram *instance) { U->user_id = *(bl->rptr ++); U->access_hash = *(long long *)bl->rptr; if (!U->print_name) { - peer_t *P = user_chat_get (MK_USER (U->user_id)); + peer_t *P = user_chat_get (bl, MK_USER (U->user_id)); if (P) { - U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + U->print_name = create_print_name (bl, U->id, "!", P->user.first_name, P->user.last_name, 0); } else { static char buf[100]; tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (U->id, "!", buf, 0, 0); + U->print_name = create_print_name (bl, U->id, "!", buf, 0, 0); } - peer_insert_name ((void *)U); + peer_insert_name (bl, (void *)U); } bl->rptr += 2; }; @@ -273,7 +263,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (id); + struct secret_chat *U = (void *)user_chat_get (bl, id); assert (U); U->state = sc_ok; } @@ -282,24 +272,24 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { peer_id_t id = MK_USER (fetch_int (self)); - peer_t *_U = user_chat_get (id); + peer_t *_U = user_chat_get (bl, id); if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = id; - insert_user (_U); + insert_user (bl, _U); } else { assert (!(_U->flags & FLAG_CREATED)); } struct user *U = (void *)_U; U->flags |= FLAG_CREATED; - if (get_peer_id (id) == our_id) { + if (get_peer_id (id) == instance->our_id) { U->flags |= FLAG_USER_SELF; } U->first_name = fetch_str_dup (self); U->last_name = fetch_str_dup (self); assert (!U->print_name); - U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); - peer_insert_name ((void *)U); + U->print_name = create_print_name (bl, U->id, U->first_name, U->last_name, 0, 0); + peer_insert_name (bl, (void *)U); U->access_hash = fetch_long (self); U->phone = fetch_str_dup (self); if (fetch_int (self)) { @@ -312,7 +302,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); U->flags |= FLAG_DELETED; } @@ -321,7 +311,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); U->user.access_hash = *(long long *)bl->rptr; bl->rptr += 2; @@ -331,7 +321,7 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); if (U->user.phone) { tfree_str (U->user.phone); } U->user.phone = fetch_str_dup (self); @@ -342,7 +332,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); int friend = *(bl->rptr ++); if (friend) { U->flags |= FLAG_USER_CONTACT; } @@ -353,7 +343,7 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); if (U->flags & FLAG_HAS_PHOTO) { free_photo (&U->user.photo); @@ -366,7 +356,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); U->user.blocked = *(bl->rptr ++); } @@ -375,7 +365,7 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); if (U->user.real_first_name) { tfree_str (U->user.real_first_name); } if (U->user.real_last_name) { tfree_str (U->user.real_last_name); } @@ -388,7 +378,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (id); + peer_t *_U = user_chat_get (bl, id); assert (_U); struct secret_chat *U = &_U->encr_chat; memset (U->key, 0, sizeof (U->key)); @@ -408,11 +398,11 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (id); + peer_t *_U = user_chat_get (bl, id); if (!_U) { _U = talloc0 (sizeof (*_U)); _U->id = id; - insert_encrypted_chat (_U); + insert_encrypted_chat (bl, _U); } else { assert (!(_U->flags & FLAG_CREATED)); } @@ -423,16 +413,16 @@ void replay_log_event (struct telegram *instance) { U->admin_id = *(bl->rptr ++); U->user_id = *(bl->rptr ++); - peer_t *Us = user_chat_get (MK_USER (U->user_id)); + peer_t *Us = user_chat_get (bl, MK_USER (U->user_id)); assert (!U->print_name); if (Us) { - U->print_name = create_print_name (id, "!", Us->user.first_name, Us->user.last_name, 0); + U->print_name = create_print_name (bl, id, "!", Us->user.first_name, Us->user.last_name, 0); } else { static char buf[100]; tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (id, "!", buf, 0, 0); + U->print_name = create_print_name (bl, id, "!", buf, 0, 0); } - peer_insert_name ((void *)U); + peer_insert_name (bl, (void *)U); U->g_key = talloc (256); U->nonce = talloc (256); memcpy (U->g_key, bl->rptr, 256); @@ -448,7 +438,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); U->encr_chat.access_hash = *(long long *)bl->rptr; bl->rptr += 2; @@ -458,7 +448,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); U->encr_chat.date = *(bl->rptr ++); } @@ -467,7 +457,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U); U->encr_chat.state = *(bl->rptr ++); } @@ -476,7 +466,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (id); + peer_t *_U = user_chat_get (bl, id); assert (_U); struct secret_chat *U = &_U->encr_chat; if (!U->g_key) { @@ -492,7 +482,7 @@ void replay_log_event (struct telegram *instance) { U->key_fingerprint = *(long long *)bl->rptr; bl->rptr += 2; if (U->state == sc_waiting) { - do_create_keys_end (U); + do_create_keys_end (instance, U); } U->state = sc_ok; } @@ -501,7 +491,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (id); + peer_t *_U = user_chat_get (bl, id); assert (_U); struct secret_chat *U = &_U->encr_chat; memcpy (U->key, bl->rptr, 256); @@ -513,12 +503,12 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_dh_params: bl->rptr ++; { - if (encr_prime) { tfree (encr_prime, 256); } - encr_root = *(bl->rptr ++); - encr_prime = talloc (256); - memcpy (encr_prime, bl->rptr, 256); + if (instance->encr_prime) { tfree (instance->encr_prime, 256); } + instance->encr_root = *(bl->rptr ++); + instance->encr_prime = talloc (256); + memcpy (instance->encr_prime, bl->rptr, 256); bl->rptr += 64; - encr_param_version = *(bl->rptr ++); + instance->encr_param_version = *(bl->rptr ++); } break; case CODE_binlog_encr_chat_init: @@ -526,14 +516,14 @@ void replay_log_event (struct telegram *instance) { { peer_t *P = talloc0 (sizeof (*P)); P->id = MK_ENCR_CHAT (*(bl->rptr ++)); - assert (!user_chat_get (P->id)); + assert (!user_chat_get (bl, P->id)); P->encr_chat.user_id = *(bl->rptr ++); - P->encr_chat.admin_id = our_id; - insert_encrypted_chat (P); - peer_t *Us = user_chat_get (MK_USER (P->encr_chat.user_id)); + P->encr_chat.admin_id = instance->our_id; + insert_encrypted_chat (bl, P); + peer_t *Us = user_chat_get (bl, MK_USER (P->encr_chat.user_id)); assert (Us); - P->print_name = create_print_name (P->id, "!", Us->user.first_name, Us->user.last_name, 0); - peer_insert_name (P); + P->print_name = create_print_name (bl, P->id, "!", Us->user.first_name, Us->user.last_name, 0); + peer_insert_name (bl, P); memcpy (P->encr_chat.key, bl->rptr, 256); bl->rptr += 64; P->encr_chat.g_key = talloc (256); @@ -544,29 +534,29 @@ void replay_log_event (struct telegram *instance) { break; case CODE_binlog_set_pts: bl->rptr ++; - pts = *(bl->rptr ++); + instance->proto.pts = *(bl->rptr ++); break; case CODE_binlog_set_qts: bl->rptr ++; - qts = *(bl->rptr ++); + instance->proto.qts = *(bl->rptr ++); break; case CODE_binlog_set_date: bl->rptr ++; - last_date = *(bl->rptr ++); + instance->proto.last_date = *(bl->rptr ++); break; case CODE_binlog_set_seq: bl->rptr ++; - seq = *(bl->rptr ++); + instance->proto.seq = *(bl->rptr ++); break; case CODE_binlog_chat_create: self->in_ptr ++; { peer_id_t id = MK_CHAT (fetch_int (self)); - peer_t *_C = user_chat_get (id); + peer_t *_C = user_chat_get (bl, id); if (!_C) { _C = talloc0 (sizeof (*_C)); _C->id = id; - insert_chat (_C); + insert_chat (bl, _C); } else { assert (!(_C->flags & FLAG_CREATED)); } @@ -574,8 +564,8 @@ void replay_log_event (struct telegram *instance) { C->flags = FLAG_CREATED | fetch_int (self); C->title = fetch_str_dup (self); assert (!C->print_title); - C->print_title = create_print_name (id, C->title, 0, 0, 0); - peer_insert_name ((void *)C); + C->print_title = create_print_name (bl, id, C->title, 0, 0, 0); + peer_insert_name (bl, (void *)C); C->users_num = fetch_int (self); C->date = fetch_int (self); C->version = fetch_int (self); @@ -587,7 +577,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_chat_change_flags: bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); + peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->flags |= *(bl->rptr ++); C->flags &= ~*(bl->rptr ++); @@ -596,24 +586,24 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_chat_title: self->in_ptr ++; { - peer_t *_C = user_chat_get (MK_CHAT (fetch_int (self))); + peer_t *_C = user_chat_get (bl, MK_CHAT (fetch_int (self))); assert (_C && (_C->flags & FLAG_CREATED)); struct chat *C = &_C->chat; if (C->title) { tfree_str (C->title); } C->title = fetch_str_dup (self); if (C->print_title) { - peer_delete_name ((void *)C); + peer_delete_name (bl, (void *)C); tfree_str (C->print_title); } - C->print_title = create_print_name (C->id, C->title, 0, 0, 0); - peer_insert_name ((void *)C); + C->print_title = create_print_name (bl, C->id, C->title, 0, 0, 0); + peer_insert_name (bl, (void *)C); }; bl->rptr = self->in_ptr; break; case CODE_binlog_set_chat_photo: self->in_ptr ++; { - peer_t *C = user_chat_get (MK_CHAT (fetch_int (self))); + peer_t *C = user_chat_get (bl, MK_CHAT (fetch_int (self))); assert (C && (C->flags & FLAG_CREATED)); fetch_data (self, &C->photo_big, sizeof (struct file_location)); fetch_data (self, &C->photo_small, sizeof (struct file_location)); @@ -623,7 +613,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_chat_date: bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); + peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.date = *(bl->rptr ++); }; @@ -631,7 +621,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_chat_version: bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); + peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.version = *(bl->rptr ++); C->chat.users_num = *(bl->rptr ++); @@ -640,7 +630,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_chat_admin: bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); + peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.admin_id = *(bl->rptr ++); }; @@ -648,7 +638,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_chat_participants: bl->rptr ++; { - peer_t *C = user_chat_get (MK_CHAT (*(bl->rptr ++))); + peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); assert (C && (C->flags & FLAG_CREATED)); C->chat.user_list_version = *(bl->rptr ++); if (C->chat.user_list) { tfree (C->chat.user_list, 12 * C->chat.user_list_size); } @@ -662,7 +652,7 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { peer_id_t id = MK_CHAT (fetch_int (self)); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (bl, id); assert (U && (U->flags & FLAG_CREATED)); if (U->flags & FLAG_HAS_PHOTO) { free_photo (&U->chat.photo); @@ -675,7 +665,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_CHAT (*(bl->rptr ++)); - peer_t *_C = user_chat_get (id); + peer_t *_C = user_chat_get (bl, id); assert (_C && (_C->flags & FLAG_CREATED)); struct chat *C = &_C->chat; @@ -701,7 +691,7 @@ void replay_log_event (struct telegram *instance) { bl->rptr ++; { peer_id_t id = MK_CHAT (*(bl->rptr ++)); - peer_t *_C = user_chat_get (id); + peer_t *_C = user_chat_get (bl, id); assert (_C && (_C->flags & FLAG_CREATED)); struct chat *C = &_C->chat; @@ -734,12 +724,13 @@ void replay_log_event (struct telegram *instance) { } else { id = fetch_long (self); } - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; + M->instance = instance; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -764,7 +755,7 @@ void replay_log_event (struct telegram *instance) { M->media.type = CODE_message_media_empty; } M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; message_insert (M); if (op == CODE_binlog_send_message_text) { @@ -778,12 +769,12 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { int id = fetch_int (self); - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -803,7 +794,7 @@ void replay_log_event (struct telegram *instance) { M->media.type = CODE_message_media_empty; M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; message_insert (M); } @@ -813,12 +804,12 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { int id = fetch_int (self); - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -836,7 +827,7 @@ void replay_log_event (struct telegram *instance) { fetch_message_media (self, &M->media); M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; message_insert (M); } @@ -846,12 +837,12 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { long long id = fetch_long (self); - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -871,7 +862,7 @@ void replay_log_event (struct telegram *instance) { fetch_encrypted_message_file (self, &M->media); M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; message_insert (M); } @@ -881,12 +872,12 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { int id = fetch_int (self); - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -906,7 +897,7 @@ void replay_log_event (struct telegram *instance) { fetch_message_media (self, &M->media); M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; message_insert (M); } @@ -916,12 +907,12 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { int id = fetch_int (self); - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -933,7 +924,7 @@ void replay_log_event (struct telegram *instance) { fetch_message_action (self, &M->action); M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; M->service = 1; message_insert (M); @@ -944,12 +935,12 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { long long id = fetch_long (self); - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -962,7 +953,7 @@ void replay_log_event (struct telegram *instance) { fetch_message_action_encrypted (self, &M->action); M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; M->service = 1; message_insert (M); @@ -973,12 +964,12 @@ void replay_log_event (struct telegram *instance) { self->in_ptr ++; { int id = fetch_int (self); - struct message *M = message_get (id); + struct message *M = message_get(bl, id); if (!M) { M = talloc0 (sizeof (*M)); M->id = id; message_insert_tree (M); - messages_allocated ++; + bl->messages_allocated ++; } else { assert (!(M->flags & FLAG_CREATED)); } @@ -991,7 +982,7 @@ void replay_log_event (struct telegram *instance) { M->fwd_date = fetch_int (self); fetch_message_action (self, &M->action); M->unread = 1; - M->out = get_peer_id (M->from_id) == our_id; + M->out = get_peer_id (M->from_id) == instance->our_id; M->service = 1; message_insert (M); @@ -1001,7 +992,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_unread: bl->rptr ++; { - struct message *M = message_get (*(bl->rptr ++)); + struct message *M = message_get(bl, *(bl->rptr ++)); assert (M); M->unread = 0; } @@ -1009,7 +1000,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_message_sent: bl->rptr ++; { - struct message *M = message_get (*(long long *)bl->rptr); + struct message *M = message_get(bl, *(long long *)bl->rptr); bl->rptr += 2; assert (M); message_remove_unsent (M); @@ -1019,7 +1010,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_set_msg_id: bl->rptr ++; { - struct message *M = message_get (*(long long *)bl->rptr); + struct message *M = message_get(bl, *(long long *)bl->rptr); bl->rptr += 2; assert (M); if (M->flags & FLAG_PENDING) { @@ -1029,7 +1020,7 @@ void replay_log_event (struct telegram *instance) { message_remove_tree (M); message_del_peer (M); M->id = *(bl->rptr ++); - if (message_get (M->id)) { + if (message_get(bl, M->id)) { free_message (M); tfree (M, sizeof (*M)); } else { @@ -1041,7 +1032,7 @@ void replay_log_event (struct telegram *instance) { case CODE_binlog_delete_msg: bl->rptr ++; { - struct message *M = message_get (*(long long *)bl->rptr); + struct message *M = message_get(bl, *(long long *)bl->rptr); bl->rptr += 2; assert (M); if (M->flags & FLAG_PENDING) { @@ -1250,7 +1241,6 @@ void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, stru add_log_event (bl, self, ev, 8); } -extern int last_date; void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long photo_id, struct file_location *big, struct file_location *small) { if (photo_id == U->photo_id) { return; } @@ -1258,7 +1248,7 @@ void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection int *ev = alloc_log_event (bl, 20); ev[0] = CODE_update_user_photo; ev[1] = get_peer_id (U->id); - ev[2] = last_date; + ev[2] = self->connection->instance->proto.last_date; ev[3] = CODE_user_profile_photo_empty; ev[4] = CODE_bool_false; add_log_event (bl, self, ev, 20); @@ -1266,7 +1256,7 @@ void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection clear_packet (self); out_int (self, CODE_update_user_photo); out_int (self, get_peer_id (U->id)); - out_int (self, last_date); + out_int (self, self->connection->instance->proto.last_date); out_int (self, CODE_user_profile_photo); out_long (self, photo_id); if (small->dc >= 0) { diff --git a/loop.c b/loop.c index c2a72bf..bdeea3f 100644 --- a/loop.c +++ b/loop.c @@ -48,17 +48,12 @@ -extern char *auth_token; int test_dc = 0; int default_dc_num; extern int binlog_enabled; -extern int unknown_user_list_pos; -extern int unknown_user_list[]; int register_mode; -extern int safe_quit; -int unread_messages; void got_it (char *line, int len); char **_s; @@ -289,9 +284,9 @@ extern int encr_root; extern unsigned char *encr_prime; extern int encr_param_version; extern int dialog_list_got; - // TODO: Refactor -void read_secret_chat_file (const char *file) { +void read_secret_chat_file (struct telegram *instance, const char *file) { + struct binlog *bl = instance->bl; if (binlog_enabled) { return; } int fd = open (file, O_CREAT | O_RDWR, 0600); @@ -320,7 +315,7 @@ void read_secret_chat_file (const char *file) { P->print_name = talloc (t + 1); assert (read (fd, P->print_name, t) == t); P->print_name[t] = 0; - peer_insert_name (P); + peer_insert_name (bl, P); assert (read (fd, &E->state, 4) == 4); assert (read (fd, &E->user_id, 4) == 4); @@ -336,21 +331,23 @@ void read_secret_chat_file (const char *file) { } assert (read (fd, E->key, 256) == 256); assert (read (fd, &E->key_fingerprint, 8) == 8); - insert_encrypted_chat (P); + insert_encrypted_chat (bl, P); } if (version >= 1) { - assert (read (fd, &encr_root, 4) == 4); - if (encr_root) { - assert (read (fd, &encr_param_version, 4) == 4); - encr_prime = talloc (256); - assert (read (fd, encr_prime, 256) == 256); + assert (read (fd, &instance->encr_root, 4) == 4); + if (instance->encr_root) { + assert (read (fd, &instance->encr_param_version, 4) == 4); + instance->encr_prime = talloc (256); + assert (read (fd, instance->encr_prime, 256) == 256); } } close (fd); } // TODO: Refactor -void write_secret_chat_file (const char *filename) { +void write_secret_chat_file (struct telegram *instance, const char *filename) { + struct binlog *bl = instance->bl; + if (binlog_enabled) { return; } int fd = open (filename, O_CREAT | O_RDWR, 0600); if (fd < 0) { @@ -362,59 +359,46 @@ void write_secret_chat_file (const char *filename) { assert (write (fd, x, 8) == 8); int i; int cc = 0; - for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) { - if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) { + for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) { + if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) { cc ++; } } assert (write (fd, &cc, 4) == 4); - for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) { - if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) { - int t = get_peer_id (Peers[i]->id); + for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) { + if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) { + int t = get_peer_id (bl->Peers[i]->id); assert (write (fd, &t, 4) == 4); - t = Peers[i]->flags; + t = bl->Peers[i]->flags; assert (write (fd, &t, 4) == 4); - t = strlen (Peers[i]->print_name); + t = strlen (bl->Peers[i]->print_name); assert (write (fd, &t, 4) == 4); - assert (write (fd, Peers[i]->print_name, t) == t); + assert (write (fd, bl->Peers[i]->print_name, t) == t); - assert (write (fd, &Peers[i]->encr_chat.state, 4) == 4); + assert (write (fd, &bl->Peers[i]->encr_chat.state, 4) == 4); - assert (write (fd, &Peers[i]->encr_chat.user_id, 4) == 4); - assert (write (fd, &Peers[i]->encr_chat.admin_id, 4) == 4); - assert (write (fd, &Peers[i]->encr_chat.ttl, 4) == 4); - assert (write (fd, &Peers[i]->encr_chat.access_hash, 8) == 8); - if (Peers[i]->encr_chat.state != sc_waiting) { - assert (write (fd, Peers[i]->encr_chat.g_key, 256) == 256); + assert (write (fd, &bl->Peers[i]->encr_chat.user_id, 4) == 4); + assert (write (fd, &bl->Peers[i]->encr_chat.admin_id, 4) == 4); + assert (write (fd, &bl->Peers[i]->encr_chat.ttl, 4) == 4); + assert (write (fd, &bl->Peers[i]->encr_chat.access_hash, 8) == 8); + if (bl->Peers[i]->encr_chat.state != sc_waiting) { + assert (write (fd, bl->Peers[i]->encr_chat.g_key, 256) == 256); } - if (Peers[i]->encr_chat.state != sc_waiting) { - assert (write (fd, Peers[i]->encr_chat.nonce, 256) == 256); + if (bl->Peers[i]->encr_chat.state != sc_waiting) { + assert (write (fd, bl->Peers[i]->encr_chat.nonce, 256) == 256); } - assert (write (fd, Peers[i]->encr_chat.key, 256) == 256); - assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8); + assert (write (fd, bl->Peers[i]->encr_chat.key, 256) == 256); + assert (write (fd, &bl->Peers[i]->encr_chat.key_fingerprint, 8) == 8); } } - assert (write (fd, &encr_root, 4) == 4); - if (encr_root) { - assert (write (fd, &encr_param_version, 4) == 4); - assert (write (fd, encr_prime, 256) == 256); + assert (write (fd, &instance->encr_root, 4) == 4); + if (instance->encr_root) { + assert (write (fd, &instance->encr_param_version, 4) == 4); + assert (write (fd, instance->encr_prime, 256) == 256); } close (fd); } -extern int max_chat_size; -int mcs (void) { - return max_chat_size; -} - -extern int difference_got; -int dgot (void) { - return difference_got; -} -int dlgot (void) { - return dialog_list_got; -} - int readline_active; int new_dc_num; int wait_dialog_list; diff --git a/mtproto-client.c b/mtproto-client.c index e787362..411ec79 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -797,24 +797,26 @@ void fetch_seq (struct mtproto_connection *self) { } void work_update_binlog (struct mtproto_connection *self) { + struct binlog *bl = self->bl; + unsigned op = fetch_int (self); switch (op) { case CODE_update_user_name: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (user_id); + peer_t *UC = user_chat_get (bl, user_id); if (UC) { struct user *U = &UC->user; if (U->first_name) { tfree_str (U->first_name); } if (U->last_name) { tfree_str (U->last_name); } if (U->print_name) { - peer_delete_name (UC); + peer_delete_name (bl, UC); tfree_str (U->print_name); } U->first_name = fetch_str_dup (self); U->last_name = fetch_str_dup (self); - U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); - peer_insert_name ((void *)U); + U->print_name = create_print_name (bl, U->id, U->first_name, U->last_name, 0, 0); + peer_insert_name (bl, (void *)U); } else { fetch_skip_str (self); fetch_skip_str (self); @@ -824,7 +826,7 @@ void work_update_binlog (struct mtproto_connection *self) { case CODE_update_user_photo: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (user_id); + peer_t *UC = user_chat_get (bl, user_id); fetch_date (self); if (UC) { struct user *U = &UC->user; @@ -860,8 +862,9 @@ void work_update_binlog (struct mtproto_connection *self) { } void work_update (struct mtproto_connection *self, long long msg_id UU) { - struct connection *c UU = self->connection; + struct connection *c = self->connection; struct telegram *tg = c->instance; + struct binlog *bl = self->bl; unsigned op = fetch_int (self); logprintf("work_update(): OP:%d\n", op); @@ -881,7 +884,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { int id = fetch_int (self); // id int new = fetch_long (self); // random_id - struct message *M = message_get (new); + struct message *M = message_get (bl, new); if (M) { bl_do_set_msg_id (self->bl, self, M, id); } @@ -894,7 +897,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { int i; for (i = 0; i < n; i++) { int id = fetch_int (self); - struct message *M = message_get (id); + struct message *M = message_get (bl, id); if (M) { bl_do_set_unread (self->bl, self, M, 0); } @@ -913,7 +916,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_user_typing: { peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (id); + peer_t *U UU = user_chat_get (bl, id); event_update_user_typing (tg, U); if (log_level >= 2) { //print_start (); @@ -931,8 +934,8 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { peer_id_t chat_id = MK_CHAT (fetch_int (self)); peer_id_t id = MK_USER (fetch_int (self)); - peer_t *C UU = user_chat_get (chat_id); - peer_t *U UU = user_chat_get (id); + peer_t *C UU = user_chat_get (bl, chat_id); + peer_t *U UU = user_chat_get (bl, id); event_update_user_typing(tg, U); if (log_level >= 2) { //print_start (); @@ -951,7 +954,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_user_status: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (user_id); + peer_t *U = user_chat_get (bl, user_id); if (U) { fetch_user_status (self, &U->user.status); event_update_user_status(tg, U); @@ -975,7 +978,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_user_name: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (user_id); + peer_t *UC = user_chat_get (bl, user_id); if (UC && (UC->flags & FLAG_CREATED)) { int l1 = prefetch_strlen (self); char *f = fetch_str (self, l1); @@ -1002,7 +1005,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_user_photo: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (user_id); + peer_t *UC = user_chat_get (bl, user_id); fetch_date (self); if (UC && (UC->flags & FLAG_CREATED)) { struct user *U = &UC->user; @@ -1080,7 +1083,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { assert (x == CODE_chat_participants || x == CODE_chat_participants_forbidden); peer_id_t chat_id = MK_CHAT (fetch_int (self)); int n = 0; - peer_t *C = user_chat_get (chat_id); + peer_t *C = user_chat_get (bl, chat_id); if (C && (C->flags & FLAG_CREATED)) { if (x == CODE_chat_participants) { bl_do_set_chat_admin (self->bl, self, &C->chat, fetch_int (self)); @@ -1123,7 +1126,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_contact_registered: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (user_id); + peer_t *U UU = user_chat_get (bl, user_id); fetch_int (self); // date //print_start (); //push_color (COLOR_YELLOW); @@ -1138,7 +1141,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_contact_link: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (user_id); + peer_t *U UU = user_chat_get (bl, user_id); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1162,7 +1165,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_activation: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (user_id); + peer_t *U UU = user_chat_get (bl, user_id); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1251,7 +1254,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { case CODE_update_encrypted_chat_typing: { peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); - peer_t *P = user_chat_get (id); + peer_t *P = user_chat_get (bl, id); //print_start (); //push_color (COLOR_YELLOW); //print_date (time (0)); @@ -1259,7 +1262,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { if (P) { printf (" User "); peer_id_t user_id UU = MK_USER (P->encr_chat.user_id); - //print_user_name (user_id, user_chat_get (user_id)); + //print_user_name (user_id, user_chat_get (bl, user_id)); printf (" typing in secret chat "); //print_encr_chat_name (id, P); printf ("\n"); @@ -1275,7 +1278,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); // chat_id fetch_int (self); // max_date fetch_int (self); // date - peer_t *P = user_chat_get (id); + peer_t *P = user_chat_get (bl, id); int x = -1; if (P && P->last) { x = 0; @@ -1293,7 +1296,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { //push_color (COLOR_YELLOW); //print_date (time (0)); printf (" Encrypted chat "); - //print_encr_chat_name_full (id, user_chat_get (id)); + //print_encr_chat_name_full (id, user_chat_get (bl, id)); printf (": %d messages marked read \n", x); //pop_color (); //print_end (); @@ -1307,7 +1310,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_id_t inviter_id = MK_USER (fetch_int (self)); int version = fetch_int (self); - peer_t *C = user_chat_get (chat_id); + peer_t *C = user_chat_get (bl, chat_id); if (C && (C->flags & FLAG_CREATED)) { bl_do_chat_add_user (self->bl, self, &C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); } @@ -1316,11 +1319,11 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { //push_color (COLOR_YELLOW); //print_date (time (0)); printf (" Chat "); - //print_chat_name (chat_id, user_chat_get (chat_id)); + //print_chat_name (chat_id, user_chat_get (bl, chat_id)); printf (": user "); - //print_user_name (user_id, user_chat_get (user_id)); + //print_user_name (user_id, user_chat_get (bl, user_id)); printf (" added by user "); - //print_user_name (inviter_id, user_chat_get (inviter_id)); + //print_user_name (inviter_id, user_chat_get (bl, inviter_id)); printf ("\n"); //pop_color (); //print_end (); @@ -1332,7 +1335,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_id_t user_id = MK_USER (fetch_int (self)); int version = fetch_int (self); - peer_t *C = user_chat_get (chat_id); + peer_t *C = user_chat_get (bl, chat_id); if (C && (C->flags & FLAG_CREATED)) { bl_do_chat_del_user (self->bl, self, &C->chat, version, get_peer_id (user_id)); } @@ -1341,9 +1344,9 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { //push_color (COLOR_YELLOW); //print_date (time (0)); printf (" Chat "); - //print_chat_name (chat_id, user_chat_get (chat_id)); + //print_chat_name (chat_id, user_chat_get (bl, chat_id)); printf (": user "); - //print_user_name (user_id, user_chat_get (user_id)); + //print_user_name (user_id, user_chat_get (bl, user_id)); printf (" deleted\n"); //pop_color (); //print_end (); @@ -1464,7 +1467,7 @@ void work_msgs_ack (struct connection *c UU, long long msg_id UU) { for (i = 0; i < n; i++) { long long id = fetch_long (c->mtconnection); logprintf ("ack for %lld\n", id); - query_ack (id); + query_ack (c->instance, id); } } @@ -1474,9 +1477,9 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { long long id = fetch_long (c->mtconnection); int op = prefetch_int (c->mtconnection); if (op == CODE_rpc_error) { - query_error (id); + query_error (c->instance, id); } else { - query_result (id); + query_result (c->instance, id); } } @@ -1510,7 +1513,7 @@ void work_packed (struct connection *c, long long msg_id) { void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { assert (fetch_int (c->mtconnection) == (int)CODE_bad_server_salt); long long id = fetch_long (c->mtconnection); - query_restart (id); + query_restart (c->instance, id); fetch_int (c->mtconnection); // seq_no fetch_int (c->mtconnection); // error_code long long new_server_salt = fetch_long (c->mtconnection); @@ -1809,19 +1812,15 @@ struct connection_methods mtproto_methods = { .close = rpc_close }; -// TODO: use a list or tree instead -struct mtproto_connection *Cs[100]; - /** * Create a new struct mtproto_connection connection using the giving datacenter for authorization and * session handling */ struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg) { - static int cs = 0; - struct mtproto_connection *mtp = talloc(sizeof(struct mtproto_connection)); - Cs[cs++] = mtp; - memset(mtp, 0, sizeof(struct mtproto_connection)); + struct mtproto_connection *mtp = talloc0(sizeof(struct mtproto_connection)); + tg->Cs[tg->cs++] = mtp; + mtp->instance = tg; mtp->packet_buffer = mtp->__packet_buffer + 16; mtp->connection = fd_create_connection(DC, fd, tg, &mtproto_methods, mtp); @@ -1875,14 +1874,14 @@ void mtproto_destroy (struct mtproto_connection *self) { void mtproto_free_closed () { int i; for (i = 0; i < 100; i++) { - if (Cs[i] == NULL) continue; - struct mtproto_connection *c = Cs[i]; + if (tg->Cs[i] == NULL) continue; + struct mtproto_connection *c = tg->Cs[i]; logprintf ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", i, c->c_state, c->destroy, c->queries_num); if (c->destroy == 0) continue; if (c->queries_num > 0) continue; mtproto_destroy (c); - Cs[i] = NULL; + tg->Cs[i] = NULL; } } diff --git a/mtproto-client.h b/mtproto-client.h index 2130ec5..5fdcebe 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -213,6 +213,8 @@ struct mtproto_connection { int longpoll_count, good_messages; + // TODO: decide whether this should be in struct telegram + // or in struct mtproto_client int unread_messages; int our_id; int pts; @@ -243,6 +245,11 @@ struct mtproto_connection { // marks this connection for destruction, so it // will be freed once all queries received a response or timed out int destroy; + + // + // the corresponding telegram instance + // + struct telegram *instance; }; void mtproto_connection_init (struct mtproto_connection *c); @@ -498,7 +505,7 @@ static inline void hexdump_out (struct mtproto_connection *self) { #endif void my_clock_gettime (int clock_id, struct timespec *T); -void mtproto_free_closed (); +void mtproto_free_closed (struct telegram *tg); #endif diff --git a/net.c b/net.c index fad9eb5..d935d1f 100644 --- a/net.c +++ b/net.c @@ -116,14 +116,14 @@ int ping_alarm (struct connection *c) { } void stop_ping_timer (struct connection *c) { - remove_event_timer (&c->ev); + remove_event_timer (c->instance, &c->ev); } void start_ping_timer (struct connection *c) { c->ev.timeout = get_double_time () + PING_TIMEOUT; c->ev.alarm = (void *)ping_alarm; c->ev.self = c; - insert_event_timer (&c->ev); + insert_event_timer (c->instance, &c->ev); } void restart_connection (struct connection *c); @@ -138,7 +138,7 @@ void start_fail_timer (struct connection *c) { c->ev.timeout = get_double_time () + 10; c->ev.alarm = (void *)fail_alarm; c->ev.self = c; - insert_event_timer (&c->ev); + insert_event_timer (c->instance, &c->ev); } struct connection_buffer *new_connection_buffer (int size) { @@ -636,18 +636,17 @@ int send_all_acks (struct session *S) { void insert_msg_id (struct session *S, long long id) { if (!S->ack_tree) { + logprintf ("Creating ack_tree pointing to session %p\n"); S->ev.alarm = (void *)send_all_acks; S->ev.self = (void *)S; S->ev.timeout = get_double_time () + ACK_TIMEOUT; - insert_event_timer (&S->ev); + insert_event_timer (S->c->instance, &S->ev); } if (!tree_lookup_long (S->ack_tree, id)) { S->ack_tree = tree_insert_long (S->ack_tree, id, lrand48 ()); } } -extern struct dc *DC_list[]; - struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { assert (!DC_list[id]); struct dc *DC = talloc0 (sizeof (*DC)); diff --git a/queries.c b/queries.c index 6389dac..63e0a4f 100644 --- a/queries.c +++ b/queries.c @@ -62,11 +62,6 @@ int verbosity; extern int offline_mode; int offline_mode = 0; -long long cur_uploading_bytes; -long long cur_uploaded_bytes; -long long cur_downloading_bytes; -long long cur_downloaded_bytes; - extern int sync_from_start; int sync_from_start = 0; @@ -74,12 +69,14 @@ void telegram_flush_queries (struct telegram *instance) { instance->config->on_output(instance); } -void out_peer_id (struct mtproto_connection *self, peer_id_t id); -#define QUERY_TIMEOUT 6.0 - #define memcmp8(a,b) memcmp ((a), (b), 8) DEFINE_TREE (query, struct query *, memcmp8, 0) ; -struct tree_query *queries_tree; + +#define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) +DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) + +void out_peer_id (struct mtproto_connection *self, peer_id_t id); +#define QUERY_TIMEOUT 6.0 /** * Get the struct mtproto_connection connection this connection was attached to @@ -94,23 +91,21 @@ double get_double_time (void) { return tv.tv_sec + 1e-9 * tv.tv_nsec; } -struct query *query_get (long long id) { - return tree_lookup_query (queries_tree, (void *)&id); +struct query *query_get (struct telegram *instance, long long id) { + return tree_lookup_query (instance->queries_tree, (void *)&id); } int alarm_query (struct query *q) { assert (q); - if (verbosity >= 1) { - logprintf ("Alarm query %lld\n", q->msg_id); - } + struct mtproto_connection *mtp = query_get_mtproto(q); + logprintf ("Alarm query %lld\n", q->msg_id); q->ev.timeout = get_double_time () + QUERY_TIMEOUT; - insert_event_timer (&q->ev); + insert_event_timer (mtp->connection->instance, &q->ev); if (q->session->c->out_bytes >= 100000) { return 0; } - struct mtproto_connection *mtp = query_get_mtproto(q); clear_packet (mtp); out_int (mtp, CODE_msg_container); out_int (mtp, 1); @@ -123,15 +118,15 @@ int alarm_query (struct query *q) { return 0; } -void query_restart (long long id) { - struct query *q = query_get (id); +void query_restart (struct telegram *instance, long long id) { + struct query *q = query_get (instance, id); if (q) { - remove_event_timer (&q->ev); + remove_event_timer (instance, &q->ev); alarm_query (q); } } -struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { +struct query *send_query (struct telegram *instance, struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { logprintf("send_query(...)\n"); logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); struct query *q = talloc0 (sizeof (*q)); @@ -144,36 +139,36 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth logprintf ( "Msg_id is %lld %p\n", q->msg_id, q); q->methods = methods; q->DC = DC; - if (queries_tree) { + if (instance->queries_tree) { if (verbosity >= 2) { - logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + logprintf ( "%lld %lld\n", q->msg_id, instance->queries_tree->x->msg_id); } } - queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); + instance->queries_tree = tree_insert_query (instance->queries_tree, q, lrand48 ()); struct mtproto_connection *mtp = query_get_mtproto(q); logprintf("queries_num: %d\n", ++ mtp->queries_num); q->ev.alarm = (void *)alarm_query; q->ev.timeout = get_double_time () + QUERY_TIMEOUT; q->ev.self = (void *)q; - insert_event_timer (&q->ev); + insert_event_timer (instance, &q->ev); q->extra = extra; return q; } -void query_ack (long long id) { - struct query *q = query_get (id); +void query_ack (struct telegram *instance, long long id) { + struct query *q = query_get (instance, id); if (q && !(q->flags & QUERY_ACK_RECEIVED)) { assert (q->msg_id == id); q->flags |= QUERY_ACK_RECEIVED; - remove_event_timer (&q->ev); + remove_event_timer (instance, &q->ev); } } -void query_error (long long id) { - struct query *q = query_get (id); +void query_error (struct telegram *instance, long long id) { + struct query *q = query_get (instance, id); struct mtproto_connection *mtp = query_get_mtproto(q); assert (fetch_int (mtp) == CODE_rpc_error); @@ -185,9 +180,9 @@ void query_error (long long id) { logprintf ( "No such query\n"); } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { - remove_event_timer (&q->ev); + remove_event_timer (instance, &q->ev); } - queries_tree = tree_delete_query (queries_tree, q); + instance->queries_tree = tree_delete_query (instance->queries_tree, q); logprintf("queries_num: %d\n", -- mtp->queries_num); if (q->methods && q->methods->on_error) { @@ -202,11 +197,8 @@ void query_error (long long id) { } -#define MAX_PACKED_SIZE (1 << 24) -static int packed_buffer[MAX_PACKED_SIZE / 4]; - -void query_result (long long id UU) { - struct query *q = query_get (id); +void query_result (struct telegram *instance, long long id UU) { + struct query *q = query_get (instance, id); struct mtproto_connection *mtp = query_get_mtproto(q); logprintf ( "result for query #%lld\n", id); @@ -222,11 +214,11 @@ void query_result (long long id UU) { fetch_int (mtp); int l = prefetch_strlen (mtp); char *s = fetch_str (mtp, l); - int total_out = tinflate (s, l, packed_buffer, MAX_PACKED_SIZE); + int total_out = tinflate (s, l, instance->packed_buffer, MAX_PACKED_SIZE); end = mtp->in_ptr; eend = mtp->in_end; //assert (total_out % 4 == 0); - mtp->in_ptr = packed_buffer; + mtp->in_ptr = instance->packed_buffer; mtp->in_end = mtp->in_ptr + total_out / 4; if (verbosity >= 4) { logprintf ( "Unzipped data: "); @@ -238,9 +230,9 @@ void query_result (long long id UU) { mtp->in_ptr = mtp->in_end; } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { - remove_event_timer (&q->ev); + remove_event_timer (instance, &q->ev); } - queries_tree = tree_delete_query (queries_tree, q); + instance->queries_tree = tree_delete_query (instance->queries_tree, q); logprintf("queries_num: %d\n", -- mtp->queries_num); if (q->methods && q->methods->on_answer) { @@ -256,43 +248,36 @@ void query_result (long long id UU) { } } -#define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) -DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) -struct tree_timer *timer_tree; -void insert_event_timer (struct event_timer *ev) { +void insert_event_timer (struct telegram *instance, struct event_timer *ev) { logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - timer_tree = tree_insert_timer (timer_tree, ev, lrand48 ()); + instance->timer_tree = tree_insert_timer (instance->timer_tree, ev, lrand48 ()); } -void remove_event_timer (struct event_timer *ev) { +void remove_event_timer (struct telegram *instance, struct event_timer *ev) { logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - timer_tree = tree_delete_timer (timer_tree, ev); + instance->timer_tree = tree_delete_timer (instance->timer_tree, ev); } -double next_timer_in (void) { - if (!timer_tree) { return 1e100; } - return tree_get_min_timer (timer_tree)->timeout; +double next_timer_in (struct telegram *instance) { + if (!instance->timer_tree) { return 1e100; } + return tree_get_min_timer (instance->timer_tree)->timeout; } -void work_timers (void) { +void work_timers (struct telegram *instance) { logprintf ("work_timers ()\n"); double t = get_double_time (); - while (timer_tree) { - struct event_timer *ev = tree_get_min_timer (timer_tree); + while (instance->timer_tree) { + struct event_timer *ev = tree_get_min_timer (instance->timer_tree); assert (ev); if (ev->timeout > t) { break; } - remove_event_timer (ev); + remove_event_timer (instance, ev); assert (ev->alarm); logprintf ("Alarm\n"); ev->alarm (ev->self); } } -int max_chat_size; -int max_bcast_size; -int want_dc_num; -int new_dc_num; //extern struct dc *DC_list[]; //extern struct dc *DC_working; @@ -362,11 +347,11 @@ int help_get_config_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_dc_option (instance); } - max_chat_size = fetch_int (mtp); + instance->max_chat_size = fetch_int (mtp); if (op == CODE_config) { - max_bcast_size = fetch_int (mtp); + instance->max_bcast_size = fetch_int (mtp); } - logprintf ( "max_chat_size = %d\n", max_chat_size); + logprintf ( "max_chat_size = %d\n", instance->max_chat_size); telegram_change_state(instance, STATE_CONFIG_RECEIVED, NULL); return 0; @@ -383,7 +368,7 @@ void do_help_get_config (struct telegram *instance) { clear_packet (mtp); out_int (mtp, CODE_help_get_config); struct dc *DC_working = telegram_get_working_dc(instance); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &help_get_config_methods, instance); } /* }}} */ @@ -401,7 +386,7 @@ int send_code_on_answer (struct query *q UU) { logprintf("telegram: phone_code_hash: %s\n", phone_code_hash); fetch_int (mtp); fetch_bool (mtp); - want_dc_num = -1; + instance->want_dc_num = -1; if (instance->session_state == STATE_PHONE_CODE_REQUESTED) { telegram_change_state(instance, STATE_PHONE_CODE_NOT_ENTERED, NULL); } else if (instance->session_state == STATE_CLIENT_CODE_REQUESTED) { @@ -438,17 +423,12 @@ struct query_methods send_code_methods = { .on_error = send_code_on_error }; -int code_is_sent (void) { - return want_dc_num; -} - -char *suser; void do_send_code (struct telegram *instance, const char *user) { struct mtproto_connection *mtp = instance->connection; logprintf ("sending code\n"); - suser = tstrdup (user); - want_dc_num = 0; + instance->suser = tstrdup (user); + instance->want_dc_num = 0; clear_packet (mtp); do_insert_header (mtp); out_int (mtp, CODE_auth_send_code); @@ -459,7 +439,7 @@ void do_send_code (struct telegram *instance, const char *user) { out_string (mtp, "en"); logprintf ("send_code: dc_num = %d\n", instance->auth.dc_working_num); - send_query (telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_code_methods, instance); + send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_code_methods, instance); if (instance->session_state == STATE_PHONE_NOT_REGISTERED) { telegram_change_state(instance, STATE_PHONE_CODE_REQUESTED, NULL); } else if (instance->session_state == STATE_CLIENT_NOT_REGISTERED) { @@ -494,8 +474,8 @@ void do_phone_call (struct telegram *instance, const char *user) { struct mtproto_connection *mtp = instance->connection; logprintf ("calling user\n"); - suser = tstrdup (user); - want_dc_num = 0; + instance->suser = tstrdup (user); + instance->want_dc_num = 0; clear_packet (mtp); do_insert_header (mtp); out_int (mtp, CODE_auth_send_call); @@ -503,7 +483,7 @@ void do_phone_call (struct telegram *instance, const char *user) { out_string (mtp, instance->phone_code_hash); logprintf ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); - send_query (telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &phone_call_methods, 0); + send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &phone_call_methods, instance); } /* }}} */ @@ -563,32 +543,29 @@ struct query_methods check_phone_methods = { void do_auth_check_phone (struct telegram *instance, const char *user) { struct mtproto_connection *mtp = instance->connection; - suser = tstrdup (user); + instance->suser = tstrdup (user); clear_packet (mtp); out_int (mtp, CODE_auth_check_phone); out_string (mtp, user); check_phone_result = -1; struct dc *DC_working = telegram_get_working_dc(instance); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &check_phone_methods, instance); } /* }}} */ /* {{{ Nearest DC */ -int nearest_dc_num; -int nr_f (void) { - return nearest_dc_num >= 0; -} int nearest_dc_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); + struct telegram *instance = mtp->connection->instance; assert (fetch_int (mtp) == (int)CODE_nearest_dc); char *country = fetch_str_dup (mtp); logprintf ("Server thinks that you are in %s\n", country); fetch_int (mtp); // this_dc - nearest_dc_num = fetch_int (mtp); - assert (nearest_dc_num >= 0); + instance->nearest_dc_num = fetch_int (mtp); + assert (instance->nearest_dc_num >= 0); return 0; } @@ -608,31 +585,30 @@ void do_get_nearest_dc (struct telegram *instance) { struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (mtp); out_int (mtp, CODE_help_get_nearest_dc); - nearest_dc_num = -1; - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &nearest_dc_methods, 0); + instance->nearest_dc_num = -1; + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &nearest_dc_methods, instance); //net_loop (0, nr_f); //return nearest_dc_num; } /* }}} */ /* {{{ Sign in / Sign up */ -int our_id; - -struct user User; int sign_in_on_answer (struct query *q) { logprintf ("sign_in_on_answer()\n"); struct mtproto_connection *mtp = query_get_mtproto(q); + struct telegram *instance = mtp->connection->instance; + struct dc *DC_working = telegram_get_working_dc(mtp->connection->instance); assert (fetch_int (mtp) == (int)CODE_auth_authorization); int expires = fetch_int (mtp); - fetch_user (mtp, &User); - if (!our_id) { - our_id = get_peer_id (User.id); - bl_do_set_our_id (mtp->bl, mtp, our_id); + fetch_user (mtp, &instance->User); + if (!instance->our_id) { + instance->our_id = get_peer_id (instance->User.id); + bl_do_set_our_id (mtp->bl, mtp, instance->our_id); } logprintf ( "telegram: authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", - User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); + instance->User.first_name, instance->User.last_name, instance->User.phone, (int)(expires - get_double_time ())); DC_working->has_auth = 1; bl_do_dc_signed (mtp->bl, mtp, DC_working->id); @@ -661,11 +637,11 @@ void do_send_code_result (struct telegram *instance, const char *code) { struct dc *DC_working = telegram_get_working_dc(instance); clear_packet (mtp); out_int (mtp, CODE_auth_sign_in); - out_string (mtp, suser); + out_string (mtp, instance->suser); out_string(mtp, instance->phone_code_hash); out_string (mtp, code); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, - &sign_in_methods, NULL); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, + &sign_in_methods, instance); } void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name) { @@ -674,19 +650,18 @@ void do_send_code_result_auth (struct telegram *instance, const char *code, cons clear_packet (mtp); out_int (mtp, CODE_auth_sign_up); - out_string (mtp ,suser); + out_string (mtp, instance->suser); out_string (mtp, instance->phone_code_hash); out_string (mtp, code); out_string (mtp, first_name); out_string (mtp, last_name); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); } /* }}} */ /* {{{ Get contacts */ extern char *user_list[]; -int contacts_got = 0; int get_contacts_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); int i; @@ -703,7 +678,6 @@ int get_contacts_on_answer (struct query *q UU) { for (i = 0; i < n; i++) { fetch_alloc_user (mtp); } - contacts_got = 1; return 0; } @@ -715,11 +689,10 @@ void do_update_contact_list (struct telegram *instance) { struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); - contacts_got = 0; clear_packet (mtp); out_int (mtp, CODE_contacts_get_contacts); out_string (mtp, ""); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_contacts_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_contacts_methods, instance); } @@ -888,14 +861,11 @@ struct query_methods msg_send_encr_methods = { .on_answer = msg_send_encr_on_answer }; -int out_message_num; -int our_id; - void do_send_encr_msg (struct telegram *instance, struct message *M) { struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); - peer_t *P = user_chat_get (M->to_id); + peer_t *P = user_chat_get (mtp->bl, M->to_id); if (!P || P->encr_chat.state != sc_ok) { return; } clear_packet (mtp); @@ -914,7 +884,7 @@ void do_send_encr_msg (struct telegram *instance, struct message *M) { out_int (mtp, CODE_decrypted_message_media_empty); encr_finish (mtp, &P->encr_chat); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_send_encr_methods, M); } @@ -931,13 +901,13 @@ void do_send_msg (struct telegram *instance, struct message *M) { out_peer_id (mtp, M->to_id); out_cstring (mtp, M->message, M->message_len); out_long (mtp, M->id); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_send_methods, M); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_send_methods, M); } void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len) { struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT) { - peer_t *P = user_chat_get (id); + peer_t *P = user_chat_get (mtp->bl, id); if (!P) { logprintf ("Can not send to unknown encrypted chat\n"); return; @@ -950,8 +920,8 @@ void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, long long t; secure_random (&t, 8); logprintf ("t = %lld, len = %d\n", t, len); - bl_do_send_message_text (mtp->bl, mtp, t, our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); - struct message *M = message_get (t); + bl_do_send_message_text (mtp->bl, mtp, t, instance->our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); + struct message *M = message_get (mtp->bl, t); assert (M); do_send_msg (instance, M); //print_message (M); @@ -1016,7 +986,7 @@ void do_messages_mark_read (struct telegram *instance, peer_id_t id, int max_id) out_peer_id (mtp, id); out_int (mtp, max_id); out_int (mtp, 0); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_methods, 0); } void do_messages_mark_read_encr (struct telegram *instance, peer_id_t id, long long access_hash, int last_time) { @@ -1029,11 +999,13 @@ void do_messages_mark_read_encr (struct telegram *instance, peer_id_t id, long l out_int (mtp, get_peer_id (id)); out_long (mtp, access_hash); out_int (mtp, last_time); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_encr_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_encr_methods, 0); } void do_mark_read (struct telegram *instance, peer_id_t id) { - peer_t *P = user_chat_get (id); + struct mtproto_connection *mtp = instance->connection; + + peer_t *P = user_chat_get (mtp->bl, id); if (!P) { logprintf ("Unknown peer\n"); return; @@ -1112,8 +1084,9 @@ struct query_methods get_history_methods = { .on_answer = get_history_on_answer, }; -void do_get_local_history (peer_id_t id, int limit) { - peer_t *P = user_chat_get (id); +void do_get_local_history (struct telegram *instance, peer_id_t id, int limit) { + struct mtproto_connection *mtp = instance->connection; + peer_t *P = user_chat_get (mtp->bl, id); if (!P || !P->last) { return; } struct message *M = P->last; int count = 1; @@ -1132,7 +1105,7 @@ void do_get_history (struct telegram *instance, peer_id_t id, int limit) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT || offline_mode) { - do_get_local_history (id, limit); + do_get_local_history (instance, id, limit); do_mark_read (instance, id); return; } @@ -1147,7 +1120,7 @@ void do_get_history (struct telegram *instance, peer_id_t id, int limit) { extra->instance = instance; extra->peer_id = id; - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_history_methods, extra); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_history_methods, extra); } /* }}} */ @@ -1202,13 +1175,13 @@ int get_dialogs_on_answer (struct query *q UU) { peer_t *UC UU; switch (get_peer_type (plist[i])) { case PEER_USER: - UC = user_chat_get (plist[i]); + UC = user_chat_get (mtp->bl, plist[i]); logprintf ("User "); //print_user_name (plist[i], UC); logprintf (": %d unread\n", dlist[2 * i + 1]); break; case PEER_CHAT: - UC = user_chat_get (plist[i]); + UC = user_chat_get (mtp->bl, plist[i]); logprintf ("Chat "); //print_chat_name (plist[i], UC); logprintf (": %d unread\n", dlist[2 * i + 1]); @@ -1235,7 +1208,7 @@ void do_get_dialog_list (struct telegram *instance) { out_int (mtp, 0); out_int (mtp, 0); out_int (mtp, 1000); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dialogs_methods, instance); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dialogs_methods, instance); } /* }}} */ @@ -1267,7 +1240,7 @@ void out_peer_id (struct mtproto_connection *self, peer_id_t id) { out_int (self, get_peer_id (id)); break; case PEER_USER: - U = user_chat_get (id); + U = user_chat_get (self->bl, id); if (U && U->user.access_hash) { out_int (self, CODE_input_peer_foreign); out_int (self, get_peer_id (id)); @@ -1288,9 +1261,9 @@ struct send_file_extra { }; void send_part (struct telegram *instance, struct send_file *f); -int send_file_part_on_answer (struct query *q) { - struct mtproto_connection *mtp = query_get_mtproto(q); +int send_file_part_on_answer (struct query *q) { + struct mtproto_connection *mtp = query_get_mtproto (q); struct send_file_extra *extra = q->extra; assert (fetch_int (mtp) == (int)CODE_bool_true); send_part (extra->instance, extra->file); @@ -1359,7 +1332,7 @@ void send_part (struct telegram *instance, struct send_file *f) { struct dc *DC_working = telegram_get_working_dc(instance); if (f->fd >= 0) { if (!f->part_num) { - cur_uploading_bytes += f->size; + instance->cur_uploading_bytes += f->size; } clear_packet (mtp); if (f->size < (16 << 20)) { @@ -1376,7 +1349,7 @@ void send_part (struct telegram *instance, struct send_file *f) { int x = read (f->fd, buf, f->part_size); assert (x > 0); f->offset += x; - cur_uploaded_bytes += x; + instance->cur_uploaded_bytes += x; if (f->encr) { if (x & 15) { @@ -1405,10 +1378,10 @@ void send_part (struct telegram *instance, struct send_file *f) { struct send_file_extra *extra = malloc(sizeof(struct send_file_extra)); extra->instance = instance; extra->file = f; - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, extra); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, extra); } else { - cur_uploaded_bytes -= f->size; - cur_uploading_bytes -= f->size; + instance->cur_uploaded_bytes -= f->size; + instance->cur_uploading_bytes -= f->size; //update_prompt (); clear_packet (mtp); assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_audio || f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document); @@ -1450,14 +1423,14 @@ void send_part (struct telegram *instance, struct send_file *f) { } out_long (mtp, -lrand48 () * (1ll << 32) - lrand48 ()); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_methods, instance); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_methods, instance); } else { struct message *M = talloc0 (sizeof (*M)); out_int (mtp, CODE_messages_send_encrypted_file); out_int (mtp, CODE_input_encrypted_chat); out_int (mtp, get_peer_id (f->to_id)); - peer_t *P = user_chat_get (f->to_id); + peer_t *P = user_chat_get (mtp->bl, f->to_id); assert (P); out_long (mtp, P->encr_chat.access_hash); long long r = -lrand48 () * (1ll << 32) - lrand48 (); @@ -1531,7 +1504,7 @@ void send_part (struct telegram *instance, struct send_file *f) { M->media.encr_photo.size = f->size; M->flags = FLAG_ENCRYPTED; - M->from_id = MK_USER (our_id); + M->from_id = MK_USER (instance->our_id); M->to_id = f->to_id; M->unread = 1; M->message = tstrdup (""); @@ -1539,7 +1512,7 @@ void send_part (struct telegram *instance, struct send_file *f) { M->id = r; M->date = time (0); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_file_methods, M); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_file_methods, M); } tfree_str (f->file_name); tfree (f, sizeof (*f)); @@ -1555,7 +1528,7 @@ void send_file_thumb (struct telegram *instance, struct send_file *f) { out_long (mtp, f->thumb_id); out_int (mtp, 0); out_cstring (mtp, (void *)thumb_file, thumb_file_size); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, f); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, f); } void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name) { @@ -1660,7 +1633,7 @@ void do_forward_message (struct telegram *instance, peer_id_t id, int n) { out_peer_id (mtp, id); out_int (mtp, n); out_long (mtp, lrand48 () * (1ll << 32) + lrand48 ()); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &fwd_msg_methods, instance); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &fwd_msg_methods, instance); } /* }}} */ @@ -1702,7 +1675,7 @@ void do_rename_chat (struct telegram *instance, peer_id_t id, char *name UU) { assert (get_peer_type (id) == PEER_CHAT); out_int (mtp, get_peer_id (id)); out_string (mtp, name); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &rename_chat_methods, instance); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &rename_chat_methods, instance); } /* }}} */ @@ -1720,9 +1693,9 @@ void print_chat_info (struct chat *C) { int i; for (i = 0; i < C->user_list_size; i++) { logprintf ("\t\t"); - //print_user_name (MK_USER (C->user_list[i].user_id), user_chat_get (MK_USER (C->user_list[i].user_id))); + //print_user_name (MK_USER (C->user_list[i].user_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].user_id))); logprintf (" invited by "); - //print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (MK_USER (C->user_list[i].inviter_id))); + //print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].inviter_id))); logprintf (" at "); //print_date_full (C->user_list[i].date); if (C->user_list[i].user_id == C->admin_id) { @@ -1752,7 +1725,7 @@ void do_get_chat_info (struct telegram *instance, peer_id_t id) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; if (offline_mode) { - peer_t *C = user_chat_get (id); + peer_t *C = user_chat_get (mtp->bl, id); if (!C) { logprintf ("No such chat\n"); } else { @@ -1764,7 +1737,7 @@ void do_get_chat_info (struct telegram *instance, peer_id_t id) { out_int (mtp, CODE_messages_get_full_chat); assert (get_peer_type (id) == PEER_CHAT); out_int (mtp, get_peer_id (id)); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &chat_info_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &chat_info_methods, 0); } /* }}} */ @@ -1809,7 +1782,7 @@ void do_get_user_info (struct telegram *instance, peer_id_t id) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; if (offline_mode) { - peer_t *C = user_chat_get (id); + peer_t *C = user_chat_get (mtp->bl, id); if (!C) { logprintf ("No such user\n"); } else { @@ -1820,7 +1793,7 @@ void do_get_user_info (struct telegram *instance, peer_id_t id) { clear_packet (mtp); out_int (mtp, CODE_users_get_full_user); assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (mtp->bl, id); if (U && U->user.access_hash) { out_int (mtp, CODE_input_user_foreign); out_int (mtp, get_peer_id (id)); @@ -1829,7 +1802,7 @@ void do_get_user_info (struct telegram *instance, peer_id_t id) { out_int (mtp, CODE_input_user_contact); out_int (mtp, get_peer_id (id)); } - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, 0); } /* }}} */ @@ -1862,7 +1835,7 @@ void do_get_user_list_info_silent (struct telegram *instance, int num, int *list out_int (mtp, list[i]); //out_long (0); } - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_list_info_silent_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_list_info_silent_methods, 0); } /* }}} */ @@ -1885,9 +1858,9 @@ struct download { }; -void end_load (struct download *D) { - cur_downloading_bytes -= D->size; - cur_downloaded_bytes -= D->size; +void end_load (struct telegram *instance, struct download *D) { + instance->cur_downloading_bytes -= D->size; + instance->cur_downloaded_bytes -= D->size; //update_prompt (); close (D->fd); if (D->next == 1) { @@ -1934,7 +1907,7 @@ int download_on_answer (struct query *q) { fetch_int (mtp); // mtime int len = prefetch_strlen (mtp); assert (len >= 0); - cur_downloaded_bytes += len; + instance->cur_downloaded_bytes += len; //update_prompt (); if (D->iv) { unsigned char *ptr = (void *)fetch_str (mtp, len); @@ -1955,7 +1928,7 @@ int download_on_answer (struct query *q) { load_next_part (instance, D); return 0; } else { - end_load (D); + end_load (instance, D); return 0; } } @@ -1983,16 +1956,16 @@ void load_next_part (struct telegram *instance, struct download *D) { if (stat (buf, &st) >= 0) { D->offset = st.st_size; if (D->offset >= D->size) { - cur_downloading_bytes += D->size; - cur_downloaded_bytes += D->offset; + instance->cur_downloading_bytes += D->size; + instance->cur_downloaded_bytes += D->offset; logprintf ("Already downloaded\n"); - end_load (D); + end_load (instance, D); return; } } - cur_downloading_bytes += D->size; - cur_downloaded_bytes += D->offset; + instance->cur_downloading_bytes += D->size; + instance->cur_downloaded_bytes += D->offset; //update_prompt (); } clear_packet (mtp); @@ -2018,8 +1991,8 @@ void load_next_part (struct telegram *instance, struct download *D) { extra->instance = instance; extra->dl = D; - send_query (instance->auth.DC_list[D->dc], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &download_methods, extra); - //send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); + send_query (instance, instance->auth.DC_list[D->dc], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &download_methods, extra); + //send_query (instance, DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); } void do_load_photo_size (struct telegram *instance, struct photo_size *P, int next) { @@ -2141,30 +2114,23 @@ void do_load_encr_video (struct telegram *instance, struct encr_video *V, int ne /* }}} */ /* {{{ Export auth */ -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) { struct mtproto_connection *mtp = query_get_mtproto(q); + struct telegram *instance = mtp->connection->instance; assert (fetch_int (mtp) == (int)CODE_auth_exported_authorization); int l = fetch_int (mtp); - if (!our_id) { - our_id = l; + if (!instance->our_id) { + instance->our_id = l; } else { - assert (our_id == l); + assert (instance->our_id == l); } l = prefetch_strlen (mtp); char *s = talloc (l); memcpy (s, fetch_str (mtp, l), l); - export_auth_str_len = l; - export_auth_str = s; + instance->export_auth_str_len = l; + instance->export_auth_str = s; return 0; } @@ -2176,23 +2142,24 @@ struct query_methods export_auth_methods = { void do_export_auth (struct telegram *instance, int num) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; - export_auth_str = 0; + instance->export_auth_str = 0; clear_packet (mtp); out_int (mtp, CODE_auth_export_authorization); out_int (mtp, num); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, 0); } /* }}} */ /* {{{ Import auth */ int import_auth_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int (mtp) == (int)CODE_auth_authorization); + struct telegram *instance = mtp->connection->instance; + assert (fetch_int (mtp) == (int)CODE_auth_authorization); fetch_int (mtp); // expires fetch_alloc_user (mtp); - tfree_str (export_auth_str); - export_auth_str = 0; + tfree_str (instance->export_auth_str); + instance->export_auth_str = 0; return 0; } @@ -2203,11 +2170,12 @@ struct query_methods import_auth_methods = { void do_import_auth (struct telegram *instance, int num) { struct mtproto_connection *mtp = instance->connection; + clear_packet (mtp); out_int (mtp, CODE_auth_import_authorization); - out_int (mtp, our_id); - out_cstring (mtp, export_auth_str, export_auth_str_len); - send_query (instance->auth.DC_list[num], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &import_auth_methods, 0); + out_int (mtp, instance->our_id); + out_cstring (mtp, instance->export_auth_str, instance->export_auth_str_len); + send_query (instance, instance->auth.DC_list[num], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &import_auth_methods, 0); } /* }}} */ @@ -2281,7 +2249,7 @@ void do_add_contact (struct telegram *instance, const char *phone, int phone_len out_cstring (mtp, first_name, first_name_len); out_cstring (mtp, last_name, last_name_len); out_int (mtp, force ? CODE_bool_true : CODE_bool_false); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_contact_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_contact_methods, 0); } /* }}} */ @@ -2315,7 +2283,7 @@ void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, i out_int (mtp, 0); // offset out_int (mtp, 0); // max_id out_int (mtp, limit); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_search_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_search_methods, 0); } /* }}} */ @@ -2360,7 +2328,7 @@ void do_contacts_search (struct telegram *instance, int limit, const char *s) { out_int (mtp, CODE_contacts_search); out_string (mtp, s); out_int (mtp, limit); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &contacts_search_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &contacts_search_methods, 0); } /* }}} */ @@ -2422,11 +2390,6 @@ struct query_methods send_encr_request_methods = { .on_answer = send_encr_request_on_answer }; -int encr_root; -unsigned char *encr_prime; -int encr_param_version; -BN_CTX *ctx; - void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, unsigned char *random) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; @@ -2448,16 +2411,16 @@ void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, ensure_ptr (b); BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0); ensure_ptr (g_a); - assert (check_g (encr_prime, g_a) >= 0); - if (!ctx) { - ctx = BN_CTX_new (); - ensure_ptr (ctx); + assert (check_g (instance->encr_prime, g_a) >= 0); + if (!instance->ctx) { + instance->ctx = BN_CTX_new (); + ensure_ptr (instance->ctx); } - BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); ensure_ptr (p); BIGNUM *r = BN_new (); ensure_ptr (r); - ensure (BN_mod_exp (r, g_a, b, p, ctx)); + ensure (BN_mod_exp (r, g_a, b, p, instance->ctx)); static unsigned char kk[256]; memset (kk, 0, sizeof (kk)); BN_bn2bin (r, kk); @@ -2475,8 +2438,8 @@ void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, out_int (mtp, get_peer_id (E->id)); out_long (mtp, E->access_hash); - ensure (BN_set_word (g_a, encr_root)); - ensure (BN_mod_exp (r, g_a, b, p, ctx)); + ensure (BN_set_word (g_a, instance->encr_root)); + ensure (BN_mod_exp (r, g_a, b, p, instance->ctx)); static unsigned char buf[256]; memset (buf, 0, sizeof (buf)); BN_bn2bin (r, buf); @@ -2488,25 +2451,25 @@ void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, BN_clear_free (p); BN_clear_free (r); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_accept_methods, E); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_accept_methods, E); } -void do_create_keys_end (struct secret_chat *U) { - assert (encr_prime); +void do_create_keys_end (struct telegram *instance, struct secret_chat *U) { + assert (instance->encr_prime); BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); ensure_ptr (g_b); - assert (check_g (encr_prime, g_b) >= 0); - if (!ctx) { - ctx = BN_CTX_new (); - ensure_ptr (ctx); + assert (check_g (instance->encr_prime, g_b) >= 0); + if (!instance->ctx) { + instance->ctx = BN_CTX_new (); + ensure_ptr (instance->ctx); } - BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); ensure_ptr (p); BIGNUM *r = BN_new (); ensure_ptr (r); BIGNUM *a = BN_bin2bn ((void *)U->key, 256, 0); ensure_ptr (a); - ensure (BN_mod_exp (r, g_b, a, p, ctx)); + ensure (BN_mod_exp (r, g_b, a, p, instance->ctx)); unsigned char *t = talloc (256); memcpy (t, U->key, 256); @@ -2522,7 +2485,7 @@ void do_create_keys_end (struct secret_chat *U) { sha1 ((void *)U->key, 256, sha_buffer); long long k = *(long long *)(sha_buffer + 12); if (k != U->key_fingerprint) { - logprintf ("version = %d\n", encr_param_version); + logprintf ("version = %d\n", instance->encr_param_version); hexdump ((void *)U->nonce, (void *)(U->nonce + 256)); hexdump ((void *)U->g_key, (void *)(U->g_key + 256)); hexdump ((void *)U->key, (void *)(U->key + 64)); @@ -2551,45 +2514,44 @@ void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char for (i = 0; i < 256; i++) { random[i] ^= random_here[i]; } - if (!ctx) { - ctx = BN_CTX_new (); - ensure_ptr (ctx); + if (!instance->ctx) { + instance->ctx = BN_CTX_new (); + ensure_ptr (instance->ctx); } BIGNUM *a = BN_bin2bn (random, 256, 0); ensure_ptr (a); - BIGNUM *p = BN_bin2bn (encr_prime, 256, 0); + BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); ensure_ptr (p); BIGNUM *g = BN_new (); ensure_ptr (g); - ensure (BN_set_word (g, encr_root)); + ensure (BN_set_word (g, instance->encr_root)); BIGNUM *r = BN_new (); ensure_ptr (r); - ensure (BN_mod_exp (r, g, a, p, ctx)); + ensure (BN_mod_exp (r, g, a, p, instance->ctx)); BN_clear_free (a); - static char g_a[256]; - memset (g_a, 0, 256); + memset (instance->g_a, 0, 256); - BN_bn2bin (r, (void *)g_a); + BN_bn2bin (r, (void *)instance->g_a); int t = lrand48 (); - while (user_chat_get (MK_ENCR_CHAT (t))) { + while (user_chat_get (mtp->bl, MK_ENCR_CHAT (t))) { t = lrand48 (); } - bl_do_encr_chat_init (mtp->bl, mtp, t, user_id, (void *)random, (void *)g_a); - peer_t *_E = user_chat_get (MK_ENCR_CHAT (t)); + bl_do_encr_chat_init (mtp->bl, mtp, t, user_id, (void *)random, (void *)instance->g_a); + peer_t *_E = user_chat_get (mtp->bl, MK_ENCR_CHAT (t)); assert (_E); struct secret_chat *E = &_E->encr_chat; clear_packet (mtp); out_int (mtp, CODE_messages_request_encryption); - peer_t *U = user_chat_get (MK_USER (E->user_id)); + peer_t *U = user_chat_get (mtp->bl, MK_USER (E->user_id)); assert (U); if (U && U->user.access_hash) { out_int (mtp, CODE_input_user_foreign); @@ -2600,15 +2562,15 @@ void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char out_int (mtp, E->user_id); } out_int (mtp, get_peer_id (E->id)); - out_cstring (mtp, g_a, 256); + out_cstring (mtp, instance->g_a, 256); // TODO: properly... - write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); BN_clear_free (g); BN_clear_free (p); BN_clear_free (r); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_request_methods, E); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_request_methods, E); } struct create_encr_chat_extra { @@ -2666,14 +2628,14 @@ void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat clear_packet (mtp); out_int (mtp, CODE_messages_get_dh_config); - out_int (mtp, encr_param_version); + out_int (mtp, instance->encr_param_version); out_int (mtp, 256); struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); extra->callback = do_send_accept_encr_chat; extra->instance = instance; extra->data = (void*)E; - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); } void do_create_encr_chat_request (struct telegram *instance, int user_id) { @@ -2682,21 +2644,20 @@ void do_create_encr_chat_request (struct telegram *instance, int user_id) { clear_packet (mtp); out_int (mtp, CODE_messages_get_dh_config); - out_int (mtp, encr_param_version); + out_int (mtp, instance->encr_param_version); out_int (mtp, 256); struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); extra->callback = do_send_accept_encr_chat; extra->instance = instance; extra->data = (void *)(long)user_id; - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); } /* }}} */ /* {{{ Get difference */ -int unread_messages; -int difference_got; -int seq, pts, qts, last_date; +//int difference_got; +//int seq, pts, qts, last_date; int get_state_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = q->extra; @@ -2707,34 +2668,30 @@ int get_state_on_answer (struct query *q UU) { bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - unread_messages = fetch_int (mtp); + instance->unread_messages = fetch_int (mtp); //write_state_file (); - difference_got = 1; telegram_store_session (instance); return 0; } -int get_difference_active; int get_difference_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = q->extra; logprintf("get_difference_on_answer()\n"); - get_difference_active = 0; + instance->get_difference_active = 0; unsigned x = fetch_int (mtp); if (x == CODE_updates_difference_empty) { bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - difference_got = 1; } else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) { int n, i; assert (fetch_int (mtp) == CODE_vector); n = fetch_int (mtp); - static struct message *ML[10000]; int ml_pos = 0; for (i = 0; i < n; i++) { if (ml_pos < 10000) { - ML[ml_pos ++] = fetch_alloc_message (mtp, instance); + instance->ML[ml_pos ++] = fetch_alloc_message (mtp, instance); } else { fetch_alloc_message (mtp, instance); } @@ -2743,7 +2700,7 @@ int get_difference_on_answer (struct query *q UU) { n = fetch_int (mtp); for (i = 0; i < n; i++) { if (ml_pos < 10000) { - ML[ml_pos ++] = fetch_alloc_encrypted_message (mtp, instance); + instance->ML[ml_pos ++] = fetch_alloc_encrypted_message (mtp, instance); } else { fetch_alloc_encrypted_message (mtp, instance); } @@ -2751,7 +2708,7 @@ int get_difference_on_answer (struct query *q UU) { assert (fetch_int (mtp) == CODE_vector); n = fetch_int (mtp); for (i = 0; i < n; i++) { - work_update (0, 0); + work_update (mtp, 0); } assert (fetch_int (mtp) == CODE_vector); n = fetch_int (mtp); @@ -2770,16 +2727,16 @@ int get_difference_on_answer (struct query *q UU) { bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - unread_messages = fetch_int (mtp); + instance->unread_messages = fetch_int (mtp); //write_state_file (); for (i = 0; i < ml_pos; i++) { - event_update_new_message (instance, ML[i]); + event_update_new_message (instance, instance->ML[i]); ////print_message (ML[i]); } if (x == CODE_updates_difference_slice) { do_get_difference (instance); } else { - difference_got = 1; + //difference_got = 1; } } else { assert (0); @@ -2800,23 +2757,27 @@ void do_get_difference (struct telegram *instance) { struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); - logprintf("do_get_difference()\n"); - get_difference_active = 1; - difference_got = 0; + instance->get_difference_active = 1; + //difference_got = 0; clear_packet (mtp); do_insert_header (mtp); - if (seq > 0 || sync_from_start) { - if (pts == 0) { pts = 1; } - if (qts == 0) { qts = 1; } - if (last_date == 0) { last_date = 1; } + if (instance->proto.seq > 0 || sync_from_start) { + if (instance->proto.pts == 0) { instance->proto.pts = 1; } + if (instance->proto.qts == 0) { instance->proto.qts = 1; } + if (instance->proto.last_date == 0) { instance->proto.last_date = 1; } + + logprintf("do_get_difference(pts:%d, last_date:%d, qts: %d)\n", + instance->proto.pts, instance->proto.last_date, instance->proto.qts); out_int (mtp, CODE_updates_get_difference); - out_int (mtp, pts); - out_int (mtp, last_date); - out_int (mtp, qts); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); + out_int (mtp, instance->proto.pts); + out_int (mtp, instance->proto.last_date); + out_int (mtp, instance->proto.qts); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); } else { + logprintf("do_updates_get_state()\n", + instance->proto.pts, instance->proto.last_date, instance->proto.qts); out_int (mtp, CODE_updates_get_state); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, instance); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, instance); } } /* }}} */ @@ -2824,9 +2785,9 @@ void do_get_difference (struct telegram *instance) { /* {{{ Visualize key */ //char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN}; -void do_visualize_key (peer_id_t id) { +void do_visualize_key (struct binlog *bl, peer_id_t id) { assert (get_peer_type (id) == PEER_ENCR_CHAT); - peer_t *P = user_chat_get (id); + peer_t *P = user_chat_get (bl, id); assert (P); if (P->encr_chat.state != sc_ok) { logprintf ("Chat is not initialized yet\n"); @@ -2895,7 +2856,7 @@ void do_get_suggested (struct telegram *instance) { clear_packet (mtp); out_int (mtp, CODE_contacts_get_suggested); out_int (mtp, 100); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_suggested_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_suggested_methods, 0); } /* }}} */ @@ -2913,7 +2874,7 @@ void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_ out_int (mtp, get_peer_id (chat_id)); assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (mtp->bl, id); if (U && U->user.access_hash) { out_int (mtp, CODE_input_user_foreign); out_int (mtp, get_peer_id (id)); @@ -2923,7 +2884,7 @@ void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_ out_int (mtp, get_peer_id (id)); } out_int (mtp, limit); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); } void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id) { @@ -2934,7 +2895,7 @@ void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_i out_int (mtp, get_peer_id (chat_id)); assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (mtp->bl, id); if (U && U->user.access_hash) { out_int (mtp, CODE_input_user_foreign); out_int (mtp, get_peer_id (id)); @@ -2943,16 +2904,17 @@ void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_i out_int (mtp, CODE_input_user_contact); out_int (mtp, get_peer_id (id)); } - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); } /* }}} */ /* {{{ Create secret chat */ -char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); +char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); void do_create_secret_chat (struct telegram *instance, peer_id_t id) { + struct mtproto_connection *mtp = instance->connection; assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (mtp->bl, id); if (!U) { logprintf ("Can not create chat with unknown user\n"); return; @@ -2970,7 +2932,7 @@ struct query_methods create_group_chat_methods = { void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic) { struct mtproto_connection *mtp = instance->connection; assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (id); + peer_t *U = user_chat_get (mtp->bl, id); if (!U) { logprintf ("Can not create chat with unknown user\n"); return; @@ -2988,7 +2950,7 @@ void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_t out_int (mtp, get_peer_id (id)); } out_string (mtp, chat_topic); - send_query (telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &create_group_chat_methods, 0); + send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &create_group_chat_methods, 0); } /* }}} */ @@ -3017,7 +2979,7 @@ void do_delete_msg (struct telegram *instance, long long id) { out_int (mtp, CODE_vector); out_int (mtp, 1); out_int (mtp, id); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &delete_msg_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &delete_msg_methods, 0); } /* }}} */ @@ -3045,7 +3007,7 @@ void do_restore_msg (struct telegram *instance, long long id) { out_int (mtp, CODE_vector); out_int (mtp, 1); out_int (mtp, id); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &restore_msg_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &restore_msg_methods, 0); } /* }}} */ int update_status_on_answer (struct query *q UU) { @@ -3065,7 +3027,7 @@ void do_update_status (struct telegram *instance, int online UU) { clear_packet (mtp); out_int (mtp, CODE_account_update_status); out_int (mtp, online ? CODE_bool_false : CODE_bool_true); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); } int update_typing_on_answer (struct query *q UU) { @@ -3085,6 +3047,14 @@ void do_update_typing (struct telegram *instance, peer_id_t id) { out_int (mtp, CODE_messages_set_typing); out_peer_id (mtp, id); out_int (mtp, CODE_bool_true); - send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_typing_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_typing_methods, 0); +} + +int telegram_has_output (struct telegram *instance) +{ + if (instance->session_state == STATE_READY) { + return tree_count_query (instance->queries_tree) > 0; + } + return instance->connection->queries_num > 0; } diff --git a/queries.h b/queries.h index 8587d67..30435d6 100644 --- a/queries.h +++ b/queries.h @@ -22,11 +22,12 @@ #pragma once #include "structures.h" -// forward declare telegram struct telegram; struct encr_video; struct document; struct secret_chat; +struct tree_query; +struct tree_timer; #define QUERY_ACK_RECEIVED 1 @@ -57,16 +58,16 @@ struct query { }; -struct query *send_query (struct dc *DC, int len, void *data, struct query_methods *methods, void *extra); -void query_ack (long long id); -void query_error (long long id); -void query_result (long long id); -void query_restart (long long id); +struct query *send_query (struct telegram *instance, struct dc *DC, int len, void *data, struct query_methods *methods, void *extra); +void query_ack (struct telegram *instance, long long id); +void query_error (struct telegram *instance, long long id); +void query_result (struct telegram *instance, long long id); +void query_restart (struct telegram *instance, long long id); -void insert_event_timer (struct event_timer *ev); -void remove_event_timer (struct event_timer *ev); -double next_timer_in (void); -void work_timers (void); +void insert_event_timer (struct telegram *instance, struct event_timer *ev); +void remove_event_timer (struct telegram *instance, struct event_timer *ev); +double next_timer_in (struct telegram *instance); +void work_timers (struct telegram *instance); extern struct query_methods help_get_config_methods; @@ -113,8 +114,8 @@ void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, i void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E); void do_get_difference (struct telegram*); void do_mark_read (struct telegram *instance, peer_id_t id); -void do_visualize_key (peer_id_t id); -void do_create_keys_end (struct secret_chat *U); +void do_visualize_key (struct binlog *bl, peer_id_t id); +void do_create_keys_end (struct telegram *, struct secret_chat *U); void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit); void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id); @@ -128,6 +129,8 @@ void do_restore_msg (struct telegram *instance, long long id); int get_dh_config_on_answer (struct query *q); void fetch_dc_option (struct telegram *instance); +void free_queries (struct telegram *instance); +void free_timers (struct telegram *instance); #endif const char *get_last_err(); diff --git a/structures.c b/structures.c index 8b36ab1..d887814 100644 --- a/structures.c +++ b/structures.c @@ -45,24 +45,8 @@ struct message message_list = { .prev_use = &message_list }; -struct tree_peer *peer_tree; -struct tree_peer_by_name *peer_by_name_tree; -struct tree_message *message_tree; -struct tree_message *message_unsent_tree; - -int users_allocated; -int chats_allocated; -int messages_allocated; -int peer_num; -int encr_chats_allocated; -int geo_chats_allocated; - -int our_id; int verbosity; -peer_t *Peers[MAX_PEER_NUM]; - - void fetch_skip_photo (struct mtproto_connection *mtp); #define code_assert(x) if (!(x)) { logprintf ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } @@ -141,7 +125,7 @@ int fetch_skip_user_status (struct mtproto_connection *mtp) { return 0; } -char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) { +char *create_print_name (struct binlog *bl, 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; static char buf[10000]; @@ -163,7 +147,7 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha int fl = strlen (s); int cc = 0; while (1) { - peer_t *P = peer_lookup_name (s); + peer_t *P = peer_lookup_name (bl, s); if (!P || !cmp_peer_id (P->id, id)) { break; } @@ -216,6 +200,8 @@ int user_get_alias(peer_t *user, char *buffer, int maxlen) } int fetch_user (struct mtproto_connection *mtp, struct user *U) { + struct telegram *instance = mtp->instance; + unsigned x = fetch_int (mtp); code_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 = MK_USER (fetch_int (mtp)); @@ -224,8 +210,8 @@ int fetch_user (struct mtproto_connection *mtp, struct user *U) { } if (x == CODE_user_self) { - assert (!our_id || (our_id == get_peer_id (U->id))); - if (!our_id) { + assert (!instance->our_id || (instance->our_id == get_peer_id (U->id))); + if (!instance->our_id) { bl_do_set_our_id (mtp->bl, mtp, get_peer_id (U->id)); // TODO: What to do here? //write_auth_file (); @@ -306,6 +292,8 @@ int fetch_user (struct mtproto_connection *mtp, struct user *U) { } void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U) { + struct telegram *instance = mtp->instance; + unsigned x = fetch_int (mtp); assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); U->id = MK_ENCR_CHAT (fetch_int (mtp)); @@ -322,7 +310,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U bl_do_encr_chat_delete (mtp->bl, mtp, U); // TODO: properly - write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); return; } @@ -332,7 +320,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U long long access_hash = fetch_long (mtp); int date = fetch_int (mtp); int admin_id = fetch_int (mtp); - int user_id = fetch_int (mtp) + admin_id - our_id; + int user_id = fetch_int (mtp) + admin_id - instance->our_id; if (x == CODE_encrypted_chat_waiting) { logprintf ("Unknown chat in waiting state. May be we forgot something...\n"); @@ -371,7 +359,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } bl_do_encr_chat_requested (mtp->bl, mtp, U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); - write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); } else { bl_do_set_encr_chat_access_hash (mtp->bl, mtp, U, fetch_long (mtp)); bl_do_set_encr_chat_date (mtp->bl, mtp, U, fetch_int (mtp)); @@ -379,13 +367,13 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U logprintf ("Changed admin in secret chat. WTF?\n"); return; } - if (U->user_id != U->admin_id + fetch_int (mtp) - our_id) { + if (U->user_id != U->admin_id + fetch_int (mtp) - instance->our_id) { logprintf ("Changed partner in secret chat. WTF?\n"); return; } if (x == CODE_encrypted_chat_waiting) { bl_do_set_encr_chat_state (mtp->bl, mtp, U, sc_waiting); - write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); return; // We needed only access hash from here } @@ -417,7 +405,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } bl_do_encr_chat_accepted (mtp->bl, mtp, U, (void *)g_key, (void *)nonce, fetch_long (mtp)); } - write_secret_chat_file ("/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); } void fetch_notify_settings (struct mtproto_connection *mtp); @@ -870,12 +858,14 @@ void fetch_skip_message_action (struct mtproto_connection *mtp) { } void fetch_message_short (struct mtproto_connection *mtp, struct message *M) { + struct telegram *instance = mtp->instance; + int new = !(M->flags & FLAG_CREATED); if (new) { int id = fetch_int (mtp); int from_id = fetch_int (mtp); - int to_id = our_id; + int to_id = instance->our_id; int l = prefetch_strlen (mtp); char *s = fetch_str (mtp, l); @@ -1405,6 +1395,8 @@ int decrypt_encrypted_message (struct secret_chat *E) { } void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) { + struct binlog *bl = mtp->bl; + unsigned x = fetch_int (mtp); assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service); unsigned sx = x; @@ -1414,7 +1406,7 @@ void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) peer_id_t chat = MK_ENCR_CHAT (to_id); int date = fetch_int (mtp); - peer_t *P = user_chat_get (chat); + peer_t *P = user_chat_get (bl, chat); if (!P) { logprintf ("Encrypted message to unknown chat. Dropping\n"); M->flags |= FLAG_MESSAGE_EMPTY; @@ -1530,17 +1522,19 @@ static int id_cmp (struct message *M1, struct message *M2) { } struct user *fetch_alloc_user (struct mtproto_connection *mtp) { + struct binlog *bl = mtp->instance->bl; + logprintf("fetch_alloc_user()\n"); int data[2]; prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (MK_USER (data[1])); + peer_t *U = user_chat_get (bl, MK_USER (data[1])); if (!U) { - users_allocated ++; + bl->users_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_USER (data[1]); - peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = U; + bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = U; fetch_user (mtp, &U->user); event_update_user_status(mtp->connection->instance, U); event_peer_allocated(mtp->connection->instance, U); @@ -1552,59 +1546,62 @@ struct user *fetch_alloc_user (struct mtproto_connection *mtp) { } struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp) { + struct binlog *bl = mtp->bl; + logprintf("fetch_alloc_encrypted_chat()\n"); int data[2]; prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); + peer_t *U = user_chat_get (bl, MK_ENCR_CHAT (data[1])); if (!U) { U = talloc0 (sizeof (*U)); U->id = MK_ENCR_CHAT (data[1]); - encr_chats_allocated ++; - peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = U; + bl->encr_chats_allocated ++; + bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = U; } fetch_encrypted_chat (mtp, &U->encr_chat); event_peer_allocated(mtp->connection->instance, U); return &U->encr_chat; } -void insert_encrypted_chat (peer_t *P) { - encr_chats_allocated ++; - peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = P; +void insert_encrypted_chat (struct binlog *bl, peer_t *P) { + bl->encr_chats_allocated ++; + bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = P; } -void insert_user (peer_t *P) { - users_allocated ++; - peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = P; +void insert_user (struct binlog *bl, peer_t *P) { + bl->users_allocated ++; + bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = P; } -void insert_chat (peer_t *P) { - chats_allocated ++; - peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = P; +void insert_chat (struct binlog *bl, peer_t *P) { + bl->chats_allocated ++; + bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = P; } struct user *fetch_alloc_user_full (struct mtproto_connection *mtp) { + struct binlog *bl = mtp->bl; int data[3]; prefetch_data (mtp, data, 12); - peer_t *U = user_chat_get (MK_USER (data[2])); + peer_t *U = user_chat_get (bl, MK_USER (data[2])); if (U) { fetch_user_full (mtp, &U->user); return &U->user; } else { - users_allocated ++; + bl->users_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_USER (data[2]); - peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); fetch_user_full (mtp, &U->user); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = U; + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = U; return &U->user; } } @@ -1735,33 +1732,34 @@ void message_add_use (struct message *M) { } void message_add_peer (struct message *M) { + struct binlog *bl = M->instance->bl; peer_id_t id; - if (!cmp_peer_id (M->to_id, MK_USER (our_id))) { + if (!cmp_peer_id (M->to_id, MK_USER (M->instance->our_id))) { id = M->from_id; } else { id = M->to_id; } - peer_t *P = user_chat_get (id); + peer_t *P = user_chat_get (bl, id); if (!P) { P = talloc0 (sizeof (*P)); P->id = id; switch (get_peer_type (id)) { case PEER_USER: - users_allocated ++; + bl->users_allocated ++; break; case PEER_CHAT: - chats_allocated ++; + bl->chats_allocated ++; break; case PEER_GEO_CHAT: - geo_chats_allocated ++; + bl->geo_chats_allocated ++; break; case PEER_ENCR_CHAT: - encr_chats_allocated ++; + bl->encr_chats_allocated ++; break; } - peer_tree = tree_insert_peer (peer_tree, P, lrand48 ()); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = P; + bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = P; } if (!P->last) { P->last = M; @@ -1794,12 +1792,12 @@ void message_add_peer (struct message *M) { void message_del_peer (struct message *M) { peer_id_t id; - if (!cmp_peer_id (M->to_id, MK_USER (our_id))) { + if (!cmp_peer_id (M->to_id, MK_USER (M->instance->our_id))) { id = M->from_id; } else { id = M->to_id; } - peer_t *P = user_chat_get (id); + peer_t *P = user_chat_get (M->instance->bl, id); if (M->prev) { M->prev->next = M->next; } @@ -1812,19 +1810,20 @@ void message_del_peer (struct message *M) { } struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct telegram *instance) { + struct binlog *bl = mtp->bl; + logprintf("fetch_alloc_message()\n"); int data[2]; prefetch_data (mtp, data, 8); - struct message *M = message_get (data[1]); + struct message *M = message_get (bl, data[1]); if (!M) { M = talloc0 (sizeof (*M)); M->id = data[1]; M->instance = instance; message_insert_tree (M); - messages_allocated ++; + mtp->bl->messages_allocated ++; fetch_message (mtp, M); - event_update_new_message (instance, M); return M; } M->instance = instance; @@ -1837,8 +1836,8 @@ struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct struct message *M = talloc (sizeof (*M)); M->instance = instance; fetch_geo_message (mtp, M); - struct message *M1 = tree_lookup_message (message_tree, M); - messages_allocated ++; + struct message *M1 = tree_lookup_message (mtp->bl->message_tree, M); + mtp->bl->messages_allocated ++; if (M1) { message_del_use (M1); message_del_peer (M1); @@ -1847,30 +1846,31 @@ struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct tfree (M, sizeof (*M)); message_add_use (M1); message_add_peer (M1); - messages_allocated --; + mtp->bl->messages_allocated --; return M1; } else { message_add_use (M); message_add_peer (M); - message_tree = tree_insert_message (message_tree, M, lrand48 ()); + mtp->bl->message_tree = tree_insert_message (mtp->bl->message_tree, M, lrand48 ()); return M; } } struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, struct telegram *instance) { + struct binlog *bl = mtp->bl; logprintf("fetch_alloc_encrypted_message()\n"); int data[3]; prefetch_data (mtp, data, 12); - struct message *M = message_get (*(long long *)(data + 1)); + struct message *M = message_get (bl, *(long long *)(data + 1)); M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); M->id = *(long long *)(data + 1); message_insert_tree (M); - messages_allocated ++; - assert (message_get (M->id) == M); + mtp->bl->messages_allocated ++; + assert (message_get (bl, M->id) == M); logprintf ("id = %lld\n", M->id); } fetch_encrypted_message (mtp, M); @@ -1879,51 +1879,54 @@ struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, struct telegram *instance) { + struct binlog *bl = mtp->bl; int data[1]; prefetch_data (mtp, data, 4); - struct message *M = message_get (data[0]); + struct message *M = message_get (bl, data[0]); M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); M->id = data[0]; message_insert_tree (M); - messages_allocated ++; + mtp->bl->messages_allocated ++; } fetch_message_short (mtp, M); return M; } struct message *fetch_alloc_message_short_chat (struct mtproto_connection *mtp, struct telegram *instance) { + struct binlog *bl = mtp->bl; int data[1]; prefetch_data (mtp, data, 4); - struct message *M = message_get (data[0]); + struct message *M = message_get (bl, data[0]); M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); M->id = data[0]; message_insert_tree (M); - messages_allocated ++; + mtp->bl->messages_allocated ++; } fetch_message_short_chat (mtp, M); return M; } struct chat *fetch_alloc_chat (struct mtproto_connection *mtp) { + struct binlog *bl = mtp->bl; logprintf("fetch_alloc_chat()\n"); int data[2]; prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (MK_CHAT (data[1])); + peer_t *U = user_chat_get (bl, MK_CHAT (data[1])); logprintf("id %d\n", U->id.id); logprintf("type %d\n", U->id.type); if (!U) { - chats_allocated ++; + bl->chats_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[1]); - peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = U; + bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = U; } fetch_chat (mtp, &U->chat); event_peer_allocated(mtp->connection->instance, U); @@ -1931,20 +1934,21 @@ struct chat *fetch_alloc_chat (struct mtproto_connection *mtp) { } struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp) { + struct binlog *bl = mtp->bl; int data[3]; prefetch_data (mtp, data, 12); - peer_t *U = user_chat_get (MK_CHAT (data[2])); + peer_t *U = user_chat_get (bl, MK_CHAT (data[2])); if (U) { fetch_chat_full (mtp, &U->chat); return &U->chat; } else { - chats_allocated ++; + bl->chats_allocated ++; U = talloc0 (sizeof (*U)); U->id = MK_CHAT (data[2]); - peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); + bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); fetch_chat_full (mtp, &U->chat); - assert (peer_num < MAX_PEER_NUM); - Peers[peer_num ++] = U; + assert (bl->peer_num < MAX_PEER_NUM); + bl->Peers[bl->peer_num ++] = U; return &U->chat; } } @@ -1954,47 +1958,50 @@ void free_chat (struct chat *U) { if (U->print_title) { tfree_str (U->print_title); } } -int print_stat (char *s, int len) { +int print_stat (struct binlog *bl, char *s, int len) { return tsnprintf (s, len, - "users_allocated\t%d\n" - "chats_allocated\t%d\n" - "secret_chats_allocated\t%d\n" - "peer_num\t%d\n" - "messages_allocated\t%d\n", - users_allocated, - chats_allocated, - encr_chats_allocated, - peer_num, - messages_allocated - ); + "bl->users_allocated\t%d\n" + "bl->chats_allocated\t%d\n" + "secret_bl->chats_allocated\t%d\n" + "bl->peer_num\t%d\n" + "bl->messages_allocated\t%d\n", + bl->users_allocated, + bl->chats_allocated, + bl->encr_chats_allocated, + bl->peer_num, + bl->messages_allocated + ); } -peer_t *user_chat_get (peer_id_t id) { +peer_t *user_chat_get (struct binlog *bl, peer_id_t id) { static peer_t U; U.id = id; - return tree_lookup_peer (peer_tree, &U); + return tree_lookup_peer (bl->peer_tree, &U); } -struct message *message_get (long long id) { +struct message *message_get (struct binlog *bl, long long id) { struct message M; M.id = id; - return tree_lookup_message (message_tree, &M); + return tree_lookup_message (bl->message_tree, &M); } void update_message_id (struct message *M, long long id) { - message_tree = tree_delete_message (message_tree, M); + struct binlog *bl = M->instance->bl; + bl->message_tree = tree_delete_message (bl->message_tree, M); M->id = id; - message_tree = tree_insert_message (message_tree, M, lrand48 ()); + bl->message_tree = tree_insert_message (bl->message_tree, M, lrand48 ()); } void message_insert_tree (struct message *M) { + struct binlog *bl = M->instance->bl; assert (M->id); - message_tree = tree_insert_message (message_tree, M, lrand48 ()); + bl->message_tree = tree_insert_message (bl->message_tree, M, lrand48 ()); } void message_remove_tree (struct message *M) { + struct binlog *bl = M->instance->bl; assert (M->id); - message_tree = tree_delete_message (message_tree, M); + bl->message_tree = tree_delete_message (bl->message_tree, M); } void message_insert (struct message *M) { @@ -2003,11 +2010,13 @@ void message_insert (struct message *M) { } void message_insert_unsent (struct message *M) { - message_unsent_tree = tree_insert_message (message_unsent_tree, M, lrand48 ()); + struct binlog *bl = M->instance->bl; + bl->message_unsent_tree = tree_insert_message (bl->message_unsent_tree, M, lrand48 ()); } void message_remove_unsent (struct message *M) { - message_unsent_tree = tree_delete_message (message_unsent_tree, M); + struct binlog *bl = M->instance->bl; + bl->message_unsent_tree = tree_delete_message (bl->message_unsent_tree, M); } void __send_msg (struct message *M) { @@ -2018,25 +2027,54 @@ void __send_msg (struct message *M) { do_send_msg (M->instance, M); } -void send_all_unsent (void ) { - tree_act_message (message_unsent_tree, __send_msg); +void send_all_unsent (struct binlog *bl) { + tree_act_message (bl->message_unsent_tree, __send_msg); } -void peer_insert_name (peer_t *P) { +void peer_insert_name (struct binlog *bl, peer_t *P) { //if (!P->print_name || !strlen (P->print_name)) { return; } //logprintf ("+%s\n", P->print_name); - peer_by_name_tree = tree_insert_peer_by_name (peer_by_name_tree, P, lrand48 ()); + bl->peer_by_name_tree = tree_insert_peer_by_name (bl->peer_by_name_tree, P, lrand48 ()); } -void peer_delete_name (peer_t *P) { +void peer_delete_name (struct binlog *bl, peer_t *P) { //if (!P->print_name || !strlen (P->print_name)) { return; } //logprintf ("-%s\n", P->print_name); - peer_by_name_tree = tree_delete_peer_by_name (peer_by_name_tree, P); + bl->peer_by_name_tree = tree_delete_peer_by_name (bl->peer_by_name_tree, P); } -peer_t *peer_lookup_name (const char *s) { +peer_t *peer_lookup_name (struct binlog *bl, const char *s) { static peer_t P; P.print_name = (void *)s; - peer_t *R = tree_lookup_peer_by_name (peer_by_name_tree, &P); + peer_t *R = tree_lookup_peer_by_name (bl->peer_by_name_tree, &P); return R; } + +void free_messages (struct binlog *bl) +{ + while (bl->message_tree) { + struct message *M = tree_get_min_message (bl->message_tree); + assert (M); + logprintf ("freeing message: %lld\n", M->id); + bl->message_tree = tree_delete_message (bl->message_tree, M); + bl->messages_allocated --; + free_message (M); + } +} + +void free_peers (struct binlog *bl) +{ + while (bl->peer_by_name_tree) { + bl->peer_by_name_tree = tree_delete_peer_by_name (bl->peer_by_name_tree, + tree_get_min_peer_by_name(bl->peer_by_name_tree)); + } + while (bl->peer_tree) { + union peer *P = tree_get_min_peer (bl->peer_tree); + assert (P); + bl->peer_tree = tree_delete_peer (bl->peer_tree, P); + bl->peer_num --; + free (P->print_name); + tfree (P, sizeof (union peer)); + } +} + diff --git a/structures.h b/structures.h index 616f417..ff68ad1 100644 --- a/structures.h +++ b/structures.h @@ -22,6 +22,7 @@ // forward-declrataions struct mtproto_connection; +struct binlog; typedef struct { int type; int id; } peer_id_t; #include @@ -44,6 +45,7 @@ typedef struct { int type; int id; } peer_id_t; #define FLAG_ENCRYPTED 4096 #define FLAG_PENDING 8192 + struct file_location { int dc; long long volume; @@ -359,29 +361,29 @@ void message_insert_tree (struct message *M); void free_user (struct user *U); void free_chat (struct chat *U); -char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); +char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); -int print_stat (char *s, int len); -peer_t *user_chat_get (peer_id_t id); -struct message *message_get (long long id); +int print_stat (struct binlog *bl, char *s, int len); +peer_t *user_chat_get (struct binlog *bl, peer_id_t id); +struct message *message_get (struct binlog *bl, long long id); void update_message_id (struct message *M, long long id); void message_insert (struct message *M); void fetch_photo (struct mtproto_connection *mtp, struct photo *P); -void insert_encrypted_chat (peer_t *P); -void insert_user (peer_t *P); -void insert_chat (peer_t *P); +void insert_encrypted_chat (struct binlog *bl, peer_t *P); +void insert_user (struct binlog *bl, peer_t *P); +void insert_chat (struct binlog *bl, peer_t *P); void free_photo (struct photo *P); void message_insert_unsent (struct message *M); void message_remove_unsent (struct message *M); -void send_all_unsent (void); +void send_all_unsent (struct binlog *bl); void message_remove_tree (struct message *M); void message_add_peer (struct message *M); void message_del_peer (struct message *M); void free_message (struct message *M); void message_del_use (struct message *M); -void peer_insert_name (peer_t *P); -void peer_delete_name (peer_t *P); -peer_t *peer_lookup_name (const char *s); +void peer_insert_name (struct binlog *bl, peer_t *P); +void peer_delete_name (struct binlog *bl, peer_t *P); +peer_t *peer_lookup_name (struct binlog *bl, const char *s); int user_get_alias(peer_t *user, char *buffer, int maxlen); diff --git a/telegram.h b/telegram.h index f1b85b9..a5c3468 100644 --- a/telegram.h +++ b/telegram.h @@ -8,6 +8,7 @@ #ifndef __TELEGRAM_H__ #define __TELEGRAM_H__ +#define MAX_PACKED_SIZE (1 << 24) #define MAX_DC_NUM 9 #define MAX_PEER_NUM 100000 @@ -18,12 +19,17 @@ #include #include "glib.h" #include "loop.h" -//#include "mtproto-client.h" +#include "tree.h" +#include "queries.h" +#include // forward declarations struct message; struct protocol_state; struct authorization_state; +struct tree_query; +struct tree_timer; + /* * telegram states @@ -65,11 +71,15 @@ struct authorization_state; // Ready for sending and receiving messages #define STATE_READY 22 +struct tree_peer; +struct tree_peer_by_name; +struct tree_message; + +#define BINLOG_BUFFER_SIZE (1 << 20) + /** * Binary log */ - -#define BINLOG_BUFFER_SIZE (1 << 20) struct binlog { int binlog_buffer[BINLOG_BUFFER_SIZE]; int *rptr; @@ -81,6 +91,21 @@ struct binlog { long long binlog_pos; int s[1000]; + + // + struct tree_peer *peer_tree; + struct tree_peer_by_name *peer_by_name_tree; + struct tree_message *message_tree; + struct tree_message *message_unsent_tree; + + int users_allocated; + int chats_allocated; + int messages_allocated; + int peer_num; + int encr_chats_allocated; + int geo_chats_allocated; + + peer_t *Peers[MAX_PEER_NUM]; }; struct telegram; @@ -105,13 +130,13 @@ struct telegram_config { * and port by calling telegram_set_proxy. This is useful for tunelling * the connection through a proxy server. */ - void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port); + void (*proxy_request_cb) (struct telegram *instance, const char *ip, int port); /** * A callback function that is called once the proxy connection is no longer * needed. This is useful for freeing all used resources. */ - void (*proxy_close_cb)(struct telegram *instance, int fd); + void (*proxy_close_cb) (struct telegram *instance, int fd); /** * A callback function that is called when a phone registration is required. @@ -143,13 +168,13 @@ struct telegram_config { * A callback function that is called when a new message was allocated. This is useful * for adding new messages to the GUI. */ - void (*on_msg_handler)(struct telegram *instance, struct message *M); + void (*on_msg_handler) (struct telegram *instance, struct message *M); /** * A callback function that is called when a new peer was allocated. This is useful * for populating the GUI with new peers. */ - void (*on_peer_allocated_handler)(struct telegram *instance, void *peer); + void (*on_peer_allocated_handler) (struct telegram *instance, void *peer); /** * A callback function that is called when a user's status has changed @@ -202,6 +227,40 @@ struct telegram { // valid in its context char *phone_code_hash; + int unread_messages; + long long cur_uploading_bytes; + long long cur_uploaded_bytes; + long long cur_downloading_bytes; + long long cur_downloaded_bytes; + int our_id; + struct user User; + BN_CTX *ctx; + int encr_root; + unsigned char *encr_prime; + int encr_param_version; + int max_chat_size; + int max_bcast_size; + int want_dc_num; + int new_dc_num; + int out_message_num; + char *suser; + int nearest_dc_num; + int packed_buffer[MAX_PACKED_SIZE / 4]; + struct tree_query *queries_tree; + struct tree_timer *timer_tree; + char *export_auth_str; + int export_auth_str_len; + char g_a[256]; + // do_get_difference + int get_difference_active; + struct message *ML[MSG_STORE_SIZE]; + + int cs; + struct mtproto_connection *Cs[100]; + + /* + * additional user data + */ void *extra; }; From b90c9453dae671892958bc06f9ce71a07bcc6c73 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 21:57:35 +0200 Subject: [PATCH 363/465] Free memory and close connections on disconnect --- mtproto-client.c | 37 ++++++++++++++----------- net.h | 4 +++ purple-plugin/telegram-purple.c | 48 ++++++++++++++++----------------- purple-plugin/telegram-purple.h | 5 ++++ queries.c | 23 ++++++++++++++++ structures.h | 3 +++ telegram.c | 41 +++++++++++++++++++++++----- telegram.h | 2 +- 8 files changed, 116 insertions(+), 47 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 411ec79..e65a05c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1839,7 +1839,7 @@ void mtproto_connect(struct mtproto_connection *c) c->connection->methods->ready(c->connection); // Don't ping TODO: Really? Timeout callback functions of libpurple - //start_ping_timer (c->connection); + start_ping_timer (c->connection); } /** @@ -1849,29 +1849,32 @@ void mtproto_close(struct mtproto_connection *mtp) { logprintf ("closing mtproto_connection...\n"); mtp->destroy = 1; - // TODO: Use Pings? - // stop_ping_timer (c->connection); - - // TODO: Set destruction timeout? - // add_destruction_timer (c, 5000) - /* - Timout: - - alle queries und acks löschen? - - was passiert wenn eine antwort auf eine query - in einer neuen instanz ankommt? - */ + // send all pending acks on this connection so the server won't + // resend messages. We might not be able to send the acknowledgements later + // in case the session is switched and this DC is not reachable anymore + send_all_acks (mtp->connection->session); + + // remove all ping timer that point to this connection + stop_ping_timer (mtp->connection); } +/** + * Close the connection and + */ void mtproto_destroy (struct mtproto_connection *self) { logprintf("destroying mtproto_connection: %p\n", self); - // TODO: Remove all pending timers, queries, acks // TODO: Call destruction callback fd_close_connection(self->connection); tfree(self->connection, sizeof(struct connection)); + tfree(self, sizeof(struct mtproto_connection)); } -void mtproto_free_closed () { + +/** + * Free all destroyed connections + */ +void mtproto_free_closed (struct telegram *tg) { int i; for (i = 0; i < 100; i++) { if (tg->Cs[i] == NULL) continue; @@ -1879,9 +1882,13 @@ void mtproto_free_closed () { logprintf ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", i, c->c_state, c->destroy, c->queries_num); if (c->destroy == 0) continue; - if (c->queries_num > 0) continue; + if (c->queries_num > 0) { + logprintf ("still pending queries left, skipping connection...\n"); + continue; + } mtproto_destroy (c); tg->Cs[i] = NULL; + tg->connection = NULL; } } diff --git a/net.h b/net.h index 3152fe6..b7a4763 100644 --- a/net.h +++ b/net.h @@ -159,4 +159,8 @@ struct connection *fd_create_connection (struct dc *DC, int fd, struct telegram struct connection_methods *methods, struct mtproto_connection *mtp); void fd_close_connection(struct connection *c); +void start_ping_timer (struct connection *c); +void stop_ping_timer (struct connection *c); +int send_all_acks (struct session *S); + #endif diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 7fbd13c..ae140a7 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -240,6 +240,19 @@ void client_registration_canceled (gpointer data) // TODO: disconnect and exit } +gboolean queries_timerfunc (gpointer data) { + logprintf ("queries_timerfunc()\n"); + telegram_conn *conn = data; + work_timers (conn->tg); + + if (conn->updated) { + logprintf ("State updated, storing current session...\n"); + conn->updated = 0; + telegram_store_session (conn->tg); + } + return 1; +} + void telegram_on_client_registration (struct telegram *instance) { purple_debug_info(PLUGIN_ID, "Client is not registered, registering...\n"); @@ -293,6 +306,7 @@ void telegram_on_ready (struct telegram *instance) do_get_difference(instance); tgprpl_has_output(instance); + conn->timer = purple_timeout_add (4000, queries_timerfunc, conn); } void telegram_on_disconnected (struct telegram *tg) @@ -313,7 +327,7 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa telegram_conn *conn = tg->extra; if (fd == -1) { logprintf("purple_proxy_connect failed: %s\n", error_message); - telegram_free(tg); + telegram_destroy(tg); return; } @@ -340,20 +354,6 @@ struct telegram_config tgconf = { on_user_typing }; -gboolean queries_timerfunc (gpointer data) { - logprintf ("queries_timerfunc()\n"); - telegram_conn *conn = data; - // work_timers (); - // TODO: work pending timers - - if (conn->updated) { - logprintf ("State updated, storing current session...\n"); - conn->updated = 0; - telegram_store_session (conn->tg); - } - return 1; -} - /** * This must be implemented. @@ -382,7 +382,15 @@ static void tgprpl_login(PurpleAccount * acct) purple_connection_set_state (conn->gc, PURPLE_CONNECTING); telegram_network_connect (tg); - purple_timeout_add (2000, queries_timerfunc, conn); +/** + * This must be implemented. + */ +static void tgprpl_close(PurpleConnection * gc) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_close()\n"); + telegram_conn *conn = purple_connection_get_protocol_data(gc); + purple_timeout_remove(conn->timer); + telegram_destroy(conn->tg); } void message_allocated_handler(struct telegram *tg, struct message *M) @@ -557,14 +565,6 @@ void peer_allocated_handler(struct telegram *tg, void *usr) } } -/** - * This must be implemented. - */ -static void tgprpl_close(PurpleConnection * gc) -{ - purple_debug_info(PLUGIN_ID, "tgprpl_close()\n"); -} - /** * This PRPL function should return a positive value on success. * If the message is too big to be sent, return -E2BIG. If diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 761377c..6213264 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -51,6 +51,11 @@ typedef struct { * Read handler returned by purple_input_add */ guint rh; + /** + * The used purple timeout handler + */ + guint timer; + } telegram_conn; #endif diff --git a/queries.c b/queries.c index 63e0a4f..2875870 100644 --- a/queries.c +++ b/queries.c @@ -278,6 +278,29 @@ void work_timers (struct telegram *instance) { } } +void free_timers (struct telegram *instance) +{ + while (instance->timer_tree) { + struct event_timer *ev = tree_get_min_timer (instance->timer_tree); + assert (ev); + logprintf ("freeing event timer with timeout: %d\n", ev->timeout); + remove_event_timer (instance, ev); + tfree (ev, sizeof(struct event_timer)); + } +} + +void free_queries (struct telegram *instance) +{ + while (instance->queries_tree) { + struct query *q = tree_get_min_query (instance->queries_tree); + assert (q); + logprintf ("freeing query with msg_id %d and len\n", q->msg_id, q->data_len); + instance->queries_tree = tree_delete_query (instance->queries_tree, q); + tfree (q->data, 4 * q->data_len); + tfree (q, sizeof (struct query)); + } +} + //extern struct dc *DC_list[]; //extern struct dc *DC_working; diff --git a/structures.h b/structures.h index ff68ad1..00bef50 100644 --- a/structures.h +++ b/structures.h @@ -417,4 +417,7 @@ static inline int cmp_peer_id (peer_id_t a, peer_id_t b) { return memcmp (&a, &b, sizeof (a)); } +void free_messages (struct binlog *bl); +void free_peers (struct binlog *bl); #endif + diff --git a/telegram.c b/telegram.c index 40332ff..56cb768 100755 --- a/telegram.c +++ b/telegram.c @@ -96,7 +96,7 @@ void telegram_change_state (struct telegram *instance, int state, void *data) } logprintf("telegram errored: %s\n", err); - // close the connection + // mark the connection for closing mtproto_close (instance->connection); } break; @@ -195,18 +195,45 @@ struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_ return this; } -void telegram_free(struct telegram *this) +void free_bl (struct binlog *bl); +void telegram_destroy(struct telegram *this) { + // close all open connections + int i = 0; + for (; i < 100; i++) { + if (this->Cs[i] != NULL && !this->Cs[i]->destroy) { + mtproto_close (this->Cs[i]); + } + } + free_queries (this); + free_timers (this); + mtproto_free_closed (this); + + free_bl (this->bl); + g_free(this->login); g_free(this->config_path); g_free(this->download_path); g_free(this->auth_path); g_free(this->state_path); g_free(this->secret_path); - tfree(this->bl, sizeof(struct binlog)); + + // TODO: BN_CTX *ctx + free (this->phone_code_hash); + free (this->suser); + free (this->export_auth_str); + //tfree (this->ML, sizeof(struct message) * MSG_STORE_SIZE); tfree(this, sizeof(struct telegram)); } +void free_bl (struct binlog *bl) +{ + // TODO: rptr, wptr + free_peers (bl); + free_messages (bl); + tfree (bl, sizeof (struct binlog)); +} + void assert_file_usable(const char *file) { logprintf ("assert_file_usable (%s)\n", file); @@ -317,10 +344,10 @@ void on_authorized(struct mtproto_connection *c, void *data) void telegram_read_input (struct telegram *instance) { - try_read(instance->connection->connection); - mtproto_free_closed(); - // free all mtproto_connections that may have errored through - // a received query + try_read (instance->connection->connection); + + // free all mtproto_connections that may have errored + mtproto_free_closed(instance); } void telegram_set_proxy(struct telegram *instance, int fd) diff --git a/telegram.h b/telegram.h index a5c3468..52669c5 100644 --- a/telegram.h +++ b/telegram.h @@ -286,7 +286,7 @@ void telegram_store_session(struct telegram *instance); /** * Destructor */ -void telegram_free(struct telegram *instance); +void telegram_destroy(struct telegram *instance); /** * Get the currently active connection From fa457a6900b4f64e9179d14c87b5c2d2c748172d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 21:59:23 +0200 Subject: [PATCH 364/465] Clean up out-commented code --- loop.c | 10 +--------- purple-plugin/telegram-purple.c | 10 ---------- telegram.h | 26 +------------------------- 3 files changed, 2 insertions(+), 44 deletions(-) diff --git a/loop.c b/loop.c index bdeea3f..37833d2 100644 --- a/loop.c +++ b/loop.c @@ -254,14 +254,7 @@ struct protocol_state read_state_file (const char *filename) { } void write_state_file (struct protocol_state *state, const char* filename) { - /* - static int wseq; - static int wpts; - static int wqts; - static int wdate; - if (wseq >= seq && wpts >= pts && wqts >= qts && wdate >= last_date) { return; } - */ - int state_file_fd = open (filename /*get_state_filename ()*/, O_CREAT | O_RDWR, 0600); + int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600); if (state_file_fd < 0) { return; } @@ -274,7 +267,6 @@ void write_state_file (struct protocol_state *state, const char* filename) { x[5] = state->last_date; assert (write (state_file_fd, x, 24) == 24); close (state_file_fd); - //wseq = seq; wpts = pts; wqts = qts; wdate = last_date; } extern peer_t *Peers[]; diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index ae140a7..59c9a83 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -293,18 +293,9 @@ void telegram_on_ready (struct telegram *instance) tggroup = purple_group_new ("Telegram"); purple_blist_add_group (tggroup, NULL); } - - // get all current contacts - purple_debug_info(PLUGIN_ID, "Fetching all current contacts...\n"); do_update_contact_list(instance); - - purple_debug_info(PLUGIN_ID, "Fetching all current chats...\n"); do_get_dialog_list(instance); - - // get new messages - purple_debug_info(PLUGIN_ID, "Fetching new messages...\n"); do_get_difference(instance); - tgprpl_has_output(instance); conn->timer = purple_timeout_add (4000, queries_timerfunc, conn); } @@ -401,7 +392,6 @@ void message_allocated_handler(struct telegram *tg, struct message *M) // TODO: this should probably be freed again somwhere int id = get_peer_id(M->from_id); - logprintf ("id: %d\n", id); char *who = g_strdup_printf("%d", id); if (who) { logprintf ("who: %s\n", who); diff --git a/telegram.h b/telegram.h index 52669c5..c13590e 100644 --- a/telegram.h +++ b/telegram.h @@ -1,10 +1,3 @@ -/* - * libtelegram - * =========== - * - * struct telegram library based on the telegram cli application, that was originally made by vysheng (see https://github.com/vysheng/tg) - */ - #ifndef __TELEGRAM_H__ #define __TELEGRAM_H__ @@ -37,16 +30,10 @@ struct tree_timer; #define STATE_INITIALISED 0 #define STATE_DISCONNECTED 1 - -// Error #define STATE_ERROR 2 - -// intermediate authorization states already present and handled in mtproto-client.c -//#define STATE_PQ_REQUESTED 3 -//#define STATE_DH_REQUESTED 4 -//#define STATE_CDH_REQUESTED 5 #define STATE_AUTHORIZED 6 + // dc discovery #define STATE_CONFIG_REQUESTED 7 #define STATE_EXPORTING_CONFIG 8 @@ -273,19 +260,8 @@ struct telegram { */ struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_config *config); -/** - * Resume the session to - */ void telegram_restore_session(struct telegram *instance); - -/** - * Store - */ void telegram_store_session(struct telegram *instance); - -/** - * Destructor - */ void telegram_destroy(struct telegram *instance); /** From 0aa8a9de1506c7fe588529eb22961252f8ce6ac6 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 22:02:27 +0200 Subject: [PATCH 365/465] Remove "_network" from telegram connect function --- purple-plugin/telegram-purple.c | 3 ++- telegram.c | 12 ++++++------ telegram.h | 7 ++++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 59c9a83..abf13f8 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -371,7 +371,8 @@ static void tgprpl_login(PurpleAccount * acct) tg->extra = conn; purple_connection_set_state (conn->gc, PURPLE_CONNECTING); - telegram_network_connect (tg); + telegram_connect (tg); +} /** * This must be implemented. diff --git a/telegram.c b/telegram.c index 56cb768..60c22e3 100755 --- a/telegram.c +++ b/telegram.c @@ -161,9 +161,8 @@ void telegram_change_state (struct telegram *instance, int state, void *data) instance->config->proxy_close_cb (instance, instance->connection->connection->fd); // start a new connection to the demanded data center. The pointer to the - // currently working dc should have already been updated by the - // on_error function of the query - telegram_network_connect (instance); + // new dc should was already updated by the on_error function of the query + telegram_connect (instance); } break; } @@ -308,7 +307,7 @@ void on_authorized(struct mtproto_connection *c, void* data); /** * Connect to the currently active data center */ -void telegram_network_connect(struct telegram *instance) +void telegram_connect (struct telegram *instance) { logprintf ("telegram_network_connect()\n"); if (! instance->auth.DC_list) { @@ -364,8 +363,9 @@ int telegram_write_output (struct telegram *instance) return try_write(instance->connection->connection); } -int telegram_has_output (struct telegram *instance) +int telegram_authenticated (struct telegram *instance) { - return instance->connection->queries_num > 0; + return telegram_get_working_dc (instance)->auth_key_id > 0; } + diff --git a/telegram.h b/telegram.h index c13590e..7eb3c89 100644 --- a/telegram.h +++ b/telegram.h @@ -290,7 +290,7 @@ void telegram_change_state(struct telegram *instance, int state, void *data); /** * Connect to the telegram network with the given configuration */ -void telegram_network_connect(struct telegram *instance); +void telegram_connect(struct telegram *instance); int telegram_login (struct telegram *instance); @@ -397,4 +397,9 @@ void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); */ void telegram_set_proxy(struct telegram *instance, int fd); +/** + * Return wether telegram is authenticated with the currently active data center + */ +int telegram_authenticated (struct telegram *instance); + #endif From 305253b3f67c1ee2871ccba8c06c2f52fa645737 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 22:17:42 +0200 Subject: [PATCH 366/465] Add a few comments --- loop.h | 51 ++++++++++++++++++++++++--------- purple-plugin/telegram-purple.h | 8 ++++-- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/loop.h b/loop.h index 5b6a999..516b40e 100644 --- a/loop.h +++ b/loop.h @@ -17,27 +17,20 @@ Copyright Vitaly Valtman 2013 */ +#include "telegram.h" + #ifndef __LOOP_H__ #define __LOOP_H__ // forward declarations struct dc; +struct telegram; -#ifndef __TELEGRAM_H__ -struct authorization_state; -struct protocol_state; -#endif - -int loop(); -void write_secret_chat_file (const char *filename); - -struct protocol_state { - int pts; - int qts; - int seq; - int last_date; -}; +/** + * The authorization state, storing all known data centers of the telegram + * network and associated shared keys for transport encryption + */ struct authorization_state { int dc_working_num; int auth_state; @@ -45,6 +38,36 @@ struct authorization_state { int our_id; }; +/** + * Stores the current update state of a client + */ +struct protocol_state { + + /** + * Number of events occured in a text box + */ + int pts; + + /** + * Position within a siccession of unconfirmed updates, used for encrypted + * messages + */ + int qts; + + /** + * Number of sent updates + */ + int seq; + + /** + * Last update + */ + int last_date; +}; + +int loop(); +void write_secret_chat_file (struct telegram *instance, const char *filename); + void write_auth_file (struct authorization_state *state, const char *filename); struct authorization_state read_auth_file (const char *filename); diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 6213264..b44fe81 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -40,8 +40,6 @@ typedef struct { PurpleAccount *pa; PurpleConnection *gc; - int updated; - /** * Write handler returned by purple_input_add */ @@ -51,6 +49,12 @@ typedef struct { * Read handler returned by purple_input_add */ guint rh; + + /** + * Whether the state of the protocol has changed since the last save + */ + int updated; + /** * The used purple timeout handler */ From f39eaa5f99da5bb52802dadb2d228ac4f3837a3d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 22:21:45 +0200 Subject: [PATCH 367/465] Fix telegram-purple functions that broke when removing globals --- purple-plugin/telegram-purple.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index abf13f8..198557d 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -90,20 +90,28 @@ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) return "telegram"; } +static telegram_conn *get_conn_from_buddy (PurpleBuddy *buddy) +{ + telegram_conn *c = purple_connection_get_protocol_data ( + purple_account_get_connection (purple_buddy_get_account (buddy))); + return c; +} + /** * Allows the prpl to add text to a buddy's tooltip. */ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); + + logprintf ("purple_buddy_get_protocol_data: %s\n", buddy->name); peer_id_t *peer = purple_buddy_get_protocol_data(buddy); if(peer == NULL) { purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline"); return; } - peer_t *P = user_chat_get (*peer); - + peer_t *P = user_chat_get (get_conn_from_buddy(buddy)->tg->bl, *peer); purple_notify_user_info_add_pair_plaintext(info, "Status", P->user.status.online == 1 ? "Online" : "Offline"); struct tm *tm = localtime ((void *)&P->user.status.when); char buffer [21]; @@ -342,7 +350,8 @@ struct telegram_config tgconf = { message_allocated_handler, peer_allocated_handler, on_new_user_status, - on_user_typing + on_user_typing, + NULL }; @@ -659,13 +668,14 @@ static void tgprpl_rem_deny(PurpleConnection * gc, const char *name) */ static unsigned int tgprpl_send_typing(PurpleConnection * gc, const char *who, PurpleTypingState typing) { - telegram_conn *conn = purple_connection_get_protocol_data(gc); - purple_debug_info(PLUGIN_ID, "tgprpl_send_typing()\n"); + telegram_conn *conn = purple_connection_get_protocol_data(gc); PurpleBuddy *b = purple_find_buddy(conn->pa, who); if (b) { peer_id_t *peer = purple_buddy_get_protocol_data(b); - do_update_typing (conn->tg, *peer); + if (peer) { + do_update_typing (conn->tg, *peer); + } } return 0; } @@ -1003,8 +1013,8 @@ static PurplePluginInfo info = { "Adds support for the telegram protocol to libpurple.", "Christopher Althaus , Markus Endres , Matthias Jentsch ", "https://bitbucket.org/telegrampurple/telegram-purple", - NULL, // on load - NULL, // on unload + NULL, // on load + NULL, // on unload NULL, // on destroy NULL, // ui specific struct &prpl_info, // plugin info struct From 178583cd72439274c4cd78c013b05351ac91b117 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 22:23:59 +0200 Subject: [PATCH 368/465] Clean up whitespaces and ugly code --- purple-plugin/telegram-purple.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 198557d..9d44c6d 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -136,11 +136,7 @@ static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition co logprintf("tgprpl_output_cb()\n"); struct telegram *tg = data; telegram_conn *conn = tg->extra; - - int written = telegram_write_output(tg); - - logprintf("written(%d): %d.\n", telegram_get_connection(tg)->fd, written); - if (written == 0) { + if (telegram_write_output(tg) == 0) { logprintf("no output, removing output...\n"); purple_input_remove(conn->wh); conn->wh = 0; @@ -219,7 +215,6 @@ void telegram_on_phone_registration (struct telegram *instance) telegram_conn *conn = instance->extra; // TODO: Request first and last name - // TODO: Fetch PurpleAccount and don't use global purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); const char *first_name = purple_account_get_string(conn->pa, "first_name", NULL); const char *last_name = purple_account_get_string(conn->pa, "last_name", NULL); @@ -290,10 +285,8 @@ void telegram_on_ready (struct telegram *instance) { purple_debug_info(PLUGIN_ID, "telegram_on_ready().\n"); telegram_conn *conn = instance->extra; - purple_connection_set_state(conn->gc, PURPLE_CONNECTED); purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa)); - purple_blist_add_account(conn->pa); tggroup = purple_find_group("Telegram"); if (tggroup == NULL) { From a7bb59a13aa1acf8e89fc97774d2908a856453e0 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 1 Sep 2014 22:25:02 +0200 Subject: [PATCH 369/465] move message store size into telegram.h --- telegram.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telegram.h b/telegram.h index 7eb3c89..d5ef910 100644 --- a/telegram.h +++ b/telegram.h @@ -174,6 +174,8 @@ struct telegram_config { void (*on_update_uesr_typing_handler) (struct telegram *instance, void *peer); }; +#define MSG_STORE_SIZE 10000 + /** * A telegram session * From 4f33201d09d1deb4afbbc18055f513aef545a292 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 4 Sep 2014 22:07:25 +0200 Subject: [PATCH 370/465] Don't leak data center list when closing down telegram --- telegram.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/telegram.c b/telegram.c index 60c22e3..0ac15e5 100755 --- a/telegram.c +++ b/telegram.c @@ -195,6 +195,7 @@ struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_ } void free_bl (struct binlog *bl); +void free_auth (struct dc* DC_list[], int count); void telegram_destroy(struct telegram *this) { // close all open connections @@ -209,6 +210,7 @@ void telegram_destroy(struct telegram *this) mtproto_free_closed (this); free_bl (this->bl); + free_auth (this->auth.DC_list, 11); g_free(this->login); g_free(this->config_path); @@ -233,6 +235,14 @@ void free_bl (struct binlog *bl) tfree (bl, sizeof (struct binlog)); } +void free_auth (struct dc* DC_list[], int count) +{ + int i; + for (i = 0; i < count; i++ ) if (DC_list[i]) { + tfree (DC_list[i], sizeof(struct dc)); + } +} + void assert_file_usable(const char *file) { logprintf ("assert_file_usable (%s)\n", file); From a05b3b84052bafe10c5e2b6d46857c39dedd8d06 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 5 Sep 2014 21:19:37 +0200 Subject: [PATCH 371/465] fix typo --- purple-plugin/telegram-purple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 9d44c6d..0b2dab6 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -72,7 +72,7 @@ void tg_cli_log_cb(const char* format, va_list ap) void message_allocated_handler (struct telegram *instance, struct message *M); void peer_allocated_handler (struct telegram *instance, void *user); void telegram_on_phone_registration (struct telegram *instance); -void elegram_on_client_registration (struct telegram *instance); +void telegram_on_client_registration (struct telegram *instance); void on_new_user_status(struct telegram *instance, void *user); void on_user_typing(struct telegram *instance, void *user); From 40485fabdcc63844a1d227bde5891c31d3f24c73 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 5 Sep 2014 21:23:22 +0200 Subject: [PATCH 372/465] Remove unused code --- loop.c | 47 +---------------------------------------------- loop.h | 3 --- telegram.h | 7 ------- 3 files changed, 1 insertion(+), 56 deletions(-) diff --git a/loop.c b/loop.c index 37833d2..392e2dd 100644 --- a/loop.c +++ b/loop.c @@ -46,34 +46,6 @@ #include "purple-plugin/telegram-purple.h" // - - -int test_dc = 0; -int default_dc_num; -extern int binlog_enabled; - -int register_mode; - -void got_it (char *line, int len); - -char **_s; -size_t *_l; -int got_it_ok; - -void got_it (char *line, int len) { - assert (len > 0); - line[-- len] = 0; // delete end of line - *_s = line; - *_l = len; - got_it_ok = 1; -} - -int is_got_it (void) { - return got_it_ok; -} - -int ret1 (void) { return 0; } - char *get_auth_key_filename (void); char *get_state_filename (void); int zero[512]; @@ -96,8 +68,6 @@ void write_dc (int auth_file_fd, struct dc *DC) { assert (write (auth_file_fd, &DC->has_auth, 4) == 4); } -int our_id; - void write_auth_file (struct authorization_state *state, const char *filename) { logprintf("Writing to auth_file: %s\n", filename); int auth_file_fd = open (filename, O_CREAT | O_RDWR, 0600); @@ -152,7 +122,7 @@ void empty_auth_file (const char *filename) { memset(state.DC_list, 0, 11 * sizeof(void *)); logprintf("empty_auth_file()\n"); - alloc_dc (state.DC_list, 1, tstrdup (test_dc ? TG_SERVER_TEST : TG_SERVER), 443); + alloc_dc (state.DC_list, 1, tstrdup (TG_SERVER), 443); state.dc_working_num = 1; state.auth_state = 0; write_auth_file (&state, filename); @@ -223,8 +193,6 @@ struct authorization_state read_auth_file (const char *filename) { return state; } -int pts, qts, seq, last_date; - struct protocol_state read_state_file (const char *filename) { logprintf("read_state_file()\n"); struct protocol_state state = {0, 0, 0, 0}; @@ -269,18 +237,10 @@ void write_state_file (struct protocol_state *state, const char* filename) { close (state_file_fd); } -extern peer_t *Peers[]; -extern int peer_num; - -extern int encr_root; -extern unsigned char *encr_prime; -extern int encr_param_version; -extern int dialog_list_got; // TODO: Refactor void read_secret_chat_file (struct telegram *instance, const char *file) { struct binlog *bl = instance->bl; - if (binlog_enabled) { return; } int fd = open (file, O_CREAT | O_RDWR, 0600); if (fd < 0) { return; @@ -340,7 +300,6 @@ void read_secret_chat_file (struct telegram *instance, const char *file) { void write_secret_chat_file (struct telegram *instance, const char *filename) { struct binlog *bl = instance->bl; - if (binlog_enabled) { return; } int fd = open (filename, O_CREAT | O_RDWR, 0600); if (fd < 0) { return; @@ -391,7 +350,3 @@ void write_secret_chat_file (struct telegram *instance, const char *filename) { close (fd); } -int readline_active; -int new_dc_num; -int wait_dialog_list; - diff --git a/loop.h b/loop.h index 516b40e..a6cdfa0 100644 --- a/loop.h +++ b/loop.h @@ -65,7 +65,6 @@ struct protocol_state { int last_date; }; -int loop(); void write_secret_chat_file (struct telegram *instance, const char *filename); void write_auth_file (struct authorization_state *state, const char *filename); @@ -74,6 +73,4 @@ struct authorization_state read_auth_file (const char *filename); void write_state_file (struct protocol_state *state, const char *filename); struct protocol_state read_state_file (const char *filename); -void on_start(); - #endif diff --git a/telegram.h b/telegram.h index d5ef910..14ea7eb 100644 --- a/telegram.h +++ b/telegram.h @@ -296,13 +296,6 @@ void telegram_connect(struct telegram *instance); int telegram_login (struct telegram *instance); -/** - * Read the authorization_state stored in the given file - */ - -// Export functions for plugins -void running_for_first_time (); - /** * Read and process all available input from the network */ From ce96381ef950e0457c082a9f5b0281e457e08f4a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 6 Sep 2014 01:04:57 +0200 Subject: [PATCH 373/465] write secret chat file into user-specific directory and fix config path creation --- loop.c | 1 - loop.h | 3 +++ queries.c | 2 +- structures.c | 9 ++++----- telegram.c | 6 +++++- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/loop.c b/loop.c index 392e2dd..2f6d251 100644 --- a/loop.c +++ b/loop.c @@ -237,7 +237,6 @@ void write_state_file (struct protocol_state *state, const char* filename) { close (state_file_fd); } -// TODO: Refactor void read_secret_chat_file (struct telegram *instance, const char *file) { struct binlog *bl = instance->bl; diff --git a/loop.h b/loop.h index a6cdfa0..a48e34c 100644 --- a/loop.h +++ b/loop.h @@ -73,4 +73,7 @@ struct authorization_state read_auth_file (const char *filename); void write_state_file (struct protocol_state *state, const char *filename); struct protocol_state read_state_file (const char *filename); +void write_secret_chat_file (struct telegram *instance, const char *filename); +void read_secret_chat_file (struct telegram *instance, const char *filename); + #endif diff --git a/queries.c b/queries.c index 2875870..06ee03a 100644 --- a/queries.c +++ b/queries.c @@ -2587,7 +2587,7 @@ void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char out_int (mtp, get_peer_id (E->id)); out_cstring (mtp, instance->g_a, 256); // TODO: properly... - write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, instance->secret_path); BN_clear_free (g); BN_clear_free (p); diff --git a/structures.c b/structures.c index d887814..fe66f45 100644 --- a/structures.c +++ b/structures.c @@ -309,8 +309,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } bl_do_encr_chat_delete (mtp->bl, mtp, U); - // TODO: properly - write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, instance->secret_path); return; } @@ -359,7 +358,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } bl_do_encr_chat_requested (mtp->bl, mtp, U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); - write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, instance->secret_path); } else { bl_do_set_encr_chat_access_hash (mtp->bl, mtp, U, fetch_long (mtp)); bl_do_set_encr_chat_date (mtp->bl, mtp, U, fetch_int (mtp)); @@ -373,7 +372,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } if (x == CODE_encrypted_chat_waiting) { bl_do_set_encr_chat_state (mtp->bl, mtp, U, sc_waiting); - write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, instance->secret_path); return; // We needed only access hash from here } @@ -405,7 +404,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } bl_do_encr_chat_accepted (mtp->bl, mtp, U, (void *)g_key, (void *)nonce, fetch_long (mtp)); } - write_secret_chat_file (instance, "/home/dev-jessie/.telegram/+4915736384600/secret"); + write_secret_chat_file (instance, instance->secret_path); } void fetch_notify_settings (struct mtproto_connection *mtp); diff --git a/telegram.c b/telegram.c index 0ac15e5..99492f5 100755 --- a/telegram.c +++ b/telegram.c @@ -12,6 +12,7 @@ #include "tools.h" #include "mtproto-client.h" #include "binlog.h" +#include "loop.h" @@ -66,7 +67,7 @@ void event_update_user_typing (struct telegram *instance, void *peer) */ char *telegram_get_config(struct telegram *instance, char *config) { - return g_strdup_printf("%s/%s", instance->config->base_config_path, config); + return g_strdup_printf("%s/%s", instance->config_path, config); } /** @@ -299,6 +300,7 @@ void telegram_restore_session(struct telegram *instance) g_mkdir_with_parents(instance->config_path, 0700); instance->auth = read_auth_file(instance->auth_path); instance->proto = read_state_file(instance->state_path); + read_secret_chat_file (instance, instance->secret_path); } /** @@ -308,8 +310,10 @@ void telegram_store_session(struct telegram *instance) { assure_file_exists(instance->config_path, "auth"); assure_file_exists(instance->config_path, "state"); + assure_file_exists(instance->config_path, "secret"); write_auth_file(&instance->auth, instance->auth_path); write_state_file(&instance->proto, instance->state_path); + write_secret_chat_file(instance, instance->state_path); } void on_authorized(struct mtproto_connection *c, void* data); From f0447fa958ef079b72f821648e23d44495472500 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 6 Sep 2014 01:09:47 +0200 Subject: [PATCH 374/465] Free all pending timers and queries after erroring --- mtproto-client.c | 3 +++ net.c | 5 +++++ queries.c | 3 +++ telegram.c | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/mtproto-client.c b/mtproto-client.c index e65a05c..ff98063 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1856,6 +1856,9 @@ void mtproto_close(struct mtproto_connection *mtp) { // remove all ping timer that point to this connection stop_ping_timer (mtp->connection); + + // + mtp->connection->session->c = 0; } /** diff --git a/net.c b/net.c index d935d1f..bbc54a2 100644 --- a/net.c +++ b/net.c @@ -619,6 +619,11 @@ void connections_poll_result (struct pollfd *fds, int max) { } int send_all_acks (struct session *S) { + logprintf ("send_all_acks()\n"); + if (!S->c) { + logprintf ("WARNING: cannot send acks, session has no active connection"); + return -1; + } struct mtproto_connection *mt = S->c->mtconnection; clear_packet (mt); diff --git a/queries.c b/queries.c index 06ee03a..8b42777 100644 --- a/queries.c +++ b/queries.c @@ -3075,6 +3075,9 @@ void do_update_typing (struct telegram *instance, peer_id_t id) { int telegram_has_output (struct telegram *instance) { + if (!instance->connection) { + return 0; + } if (instance->session_state == STATE_READY) { return tree_count_query (instance->queries_tree) > 0; } diff --git a/telegram.c b/telegram.c index 99492f5..49bffd1 100755 --- a/telegram.c +++ b/telegram.c @@ -160,6 +160,10 @@ void telegram_change_state (struct telegram *instance, int state, void *data) assert (instance->config->proxy_request_cb); // tell the proxy to close all connections instance->config->proxy_close_cb (instance, instance->connection->connection->fd); + + // remove all left over queries and timers + free_timers (instance); + free_queries (instance); // start a new connection to the demanded data center. The pointer to the // new dc should was already updated by the on_error function of the query From 709b7f2cdb99d1e33313af85c6dcafec366aa003 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 7 Sep 2014 13:48:25 +0200 Subject: [PATCH 375/465] Use current home for config instead of a static directory --- purple-plugin/telegram-purple.c | 17 ++++++++++++++--- telegram.h | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 0b2dab6..8abbf3e 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include // Libpurple Plugin Includes #include "notify.h" @@ -331,7 +334,7 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa } struct telegram_config tgconf = { - "/home/dev-jessie/.telegram", + NULL, NULL, // on output telegram_on_proxy_request, telegram_on_proxy_close, @@ -343,8 +346,7 @@ struct telegram_config tgconf = { message_allocated_handler, peer_allocated_handler, on_new_user_status, - on_user_typing, - NULL + on_user_typing }; @@ -939,6 +941,15 @@ static PurplePluginProtocolInfo prpl_info = { static void tgprpl_init(PurplePlugin *plugin) { + const char *dir = ".telegram"; + if (!tgconf.base_config_path) { + struct passwd *pw = getpwuid(getuid()); + int len = strlen (dir) + strlen (pw->pw_dir) + 2; + tgconf.base_config_path = talloc (len); + tsnprintf (tgconf.base_config_path, len, "%s/%s", pw->pw_dir, dir); + logprintf ("base configuration path: %s", tgconf.base_config_path); + } + PurpleAccountOption *option; PurpleAccountUserSplit *split; GList *verification_values = NULL; diff --git a/telegram.h b/telegram.h index 14ea7eb..0a3bfb1 100644 --- a/telegram.h +++ b/telegram.h @@ -105,7 +105,7 @@ struct telegram_config { /** * The base path containing the telegram configuration */ - const char* base_config_path; + char* base_config_path; /** * Called when there is pending network output From 956a034be18389b8ace5848ce78fc60ce7785a8c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 7 Sep 2014 20:56:44 +0200 Subject: [PATCH 376/465] Add group chats --- purple-plugin/telegram-purple.c | 80 +++++++++++++++++++++++++++++---- queries.c | 8 ++-- structures.c | 9 ++-- telegram.h | 5 +++ 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 8abbf3e..3e80c7c 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -50,8 +50,7 @@ // telegram-purple includes #include "telegram.h" #include "telegram-purple.h" - -// telegram-cli +#include "structures.h" #include "net.h" #define BUDDYNAME_MAX_LENGTH 128 @@ -78,6 +77,7 @@ void telegram_on_phone_registration (struct telegram *instance); void telegram_on_client_registration (struct telegram *instance); void on_new_user_status(struct telegram *instance, void *user); void on_user_typing(struct telegram *instance, void *user); +void on_chat_joined (struct telegram *instance, peer_id_t chatid); /** * Returns the base icon name for the given buddy and account. @@ -301,7 +301,7 @@ void telegram_on_ready (struct telegram *instance) do_get_dialog_list(instance); do_get_difference(instance); tgprpl_has_output(instance); - conn->timer = purple_timeout_add (4000, queries_timerfunc, conn); + conn->timer = purple_timeout_add (10000, queries_timerfunc, conn); } void telegram_on_disconnected (struct telegram *tg) @@ -346,7 +346,8 @@ struct telegram_config tgconf = { message_allocated_handler, peer_allocated_handler, on_new_user_status, - on_user_typing + on_user_typing, + on_chat_joined }; @@ -473,6 +474,10 @@ static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id) return blist_find_chat_by_hasht_cond(gc, hasht_cmp_id, &id); } +static char *peer_get_peer_id_as_string(peer_t *user) +{ + return g_strdup_printf("%d", get_peer_id(user->id)); +} void peer_allocated_handler(struct telegram *tg, void *usr) { @@ -481,7 +486,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) PurpleAccount *pa = conn->pa; peer_t *user = usr; - gchar *name = g_strdup_printf("%d", get_peer_id(user->id)); + gchar *name = peer_get_peer_id_as_string(user); //g_strdup_printf("%d", get_peer_id(user->id)); logprintf("Allocated peer: %s\n", name); switch (user->id.type) { case PEER_USER: { @@ -601,7 +606,14 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) { purple_debug_info(PLUGIN_ID, "tgprpl_send_chat()\n"); - return -1; + telegram_conn *conn = purple_connection_get_protocol_data (gc); + PurpleConversation *convo = purple_find_chat(gc, id); + do_send_message (conn->tg, MK_CHAT(id), message, strlen(message)); + + char *me = conn->tg->User.print_name; + logprintf ("Current user: '%s'\n", me); + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), me, message, PURPLE_MESSAGE_SEND, time(NULL)); + return 1; } /** @@ -775,7 +787,13 @@ static void tgprpl_rename_group(PurpleConnection * gc, const char *old_name, Pur static GList *tgprpl_chat_join_info(PurpleConnection * gc) { purple_debug_info(PLUGIN_ID, "tgprpl_chat_join_info()\n"); - return NULL; + struct proto_chat_entry *pce; + + pce = g_new0(struct proto_chat_entry, 1); + pce->label = "_Subject:"; + pce->identifier = "subject"; + pce->required = TRUE; + return g_list_append(NULL, pce); } /** @@ -807,6 +825,52 @@ static GHashTable *tgprpl_chat_info_defaults(PurpleConnection * gc, const char * static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) { purple_debug_info(PLUGIN_ID, "tgprpl_chat_join()\n"); + + telegram_conn *conn = purple_connection_get_protocol_data(gc); + const char *groupname = g_hash_table_lookup(data, "subject"); + + char *id = g_hash_table_lookup(data, "id"); + if (!id) { + logprintf ("Got no chat id, aborting...\n"); + return; + } + if (!purple_find_chat(gc, atoi(id))) { + char *subject, *owner, *part; + do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); + } +} + +void on_chat_joined (struct telegram *instance, peer_id_t chatid) +{ + logprintf ("on_chat_joined(%d)\n", chatid.id); + telegram_conn *conn = instance->extra; + + peer_t *peer = user_chat_get (instance->bl, chatid); + if (!peer) { + logprintf ("ERROR: chat with given id %d is not existing.\n", chatid.id); + return; + } + if (!peer->id.type == PEER_CHAT) { + logprintf ("ERROR: peer with given id %d and type %d is not a chat.\n", peer->id.id, peer->id.type); + return; + } + PurpleConversation *conv = serv_got_joined_chat(conn->gc, chatid.id, peer->chat.title); + int cnt = peer->chat.user_list_size; + struct chat_user *curr = peer->chat.user_list; + int i; + for (i = 0; i < cnt; i++) { + peer_id_t part_id = MK_USER((curr + i)->user_id); + char *name = g_strdup_printf ("%d", part_id.id); + int flags = PURPLE_CBFLAGS_NONE | peer->chat.admin_id == part_id.id ? PURPLE_CBFLAGS_FOUNDER : 0; + logprintf ("purple_conv_chat_add_user (..., name=%s, ..., flags=%d)", name, flags); + purple_conv_chat_add_user( + purple_conversation_get_chat_data(conv), + name, + "", + flags, + 0 + ); + } } /** @@ -832,7 +896,7 @@ static void tgprpl_chat_invite(PurpleConnection * gc, int id, const char *messag static char *tgprpl_get_chat_name(GHashTable * data) { purple_debug_info(PLUGIN_ID, "tgprpl_get_chat_name()\n"); - return "chat name"; + return g_strdup(g_hash_table_lookup(data, "subject")); } /** diff --git a/queries.c b/queries.c index 8b42777..41876ee 100644 --- a/queries.c +++ b/queries.c @@ -1732,11 +1732,8 @@ void print_chat_info (struct chat *C) { int chat_info_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); - - // TODO: use chat - struct chat *C UU = fetch_alloc_chat_full (mtp); - - //print_chat_info (C); + struct chat *C = fetch_alloc_chat_full (mtp); + mtp->instance->config->on_chat_info_received (mtp->instance, C->id); return 0; } @@ -1745,6 +1742,7 @@ struct query_methods chat_info_methods = { }; void do_get_chat_info (struct telegram *instance, peer_id_t id) { + logprintf ("do_get_chat_info (peer_id=%d)", id.id); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; if (offline_mode) { diff --git a/structures.c b/structures.c index fe66f45..473e7ff 100644 --- a/structures.c +++ b/structures.c @@ -1818,14 +1818,13 @@ struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct tele if (!M) { M = talloc0 (sizeof (*M)); - M->id = data[1]; M->instance = instance; + M->id = data[1]; message_insert_tree (M); mtp->bl->messages_allocated ++; fetch_message (mtp, M); return M; } - M->instance = instance; fetch_message (mtp, M); return M; } @@ -1862,10 +1861,10 @@ struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, int data[3]; prefetch_data (mtp, data, 12); struct message *M = message_get (bl, *(long long *)(data + 1)); - M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); + M->instance = instance; M->id = *(long long *)(data + 1); message_insert_tree (M); mtp->bl->messages_allocated ++; @@ -1882,10 +1881,10 @@ struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, int data[1]; prefetch_data (mtp, data, 4); struct message *M = message_get (bl, data[0]); - M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); + M->instance = instance; M->id = data[0]; message_insert_tree (M); mtp->bl->messages_allocated ++; @@ -1899,10 +1898,10 @@ struct message *fetch_alloc_message_short_chat (struct mtproto_connection *mtp, int data[1]; prefetch_data (mtp, data, 4); struct message *M = message_get (bl, data[0]); - M->instance = instance; if (!M) { M = talloc0 (sizeof (*M)); + M->instance = instance; M->id = data[0]; message_insert_tree (M); mtp->bl->messages_allocated ++; diff --git a/telegram.h b/telegram.h index 0a3bfb1..2b90f9b 100644 --- a/telegram.h +++ b/telegram.h @@ -172,6 +172,11 @@ struct telegram_config { * A callback function that is called when a user starts or stops typing */ void (*on_update_uesr_typing_handler) (struct telegram *instance, void *peer); + + /** + * A callback function that is called when chat info is received + */ + void (*on_chat_info_received) (struct telegram *instance, peer_id_t chatid); }; #define MSG_STORE_SIZE 10000 From 9d23ecac7f1d00f18d3fbf582c73fcefdcd6d5ba Mon Sep 17 00:00:00 2001 From: Christopher Althaus Date: Sun, 7 Sep 2014 21:44:37 +0200 Subject: [PATCH 377/465] Added group chat functions --- purple-plugin/telegram-purple.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 3e80c7c..c5514c3 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -301,7 +301,7 @@ void telegram_on_ready (struct telegram *instance) do_get_dialog_list(instance); do_get_difference(instance); tgprpl_has_output(instance); - conn->timer = purple_timeout_add (10000, queries_timerfunc, conn); + conn->timer = purple_timeout_add (500, queries_timerfunc, conn); } void telegram_on_disconnected (struct telegram *tg) @@ -399,6 +399,7 @@ void message_allocated_handler(struct telegram *tg, struct message *M) // TODO: this should probably be freed again somwhere int id = get_peer_id(M->from_id); char *who = g_strdup_printf("%d", id); + if (who) { logprintf ("who: %s\n", who); if (M->service) { @@ -408,7 +409,22 @@ void message_allocated_handler(struct telegram *tg, struct message *M) return; } logprintf ("fwd_date: %d\n", M->date); - serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time((time_t *) &M->date)); + switch (M->to_id.type) { + case PEER_USER: { + serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time((time_t *) &M->date)); + } + break; + case PEER_CHAT: { + logprintf ("PEER_CHAT\n"); + peer_t *fromPeer = user_chat_get (tg->bl, M->from_id); + char *alias = malloc(BUDDYNAME_MAX_LENGTH); + user_get_alias(fromPeer, alias, BUDDYNAME_MAX_LENGTH); + serv_got_chat_in(gc, get_peer_id(M->to_id), alias, PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); + g_free(alias); + } + break; + } + g_free(who); } @@ -610,9 +626,15 @@ static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, PurpleConversation *convo = purple_find_chat(gc, id); do_send_message (conn->tg, MK_CHAT(id), message, strlen(message)); - char *me = conn->tg->User.print_name; + peer_t *peer = user_chat_get(conn->tg->bl, MK_USER (conn->tg->our_id)); + + char *me = malloc(BUDDYNAME_MAX_LENGTH); + user_get_alias(peer, me, BUDDYNAME_MAX_LENGTH); + logprintf ("Current user: '%s'\n", me); purple_conv_chat_write(PURPLE_CONV_CHAT(convo), me, message, PURPLE_MESSAGE_SEND, time(NULL)); + tgprpl_has_output (conn->tg); + g_free(me); return 1; } @@ -837,6 +859,7 @@ static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) if (!purple_find_chat(gc, atoi(id))) { char *subject, *owner, *part; do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); + tgprpl_has_output (conn->tg); } } @@ -871,6 +894,7 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) 0 ); } + } /** From 7d8ec1ef42dcb5159cf74cfd65e3faca5c822b61 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 8 Sep 2014 23:09:20 +0200 Subject: [PATCH 378/465] Add missing message allocated handlers --- binlog.c | 1 + mtproto-client.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/binlog.c b/binlog.c index 11b5a3f..ce90436 100644 --- a/binlog.c +++ b/binlog.c @@ -731,6 +731,7 @@ void replay_log_event (struct telegram *instance) { M->instance = instance; message_insert_tree (M); bl->messages_allocated ++; + event_update_new_message (instance, M); } else { assert (!(M->flags & FLAG_CREATED)); } diff --git a/mtproto-client.c b/mtproto-client.c index ff98063..a43116d 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -871,7 +871,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { switch (op) { case CODE_update_new_message: { - struct message *M = fetch_alloc_message (self, tg); + struct message *M UU = fetch_alloc_message (self, tg); assert (M); fetch_pts (self); self->unread_messages ++; @@ -1195,8 +1195,9 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { break; case CODE_update_new_geo_chat_message: { - struct message *M UU = fetch_alloc_geo_message (self, tg); + struct message *M = fetch_alloc_geo_message (self, tg); self->unread_messages ++; + event_update_new_message (self->instance, M); //print_message (M); //update_prompt (); } @@ -1205,6 +1206,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { struct message *M UU = fetch_alloc_encrypted_message (self, tg); self->unread_messages ++; + event_update_new_message (self->instance, M); //print_message (M); //update_prompt (); fetch_qts (self); @@ -1407,6 +1409,7 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) { assert (fetch_int (c->mtconnection) == (int)CODE_update_short_message); struct message *M = fetch_alloc_message_short (self, c->instance); c->mtconnection->unread_messages ++; + event_update_new_message (self->instance, M); //print_message (M); //update_prompt (); if (M->date > c->mtconnection->last_date) { @@ -1421,6 +1424,7 @@ void work_update_short_chat_message (struct connection *c, long long msg_id UU) struct message *M = fetch_alloc_message_short_chat (self, c->instance); c->mtconnection->unread_messages ++; //print_message (M); + event_update_new_message (self->instance, M); ////update_prompt (); if (M->date > c->mtconnection->last_date) { c->mtconnection->last_date = M->date; From 00944910bc7e3ab9530488fe82ffaaaa415fa68c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 8 Sep 2014 23:09:55 +0200 Subject: [PATCH 379/465] Remove pinging --- mtproto-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index a43116d..c2f641f 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1843,7 +1843,7 @@ void mtproto_connect(struct mtproto_connection *c) c->connection->methods->ready(c->connection); // Don't ping TODO: Really? Timeout callback functions of libpurple - start_ping_timer (c->connection); + //start_ping_timer (c->connection); } /** @@ -1859,7 +1859,7 @@ void mtproto_close(struct mtproto_connection *mtp) { send_all_acks (mtp->connection->session); // remove all ping timer that point to this connection - stop_ping_timer (mtp->connection); + //stop_ping_timer (mtp->connection); // mtp->connection->session->c = 0; From 07a0766948a2bef8c14ba46c6aa540348de7c42a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 8 Sep 2014 23:10:25 +0200 Subject: [PATCH 380/465] Fix sending and receiving of messages in group chats Add received messages to correct group chat, open closed chats on received messages, display our name correctly, handle messages from ourself correctly. --- purple-plugin/telegram-purple.c | 114 +++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 17 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 3e80c7c..56d2d93 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -78,6 +78,47 @@ void telegram_on_client_registration (struct telegram *instance); void on_new_user_status(struct telegram *instance, void *user); void on_user_typing(struct telegram *instance, void *user); void on_chat_joined (struct telegram *instance, peer_id_t chatid); +static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id); +static void tgprpl_has_output(struct telegram *tg); + +static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *value) +{ + gchar *name = g_strdup_printf ("%d", id); + PurpleChat *ch = blist_find_chat_by_id(gc, name); + g_free (name); + GHashTable *table = purple_chat_get_components(ch); + return g_hash_table_lookup(table, value); +} + +/** + * Assure that the given chat is opened + */ +static PurpleConversation *chat_show (PurpleConnection *gc, int id) +{ + logprintf ("show chat"); + PurpleConversation *convo = purple_find_chat(gc, id); + if (convo) { + if (purple_conv_chat_has_left(PURPLE_CONV_CHAT(convo))) + { + serv_got_joined_chat(gc, id, chat_id_get_comp_val(gc, id, "subject")); + } + } else { + // join chat first + logprintf ("joining chat first...\n"); + telegram_conn *conn = purple_connection_get_protocol_data(gc); + do_get_chat_info (conn->tg, MK_CHAT(id)); + tgprpl_has_output (conn->tg); + } + return convo; +} + +static PurpleChat *get_chat_by_id (PurpleConnection *gc, int id) +{ + gchar *name = g_strdup_printf ("%d", id); + PurpleChat *chat = blist_find_chat_by_id (gc, name); + g_free (name); + return chat; +} /** * Returns the base icon name for the given buddy and account. @@ -398,20 +439,51 @@ void message_allocated_handler(struct telegram *tg, struct message *M) // TODO: this should probably be freed again somwhere int id = get_peer_id(M->from_id); - char *who = g_strdup_printf("%d", id); - if (who) { - logprintf ("who: %s\n", who); - if (M->service) { - // TODO: handle service messages properly, currently adding them - // causes a segfault for an unknown reason - logprintf ("service message, skipping...\n"); - return; - } - logprintf ("fwd_date: %d\n", M->date); - serv_got_im(gc, who, M->message, PURPLE_MESSAGE_RECV, time((time_t *) &M->date)); - g_free(who); + + if (M->service) { + // TODO: handle service messages properly, currently adding them + // causes a segfault for an unknown reason + logprintf ("service message, skipping...\n"); + return; } + // + peer_id_t to_id = M->to_id; + char *from = g_strdup_printf("%d", id); + char *to = g_strdup_printf("%d", to_id.id); + logprintf ("from: %s\n", from); + logprintf ("fwd_date: %d\n", M->date); + switch (to_id.type) { + case PEER_CHAT: + logprintf ("PEER_CHAT\n"); + chat_show (gc, to_id.id); + if (M->from_id.id == tg->our_id) { + serv_got_chat_in(gc, get_peer_id(M->to_id), "You", PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); + } else { + peer_t *fromPeer = user_chat_get (tg->bl, M->from_id); + char *alias = malloc(BUDDYNAME_MAX_LENGTH); + user_get_alias(fromPeer, alias, BUDDYNAME_MAX_LENGTH); + serv_got_chat_in(gc, get_peer_id(M->to_id), alias, PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); + g_free(alias); + } + break; + + case PEER_USER: + logprintf ("PEER_USER\n"); + if (M->from_id.id == tg->our_id) { + serv_got_im(gc, to, M->message, PURPLE_MESSAGE_SEND, time((time_t *) &M->date)); + } else { + serv_got_im(gc, from, M->message, PURPLE_MESSAGE_RECV, time((time_t *) &M->date)); + } + break; + + case PEER_ENCR_CHAT: + break; + + case PEER_GEO_CHAT: + break; + } + g_free(from); conn->updated = 1; } @@ -500,8 +572,10 @@ void peer_allocated_handler(struct telegram *tg, void *usr) } PurpleBuddy *buddy = purple_find_buddy(pa, name); if (!buddy) { + char *actual = user->id.id == tg->our_id ? "You" : alias; purple_debug_info(PLUGIN_ID, "Adding %s to buddy list\n", name); - buddy = purple_buddy_new(pa, name, alias); + purple_debug_info(PLUGIN_ID, "Alias %s\n", actual); + buddy = purple_buddy_new(pa, name, actual); purple_blist_add_buddy(buddy, NULL, tggroup, NULL); } purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); @@ -512,6 +586,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) else purple_prpl_got_user_status(account, name, "unavailable", "message", "", NULL); + g_free(alias); g_free(name); } break; @@ -607,12 +682,12 @@ static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, { purple_debug_info(PLUGIN_ID, "tgprpl_send_chat()\n"); telegram_conn *conn = purple_connection_get_protocol_data (gc); - PurpleConversation *convo = purple_find_chat(gc, id); + //PurpleConversation *convo = purple_find_chat(gc, id); do_send_message (conn->tg, MK_CHAT(id), message, strlen(message)); - char *me = conn->tg->User.print_name; - logprintf ("Current user: '%s'\n", me); - purple_conv_chat_write(PURPLE_CONV_CHAT(convo), me, message, PURPLE_MESSAGE_SEND, time(NULL)); + char *who = g_strdup_printf("%d", id); + serv_got_chat_in(gc, id, "You", PURPLE_MESSAGE_RECV, message, time(NULL)); + g_free(who); return 1; } @@ -835,8 +910,13 @@ static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) return; } if (!purple_find_chat(gc, atoi(id))) { + logprintf ("chat now known\n"); char *subject, *owner, *part; do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); + tgprpl_has_output (conn->tg); + } else { + logprintf ("chat already known\n"); + serv_got_joined_chat(conn->gc, atoi(id), groupname); } } From 703d6e9e2e4c6cce58126151972cd01137a78b48 Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Wed, 10 Sep 2014 16:20:34 +0200 Subject: [PATCH 381/465] Remove overlooked merge leftovers --- purple-plugin/telegram-purple.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f1100a9..887a778 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -685,21 +685,9 @@ static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, //PurpleConversation *convo = purple_find_chat(gc, id); do_send_message (conn->tg, MK_CHAT(id), message, strlen(message)); -<<<<<<< HEAD char *who = g_strdup_printf("%d", id); serv_got_chat_in(gc, id, "You", PURPLE_MESSAGE_RECV, message, time(NULL)); g_free(who); -======= - peer_t *peer = user_chat_get(conn->tg->bl, MK_USER (conn->tg->our_id)); - - char *me = malloc(BUDDYNAME_MAX_LENGTH); - user_get_alias(peer, me, BUDDYNAME_MAX_LENGTH); - - logprintf ("Current user: '%s'\n", me); - purple_conv_chat_write(PURPLE_CONV_CHAT(convo), me, message, PURPLE_MESSAGE_SEND, time(NULL)); - tgprpl_has_output (conn->tg); - g_free(me); ->>>>>>> 95347fdee590c47fa850bbf2ef30b7b01d2ae3f6 return 1; } @@ -926,12 +914,9 @@ static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) char *subject, *owner, *part; do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); tgprpl_has_output (conn->tg); -<<<<<<< HEAD } else { logprintf ("chat already known\n"); serv_got_joined_chat(conn->gc, atoi(id), groupname); -======= ->>>>>>> 95347fdee590c47fa850bbf2ef30b7b01d2ae3f6 } } From dcf9b4f42722cb5eacd3b362c171625d6b932b96 Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Wed, 10 Sep 2014 18:09:57 +0200 Subject: [PATCH 382/465] Do not free tree elements manually, the tree already does that --- queries.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/queries.c b/queries.c index 41876ee..fc4c7e4 100644 --- a/queries.c +++ b/queries.c @@ -285,7 +285,7 @@ void free_timers (struct telegram *instance) assert (ev); logprintf ("freeing event timer with timeout: %d\n", ev->timeout); remove_event_timer (instance, ev); - tfree (ev, sizeof(struct event_timer)); + //tfree (ev, sizeof(struct event_timer)); } } @@ -295,9 +295,9 @@ void free_queries (struct telegram *instance) struct query *q = tree_get_min_query (instance->queries_tree); assert (q); logprintf ("freeing query with msg_id %d and len\n", q->msg_id, q->data_len); - instance->queries_tree = tree_delete_query (instance->queries_tree, q); tfree (q->data, 4 * q->data_len); - tfree (q, sizeof (struct query)); + instance->queries_tree = tree_delete_query (instance->queries_tree, q); + //tfree (q, sizeof (struct query)); } } From 4a062b764fe83116d46f141d36ff523ab541b776 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Wed, 17 Sep 2014 22:51:46 +0200 Subject: [PATCH 383/465] Use a separate handles for each mtproto_connection --- mtproto-client.c | 35 ++++--- mtproto-client.h | 1 + net.c | 1 + purple-plugin/telegram-purple.c | 164 ++++++++++++++++++-------------- purple-plugin/telegram-purple.h | 35 +++++-- queries.c | 15 --- telegram.c | 42 +++++--- telegram.h | 29 +++--- 8 files changed, 184 insertions(+), 138 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index c2f641f..d221f4c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1843,11 +1843,12 @@ void mtproto_connect(struct mtproto_connection *c) c->connection->methods->ready(c->connection); // Don't ping TODO: Really? Timeout callback functions of libpurple - //start_ping_timer (c->connection); + start_ping_timer (c->connection); } /** - * Free all used resources and close the connection + * Mark the connection for destruction, stop all timers and initiate + * cleanup tasks */ void mtproto_close(struct mtproto_connection *mtp) { logprintf ("closing mtproto_connection...\n"); @@ -1856,24 +1857,26 @@ void mtproto_close(struct mtproto_connection *mtp) { // send all pending acks on this connection so the server won't // resend messages. We might not be able to send the acknowledgements later // in case the session is switched and this DC is not reachable anymore - send_all_acks (mtp->connection->session); - - // remove all ping timer that point to this connection - //stop_ping_timer (mtp->connection); + if (mtp->connection) { + if (mtp->connection->session && mtp->connection->session->ack_tree) { + send_all_acks (mtp->connection->session); + mtp->instance->config->on_output(mtp->handle); - // - mtp->connection->session->c = 0; + // connection no longer usable for session + mtp->connection->session->c = 0; + } + stop_ping_timer (mtp->connection); + } + // remove all ping timer that point to this connection } /** - * Close the connection and + * Close the underlying file descriptor */ void mtproto_destroy (struct mtproto_connection *self) { logprintf("destroying mtproto_connection: %p\n", self); - - // TODO: Call destruction callback + self->instance->config->proxy_close_cb(self->handle); fd_close_connection(self->connection); - tfree(self->connection, sizeof(struct connection)); tfree(self, sizeof(struct mtproto_connection)); } @@ -1889,13 +1892,15 @@ void mtproto_free_closed (struct telegram *tg) { logprintf ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", i, c->c_state, c->destroy, c->queries_num); if (c->destroy == 0) continue; - if (c->queries_num > 0) { - logprintf ("still pending queries left, skipping connection...\n"); + if (c->connection->out_bytes > 0) { + logprintf ("still %d bytes ouput left, skipping connection...\n", c->connection->out_bytes); continue; } mtproto_destroy (c); + if (tg->connection == c) { + tg->connection = NULL; + } tg->Cs[i] = NULL; - tg->connection = NULL; } } diff --git a/mtproto-client.h b/mtproto-client.h index 5fdcebe..3d93e0e 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -250,6 +250,7 @@ struct mtproto_connection { // the corresponding telegram instance // struct telegram *instance; + void *handle; }; void mtproto_connection_init (struct mtproto_connection *c); diff --git a/net.c b/net.c index bbc54a2..459c7d4 100644 --- a/net.c +++ b/net.c @@ -730,5 +730,6 @@ void fd_close_connection(struct connection *c) { c->out_head = c->out_tail = c->in_head = c->in_tail = 0; c->state = conn_stopped; c->out_bytes = c->in_bytes = 0; + tfree(c, sizeof(struct connection)); } diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 887a778..f6c2d51 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -79,7 +79,7 @@ void on_new_user_status(struct telegram *instance, void *user); void on_user_typing(struct telegram *instance, void *user); void on_chat_joined (struct telegram *instance, peer_id_t chatid); static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id); -static void tgprpl_has_output(struct telegram *tg); +static void tgprpl_has_output(void *handle); static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *value) { @@ -107,7 +107,7 @@ static PurpleConversation *chat_show (PurpleConnection *gc, int id) logprintf ("joining chat first...\n"); telegram_conn *conn = purple_connection_get_protocol_data(gc); do_get_chat_info (conn->tg, MK_CHAT(id)); - tgprpl_has_output (conn->tg); + telegram_flush (conn->tg); } return convo; } @@ -175,52 +175,73 @@ static void login_verification_fail(PurpleAccount *acct) "Please make sure you entered the correct verification code.", NULL, NULL, NULL); } +/* OUTPUT */ + +/** + * Libpurple announced that new output should be written to the write-handle + */ static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition cond) { - logprintf("tgprpl_output_cb()\n"); - struct telegram *tg = data; - telegram_conn *conn = tg->extra; - if (telegram_write_output(tg) == 0) { + mtproto_handle *conn = data; + logprintf("tgprpl_output_cb(%p)\n", data); + logprintf("mtp=%p, fd=%d, rh=%d, wh=%d\n", conn->mtp, conn->fd, conn->rh, conn->wh); + if (!conn->mtp) { + logprintf ("connection no loner existing, do nothing. \n"); + return; + } + if (mtp_write_output(conn->mtp) == 0) { logprintf("no output, removing output...\n"); purple_input_remove(conn->wh); conn->wh = 0; } } -static void tgprpl_has_output(struct telegram *tg) +/** + * Telegram announced new output in its buffers + */ +static void tgprpl_has_output(void *handle) { - logprintf("tgprpl_has_output()\n"); - telegram_conn *conn = tg->extra; + logprintf("tgprpl_has_output(%p)\n", handle); + mtproto_handle *conn = handle; if (! conn->wh) { - conn->wh = purple_input_add(telegram_get_connection(tg)->fd, PURPLE_INPUT_WRITE, - tgprpl_output_cb, tg); - logprintf("Attached write handle: %u ", conn->wh); + conn->wh = purple_input_add(conn->fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, handle); } } +/* + * Libpurple announced that new input should be read from the read-handle + */ static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition cond) { - struct telegram *tg = data; - //telegram_conn *conn = tg->extra; + mtproto_handle *conn = data; logprintf("tgprpl_input_cb()\n"); + if (!conn->fd) { + logprintf("conn for handle no longer existing, not reading input\n"); + return; + } + mtp_read_input(conn->mtp); - // TODO: remove input handler when no more input - telegram_read_input(tg); - if (telegram_has_output(tg)) { - tgprpl_has_output(tg); + if (conn->mtp) { + // processing of the answer may have inserted new queries + telegram_flush (conn->mtp->instance); + + // free all mtproto_connections that may have errored + mtproto_free_closed(conn->mtp->instance); } } -static void tgprpl_has_input(struct telegram *tg) +/** + * Telegram announced that it awaits new input from the read-handle + * TODO: this is currently unused, evaluate wether its needed at all + */ +static void tgprpl_has_input(void *handle) { logprintf("tgprpl_has_input()\n"); - telegram_conn *conn = tg->extra; + mtproto_handle *conn = handle; if (! conn->rh) { - conn->rh = purple_input_add(telegram_get_connection(tg)->fd, PURPLE_INPUT_READ, - tgprpl_input_cb, tg); + conn->rh = purple_input_add(conn->fd, PURPLE_INPUT_READ, tgprpl_input_cb, handle); logprintf("Attached read handle: %u ", conn->rh); } - } static void init_dc_settings(PurpleAccount *acc, struct dc *DC) @@ -231,15 +252,12 @@ static void init_dc_settings(PurpleAccount *acc, struct dc *DC) } /** - * Handle a proxy-request of telegram - * - * Request a new proxy connection from purple, and execute tgprpl_login_on_connected - * as callback once the connection is ready + * Telegram requests a new connectino to our configured proxy */ -void telegram_on_proxy_request(struct telegram *instance, const char *ip, int port) +void telegram_on_proxy_request(struct telegram *tg, const char *ip, int port) { - telegram_conn *conn = instance->extra; - purple_proxy_connect (conn->gc, conn->pa, ip, port, tgprpl_login_on_connected, conn->tg); + telegram_conn *conn = tg->extra; + purple_proxy_connect (conn->gc, conn->pa, ip, port, tgprpl_login_on_connected, tg); } /** @@ -247,11 +265,20 @@ void telegram_on_proxy_request(struct telegram *instance, const char *ip, int po * * Remove all open inputs added to purple */ -void telegram_on_proxy_close(struct telegram *instance, int fd UU) +void telegram_on_proxy_close(void *handle) { - telegram_conn *conn = instance->extra; - purple_input_remove (conn->rh); - purple_input_remove (conn->wh); + mtproto_handle *conn = handle; + logprintf ("Closing proxy-handles - fd: %d, write-handle: %d, read-handle: %d\n", + conn->fd, conn->wh, conn->rh); + if (conn->rh) { + purple_input_remove (conn->rh); + } + if (conn->wh) { + purple_input_remove (conn->wh); + } + conn->rh = conn->wh = 0; + conn->mtp = 0; + tfree (conn, sizeof(mtproto_handle)); } void telegram_on_phone_registration (struct telegram *instance) @@ -278,7 +305,7 @@ void client_registration_entered (gpointer data, const gchar *code) { struct telegram *tg = data; do_send_code_result (tg, code); - tgprpl_has_output (tg); + telegram_flush (tg); } void client_registration_canceled (gpointer data) @@ -341,8 +368,31 @@ void telegram_on_ready (struct telegram *instance) do_update_contact_list(instance); do_get_dialog_list(instance); do_get_difference(instance); - tgprpl_has_output(instance); - conn->timer = purple_timeout_add (500, queries_timerfunc, conn); + telegram_flush (conn->tg); + conn->timer = purple_timeout_add (5000, queries_timerfunc, conn); +} + +/** + * A proxy connection was created by purple + * + * Use the connection to create a new mtproto-connection and create a handle, + * with additional info for libpurple associated with the new connection + */ +void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); + struct telegram *tg = (struct telegram*)data; + if (fd == -1) { + logprintf("purple_proxy_connect failed: %s\n", error_message); + telegram_destroy(tg); + return; + } + + mtproto_handle *conn = talloc(sizeof (mtproto_handle)); + conn->fd = fd; + conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, conn); + conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, conn); + conn->mtp = telegram_add_proxy(tg, fd, conn); } void telegram_on_disconnected (struct telegram *tg) @@ -351,32 +401,9 @@ void telegram_on_disconnected (struct telegram *tg) assert (0); } -/** - * A proxy connection was created by purple - * - * Set the proxy to the current telegram-instance, and add callbacks to monitor - */ -void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) -{ - purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); - struct telegram *tg = (struct telegram*) data; - telegram_conn *conn = tg->extra; - if (fd == -1) { - logprintf("purple_proxy_connect failed: %s\n", error_message); - telegram_destroy(tg); - return; - } - - purple_debug_info(PLUGIN_ID, "Connecting to the telegram network...\n"); - conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, tg); - conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg); - - telegram_set_proxy(tg, fd); -} - struct telegram_config tgconf = { NULL, - NULL, // on output + tgprpl_has_output, // on output telegram_on_proxy_request, telegram_on_proxy_close, telegram_on_phone_registration, @@ -400,22 +427,21 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); char const *username = purple_account_get_username(acct); - struct dc DC; init_dc_settings(acct, &DC); - - // TODO: fetch current home directory - // use this as root + + // create a new instance of telegram struct telegram *tg = telegram_new (&DC, username, &tgconf); telegram_restore_session(tg); - + + // create handle to store additional info for libpurple in + // the new telegram instance telegram_conn *conn = g_new0(telegram_conn, 1); conn->tg = tg; conn->gc = gc; conn->pa = acct; purple_connection_set_protocol_data(gc, conn); tg->extra = conn; - purple_connection_set_state (conn->gc, PURPLE_CONNECTING); telegram_connect (tg); } @@ -658,7 +684,7 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me PurpleBuddy *b = purple_find_buddy (pa, who); peer_id_t *peer = purple_buddy_get_protocol_data (b); do_send_message (conn->tg, *peer, message, strlen(message)); - tgprpl_has_output (conn->tg); + telegram_flush (conn->tg); return 1; } @@ -913,7 +939,7 @@ static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) logprintf ("chat now known\n"); char *subject, *owner, *part; do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); - tgprpl_has_output (conn->tg); + telegram_flush (conn->tg); } else { logprintf ("chat already known\n"); serv_got_joined_chat(conn->gc, atoi(id), groupname); diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index b44fe81..4fde230 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -34,21 +34,12 @@ #include "version.h" #include "account.h" #include "connection.h" +#include "mtproto-client.h" typedef struct { struct telegram *tg; PurpleAccount *pa; PurpleConnection *gc; - - /** - * Write handler returned by purple_input_add - */ - guint wh; - - /** - * Read handler returned by purple_input_add - */ - guint rh; /** * Whether the state of the protocol has changed since the last save @@ -62,4 +53,28 @@ typedef struct { } telegram_conn; +typedef struct { + + /** + * The mtproto_connection associated with this handle + */ + struct mtproto_connection *mtp; + + /** + * Write handler returned by purple_input_add + */ + guint wh; + + /** + * Read handler returned by purple_input_add + */ + guint rh; + + /** + * The file descriptor of the used socket + */ + int fd; + +} mtproto_handle; + #endif diff --git a/queries.c b/queries.c index fc4c7e4..c095b54 100644 --- a/queries.c +++ b/queries.c @@ -65,10 +65,6 @@ int offline_mode = 0; extern int sync_from_start; int sync_from_start = 0; -void telegram_flush_queries (struct telegram *instance) { - instance->config->on_output(instance); -} - #define memcmp8(a,b) memcmp ((a), (b), 8) DEFINE_TREE (query, struct query *, memcmp8, 0) ; @@ -3071,14 +3067,3 @@ void do_update_typing (struct telegram *instance, peer_id_t id) { send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_typing_methods, 0); } -int telegram_has_output (struct telegram *instance) -{ - if (!instance->connection) { - return 0; - } - if (instance->session_state == STATE_READY) { - return tree_count_query (instance->queries_tree) > 0; - } - return instance->connection->queries_num > 0; -} - diff --git a/telegram.c b/telegram.c index 49bffd1..d402997 100755 --- a/telegram.c +++ b/telegram.c @@ -159,12 +159,12 @@ void telegram_change_state (struct telegram *instance, int state, void *data) mtproto_close (instance->connection); assert (instance->config->proxy_request_cb); // tell the proxy to close all connections - instance->config->proxy_close_cb (instance, instance->connection->connection->fd); + //instance->config->proxy_close_cb (instance, instance->connection->connection->fd); // remove all left over queries and timers free_timers (instance); free_queries (instance); - + // start a new connection to the demanded data center. The pointer to the // new dc should was already updated by the on_error function of the query telegram_connect (instance); @@ -359,26 +359,25 @@ void on_authorized(struct mtproto_connection *c, void *data) telegram_change_state(instance, STATE_AUTHORIZED, NULL); } -void telegram_read_input (struct telegram *instance) -{ - try_read (instance->connection->connection); - - // free all mtproto_connections that may have errored - mtproto_free_closed(instance); -} - -void telegram_set_proxy(struct telegram *instance, int fd) +struct mtproto_connection *telegram_add_proxy(struct telegram *instance, int fd, void *handle) { struct dc *DC_working = telegram_get_working_dc (instance); instance->connection = mtproto_new (DC_working, fd, instance); + instance->connection->handle = handle; instance->connection->on_ready = on_authorized; instance->connection->on_ready_data = instance; mtproto_connect (instance->connection); + return instance->connection; } -int telegram_write_output (struct telegram *instance) +void mtp_read_input (struct mtproto_connection *mtp) { - return try_write(instance->connection->connection); + try_read (mtp->connection); +} + +int mtp_write_output (struct mtproto_connection *mtp) +{ + return try_write(mtp->connection); } int telegram_authenticated (struct telegram *instance) @@ -386,4 +385,21 @@ int telegram_authenticated (struct telegram *instance) return telegram_get_working_dc (instance)->auth_key_id > 0; } +void telegram_flush (struct telegram *instance) +{ + logprintf ("telegram flush()\n"); + int i; + for (i = 0; i < 100; i++) { + struct mtproto_connection *c = instance->Cs[i]; + if (!c) continue; + if (!c->connection) continue; + if (c->connection->out_bytes) { + logprintf ("connection %d has %d bytes, triggering on_output.", + i, c->connection->out_bytes); + instance->config->on_output(c->handle); + } else { + logprintf ("connection %d has no bytes, skipping\n"); + } + } +} diff --git a/telegram.h b/telegram.h index 2b90f9b..3c19742 100644 --- a/telegram.h +++ b/telegram.h @@ -110,7 +110,7 @@ struct telegram_config { /** * Called when there is pending network output */ - void (*on_output)(struct telegram *instance); + void (*on_output)(void *handle); /** * A callback function that delivers a connections to the given hostname @@ -123,7 +123,7 @@ struct telegram_config { * A callback function that is called once the proxy connection is no longer * needed. This is useful for freeing all used resources. */ - void (*proxy_close_cb) (struct telegram *instance, int fd); + void (*proxy_close_cb) (void *handle); /** * A callback function that is called when a phone registration is required. @@ -249,6 +249,9 @@ struct telegram { int get_difference_active; struct message *ML[MSG_STORE_SIZE]; + /* + * All active MtProto connections + */ int cs; struct mtproto_connection *Cs[100]; @@ -304,27 +307,18 @@ int telegram_login (struct telegram *instance); /** * Read and process all available input from the network */ -void telegram_read_input (struct telegram *instance); +void mtp_read_input (struct mtproto_connection *mtp); /** * Write all available output to the network */ -int telegram_write_output (struct telegram *instance); - -/** - * Return whether there is pending output. - */ -int telegram_has_output (struct telegram *instance); +int mtp_write_output (struct mtproto_connection *mtp); /** * Try to interpret RPC calls and apply the changes to the current telegram state */ void try_rpc_interpret(struct telegram *instance, int op, int len); -/* - * TODO: Refactor all old calls to take a telegrma instance - */ - /** * Request a registration code */ @@ -391,15 +385,18 @@ void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)); void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); /** - * Set the proxy-connection to use + * Set the connection after a proxy_request_cb * - * NOTE: you may only call this function from the + * @param fd The file-descriptor of the acquired connection + * @param handle A handle that will be passed back on output and close callbacks */ -void telegram_set_proxy(struct telegram *instance, int fd); +struct mtproto_connection *telegram_add_proxy(struct telegram *tg, int fd, void *handle); /** * Return wether telegram is authenticated with the currently active data center */ int telegram_authenticated (struct telegram *instance); +void telegram_flush (struct telegram *instance); + #endif From bb87200d5ff5c7c0932fcc679f3b3b82d848bb02 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 18 Sep 2014 22:26:08 +0200 Subject: [PATCH 384/465] Fix a bug that caused old messages to not be loaded on startup Do not overwrite state file with secret chat file, provide flag for complete sync from start in do_get_difference --- mtproto-client.c | 2 +- purple-plugin/telegram-purple.c | 8 ++------ queries.c | 18 +++++++----------- queries.h | 2 +- telegram.c | 2 +- 5 files changed, 12 insertions(+), 20 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index d221f4c..c6250e8 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1548,7 +1548,7 @@ void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { void work_updates_to_long (struct connection *c UU, long long msg_id UU) { assert (fetch_int (c->mtconnection) == (int)CODE_updates_too_long); logprintf ("updates to long... Getting difference\n"); - do_get_difference (c->instance); + do_get_difference (c->instance, 0); } void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f6c2d51..dcba7c4 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -183,8 +183,6 @@ static void login_verification_fail(PurpleAccount *acct) static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition cond) { mtproto_handle *conn = data; - logprintf("tgprpl_output_cb(%p)\n", data); - logprintf("mtp=%p, fd=%d, rh=%d, wh=%d\n", conn->mtp, conn->fd, conn->rh, conn->wh); if (!conn->mtp) { logprintf ("connection no loner existing, do nothing. \n"); return; @@ -365,9 +363,9 @@ void telegram_on_ready (struct telegram *instance) tggroup = purple_group_new ("Telegram"); purple_blist_add_group (tggroup, NULL); } - do_update_contact_list(instance); + do_get_difference(instance, 0); do_get_dialog_list(instance); - do_get_difference(instance); + do_update_contact_list(instance); telegram_flush (conn->tg); conn->timer = purple_timeout_add (5000, queries_timerfunc, conn); } @@ -477,8 +475,6 @@ void message_allocated_handler(struct telegram *tg, struct message *M) peer_id_t to_id = M->to_id; char *from = g_strdup_printf("%d", id); char *to = g_strdup_printf("%d", to_id.id); - logprintf ("from: %s\n", from); - logprintf ("fwd_date: %d\n", M->date); switch (to_id.type) { case PEER_CHAT: logprintf ("PEER_CHAT\n"); diff --git a/queries.c b/queries.c index c095b54..2345565 100644 --- a/queries.c +++ b/queries.c @@ -59,12 +59,8 @@ char *get_downloads_directory (void); int verbosity; -extern int offline_mode; int offline_mode = 0; -extern int sync_from_start; -int sync_from_start = 0; - #define memcmp8(a,b) memcmp ((a), (b), 8) DEFINE_TREE (query, struct query *, memcmp8, 0) ; @@ -246,12 +242,12 @@ void query_result (struct telegram *instance, long long id UU) { void insert_event_timer (struct telegram *instance, struct event_timer *ev) { - logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + // logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); instance->timer_tree = tree_insert_timer (instance->timer_tree, ev, lrand48 ()); } void remove_event_timer (struct telegram *instance, struct event_timer *ev) { - logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + // logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); instance->timer_tree = tree_delete_timer (instance->timer_tree, ev); } @@ -2580,7 +2576,6 @@ void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char } out_int (mtp, get_peer_id (E->id)); out_cstring (mtp, instance->g_a, 256); - // TODO: properly... write_secret_chat_file (instance, instance->secret_path); BN_clear_free (g); @@ -2745,13 +2740,14 @@ int get_difference_on_answer (struct query *q UU) { bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); instance->unread_messages = fetch_int (mtp); + logprintf ("UNREAD MESSAGES: %d\n", ml_pos); //write_state_file (); for (i = 0; i < ml_pos; i++) { event_update_new_message (instance, instance->ML[i]); ////print_message (ML[i]); } if (x == CODE_updates_difference_slice) { - do_get_difference (instance); + do_get_difference (instance, 0); } else { //difference_got = 1; } @@ -2770,7 +2766,8 @@ struct query_methods get_difference_methods = { .on_answer = get_difference_on_answer }; -void do_get_difference (struct telegram *instance) { +void do_get_difference (struct telegram *instance, int sync_from_start) { + logprintf ("do_get_difference()\n"); struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); @@ -2778,13 +2775,12 @@ void do_get_difference (struct telegram *instance) { //difference_got = 0; clear_packet (mtp); do_insert_header (mtp); + logprintf("do_get_difference(pts:%d, last_date:%d, qts: %d)\n", instance->proto.pts, instance->proto.last_date, instance->proto.qts); if (instance->proto.seq > 0 || sync_from_start) { if (instance->proto.pts == 0) { instance->proto.pts = 1; } if (instance->proto.qts == 0) { instance->proto.qts = 1; } if (instance->proto.last_date == 0) { instance->proto.last_date = 1; } - logprintf("do_get_difference(pts:%d, last_date:%d, qts: %d)\n", - instance->proto.pts, instance->proto.last_date, instance->proto.qts); out_int (mtp, CODE_updates_get_difference); out_int (mtp, instance->proto.pts); out_int (mtp, instance->proto.last_date); diff --git a/queries.h b/queries.h index 30435d6..a141004 100644 --- a/queries.h +++ b/queries.h @@ -112,7 +112,7 @@ void do_export_auth (struct telegram *instance, int num); void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s); void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E); -void do_get_difference (struct telegram*); +void do_get_difference (struct telegram*, int sync_from_start); void do_mark_read (struct telegram *instance, peer_id_t id); void do_visualize_key (struct binlog *bl, peer_id_t id); void do_create_keys_end (struct telegram *, struct secret_chat *U); diff --git a/telegram.c b/telegram.c index d402997..5464243 100755 --- a/telegram.c +++ b/telegram.c @@ -317,7 +317,7 @@ void telegram_store_session(struct telegram *instance) assure_file_exists(instance->config_path, "secret"); write_auth_file(&instance->auth, instance->auth_path); write_state_file(&instance->proto, instance->state_path); - write_secret_chat_file(instance, instance->state_path); + write_secret_chat_file(instance, instance->secret_path); } void on_authorized(struct mtproto_connection *c, void* data); From 4c358b69622380deda558b9b41c173f50d15b95f Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 19 Sep 2014 18:22:11 +0200 Subject: [PATCH 385/465] Don't open multiple chats when multiple messages arrive while a chat is still not joined --- purple-plugin/telegram-purple.c | 76 +++++++++++++++++++++++---------- purple-plugin/telegram-purple.h | 10 +++++ 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index dcba7c4..431668b 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -103,11 +103,20 @@ static PurpleConversation *chat_show (PurpleConnection *gc, int id) serv_got_joined_chat(gc, id, chat_id_get_comp_val(gc, id, "subject")); } } else { - // join chat first - logprintf ("joining chat first...\n"); telegram_conn *conn = purple_connection_get_protocol_data(gc); - do_get_chat_info (conn->tg, MK_CHAT(id)); - telegram_flush (conn->tg); + gchar *name = g_strdup_printf ("%d", id); + if (g_hash_table_contains (conn->joining_chats, name)) { + // already joining this chat + g_free(name); + } else { + // mark chat as already joining + g_hash_table_insert(conn->joining_chats, name, 0); + + // join chat first + logprintf ("joining chat first...\n"); + do_get_chat_info (conn->tg, MK_CHAT(id)); + telegram_flush (conn->tg); + } } return convo; } @@ -438,7 +447,11 @@ static void tgprpl_login(PurpleAccount * acct) conn->tg = tg; conn->gc = gc; conn->pa = acct; + conn->new_messages = g_queue_new(); + + conn->joining_chats = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); purple_connection_set_protocol_data(gc, conn); + tg->extra = conn; purple_connection_set_state (conn->gc, PURPLE_CONNECTING); telegram_connect (tg); @@ -455,15 +468,35 @@ static void tgprpl_close(PurpleConnection * gc) telegram_destroy(conn->tg); } +static void chat_add_message(struct telegram *tg, struct message *M) +{ + telegram_conn *conn = tg->extra; + + if (chat_show (conn->gc, M->to_id.id)) { + // chat initialies, add message now + if (M->from_id.id == tg->our_id) { + serv_got_chat_in(conn->gc, get_peer_id(M->to_id), "You", + PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); + } else { + peer_t *fromPeer = user_chat_get (tg->bl, M->from_id); + char *alias = malloc(BUDDYNAME_MAX_LENGTH); + user_get_alias(fromPeer, alias, BUDDYNAME_MAX_LENGTH); + serv_got_chat_in(conn->gc, get_peer_id(M->to_id), alias, + PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); + g_free(alias); + } + } else { + // add message once the chat was initialised + g_queue_push_tail (conn->new_messages, M); + } +} + void message_allocated_handler(struct telegram *tg, struct message *M) { logprintf ("message_allocated_handler\n"); telegram_conn *conn = tg->extra; PurpleConnection *gc = conn->gc; - // TODO: this should probably be freed again somwhere - int id = get_peer_id(M->from_id); - if (M->service) { // TODO: handle service messages properly, currently adding them // causes a segfault for an unknown reason @@ -471,23 +504,14 @@ void message_allocated_handler(struct telegram *tg, struct message *M) return; } - // + int id = get_peer_id(M->from_id); peer_id_t to_id = M->to_id; char *from = g_strdup_printf("%d", id); char *to = g_strdup_printf("%d", to_id.id); switch (to_id.type) { case PEER_CHAT: logprintf ("PEER_CHAT\n"); - chat_show (gc, to_id.id); - if (M->from_id.id == tg->our_id) { - serv_got_chat_in(gc, get_peer_id(M->to_id), "You", PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); - } else { - peer_t *fromPeer = user_chat_get (tg->bl, M->from_id); - char *alias = malloc(BUDDYNAME_MAX_LENGTH); - user_get_alias(fromPeer, alias, BUDDYNAME_MAX_LENGTH); - serv_got_chat_in(gc, get_peer_id(M->to_id), alias, PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); - g_free(alias); - } + chat_add_message(tg, M); break; case PEER_USER: @@ -973,7 +997,17 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) 0 ); } + struct message *M = 0; + logprintf ("g_queue_pop_head()\n"); + while (M = g_queue_pop_head (conn->new_messages)) { + logprintf ("adding msg-id\n"); + int id = get_peer_id(M->from_id); + chat_add_message(instance, M); + } + gchar *name = g_strdup_printf ("%d", chatid.id); + g_hash_table_remove (conn->joining_chats, name); + g_free (name); } /** @@ -984,11 +1018,7 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) * is received. * @param who The name of the user to send the invation to. */ -static void tgprpl_chat_invite(PurpleConnection * gc, int id, const char *message, const char *name) -{ - purple_debug_info(PLUGIN_ID, "tgprpl_chat_invite()\n"); -} - +static void tgprpl_chat_invite(PurpleConnection * gc, int id, const char *message, const char *name) { purple_debug_info(PLUGIN_ID, "tgprpl_chat_invite()\n"); } /** * Returns a chat name based on the information in components. Use * #chat_info_defaults if you instead need to generate a hashtable diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 4fde230..fe5d747 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -51,6 +51,16 @@ typedef struct { */ guint timer; + /** + * Queue of all new messages that need to be added to a chat + */ + GQueue *new_messages; + + /** + * Queue of all joined chats + */ + GHashTable *joining_chats; + } telegram_conn; typedef struct { From c1f170467c99e9762bbe4c1114e6220ab3e7bee3 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 10:02:49 +0200 Subject: [PATCH 386/465] Flush connection after execiton of timer function --- purple-plugin/telegram-purple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 431668b..4991795 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -325,6 +325,7 @@ gboolean queries_timerfunc (gpointer data) { logprintf ("queries_timerfunc()\n"); telegram_conn *conn = data; work_timers (conn->tg); + telegram_flush (conn->tg); if (conn->updated) { logprintf ("State updated, storing current session...\n"); From 7fa1600e0be3d5140360823c4f98b99196b97c04 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 10:04:40 +0200 Subject: [PATCH 387/465] Add log output for received message types --- mtproto-client.c | 13 +++++++++++++ net.c | 5 ++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index c6250e8..4a45ea7 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -871,6 +871,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { switch (op) { case CODE_update_new_message: { + logprintf ("CODE_update_new_message\n"); struct message *M UU = fetch_alloc_message (self, tg); assert (M); fetch_pts (self); @@ -882,6 +883,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { }; case CODE_update_message_i_d: { + logprintf ("CODE_update_message\n"); int id = fetch_int (self); // id int new = fetch_long (self); // random_id struct message *M = message_get (bl, new); @@ -892,6 +894,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { break; case CODE_update_read_messages: { + logprintf ("CODE_update_read_message\n"); assert (fetch_int (self) == (int)CODE_vector); int n = fetch_int (self); int i; @@ -915,6 +918,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { break; case CODE_update_user_typing: { + logprintf ("CODE_update_user_typing\n"); peer_id_t id = MK_USER (fetch_int (self)); peer_t *U UU = user_chat_get (bl, id); event_update_user_typing (tg, U); @@ -1372,6 +1376,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { } void work_update_short (struct connection *c, long long msg_id) { + logprintf ("work_update_short\n"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (self) == CODE_update_short); @@ -1380,6 +1385,7 @@ void work_update_short (struct connection *c, long long msg_id) { } void work_updates (struct connection *c, long long msg_id) { + logprintf ("work_updates(\n)"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (c->mtconnection) == CODE_updates); @@ -1404,6 +1410,7 @@ void work_updates (struct connection *c, long long msg_id) { } void work_update_short_message (struct connection *c UU, long long msg_id UU) { + logprintf ("work_update_short_message(\n)"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (c->mtconnection) == (int)CODE_update_short_message); @@ -1418,6 +1425,7 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) { } void work_update_short_chat_message (struct connection *c, long long msg_id UU) { + logprintf ("work_update_chat_message(\n)"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (self) == CODE_update_short_chat_message); @@ -1489,6 +1497,7 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { #define MAX_PACKED_SIZE (1 << 24) void work_packed (struct connection *c, long long msg_id) { + logprintf ("work_packet()\n"); assert (fetch_int (c->mtconnection) == CODE_gzip_packed); static int in_gzip; static int buf[MAX_PACKED_SIZE >> 2]; @@ -1515,6 +1524,7 @@ void work_packed (struct connection *c, long long msg_id) { } void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { + logprintf ("work_bad_server_salt()\n"); assert (fetch_int (c->mtconnection) == (int)CODE_bad_server_salt); long long id = fetch_long (c->mtconnection); query_restart (c->instance, id); @@ -1525,12 +1535,14 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { } void work_pong (struct connection *c UU, long long msg_id UU) { + logprintf ("work_pong()\n"); assert (fetch_int (c->mtconnection) == CODE_pong); fetch_long (c->mtconnection); // msg_id fetch_long (c->mtconnection); // ping_id } void work_detailed_info (struct connection *c UU, long long msg_id UU) { + logprintf ("work_detailed_info()\n"); assert (fetch_int (c->mtconnection) == CODE_msg_detailed_info); fetch_long (c->mtconnection); // msg_id fetch_long (c->mtconnection); // answer_msg_id @@ -1539,6 +1551,7 @@ void work_detailed_info (struct connection *c UU, long long msg_id UU) { } void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { + logprintf ("work_new_detailed_info()\n"); assert (fetch_int (c->mtconnection) == (int)CODE_msg_new_detailed_info); fetch_long (c->mtconnection); // answer_msg_id fetch_int (c->mtconnection); // bytes diff --git a/net.c b/net.c index 459c7d4..b8d5779 100644 --- a/net.c +++ b/net.c @@ -95,15 +95,14 @@ void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_sess void start_ping_timer (struct connection *c); int ping_alarm (struct connection *c) { - if (verbosity > 2) { - logprintf ("ping alarm\n"); - } assert (c->state == conn_ready || c->state == conn_connecting); if (get_double_time () - c->last_receive_time > 20 * PING_TIMEOUT) { logprintf ( "fail connection: reason: ping timeout\n"); c->state = conn_failed; fail_connection (c); + } else if (get_double_time () - c->last_receive_time > 5 * PING_TIMEOUT && c->state == conn_ready) { + logprintf ("sending PING...\n"); int x[3]; x[0] = CODE_ping; *(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 (); From cd8866c4e2aa6c1dd55eb5d4a7e58534d9261cbc Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 16:23:39 +0200 Subject: [PATCH 388/465] Remove unused includes of libreadline --- loop.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/loop.c b/loop.c index 2f6d251..d9a7d21 100644 --- a/loop.c +++ b/loop.c @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include From 92a57d18bbd41d325f7d4aea966aaf863c221b2f Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 16:24:43 +0200 Subject: [PATCH 389/465] Don't check for libreadline and but check for glib and libpurple in configure --- configure.ac | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index fbdb867..5c9572b 100644 --- a/configure.ac +++ b/configure.ac @@ -14,21 +14,10 @@ AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([backtrace], [execinfo]) AC_CHECK_LIB([z], [inflate]) AC_CHECK_LIB([crypto], [AES_set_encrypt_key]) +AC_CHECK_LIB([glib], [g_main_loop_new]) +AC_CHECK_LIB([purple], [purple_notify_message]) EXTRA_LIBS="" -AC_CHECK_LIB([readline], [rl_save_prompt], - [ - AC_DEFINE([READLINE_GNU], [1], [Use gnu libreadline]) - [ EXTRA_LIBS="${EXTRA_LIBS} -lreadline" ; ] - ], - [ - AC_SEARCH_LIBS([tgetnum], [ncursesw ncurses curses]) - AC_CHECK_LIB([edit], [rl_set_prompt]) - AC_DEFINE([READLINE_EDIT], [1], [Use libedit]) - [ EXTRA_LIBS="${EXTRA_LIBS} -ledit" ; ] - ] -) - #check for custom prog name AC_ARG_WITH(progname,[--with-progname=], [ From 73f44ffe0b6a8e148dd000718c41f2ce4e61d1bd Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 16:57:50 +0200 Subject: [PATCH 390/465] Remove non-working checks for glib and libpurple (for now) and generate a new configure --- configure | 172 +++------------------------------------------------ configure.ac | 5 +- 2 files changed, 11 insertions(+), 166 deletions(-) diff --git a/configure b/configure index ea2640d..2922801 100755 --- a/configure +++ b/configure @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='telegram-purple' PACKAGE_TARNAME='telegram-purple' -PACKAGE_VERSION='0.1' -PACKAGE_STRING='telegram-purple 0.1' +PACKAGE_VERSION='0.2' +PACKAGE_STRING='telegram-purple 0.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1223,7 +1223,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures telegram-purple 0.1 to adapt to many kinds of systems. +\`configure' configures telegram-purple 0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1284,7 +1284,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of telegram-purple 0.1:";; + short | recursive ) echo "Configuration of telegram-purple 0.2:";; esac cat <<\_ACEOF @@ -1369,7 +1369,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -telegram-purple configure 0.1 +telegram-purple configure 0.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1788,7 +1788,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by telegram-purple $as_me 0.1, which was +It was created by telegram-purple $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3181,163 +3181,9 @@ _ACEOF fi + EXTRA_LIBS="" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_save_prompt in -lreadline" >&5 -$as_echo_n "checking for rl_save_prompt in -lreadline... " >&6; } -if ${ac_cv_lib_readline_rl_save_prompt+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lreadline $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char rl_save_prompt (); -int -main () -{ -return rl_save_prompt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_readline_rl_save_prompt=yes -else - ac_cv_lib_readline_rl_save_prompt=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_save_prompt" >&5 -$as_echo "$ac_cv_lib_readline_rl_save_prompt" >&6; } -if test "x$ac_cv_lib_readline_rl_save_prompt" = xyes; then : - - -$as_echo "#define READLINE_GNU 1" >>confdefs.h - - EXTRA_LIBS="${EXTRA_LIBS} -lreadline" ; - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetnum" >&5 -$as_echo_n "checking for library containing tgetnum... " >&6; } -if ${ac_cv_search_tgetnum+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char tgetnum (); -int -main () -{ -return tgetnum (); - ; - return 0; -} -_ACEOF -for ac_lib in '' ncursesw ncurses curses; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_tgetnum=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_tgetnum+:} false; then : - break -fi -done -if ${ac_cv_search_tgetnum+:} false; then : - -else - ac_cv_search_tgetnum=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetnum" >&5 -$as_echo "$ac_cv_search_tgetnum" >&6; } -ac_res=$ac_cv_search_tgetnum -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_set_prompt in -ledit" >&5 -$as_echo_n "checking for rl_set_prompt in -ledit... " >&6; } -if ${ac_cv_lib_edit_rl_set_prompt+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ledit $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char rl_set_prompt (); -int -main () -{ -return rl_set_prompt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_edit_rl_set_prompt=yes -else - ac_cv_lib_edit_rl_set_prompt=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_rl_set_prompt" >&5 -$as_echo "$ac_cv_lib_edit_rl_set_prompt" >&6; } -if test "x$ac_cv_lib_edit_rl_set_prompt" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBEDIT 1 -_ACEOF - - LIBS="-ledit $LIBS" - -fi - - -$as_echo "#define READLINE_EDIT 1" >>confdefs.h - - EXTRA_LIBS="${EXTRA_LIBS} -ledit" ; - - -fi - - #check for custom prog name # Check whether --with-progname was given. @@ -4557,7 +4403,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by telegram-purple $as_me 0.1, which was +This file was extended by telegram-purple $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4610,7 +4456,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -telegram-purple config.status 0.1 +telegram-purple config.status 0.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 5c9572b..5e3408b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.68]) -AC_INIT([telegram-purple], [0.1]) +AC_INIT([telegram-purple], [0.2]) # Checks for programs. AC_PROG_CC @@ -14,8 +14,7 @@ AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([backtrace], [execinfo]) AC_CHECK_LIB([z], [inflate]) AC_CHECK_LIB([crypto], [AES_set_encrypt_key]) -AC_CHECK_LIB([glib], [g_main_loop_new]) -AC_CHECK_LIB([purple], [purple_notify_message]) + EXTRA_LIBS="" #check for custom prog name From 81e9eed71f0fc371d12ecf2bb18238ac19b98baa Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 18:12:00 +0200 Subject: [PATCH 391/465] Ignore core dumps --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6a40545..524af2b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ tags *.pyc app-hash.png .gdbinit +core +core* From 55949d8d92f8401e05dfcccf4799331137a29403 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 18:12:42 +0200 Subject: [PATCH 392/465] Update build tool dependencies and add a new configure --- .travis.yml | 5 +---- configure | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index ec28eea..915d880 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,7 @@ compiler: - clang install: - - sudo apt-get install libconfig8-dev - - sudo apt-get install libreadline6-dev - - sudo apt-get install libssl-dev - - sudo apt-get install liblua5.2-dev lua5.2 + - sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev script: - ./configure diff --git a/configure b/configure index 2922801..1c22650 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for telegram-purple 0.1. +# Generated by GNU Autoconf 2.69 for telegram-purple 0.2. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. From 90bed1ef61ba545692d481825174f5630a3f3b36 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 18:13:37 +0200 Subject: [PATCH 393/465] Provide english readme file and update build instructions --- README.md | 271 +++++++++++------------------------------------------- 1 file changed, 52 insertions(+), 219 deletions(-) diff --git a/README.md b/README.md index 3abf83a..bb2e11e 100644 --- a/README.md +++ b/README.md @@ -1,252 +1,85 @@ telegram-purple =============== +Telegram-purple is a Libpurple plugin that adds support for the Telegram messenger. Its still in an early (pre-alpha) development stage, but already provides basic chat functionality and group chats. -# Installieren +This plugin is based on the great [Telegram-cli](http://github.com/vysheng/tg), a full-featured terminal-based client for Telegram created by [Vysheng](http://github.com/vysheng). -1. Sicherstellen dass Pidgin installiert ist. -2. Dieses Git-Repository klonen. +# Features +## Already Implemented + + - Group chats + - Multiple accounts at once + - Support for libpurple proxy settings + +## Planned + +We are trying to create a full-featured protocol plugin for Telegram, that can make use of all major features of +the Messenger. The following features are currently under active development (or planned) and will probably be +added in the future: + + - encrypted chats + - picture, audio and video messages + - file transfers + - geo-locations + - emojis + + +# Installation Instructions + +Unfortunately there are currently no packages, so you need to compile it yourself: + +1. Get this repository either from Bitbucket or from the Github mirror. git clone https://bitbucket.org/telegrampurple/telegram-purple -3. Im Ordner von **telegram-purple** make ausführen: +2. Fetch all needed dependencies - cd telgram-purple - ./configure --disable-liblua --disable-libconfig - make install +This plugin depends on a working libpurple client and the following packages: + - glib-2.0 + - libcrypto + - libpurple + - libzlib -Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. +On Fedora you can install all dependencies with: -# Testen und Debuggen + sudo yum install gcc openssl-devel glib2-devel libpurple-devel -Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: +And on Debian/Ubuntu you can use: - sudo chmod 777 -R `pkg-config --variable=plugindir purple` - sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol + sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev -## Testen +3. Compile and install + ./configure + make + sudo make install -Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: +# Usage - make run +After succesfully completing all steps mentioned in the installation instructions, you should restart Pidgin to ensure that the plugin is loaded. When everything went well, Telegram should show up in the account manager: +![Create a new Telegram account](lauschgift.org/telegram-purple/res/install-1.png) -Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: +The username is your current phone number, including your full country prefix instead of a leading '0'. For Germany, this would be '+49' for example. Telegram will verify your phone number by sending you a verification code via sms. You will be prompted for this code, once that happens. +![Provide a phone number](lauschgift.org/telegram-purple/res/install-2.png) + +Now you should be able to see all your contacts and chats in your buddy list and send/receive messages. - sudo killall pidgin +# A Word of Warning +This is a very early (pre-alpha) version of the plugin, mainly used for development and testing and NOT for productive use. +Even though it already provides basic features, you should stil expect bugs and crashes when running it. -### Filtern der Lognachrichten - -Wenn Pidgin einfach mit **make run** ausgeführt wird, werden alle Debugnachrichten des gesamten Programms ausgegegeben. Libpurple verwendet interne Loggingfunktionen die den Lognachrichten automatisch einen Prefix hinzufügen, z.B. "plugins:" für Nachrichten des Pluginsloaders und "prpl-telegram:" für Nachrichten dieses Plugins. - -Wenn man nur Ausgaben des Plugin-Loaders und von telegram-purple haben möchte kann man unnötige Nachrichten mit **grep** herausfiltern. - - - make run | grep -i 'prpl-telegram:\|plugins:' - - -# Deinstallieren - -Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: - - - sudo make uninstall - - - -# Coding-Guidelines - -## Coding Style - -Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. - - unsigned int some_function(int a, int b) - { - if (true) { - // ... - } else { - // ... - } - } - - -## Logging - -Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). - - - #include "debug.h" - #define PLUGIN_ID "prpl-telegram" - - // ... - - purple_debug_info(PLUGIN_ID, "Debugnachricht"); - - -## GIT -git pull -> Stand aktualisieren -git add -A -> Files hinzufügen -git push -> Stand hochladen -git commit -> Commiten - - - -## Troubleshooting - -Zum löschen der angelegten Accounts -rm /home/USER/.purple/accounts.xml - -Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden -======= -telegram-purple -=============== - - -# Installieren - -1. Sicherstellen dass Pidgin installiert ist. -2. Dieses Git-Repository klonen. - - - git clone https://bitbucket.org/telegrampurple/telegram-purple - - -3. Im Ordner von **telegram-purple** make ausführen: - - - cd telgram-purple - ./configure --disable-liblua --disable-libconfig - make install - - -Das Protokoll Telegram sollte dann beim nächsten Start in der Accountverwaltung von Pidgin automatisch auftauchen. - - -# Testen und Debuggen - -Um **telegram-purple** während der Entwicklung zu testen, ist es sinnvoll vorher die Berechtigungen des Plugin-Ordners zu ändern, damit beim Kopieren nicht jedes Mal Root-Rechte benötigt werden: - - - sudo chmod 777 -R `pkg-config --variable=plugindir purple` - sudo chmod 777 -R `pkg-config --variable=datarootdir purple`pixmaps/pidgin/protocol - - -## Testen - - -Zum Compilen, Testen und Ausgeben aller Debugnachrichten folgenden Befehl ausführen: - - - make run - - -Falls die Lognachrichten nach kurzer Zeit nicht mehr angezeigt werden, und die Meldung "Wird geschlossen, da bereits ein andere libpurple-Client läuft" erscheint, die laufende Instanz von Pidgin mit folgendem Befehl beenden: - - - sudo killall pidgin - - - -# Deinstallieren - -Mit folgendem Befehl werden alle installierten Dateien wieder aus den Plugin-Ordnern gelöscht: - - - sudo make uninstall - - - -# Coding-Guidelines - -## Speicherverwaltung - -Glib verwendet eigene Datentypen und eigene Funktionen zu Speicherverwaltung. Wenn diese mit den regulären Funktionen von c vermischt werden, z.B. malloc und g\_free auf dem selben Pointer, kann die Anwendung abstürzen. - - - char *str = malloc(10); - g_free(str); // APPLICATION ERROR - - -Beim Purple-Plugin müssen wir die Typen und Verwaltungsfunktionen von glib verwenden, deshalb werden im Unterordner ./purple-plugin ausschließlich g\_alloc g\_new und g\_free zum allozieren und löschen von Objekten verwendet. Siehe ([https://developer.gnome.org/glib/2.30/glib-Memory-Allocation.html]) - -In Telegram-Cli werden keine glib-Funktionen verwendet, deshalb müssen wie hier ausschließlich die regulären C-Funktionen malloc und free verwenden. - -### Aufrufe von Telegram-CLI - -Wir rufen Telegram-CLI vom Purple-Plugin aus auf. Um die verschiedenen Sorten der Speicherverwaltung nicht zu vermischen, muss Telegram-CLI seinen gesamten Speicher selbst verwalten. Wenn strings oder Structs vom Plugin aus an die Bibliothek übergeben werden müssen die Objekte deshalb kopiert werden. - - - void *telegram_do_something(Telegram tg, const char* string) - { - char *dup = malloc(strlen(login) * sizeof(char)); - dup = memcpy(dup, string); - global->login = dup; - } - - -Jede Komponente der Anwendung muss deshalb den Speicher den sie alloziert auch selbst verwalten, da andere Komponenten diese niemals löschen werden. Wenn der String im Plugin mit einer allozierenden Funktion wie g\_strdup erstellt wurde, muss diese deshalb auch wieder mit g\_free gelöscht werden, da sonst ein Memory Leak entsteht. - - - gchar *str = g_strdup(string); - // ... - telegram_do_something(telegram, str); - // ... - g\_gree(str); - - - -## Coding Style - -Wir wollen wenn möglichen den typischen Linux-C-Coding-Style verwenden. Bei Funktionen werden die Klammern auf der nächsten Zeile geschrieben, bei allem anderen auf der gleichen Zeile. Bei Funktionsargumenten zwischen Komma und dem nächsten Argument und nach Bedingungen von if/else-Blöcken immer ein Leerzeichen lassen. - - unsigned int some_function(int a, int b) - { - if (true) { - // ... - } else { - // ... - } - } - - -## Logging - -Wenn irgendeine Ausgabe gemacht wird, sollte das ausschließlich über die Libpurple Debugging-Funktionen passieren (Siehe die Anleitung zum Debuggen im [Libpurple-Howto](https://developer.pidgin.im/wiki/CHowTo/DebugAPIHowTo "Libpurple-HowTo")). - - - #include "debug.h" - #define PLUGIN_ID "prpl-telegram" - - // ... - - purple_debug_info(PLUGIN_ID, "Debugnachricht"); - - -## GIT -git pull -> Stand aktualisieren -git add -A -> Files hinzufügen -git push -> Stand hochladen -git commit -> Commiten - - - -## Troubleshooting - -Zum löschen der angelegten Accounts -rm /home/USER/.purple/accounts.xml - -Die lib muss eventuell nach /usr/lib/purple-2/telegram-purple.so kopiert werden - +When encountering a crash, please report it to us, preferably together with a backtrace [https://developer.pidgin.im/wiki/GetABacktrace] From 52058a52e34c292a1f5f2a52609c9d3c307055f0 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 18:18:34 +0200 Subject: [PATCH 394/465] Fix errors in README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bb2e11e..7ede9e6 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,13 @@ added in the future: Unfortunately there are currently no packages, so you need to compile it yourself: -1. Get this repository either from Bitbucket or from the Github mirror. +## Get this repository either from Bitbucket or from the Github mirror. git clone https://bitbucket.org/telegrampurple/telegram-purple -2. Fetch all needed dependencies +## Fetch all needed dependencies This plugin depends on a working libpurple client and the following packages: @@ -56,7 +56,7 @@ And on Debian/Ubuntu you can use: sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev -3. Compile and install +## Compile and install ./configure make @@ -67,11 +67,11 @@ And on Debian/Ubuntu you can use: After succesfully completing all steps mentioned in the installation instructions, you should restart Pidgin to ensure that the plugin is loaded. When everything went well, Telegram should show up in the account manager: -![Create a new Telegram account](lauschgift.org/telegram-purple/res/install-1.png) +![Create a new Telegram account](http://lauschgift.org/telegram-purple/res/install-1.png) The username is your current phone number, including your full country prefix instead of a leading '0'. For Germany, this would be '+49' for example. Telegram will verify your phone number by sending you a verification code via sms. You will be prompted for this code, once that happens. -![Provide a phone number](lauschgift.org/telegram-purple/res/install-2.png) +![Provide a phone number](http://lauschgift.org/telegram-purple/res/install-2.png) Now you should be able to see all your contacts and chats in your buddy list and send/receive messages. From 8919d2c3ec1d842d0bc17930a2bf2782a872c8b6 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 20 Sep 2014 18:31:04 +0200 Subject: [PATCH 395/465] Improve README --- README.md | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7ede9e6..d002016 100644 --- a/README.md +++ b/README.md @@ -7,23 +7,36 @@ This plugin is based on the great [Telegram-cli](http://github.com/vysheng/tg), # Features +Our long-term plan is to implement all major features of the Telegram protocol, but at the moment only a subset of the chat features is working. + ## Already Implemented - Group chats - - Multiple accounts at once - - Support for libpurple proxy settings + - Multiple accounts + - Complies with proxy settings ## Planned -We are trying to create a full-featured protocol plugin for Telegram, that can make use of all major features of -the Messenger. The following features are currently under active development (or planned) and will probably be -added in the future: +The following features are currently planned and will probably be added in the future: - - encrypted chats - - picture, audio and video messages - - file transfers - - geo-locations - - emojis + - Encrypted chats + - Picture, audio and video messages + - File transfers + - Geo-locations + - Emojie + - Adium Plugin + +## Platform Support + +Currently we can only provide an installation guide for Linux, even though it should be possible to compile this plugin on all platforms. If someone manages to create a working Windows or OSX build, please let us know. + + +# A Word of Warning + +This is a very early (pre-alpha) version for development and testing and NOT for productive use. +Even though it already provides basic features, you should still expect bugs and crashes when running it. + +When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace [https://developer.pidgin.im/wiki/GetABacktrace] # Installation Instructions @@ -75,11 +88,3 @@ The username is your current phone number, including your full country prefix in Now you should be able to see all your contacts and chats in your buddy list and send/receive messages. - -# A Word of Warning - -This is a very early (pre-alpha) version of the plugin, mainly used for development and testing and NOT for productive use. -Even though it already provides basic features, you should stil expect bugs and crashes when running it. - -When encountering a crash, please report it to us, preferably together with a backtrace [https://developer.pidgin.im/wiki/GetABacktrace] - From 164620f65d3471e8637570c48fb3ac603ff7f6e9 Mon Sep 17 00:00:00 2001 From: Christopher Althaus Date: Sat, 20 Sep 2014 23:20:14 +0200 Subject: [PATCH 396/465] Add show user icons in buddy list --- purple-plugin/telegram-purple.c | 72 +++++++++++++++++++- queries.c | 114 ++++++++++++-------------------- queries.h | 39 ++++++++--- structures.c | 4 +- telegram.c | 20 ++++++ telegram.h | 24 ++++++- 6 files changed, 190 insertions(+), 83 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 4991795..93ee6a6 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -73,6 +73,8 @@ void tg_cli_log_cb(const char* format, va_list ap) void message_allocated_handler (struct telegram *instance, struct message *M); void peer_allocated_handler (struct telegram *instance, void *user); +void user_info_received_handler (struct telegram *instance, struct user *user, int showInfo); +void download_finished_handler (struct telegram *instance, struct download *D); void telegram_on_phone_registration (struct telegram *instance); void telegram_on_client_registration (struct telegram *instance); void on_new_user_status(struct telegram *instance, void *user); @@ -421,6 +423,8 @@ struct telegram_config tgconf = { message_allocated_handler, peer_allocated_handler, + user_info_received_handler, + download_finished_handler, on_new_user_status, on_user_typing, on_chat_joined @@ -624,6 +628,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) purple_debug_info(PLUGIN_ID, "Alias %s\n", actual); buddy = purple_buddy_new(pa, name, actual); purple_blist_add_buddy(buddy, NULL, tggroup, NULL); + do_get_user_info(conn->tg, user->id, 0); } purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); @@ -632,7 +637,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) purple_prpl_got_user_status(account, name, "available", "message", "", NULL); else purple_prpl_got_user_status(account, name, "unavailable", "message", "", NULL); - + g_free(alias); g_free(name); } @@ -687,6 +692,64 @@ void peer_allocated_handler(struct telegram *tg, void *usr) } } +PurpleNotifyUserInfo *create_user_notify_info(struct user *usr) +{ + PurpleNotifyUserInfo *info = purple_notify_user_info_new(); + purple_notify_user_info_add_pair(info, "First name", usr->first_name); + purple_notify_user_info_add_pair(info, "Last name", usr->last_name); + purple_notify_user_info_add_pair(info, "Phone", usr->phone); + purple_notify_user_info_add_pair(info, "Status", usr->status.online == 1 ? "Online" : "Offline"); + return info; +} + +void user_info_received_handler(struct telegram *tg, struct user *usr, int show_info) +{ + logprintf("Get user info. \n %d", show_info); + char *who = g_strdup_printf("%d", usr->id.id); + if(usr->photo.sizes_num == 0) + { + telegram_conn *conn = tg->extra; + PurpleNotifyUserInfo *info = create_user_notify_info(usr); + purple_notify_userinfo(conn->gc, who, info, NULL, NULL); + }else{ + struct download_desc *dld = talloc(sizeof(struct download_desc)); + dld->data = usr; + dld->type = show_info == 1 ? 1 : 2; + do_load_photo(tg, &usr->photo, 0, dld); + } + g_free(who); +} + + +void download_finished_handler(struct telegram *tg, struct download *D) +{ + logprintf("download_finished_handler %s type %d\n", D->name, D->type); + //TODO: We need a type for user-photos! + if(D->type == 0) + { + struct download_desc *dl_desc = D->extra; + struct user *usr = dl_desc->data; + gchar *data = NULL; + size_t len; + GError *err = NULL; + g_file_get_contents(D->name, &data, &len, &err); + int imgStoreId = purple_imgstore_add_with_id(g_memdup(data, len), len, NULL); + logprintf("Imagestore id: %d\n", imgStoreId); + //Create user info + char *who = g_strdup_printf("%d", usr->id.id); + telegram_conn *conn = tg->extra; + if(dl_desc->type == 1) + { + PurpleNotifyUserInfo *info = create_user_notify_info(usr); + char *profile_image = profile_image = g_strdup_printf("
", imgStoreId); + purple_notify_user_info_add_pair(info, "Profile image", profile_image); + purple_notify_userinfo(conn->gc, who, info, NULL, NULL); + g_free(profile_image); + } + purple_buddy_icons_set_for_user(conn->pa, who, g_memdup(data, len), len, NULL); + g_free(who); + } +} /** * This PRPL function should return a positive value on success. * If the message is too big to be sent, return -E2BIG. If @@ -877,7 +940,14 @@ static void tgprpl_set_status(PurpleAccount * acct, PurpleStatus * status) */ static void tgprpl_get_info(PurpleConnection * gc, const char *username) { + purple_debug_info(PLUGIN_ID, "tgprpl_get_info()\n"); + telegram_conn *conn = purple_connection_get_protocol_data(gc); + peer_id_t u = MK_USER(atoi(username)); + do_get_user_info(conn->tg, u, 1); + purple_debug_info(PLUGIN_ID, "tgprpl_get_info ready()\n"); + //fetch_alloc_user_full(tg->connection); + //fetch_user_full(tg->connection, user); } diff --git a/queries.c b/queries.c index 2345565..41b68d9 100644 --- a/queries.c +++ b/queries.c @@ -1782,7 +1782,8 @@ int user_info_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); // TODO: Use user info - struct user *U UU = fetch_alloc_user_full (mtp); + struct user *U = fetch_alloc_user_full (mtp); + event_user_info_received_handler(mtp->instance, U, (int)q->extra); //print_user_info (U); return 0; } @@ -1791,18 +1792,10 @@ struct query_methods user_info_methods = { .on_answer = user_info_on_answer }; -void do_get_user_info (struct telegram *instance, peer_id_t id) { +void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo) { + logprintf ("do_get_user_info\n"); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; - if (offline_mode) { - peer_t *C = user_chat_get (mtp->bl, id); - if (!C) { - logprintf ("No such user\n"); - } else { - //print_user_info (&C->user); - } - return; - } clear_packet (mtp); out_int (mtp, CODE_users_get_full_user); assert (get_peer_type (id) == PEER_USER); @@ -1815,7 +1808,8 @@ void do_get_user_info (struct telegram *instance, peer_id_t id) { out_int (mtp, CODE_input_user_contact); out_int (mtp, get_peer_id (id)); } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, 0); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, (void*)showInfo); + logprintf ("do_get_user_info ready\n"); } /* }}} */ @@ -1852,44 +1846,14 @@ void do_get_user_list_info_silent (struct telegram *instance, int num, int *list } /* }}} */ -/* {{{ Load photo/video */ -struct download { - int offset; - int size; - long long volume; - long long secret; - long long access_hash; - int local_id; - int dc; - int next; - int fd; - char *name; - long long id; - unsigned char *iv; - unsigned char *key; - int type; -}; - void end_load (struct telegram *instance, struct download *D) { instance->cur_downloading_bytes -= D->size; instance->cur_downloaded_bytes -= D->size; //update_prompt (); close (D->fd); - if (D->next == 1) { - logprintf ("Done: %s\n", D->name); - } else if (D->next == 2) { - static char buf[PATH_MAX]; - if (tsnprintf (buf, sizeof (buf), OPEN_BIN, D->name) >= (int) sizeof (buf)) { - logprintf ("Open image command buffer overflow\n"); - } else { - int x = system (buf); - if (x < 0) { - logprintf ("Can not open image viewer: %m\n"); - logprintf ("Image is at %s\n", D->name); - } - } - } + logprintf ("Done: %s\n", D->name); + event_download_finished_handler(instance, D); if (D->iv) { tfree_secure (D->iv, 32); } @@ -1955,6 +1919,7 @@ void load_next_part (struct telegram *instance, struct download *D) { if (!D->offset) { static char buf[PATH_MAX]; int l; + if (!D->id) { l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", instance->download_path, D->volume, D->local_id); } else { @@ -1981,6 +1946,11 @@ void load_next_part (struct telegram *instance, struct download *D) { instance->cur_downloaded_bytes += D->offset; //update_prompt (); } + if(instance->auth.dc_working_num != D->dc) + { + logprintf ("Unsupported DC! Cancel query! \n"); + return; + } clear_packet (mtp); out_int (mtp, CODE_upload_get_file); if (!D->id) { @@ -2008,14 +1978,12 @@ void load_next_part (struct telegram *instance, struct download *D) { //send_query (instance, DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); } -void do_load_photo_size (struct telegram *instance, struct photo_size *P, int next) { +void do_load_photo_size (struct telegram *instance, struct photo_size *P, void *extra) { if (!P->loc.dc) { logprintf ("Bad video thumb\n"); return; } - assert (P); - assert (next); struct download *D = talloc0 (sizeof (*D)); D->id = 0; D->offset = 0; @@ -2024,92 +1992,96 @@ void do_load_photo_size (struct telegram *instance, struct photo_size *P, int ne D->dc = P->loc.dc; D->local_id = P->loc.local_id; D->secret = P->loc.secret; - D->next = next; + D->extra = extra; D->name = 0; D->fd = -1; load_next_part (instance, D); } -void do_load_photo (struct telegram *instance, struct photo *photo, int next) { +void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig, void *extra) { if (!photo->sizes_num) { return; } - int max = -1; - int maxi = 0; + int size = -1; + int sizei = 0; int i; for (i = 0; i < photo->sizes_num; i++) { - if (photo->sizes[i].w + photo->sizes[i].h > max) { - max = photo->sizes[i].w + photo->sizes[i].h; - maxi = i; + if(photoBig == 0) + { + if (photo->sizes[i].w + photo->sizes[i].h < size) { + size = photo->sizes[i].w + photo->sizes[i].h; + sizei = i; + } + }else{ + if (photo->sizes[i].w + photo->sizes[i].h > size) { + size = photo->sizes[i].w + photo->sizes[i].h; + sizei = i; + } } } - do_load_photo_size (instance, &photo->sizes[maxi], next); + do_load_photo_size (instance, &photo->sizes[sizei], extra); } -void do_load_video_thumb (struct telegram *instance, struct video *video, int next) { - do_load_photo_size (instance, &video->thumb, next); +void do_load_video_thumb (struct telegram *instance, struct video *video, void *extra) { + do_load_photo_size (instance, &video->thumb, extra); } -void do_load_document_thumb (struct telegram *instance, struct document *video, int next) { - do_load_photo_size (instance, &video->thumb, next); +void do_load_document_thumb (struct telegram *instance, struct document *video, void *extra) { + do_load_photo_size (instance, &video->thumb, extra); } -void do_load_video (struct telegram *instance, struct video *V, int next) { +void do_load_video (struct telegram *instance, struct video *V, void *extra) { assert (V); - assert (next); struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; D->access_hash = V->access_hash; D->dc = V->dc_id; - D->next = next; + D->extra = extra; D->name = 0; D->fd = -1; D->type = CODE_input_video_file_location; load_next_part (instance, D); } -void do_load_audio (struct telegram *instance, struct video *V, int next) { +void do_load_audio (struct telegram *instance, struct video *V, void *extra) { assert (V); - assert (next); struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; D->access_hash = V->access_hash; D->dc = V->dc_id; - D->next = next; + D->extra = extra; D->name = 0; D->fd = -1; D->type = CODE_input_audio_file_location; load_next_part (instance, D); } -void do_load_document (struct telegram *instance, struct document *V, int next) { +void do_load_document (struct telegram *instance, struct document *V, void *extra) { assert (V); - assert (next); struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; D->access_hash = V->access_hash; D->dc = V->dc_id; - D->next = next; + D->extra = extra; D->name = 0; D->fd = -1; D->type = CODE_input_document_file_location; load_next_part (instance, D); } -void do_load_encr_video (struct telegram *instance, struct encr_video *V, int next) { +void do_load_encr_video (struct telegram *instance, struct encr_video *V, void *extra) { assert (V); - assert (next); struct download *D = talloc0 (sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; D->access_hash = V->access_hash; D->dc = V->dc_id; - D->next = next; + D->extra = extra; D->name = 0; D->fd = -1; D->key = V->key; diff --git a/queries.h b/queries.h index a141004..d6a9489 100644 --- a/queries.h +++ b/queries.h @@ -28,7 +28,6 @@ struct document; struct secret_chat; struct tree_query; struct tree_timer; - #define QUERY_ACK_RECEIVED 1 struct query; @@ -38,6 +37,28 @@ struct query_methods { int (*on_timeout)(struct query *q); }; +struct download_desc{ + void *data; + int type; +}; + +struct download { + int offset; + int size; + long long volume; + long long secret; + long long access_hash; + int local_id; + int dc; + void *extra; + int fd; + char *name; + long long id; + unsigned char *iv; + unsigned char *key; + int type; +}; + struct event_timer { double timeout; int (*alarm)(void *self); @@ -86,10 +107,10 @@ void do_get_dialog_list_ex (struct telegram*); void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name); void do_get_chat_info (struct telegram *instance, peer_id_t id); void do_get_user_list_info_silent (struct telegram *instance, int num, int *list); -void do_get_user_info (struct telegram *instance, peer_id_t id); +void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo); void do_forward_message (struct telegram *instance, peer_id_t id, int n); void do_rename_chat (struct telegram *instance, peer_id_t id, char *name); -void do_load_encr_video (struct telegram *instance, struct encr_video *V, int next); +void do_load_encr_video (struct telegram *instance, struct encr_video *V, void *extra); void do_create_encr_chat_request (struct telegram *instance, int user_id); void do_create_secret_chat (struct telegram *instance, peer_id_t id); void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic); @@ -97,12 +118,12 @@ void do_get_suggested (struct telegram*); struct photo; struct video; -void do_load_photo (struct telegram *instance, struct photo *photo, int next); -void do_load_video_thumb (struct telegram *instance, struct video *video, int next); -void do_load_audio (struct telegram *instance, struct video *V, int next); -void do_load_video (struct telegram *instance, struct video *V, int next); -void do_load_document (struct telegram *instance, struct document *V, int next); -void do_load_document_thumb (struct telegram *instance, struct document *video, int next); +void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig, void *extra); +void do_load_video_thumb (struct telegram *instance, struct video *video, void *extra); +void do_load_audio (struct telegram *instance, struct video *V, void *extra); +void do_load_video (struct telegram *instance, struct video *V, void *extra); +void do_load_document (struct telegram *instance, struct document *V, void *extra); +void do_load_document_thumb (struct telegram *instance, struct document *video, void *extra); void do_help_get_config (struct telegram *instance); void do_auth_check_phone (struct telegram *instance, const char *user); void do_get_nearest_dc (struct telegram*); diff --git a/structures.c b/structures.c index 473e7ff..b637259 100644 --- a/structures.c +++ b/structures.c @@ -426,7 +426,7 @@ void fetch_user_full (struct mtproto_connection *mtp, struct user *U) { fetch_alloc_user (mtp); int *start = mtp->in_ptr; - fetch_skip_photo (mtp); + fetch_photo (mtp, &U->photo); bl_do_set_user_full_photo (mtp->bl, mtp, U, start, 4 * (mtp->in_ptr - start)); fetch_notify_settings (mtp); @@ -602,6 +602,7 @@ void fetch_photo_size (struct mtproto_connection *mtp, struct photo_size *S) { unsigned x = fetch_int (mtp); assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); S->type = fetch_str_dup (mtp); + logprintf("s->type %s\n", S->type); if (x != CODE_photo_size_empty) { fetch_file_location (mtp, &S->loc); S->w = fetch_int (mtp); @@ -667,6 +668,7 @@ void fetch_photo (struct mtproto_connection *mtp, struct photo *P) { fetch_geo (mtp, &P->geo); assert (fetch_int (mtp) == CODE_vector); P->sizes_num = fetch_int (mtp); + logprintf("sizes_num %d \n", P->sizes_num); P->sizes = talloc (sizeof (struct photo_size) * P->sizes_num); int i; for (i = 0; i < P->sizes_num; i++) { diff --git a/telegram.c b/telegram.c index 5464243..55862bc 100755 --- a/telegram.c +++ b/telegram.c @@ -36,6 +36,26 @@ void event_peer_allocated(struct telegram *instance, void *peer) } } +/* + * Peer user fetched full + */ +void event_user_info_received_handler(struct telegram *instance, struct user *peer, int show_info) +{ + if (instance->config->on_user_info_received_handler) { + instance->config->on_user_info_received_handler (instance, peer, show_info); + } +} + +/* + * Download finished + */ +void event_download_finished_handler(struct telegram *instance, struct download *D) +{ + if (instance->config->on_download_finished_handler) { + instance->config->on_download_finished_handler (instance, D); + } +} + /* * User status changed */ diff --git a/telegram.h b/telegram.h index 3c19742..33b0351 100644 --- a/telegram.h +++ b/telegram.h @@ -96,7 +96,7 @@ struct binlog { }; struct telegram; - +struct download; /** * Contains all options and pointer to callback functions required by telegram */ @@ -163,6 +163,18 @@ struct telegram_config { */ void (*on_peer_allocated_handler) (struct telegram *instance, void *peer); + /** + * A callback function that is called when a peer user info was received. This is useful + * for populating the GUI with new user photos. + */ + void (*on_user_info_received_handler) (struct telegram *instance, struct user *peer, int showInfo); + + /** + * A callback function that is called when a download is completed. This is useful + * for populating the GUI with new user photos. + */ + void (*on_download_finished_handler) (struct telegram *instance, struct download *D); + /** * A callback function that is called when a user's status has changed */ @@ -372,6 +384,16 @@ void event_update_user_typing(struct telegram *instance, void *peer); */ void event_peer_allocated(struct telegram *instance, void *peer); +/* + * Load known users and chats on connect + */ +void event_user_info_received_handler(struct telegram *instance, struct user *peer, int showInfo); + +/* + * Load known users and chats on connect + */ +void event_download_finished_handler(struct telegram *instance, struct download *D); + /** * Set a function to use as a handle to read from a network resource * instead of the regular socket read function From a6013016f16adef9a74484c0f15d98f8a87a7ea4 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 21 Sep 2014 00:11:07 +0200 Subject: [PATCH 397/465] Ensure that download directory exists --- telegram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/telegram.c b/telegram.c index 55862bc..d0304b7 100755 --- a/telegram.c +++ b/telegram.c @@ -322,6 +322,7 @@ struct dc *telegram_get_working_dc(struct telegram *instance) void telegram_restore_session(struct telegram *instance) { g_mkdir_with_parents(instance->config_path, 0700); + g_mkdir_with_parents(instance->download_path, 0700); instance->auth = read_auth_file(instance->auth_path); instance->proto = read_state_file(instance->state_path); read_secret_chat_file (instance, instance->secret_path); From d6530b69bb3a38bc3c440f36a6455d2757ef2da2 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 21 Sep 2014 22:30:50 +0200 Subject: [PATCH 398/465] Don't show info window on first user load --- purple-plugin/telegram-purple.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 93ee6a6..fcc4e7d 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -98,6 +98,8 @@ static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *val static PurpleConversation *chat_show (PurpleConnection *gc, int id) { logprintf ("show chat"); + telegram_conn *conn = purple_connection_get_protocol_data(gc); + PurpleConversation *convo = purple_find_chat(gc, id); if (convo) { if (purple_conv_chat_has_left(PURPLE_CONV_CHAT(convo))) @@ -105,20 +107,18 @@ static PurpleConversation *chat_show (PurpleConnection *gc, int id) serv_got_joined_chat(gc, id, chat_id_get_comp_val(gc, id, "subject")); } } else { - telegram_conn *conn = purple_connection_get_protocol_data(gc); gchar *name = g_strdup_printf ("%d", id); if (g_hash_table_contains (conn->joining_chats, name)) { // already joining this chat - g_free(name); } else { // mark chat as already joining g_hash_table_insert(conn->joining_chats, name, 0); // join chat first - logprintf ("joining chat first...\n"); do_get_chat_info (conn->tg, MK_CHAT(id)); telegram_flush (conn->tg); } + g_free(name); } return convo; } @@ -706,12 +706,12 @@ void user_info_received_handler(struct telegram *tg, struct user *usr, int show_ { logprintf("Get user info. \n %d", show_info); char *who = g_strdup_printf("%d", usr->id.id); - if(usr->photo.sizes_num == 0) + if (usr->photo.sizes_num == 0 && show_info) { telegram_conn *conn = tg->extra; PurpleNotifyUserInfo *info = create_user_notify_info(usr); purple_notify_userinfo(conn->gc, who, info, NULL, NULL); - }else{ + } else { struct download_desc *dld = talloc(sizeof(struct download_desc)); dld->data = usr; dld->type = show_info == 1 ? 1 : 2; From 5c488f9c8da09a73dd7ee03a0edb0abb230199c8 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 12:29:02 +0200 Subject: [PATCH 399/465] Support downloads from foreign DCs --- mtproto-client.c | 29 +++++-- mtproto-client.h | 1 + net.c | 8 +- net.h | 2 +- purple-plugin/telegram-purple.c | 12 ++- queries.c | 56 +++++++++--- queries.h | 6 +- telegram.c | 146 +++++++++++++++++++++++++++----- telegram.h | 25 +++++- 9 files changed, 228 insertions(+), 57 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 4a45ea7..61d77b0 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1779,8 +1779,8 @@ int tc_becomes_ready (struct connection *c) { send_req_pq_packet (c); break; case st_authorized: - auth_work_start (c); - telegram_change_state (c->instance, STATE_AUTHORIZED, NULL); + c->mtconnection->on_ready(c->mtconnection, c->mtconnection->on_ready_data); + //telegram_change_state (c->instance, STATE_AUTHORIZED, NULL); break; default: logprintf ( "c_state = %d\n", c->mtconnection->c_state); @@ -1853,10 +1853,8 @@ struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *t void mtproto_connect(struct mtproto_connection *c) { on_start(c); - c->connection->methods->ready(c->connection); - - // Don't ping TODO: Really? Timeout callback functions of libpurple start_ping_timer (c->connection); + c->connection->methods->ready(c->connection); } /** @@ -1872,11 +1870,10 @@ void mtproto_close(struct mtproto_connection *mtp) { // in case the session is switched and this DC is not reachable anymore if (mtp->connection) { if (mtp->connection->session && mtp->connection->session->ack_tree) { - send_all_acks (mtp->connection->session); + struct session *S = mtp->connection->session; + send_all_acks (S); mtp->instance->config->on_output(mtp->handle); - - // connection no longer usable for session - mtp->connection->session->c = 0; + S->c = 0; } stop_ping_timer (mtp->connection); } @@ -1893,6 +1890,20 @@ void mtproto_destroy (struct mtproto_connection *self) { tfree(self, sizeof(struct mtproto_connection)); } +void mtproto_close_foreign (struct telegram *instance) +{ + int i; + for (i = 0; i < 100; i++) { + struct mtproto_connection * c = instance->Cs[i]; + if (c && + !c->destroy && + c->connection->session->dc->id != instance->auth.dc_working_num) { + logprintf ("closing connection for working_dc=%d, dc=%d\n", + instance->auth.dc_working_num, c->connection->session->dc->id); + mtproto_close (c); + } + } +} /** * Free all destroyed connections diff --git a/mtproto-client.h b/mtproto-client.h index 3d93e0e..f6dfc35 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -506,6 +506,7 @@ static inline void hexdump_out (struct mtproto_connection *self) { #endif void my_clock_gettime (int clock_id, struct timespec *T); +void mtproto_close_foreign (struct telegram *instance); void mtproto_free_closed (struct telegram *tg); #endif diff --git a/net.c b/net.c index b8d5779..a63b754 100644 --- a/net.c +++ b/net.c @@ -679,7 +679,8 @@ void dc_create_session (struct dc *DC) { * Wrap an existing socket file descriptor and make it usable as a connection, */ struct connection *fd_create_connection (struct dc *DC, int fd, - struct telegram *instance, struct connection_methods *methods, struct mtproto_connection *mtp) { + struct telegram *instance, struct connection_methods *methods, + struct mtproto_connection *mtp) { // create a connection struct connection *c = talloc0 (sizeof (*c)); @@ -693,8 +694,6 @@ struct connection *fd_create_connection (struct dc *DC, int fd, c->last_receive_time = get_double_time (); logprintf ( "connect to %s:%d successful\n", DC->ip, DC->port); - // TODO: Load existing session from state file - // create an empty session and attach it to the dc and the connection if (!DC->sessions[0]) { struct session *S = talloc0 (sizeof (*S)); assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); @@ -702,6 +701,9 @@ struct connection *fd_create_connection (struct dc *DC, int fd, S->c = c; DC->sessions[0] = S; } + if (!DC->sessions[0]->c) { + DC->sessions[0]->c = c; + } // add backreference to session c->session = DC->sessions[0]; diff --git a/net.h b/net.h index b7a4763..ed02eba 100644 --- a/net.h +++ b/net.h @@ -148,7 +148,7 @@ void dc_create_session (struct dc *DC); void insert_msg_id (struct session *S, long long id); struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port); -#define GET_DC(c) (telegram_get_working_dc(c->instance)) +#define GET_DC(c) (c->session->dc) // export read and write methods to redirect network control void try_read (struct connection *c); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index fcc4e7d..c3e22e0 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -263,10 +263,12 @@ static void init_dc_settings(PurpleAccount *acc, struct dc *DC) /** * Telegram requests a new connectino to our configured proxy */ -void telegram_on_proxy_request(struct telegram *tg, const char *ip, int port) +void telegram_on_proxy_request(struct telegram *tg, struct proxy_request *req) { telegram_conn *conn = tg->extra; - purple_proxy_connect (conn->gc, conn->pa, ip, port, tgprpl_login_on_connected, tg); + req->extra = tg; + purple_proxy_connect (conn->gc, conn->pa, req->DC->ip, req->DC->port, + tgprpl_login_on_connected, req); } /** @@ -391,7 +393,9 @@ void telegram_on_ready (struct telegram *instance) void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) { purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); - struct telegram *tg = (struct telegram*)data; + struct proxy_request *req = (struct proxy_request*)data; + struct telegram *tg = req->tg; + if (fd == -1) { logprintf("purple_proxy_connect failed: %s\n", error_message); telegram_destroy(tg); @@ -402,7 +406,7 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa conn->fd = fd; conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, conn); conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, conn); - conn->mtp = telegram_add_proxy(tg, fd, conn); + conn->mtp = telegram_add_proxy(tg, req, fd, conn); } void telegram_on_disconnected (struct telegram *tg) diff --git a/queries.c b/queries.c index 41b68d9..915796f 100644 --- a/queries.c +++ b/queries.c @@ -1781,9 +1781,8 @@ void print_user_info (struct user *U) { int user_info_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); - // TODO: Use user info struct user *U = fetch_alloc_user_full (mtp); - event_user_info_received_handler(mtp->instance, U, (int)q->extra); + event_user_info_received_handler (mtp->instance, U, (int)q->extra); //print_user_info (U); return 0; } @@ -1854,11 +1853,17 @@ void end_load (struct telegram *instance, struct download *D) { close (D->fd); logprintf ("Done: %s\n", D->name); event_download_finished_handler(instance, D); + instance->dl_curr = 0; + if (D->dc != telegram_get_working_dc(instance)->id) { + logprintf ("%d Not the working dc %d, closing...\n", D->dc, + telegram_get_working_dc(instance)->id); + } if (D->iv) { tfree_secure (D->iv, 32); } tfree_str (D->name); tfree (D, sizeof (*D)); + telegram_dl_next (instance); } struct download_extra { @@ -1946,11 +1951,6 @@ void load_next_part (struct telegram *instance, struct download *D) { instance->cur_downloaded_bytes += D->offset; //update_prompt (); } - if(instance->auth.dc_working_num != D->dc) - { - logprintf ("Unsupported DC! Cancel query! \n"); - return; - } clear_packet (mtp); out_int (mtp, CODE_upload_get_file); if (!D->id) { @@ -1995,7 +1995,9 @@ void do_load_photo_size (struct telegram *instance, struct photo_size *P, void * D->extra = extra; D->name = 0; D->fd = -1; - load_next_part (instance, D); + + telegram_dl_add (instance, D); + telegram_dl_next (instance); } void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig, void *extra) { @@ -2004,13 +2006,13 @@ void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig int sizei = 0; int i; for (i = 0; i < photo->sizes_num; i++) { - if(photoBig == 0) + if (photoBig == 0) { if (photo->sizes[i].w + photo->sizes[i].h < size) { size = photo->sizes[i].w + photo->sizes[i].h; sizei = i; } - }else{ + } else { if (photo->sizes[i].w + photo->sizes[i].h > size) { size = photo->sizes[i].w + photo->sizes[i].h; sizei = i; @@ -2100,6 +2102,11 @@ void do_load_encr_video (struct telegram *instance, struct encr_video *V, void * /* {{{ Export auth */ +struct export_info { + void *extra; + void (*cb)(char *export_auth_str, int len, void *extra); +}; + int export_auth_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = mtp->connection->instance; @@ -2116,6 +2123,10 @@ int export_auth_on_answer (struct query *q UU) { memcpy (s, fetch_str (mtp, l), l); instance->export_auth_str_len = l; instance->export_auth_str = s; + + struct export_info *info = q->extra; + info->cb(instance->export_auth_str, instance->export_auth_str_len, info->extra); + tfree(info, sizeof(struct export_info)); return 0; } @@ -2124,27 +2135,39 @@ struct query_methods export_auth_methods = { .on_error = fail_on_error }; -void do_export_auth (struct telegram *instance, int num) { +void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; instance->export_auth_str = 0; clear_packet (mtp); out_int (mtp, CODE_auth_export_authorization); out_int (mtp, num); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, 0); + + struct export_info *info = talloc0(sizeof(struct export_info)); + info->cb = cb; + info->extra = extra; + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, info); } /* }}} */ +struct import_info { + void *extra; + void (*cb)(void* extra); +}; + /* {{{ Import auth */ int import_auth_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = mtp->connection->instance; + struct import_info *info = q->extra; assert (fetch_int (mtp) == (int)CODE_auth_authorization); fetch_int (mtp); // expires fetch_alloc_user (mtp); tfree_str (instance->export_auth_str); instance->export_auth_str = 0; + info->cb(info->extra); + tfree (info, sizeof(struct import_info)); return 0; } @@ -2153,14 +2176,19 @@ struct query_methods import_auth_methods = { .on_error = fail_on_error }; -void do_import_auth (struct telegram *instance, int num) { +void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra) { struct mtproto_connection *mtp = instance->connection; + struct import_info *info = talloc0(sizeof (struct import_info)); + info->cb = cb; + info->extra = extra; clear_packet (mtp); out_int (mtp, CODE_auth_import_authorization); out_int (mtp, instance->our_id); out_cstring (mtp, instance->export_auth_str, instance->export_auth_str_len); - send_query (instance, instance->auth.DC_list[num], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &import_auth_methods, 0); + + send_query (instance, instance->auth.DC_list[num], mtp->packet_ptr - mtp->packet_buffer, + mtp->packet_buffer, &import_auth_methods, info); } /* }}} */ diff --git a/queries.h b/queries.h index d6a9489..c8c93b7 100644 --- a/queries.h +++ b/queries.h @@ -57,7 +57,9 @@ struct download { unsigned char *iv; unsigned char *key; int type; + struct mtproto_connection *c; }; +void load_next_part (struct telegram *instance, struct download *D); struct event_timer { double timeout; @@ -128,8 +130,8 @@ void do_help_get_config (struct telegram *instance); void do_auth_check_phone (struct telegram *instance, const char *user); void do_get_nearest_dc (struct telegram*); void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name); -void do_import_auth (struct telegram *instance, int num); -void do_export_auth (struct telegram *instance, int num); +void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra); +void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra); void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s); void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E); diff --git a/telegram.c b/telegram.c index d0304b7..60c8739 100755 --- a/telegram.c +++ b/telegram.c @@ -116,8 +116,6 @@ void telegram_change_state (struct telegram *instance, int state, void *data) err = ""; } logprintf("telegram errored: %s\n", err); - - // mark the connection for closing mtproto_close (instance->connection); } break; @@ -147,7 +145,6 @@ void telegram_change_state (struct telegram *instance, int state, void *data) logprintf("phone authenticion, user needs to enter code, first and last name.\n"); assert (instance->config->on_phone_registration_required); instance->config->on_phone_registration_required (instance); - // wait for user input ... break; case STATE_CLIENT_NOT_REGISTERED: @@ -178,8 +175,6 @@ void telegram_change_state (struct telegram *instance, int state, void *data) // close old connection and mark it for destruction mtproto_close (instance->connection); assert (instance->config->proxy_request_cb); - // tell the proxy to close all connections - //instance->config->proxy_close_cb (instance, instance->connection->connection->fd); // remove all left over queries and timers free_timers (instance); @@ -343,8 +338,17 @@ void telegram_store_session(struct telegram *instance) void on_authorized(struct mtproto_connection *c, void* data); +void telegram_main_connected (struct proxy_request *req) +{ + struct telegram *instance = req->data; + logprintf("Authorized... storing current session %d.\n", + instance->connection->connection->session[0]); + telegram_store_session(instance); + telegram_change_state(instance, STATE_AUTHORIZED, NULL); +} + /** - * Connect to the currently active data center + * Connect to the nearest data center */ void telegram_connect (struct telegram *instance) { @@ -354,8 +358,101 @@ void telegram_connect (struct telegram *instance) assert(0); } struct dc *DC_working = telegram_get_working_dc (instance); + + struct proxy_request *req = talloc0(sizeof(struct proxy_request)); + req->type = REQ_CONNECTION; + req->tg = instance; + req->data = instance; + req->DC = DC_working; + req->done = telegram_main_connected; + assert (instance->config->proxy_request_cb); - instance->config->proxy_request_cb (instance, DC_working->ip, DC_working->port); + instance->config->proxy_request_cb (instance, req); +} + +void on_auth_imported (void *extra) +{ + logprintf ("on_auth_imported()\n"); + struct download *dl = extra; + struct mtproto_connection *c = dl->c; + struct telegram *tg = c->instance; + bl_do_dc_signed (tg->bl, c, dl->dc); + write_auth_file (&tg->auth, tg->auth_path); + load_next_part (tg, dl); + telegram_flush (tg); +} + +void on_auth_exported (char *export_auth_str UU, int len UU, void *extra) +{ + logprintf ("on_auth_exported()\n"); + struct download *dl = extra; + do_import_auth (dl->c->instance, dl->dc, on_auth_imported, extra); + telegram_flush (dl->c->instance); +} + +void telegram_dl_connected (struct proxy_request *req) +{ + logprintf ("telegram_dl_connected(dc=%d)\n", req->DC->id); + struct telegram *tg = req->tg; + // TODO: error handling + + struct download *dl = req->data; + dl->c = req->conn; + struct dc *DC = tg->auth.DC_list[dl->dc]; + if (!DC->has_auth) { + do_export_auth (tg, dl->dc, on_auth_exported, dl); + telegram_flush (tg); + } else { + on_auth_imported (dl); + } +} + + +/** + * Create a connection for the given download + */ +void telegram_dl_add (struct telegram *instance, struct download *dl) +{ + logprintf ("telegram_connect_dl(dc=%d)\n", instance->auth.DC_list[dl->dc]); + if (!instance->dl_queue) { + instance->dl_queue = g_queue_new (); + } + g_queue_push_tail(instance->dl_queue, dl); +} + +void telegram_dl_next (struct telegram *instance) +{ + assert (instance->dl_queue); + assert (instance->config->proxy_request_cb); + if (!instance->dl_curr) { + struct download *dl = g_queue_pop_head (instance->dl_queue); + if (dl) { + struct proxy_request *req = talloc0(sizeof(struct proxy_request)); + req->type = REQ_DOWNLOAD; + req->DC = instance->auth.DC_list[dl->dc]; + req->tg = instance; + req->done = telegram_dl_connected; + req->data = dl; + instance->dl_curr = dl; + + logprintf ("telegrma_dl_start(): starting new download..\n"); + if (dl->dc == instance->auth.dc_working_num) { + logprintf ("is working DC, start download...\n"); + assert (telegram_get_working_dc(instance)->sessions[0]->c); + req->conn = instance->connection; + dl->c = req->conn; + telegram_dl_connected (req); + } else { + logprintf ("is remote DC, requesting connection...\n"); + instance->config->proxy_request_cb (instance, req); + } + } else { + logprintf ("telegrma_dl_start(): no more downloads, DONE!\n"); + mtproto_close_foreign (instance); + } + } else { + logprintf ("telegrma_dl_start(): download busy...\n"); + } } /** @@ -372,23 +469,28 @@ int telegram_login(struct telegram *instance) return 0; } -void on_authorized(struct mtproto_connection *c, void *data) +void on_authorized(struct mtproto_connection *c UU, void *data) { - struct telegram *instance = data; - logprintf("Authorized... storing current session %d.\n", c->connection->session[0]); - telegram_store_session(instance); - telegram_change_state(instance, STATE_AUTHORIZED, NULL); + logprintf ("on_authorized()...\n"); + struct proxy_request *req = data; + assert (req->done); + req->done (req); + tfree (req, sizeof(struct proxy_request)); } -struct mtproto_connection *telegram_add_proxy(struct telegram *instance, int fd, void *handle) +struct mtproto_connection *telegram_add_proxy(struct telegram *instance, struct proxy_request *req, + int fd, void *handle) { - struct dc *DC_working = telegram_get_working_dc (instance); - instance->connection = mtproto_new (DC_working, fd, instance); - instance->connection->handle = handle; - instance->connection->on_ready = on_authorized; - instance->connection->on_ready_data = instance; - mtproto_connect (instance->connection); - return instance->connection; + struct mtproto_connection *c = mtproto_new (req->DC, fd, instance); + c->handle = handle; + c->on_ready = on_authorized; + c->on_ready_data = req; + req->conn = c; + if (req->type == REQ_CONNECTION) { + req->tg->connection = c; + } + mtproto_connect (c); + return c; } void mtp_read_input (struct mtproto_connection *mtp) @@ -415,11 +517,11 @@ void telegram_flush (struct telegram *instance) if (!c) continue; if (!c->connection) continue; if (c->connection->out_bytes) { - logprintf ("connection %d has %d bytes, triggering on_output.", + logprintf ("connection %d has %d bytes, triggering on_output.\n", i, c->connection->out_bytes); instance->config->on_output(c->handle); } else { - logprintf ("connection %d has no bytes, skipping\n"); + logprintf ("connection %d has no bytes, skipping\n", i); } } } diff --git a/telegram.h b/telegram.h index 33b0351..d39862f 100644 --- a/telegram.h +++ b/telegram.h @@ -95,6 +95,18 @@ struct binlog { peer_t *Peers[MAX_PEER_NUM]; }; +#define REQ_CONNECTION 1 +#define REQ_DOWNLOAD 2 +struct proxy_request { + struct telegram *tg; + struct dc *DC; + struct mtproto_connection *conn; + int type; + void *data; + void (*done) (struct proxy_request *req); + void *extra; +}; + struct telegram; struct download; /** @@ -117,7 +129,7 @@ struct telegram_config { * and port by calling telegram_set_proxy. This is useful for tunelling * the connection through a proxy server. */ - void (*proxy_request_cb) (struct telegram *instance, const char *ip, int port); + void (*proxy_request_cb) (struct telegram *instance, struct proxy_request *req); /** * A callback function that is called once the proxy connection is no longer @@ -267,6 +279,12 @@ struct telegram { int cs; struct mtproto_connection *Cs[100]; + /* + * Downloads + */ + GQueue *dl_queue; + struct download *dl_curr; + /* * additional user data */ @@ -412,7 +430,7 @@ void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); * @param fd The file-descriptor of the acquired connection * @param handle A handle that will be passed back on output and close callbacks */ -struct mtproto_connection *telegram_add_proxy(struct telegram *tg, int fd, void *handle); +struct mtproto_connection *telegram_add_proxy(struct telegram *tg, struct proxy_request *req, int fd, void *handle); /** * Return wether telegram is authenticated with the currently active data center @@ -421,4 +439,7 @@ int telegram_authenticated (struct telegram *instance); void telegram_flush (struct telegram *instance); +void telegram_dl_add (struct telegram *instance, struct download *dl); +void telegram_dl_next (struct telegram *instance); + #endif From 1954cb0d63e6533ab2198dd10f5c8794a65f9426 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 12:31:17 +0200 Subject: [PATCH 400/465] Add hotfix for "new group message"-infinite loop --- purple-plugin/telegram-purple.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index c3e22e0..46837ff 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -477,7 +477,7 @@ static void tgprpl_close(PurpleConnection * gc) telegram_destroy(conn->tg); } -static void chat_add_message(struct telegram *tg, struct message *M) +static int chat_add_message(struct telegram *tg, struct message *M) { telegram_conn *conn = tg->extra; @@ -494,9 +494,11 @@ static void chat_add_message(struct telegram *tg, struct message *M) PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); g_free(alias); } + return 1; } else { // add message once the chat was initialised g_queue_push_tail (conn->new_messages, M); + return 0; } } @@ -1074,10 +1076,15 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) } struct message *M = 0; logprintf ("g_queue_pop_head()\n"); + while (M = g_queue_pop_head (conn->new_messages)) { logprintf ("adding msg-id\n"); int id = get_peer_id(M->from_id); - chat_add_message(instance, M); + if (!chat_add_message(instance, M)) { + // chat still not working? + logprintf ("WARNING, chat %d still not existing... \n", chatid.id); + break; + } } gchar *name = g_strdup_printf ("%d", chatid.id); From 7c69af9b00c361fa740d4956b8368790c7767cfa Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 12:46:19 +0200 Subject: [PATCH 401/465] Remove unused code --- mtproto-client.c | 2 - net.c | 170 +---------------------------------------------- net.h | 3 - telegram.h | 12 ---- 4 files changed, 2 insertions(+), 185 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 61d77b0..812eb89 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1840,8 +1840,6 @@ struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *t mtp->instance = tg; mtp->packet_buffer = mtp->__packet_buffer + 16; mtp->connection = fd_create_connection(DC, fd, tg, &mtproto_methods, mtp); - - // binlog must exist assert (tg->bl); mtp->bl = tg->bl; return mtp; diff --git a/net.c b/net.c index a63b754..1509d76 100644 --- a/net.c +++ b/net.c @@ -54,39 +54,6 @@ FILE *log_net_f = 0; void fail_connection (struct connection *c); -/* - * Delegate the read-oprations to external function - */ -ssize_t (*netread)(int fd, void *buff, size_t size) = read; -void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)) { - netread = cb; -} - -/* - * Delegate the write operations to external function - */ -ssize_t (*netwrite)(int fd, const void *buff, size_t size) = write; -void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)) { - netwrite = cb; -} - -/* - * Delegate the session creation to an external callback - * - * TODO: use dc_ensure_session instead of dc_create_session to create sessions, - * to make this actually work - */ -void dc_create_session (struct dc *DC); -void dc_ensure_session_local (struct dc *DC, void (*on_session_ready)(void)) { - dc_create_session(DC); - on_session_ready(); -} -void (*dc_ensure_session)(struct dc *DC, void (*on_session_ready)(void)); -void set_dc_ensure_session_cb (void (*dc_ens_sess)(struct dc *DC, void (*on_session_ready)(void))) -{ - dc_ensure_session = dc_ens_sess; -} - /* * */ @@ -263,74 +230,6 @@ void rotate_port (struct connection *c) { } } -struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods) { - struct connection *c = talloc0 (sizeof (*c)); - int fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd == -1) { - logprintf ("Can not create socket: %m\n"); - exit (1); - } - assert (fd >= 0 && fd < MAX_CONNECTIONS); - if (fd > max_connection_fd) { - max_connection_fd = fd; - } - int flags = -1; - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); - setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)); - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags)); - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons (port); - addr.sin_addr.s_addr = inet_addr (host); - - - fcntl (fd, F_SETFL, O_NONBLOCK); - - if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { - if (errno != EINPROGRESS) { - logprintf ( "Can not connect to %s:%d %m\n", host, port); - close (fd); - tfree (c, sizeof (*c)); - return 0; - } - } - - struct pollfd s; - s.fd = fd; - s.events = POLLOUT | POLLERR | POLLRDHUP | POLLHUP; - errno = 0; - - while (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { - if (errno == EINTR) { continue; } - if (errno) { - logprintf ("Problems in poll: %m\n"); - exit (1); - } - logprintf ("Connect with %s:%d timeout\n", host, port); - close (fd); - tfree (c, sizeof (*c)); - return 0; - } - - c->session = session; - c->fd = fd; - c->ip = tstrdup (host); - c->flags = 0; - c->state = conn_ready; - c->methods = methods; - c->port = port; - assert (!Connections[fd]); - Connections[fd] = c; - logprintf ( "connect to %s:%d successful\n", host, port); - if (c->methods->ready) { - c->methods->ready (c); - } - c->last_receive_time = get_double_time (); - start_ping_timer (c); - return c; -} - void restart_connection (struct connection *c) { if (c->last_connect_time == time (0)) { start_fail_timer (c); @@ -411,7 +310,7 @@ int try_write (struct connection *c) { logprintf ( "try write: fd = %d\n", c->fd); int x = 0; while (c->out_head) { - int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); // Log all written packages if (r > 0 && log_net_f) { @@ -524,7 +423,7 @@ void try_read (struct connection *c) { } int x = 0; while (1) { - int r = netread (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); + int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); if (r > 0 && log_net_f) { fprintf (log_net_f, "%.02lf %d IN %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; @@ -566,57 +465,6 @@ void try_read (struct connection *c) { } } -int connections_make_poll_array (struct pollfd *fds, int max) { - int _max = max; - int i; - for (i = 0; i <= max_connection_fd; i++) { - if (Connections[i] && Connections[i]->state == conn_failed) { - restart_connection (Connections[i]); - } - if (Connections[i] && Connections[i]->state != conn_failed) { - assert (max > 0); - struct connection *c = Connections[i]; - fds[0].fd = c->fd; - fds[0].events = POLLERR | POLLHUP | POLLRDHUP | POLLIN; - if (c->out_bytes || c->state == conn_connecting) { - fds[0].events |= POLLOUT; - } - fds ++; - max --; - } - } - if (verbosity >= 10) { - logprintf ( "%d connections in poll\n", _max - max); - } - return _max - max; -} - -void connections_poll_result (struct pollfd *fds, int max) { - if (verbosity >= 10) { - logprintf ( "connections_poll_result: max = %d\n", max); - } - int i; - for (i = 0; i < max; i++) { - struct connection *c = Connections[fds[i].fd]; - if (fds[i].revents & POLLIN) { - try_read (c); - } - if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) { - logprintf ("fail_connection: events_mask=0x%08x\n", fds[i].revents); - fail_connection (c); - } else if (fds[i].revents & POLLOUT) { - if (c->state == conn_connecting) { - logprintf ("connection ready\n"); - c->state = conn_ready; - c->last_receive_time = get_double_time (); - } - if (c->out_bytes) { - try_write (c); - } - } - } -} - int send_all_acks (struct session *S) { logprintf ("send_all_acks()\n"); if (!S->c) { @@ -661,20 +509,6 @@ struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { return DC; } -void dc_create_session (struct dc *DC) { - logprintf("dc_create_session(...)\n"); - struct session *S = talloc0 (sizeof (*S)); - assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); - S->dc = DC; - S->c = create_connection (DC->ip, DC->port, S, &auth_methods); - if (!S->c) { - logprintf ("Can not create connection to DC. Is network down?\n"); - exit (1); - } - assert (!DC->sessions[0]); - DC->sessions[0] = S; -} - /** * Wrap an existing socket file descriptor and make it usable as a connection, */ diff --git a/net.h b/net.h index ed02eba..d95b41d 100644 --- a/net.h +++ b/net.h @@ -141,9 +141,6 @@ int read_in (struct connection *c, void *data, int len); void create_all_outbound_connections (void); -struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods); -int connections_make_poll_array (struct pollfd *fds, int max); -void connections_poll_result (struct pollfd *fds, int max); void dc_create_session (struct dc *DC); void insert_msg_id (struct session *S, long long id); struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port); diff --git a/telegram.h b/telegram.h index d39862f..cc5834c 100644 --- a/telegram.h +++ b/telegram.h @@ -412,18 +412,6 @@ void event_user_info_received_handler(struct telegram *instance, struct user *pe */ void event_download_finished_handler(struct telegram *instance, struct download *D); -/** - * Set a function to use as a handle to read from a network resource - * instead of the regular socket read function - */ -void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)); - -/** - * Set a function to use as handle to write to a newtork resource - * instead of the regular socket write function - */ -void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); - /** * Set the connection after a proxy_request_cb * From 89ddae23ef241e0e887007499059784e2e86da87 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 12:49:46 +0200 Subject: [PATCH 402/465] Restart ping-timer on read --- net.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net.c b/net.c index 1509d76..8cdc646 100644 --- a/net.c +++ b/net.c @@ -435,9 +435,8 @@ void try_read (struct connection *c) { } if (r > 0) { c->last_receive_time = get_double_time (); - // TODO implement ping? - //stop_ping_timer (c); - //start_ping_timer (c); + stop_ping_timer (c); + start_ping_timer (c); } if (r >= 0) { c->in_tail->wptr += r; From 3fa72a9d42834840192dd22bd649d1fa6ef668e0 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 13:01:28 +0200 Subject: [PATCH 403/465] Remove unused binlog functions --- binlog.c | 120 -------------------------------- binlog.h | 1 - purple-plugin/telegram-purple.c | 1 - 3 files changed, 122 deletions(-) diff --git a/binlog.c b/binlog.c index ce90436..dc820bc 100644 --- a/binlog.c +++ b/binlog.c @@ -39,13 +39,6 @@ #define MAX_LOG_EVENT_SIZE (1 << 17) -// TODO: remove this completely -char *get_binlog_file_name (void); -char *get_binlog_file_name() -{ - return "/home/dev-jessie/.telegram/binlog"; -} - int binlog_enabled = 0; void *alloc_log_event (struct binlog *bl, int l UU) { @@ -1064,119 +1057,6 @@ void replay_log_event (struct telegram *instance) { bl->binlog_pos += (bl->rptr - start) * 4; } -void create_new_binlog (struct binlog *bl, struct mtproto_connection *self) { - logprintf("create_new_binlog()"); - - static int s[1000]; - self->packet_ptr = s; - //self->packet_ptr = self->packet_buffer; // (int *)&bl->s; - out_int (self, LOG_START); - out_int (self, CODE_binlog_dc_option); - out_int (self, 1); - out_string (self, ""); - out_string (self, bl->test_dc ? TG_SERVER_TEST : TG_SERVER); - out_int (self, 443); - out_int (self, LOG_DEFAULT_DC); - out_int (self, 1); - - int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL | O_CREAT, 0600); - if (fd < 0) { - perror ("Write new binlog"); - exit (2); - } - assert (write (fd, s, (self->packet_ptr - s) * 4) == (self->packet_ptr - s) * 4); - close (fd); -} - -/** - * Loag the logfile and replay all stored log events - */ -void replay_log (struct telegram *instance) { - assert(instance->connection); - assert(instance->bl); - struct mtproto_connection *self = instance->connection; - struct binlog *bl = instance->bl; - - logprintf("replaying binlog...\n"); - if (access (get_binlog_file_name (), F_OK) < 0) { - printf ("No binlog found. Creating new one\n"); - create_new_binlog (bl, self); - } - int fd = open (get_binlog_file_name (), O_RDONLY); - if (fd < 0) { - perror ("binlog open"); - exit (2); - } - int end = 0; - while (1) { - if (!end && bl->wptr - bl->rptr < MAX_LOG_EVENT_SIZE / 4) { - if (bl->wptr == bl->rptr) { - // nothing to read, - // reset read and write pointer to start of buffer - bl->wptr = bl->rptr = bl->binlog_buffer; - } else { - // get difference between read and write pointer - int x = bl->wptr - bl->rptr; - - // copy everything between read and write pointer - // to the start of the binlog buffer - memcpy (bl->binlog_buffer, bl->rptr, 4 * x); - - // reset binlog buffer position - // +-----------+------+------+ - // ^ ^ ^ ^ - // bl_buffer rptr wptr BUFFER_SIZE - // - // +------+------------------+ - // ^ ^ ^ - // rptr wptr BUFFER_SIZE - // bl_buffer - // - bl->wptr -= (bl->rptr - bl->binlog_buffer); - bl->rptr = bl->binlog_buffer; - } - // calculate the remaining space in the binlog buffer - int l = (bl->binlog_buffer + BINLOG_BUFFER_SIZE - bl->wptr) * 4; - - // try to read the remining bytes from the file - int k = read (fd, bl->wptr, l); - if (k < 0) { - perror ("read binlog"); - exit (2); - } - // amount of read bytes must be divisible by 4, since we - // store 4-byte integers - assert (!(k & 3)); - if (k < l) { - // reached end of file - end = 1; - } - // move the write pointer to the first empty byte - bl->wptr += (k / 4); - } - if (bl->wptr == bl->rptr) { - // no further log entries, done... - break; - } - replay_log_event (instance); - } - close (fd); -} - -void write_binlog (struct binlog *bl) { - bl->binlog_fd = open (get_binlog_file_name (), O_WRONLY); - if (bl->binlog_fd < 0) { - perror ("binlog open"); - exit (2); - } - - assert (lseek (bl->binlog_fd, bl->binlog_pos, SEEK_SET) == bl->binlog_pos); - if (flock (bl->binlog_fd, LOCK_EX | LOCK_NB) < 0) { - perror ("get lock"); - exit (2); - } -} - void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int len) { logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); assert (!(len & 3)); diff --git a/binlog.h b/binlog.h index fcc73bb..1f6b1ed 100644 --- a/binlog.h +++ b/binlog.h @@ -85,7 +85,6 @@ #define CODE_binlog_delete_msg 0xa1d6ab6d void *alloc_log_event (struct binlog *bl, int l); -void replay_log (struct telegram *instance); void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int l); void write_binlog (struct binlog *bl); void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 46837ff..8fa3a4f 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -141,7 +141,6 @@ static PurpleChat *get_chat_by_id (PurpleConnection *gc, int id) */ static const char *tgprpl_list_icon(PurpleAccount * acct, PurpleBuddy * buddy) { - //purple_debug_info(PLUGIN_ID, "tgrpl_list_icon()\n"); return "telegram"; } From d4eff42a4282533c40b2f6f7a8876a53b6664e1e Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 13:29:54 +0200 Subject: [PATCH 404/465] Use our own application configuration --- net.h | 14 +++++++------- purple-plugin/telegram-purple.c | 27 +++++---------------------- purple-plugin/telegram-purple.h | 7 ------- 3 files changed, 12 insertions(+), 36 deletions(-) diff --git a/net.h b/net.h index d95b41d..305b2ed 100644 --- a/net.h +++ b/net.h @@ -27,13 +27,13 @@ struct dc; #include "telegram.h" #include "queries.h" -#define TG_SERVER "173.240.5.1" -#define TG_SERVER_TEST "173.240.5.253" -#define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74" -#define TG_APP_ID 2899 -#define TG_BUILD "209" - -#define TG_VERSION "0.01-beta" +#define TG_SERVER "149.154.167.50" +#define TG_SERVER_TEST "149.154.167.40" +#define TG_PORT 443 +#define TG_APP_HASH "99428c722d0ed59b9cd844e4577cb4bb" +#define TG_APP_ID 16154 +#define TG_BUILD "0" +#define TG_VERSION "0.2.0" #define ACK_TIMEOUT 1 #define MAX_DC_ID 10 diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 8fa3a4f..ba90d58 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -174,17 +174,6 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info } -/** - * Handle a failed verification by removing the invalid sms code and notifying the user - */ -static void login_verification_fail(PurpleAccount *acct) -{ - // remove invalid sms code, so we won't try to register again - purple_account_set_string(acct, "verification_key", ""); - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Verification Failed", - "Please make sure you entered the correct verification code.", NULL, NULL, NULL); -} - /* OUTPUT */ /** @@ -254,8 +243,8 @@ static void tgprpl_has_input(void *handle) static void init_dc_settings(PurpleAccount *acc, struct dc *DC) { - DC->port = purple_account_get_int(acc, "port", TELEGRAM_DEFAULT_PORT); - DC->ip = g_strdup(purple_account_get_string(acc, "server", TELEGRAM_TEST_SERVER)); + DC->port = purple_account_get_int(acc, "port", TG_PORT); + DC->ip = g_strdup(purple_account_get_string(acc, "server", TG_SERVER)); DC->id = 0; } @@ -293,9 +282,9 @@ void telegram_on_proxy_close(void *handle) void telegram_on_phone_registration (struct telegram *instance) { + // TODO: Query first and last name from user and start phone registration telegram_conn *conn = instance->extra; - // TODO: Request first and last name purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); const char *first_name = purple_account_get_string(conn->pa, "first_name", NULL); const char *last_name = purple_account_get_string(conn->pa, "last_name", NULL); @@ -1248,12 +1237,6 @@ static void tgprpl_init(PurplePlugin *plugin) option = purple_account_option_list_new("Verification type", "verification_type", verification_values); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_string_new("Verification key", "verification_key", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - - option = purple_account_option_string_new("Verification hash", "verification_hash", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_string_new("First Name", "first_name", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); @@ -1264,10 +1247,10 @@ static void tgprpl_init(PurplePlugin *plugin) // TODO: Path to public key (When you can change the server hostname, // you should also be able to change the public key) - option = purple_account_option_string_new("Server", "server", TELEGRAM_TEST_SERVER); + option = purple_account_option_string_new("Server", "server", TG_SERVER); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new("Port", "port", TELEGRAM_DEFAULT_PORT); + option = purple_account_option_int_new("Port", "port", TG_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); _telegram_protocol = plugin; diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index fe5d747..66ad820 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -18,13 +18,6 @@ #define __TG_PURPLE_H__ #define PLUGIN_ID "prpl-telegram" -#define TELEGRAM_APP_API_ID 16944 -#define TELEGRAM_APP_API_HASH "457b5a190c750ed0a772bc48bbdf75dc" -#define TELEGRAM_TEST_SERVER "173.240.5.253" -#define TELEGRAM_PRODUCTION_SERVER "173.240.5.1" -#define TELEGRAM_DEFAULT_PORT 443 -#define TELEGRAM_PUBLIC_KEY "-----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daSan9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTwEfzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3nSlv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB-----END RSA PUBLIC KEY-----" - #define TELEGRAM_AUTH_MODE_PHONE "phone" #define TELEGRAM_AUTH_MODE_SMS "sms" From 97c8b371212724d8fdb3b64a970becafe79f679b Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 13:30:44 +0200 Subject: [PATCH 405/465] Do not use old tg-cli directory for storing files --- purple-plugin/telegram-purple.c | 3 ++- telegram.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index ba90d58..7ebeb01 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -53,6 +53,7 @@ #include "structures.h" #include "net.h" +#define CONFIG_DIR ".telegram-purple" #define BUDDYNAME_MAX_LENGTH 128 static PurplePlugin *_telegram_protocol = NULL; @@ -1208,7 +1209,7 @@ static PurplePluginProtocolInfo prpl_info = { static void tgprpl_init(PurplePlugin *plugin) { - const char *dir = ".telegram"; + const char *dir = CONFIG_DIR; if (!tgconf.base_config_path) { struct passwd *pw = getpwuid(getuid()); int len = strlen (dir) + strlen (pw->pw_dir) + 2; diff --git a/telegram.h b/telegram.h index cc5834c..407f9b4 100644 --- a/telegram.h +++ b/telegram.h @@ -6,7 +6,7 @@ #define MAX_PEER_NUM 100000 #ifndef PROG_NAME -#define PROG_NAME "telegram" +#define PROG_NAME "telegram-purple" #endif #include From a7f0b165993c8256bb3e5db0af67eb32ddeed1f3 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 13:56:29 +0200 Subject: [PATCH 406/465] Remove automake --- Makefile.in | 115 -- configure | 5019 -------------------------------------------------- configure.ac | 51 - net.h | 2 - 4 files changed, 5187 deletions(-) delete mode 100644 Makefile.in delete mode 100755 configure delete mode 100644 configure.ac diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index 9e0183a..0000000 --- a/Makefile.in +++ /dev/null @@ -1,115 +0,0 @@ -# -# Telegram Flags -# - -srcdir=@srcdir@ - -CFLAGS=@CFLAGS@ -LDFLAGS=@LDFLAGS@ -CPPFLAGS=@CPPFLAGS@ -DEFS=@DEFS@ -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb - -EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ -LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} -LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} - -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h - -INCLUDE=-I. -I${srcdir} -CC=@CC@ -OBJECTS=loop.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o msglog.o telegram.o -.SUFFIXES: - -.SUFFIXES: .c .h .o - - -# -# Plugin Flags -# - -LIBS_PURPLE = $(shell pkg-config --libs purple) -CFLAGS_PURPLE = $(shell pkg-config --cflags purple) -PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) -DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple) - -ARCH = "" -ifeq ($(ARCH),i686) - ARCHFLAGS = -m32 -else ifeq ($(ARCH),x86_64) - ARCHFLAGS = -m64 -else - ARCHFLAGS = -endif - -LD = $(CC) -PRPL_C_SRCS = purple-plugin/telegram-purple.c -PRPL_C_OBJS = $(PRPL_C_SRCS:.c=.o) -PRPL_LIBNAME = telegram-purple.so -PRPL_INCLUDE = -I. -I./purple-plugin -PRPL_LDFLAGS = $(ARCHFLAGS) -shared -STRIP = strip -PRPL_CFLAGS = \ - $(ARCHFLAGS) \ - -fPIC \ - -DPURPLE_PLUGINS \ - -DPIC \ - -DDEBUG \ - -g \ - $(CFLAGS_PURPLE) - -# -# Telegram Objects -# - -.c.o : - ${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ - -${OBJECTS}: ${HEADERS} - -telegram: ${OBJECTS} - ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ - -# -# Plugin Objects -# - -$(PRPL_C_OBJS): $(PRPL_C_SRCS) - $(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $< - -$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) - $(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $(PRPL_C_OBJS) $(OBJECTS) - -plugin: $(PRPL_LIBNAME) - -.PHONY: strip -strip: $(PRPL_LIBNAME) - $(STRIP) --strip-unneeded $(PRPL_LIBNAME) - -# TODO: Find a better place for server.pub -install: $(PRPL_LIBNAME) - install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) - install -D tg-server.pub /etc/telegram/server.pub - install -D purple-plugin/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png - install -D purple-plugin/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png - install -D purple-plugin/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png - -.PHONY: uninstall -uninstall: $(PRPL_LIBNAME) - rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) - rm -f /etc/telegram/server.pub - rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png - rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png - rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png - -.PHONY: run -run: install - pidgin -d | grep 'telegram\|plugin\|proxy' - -.PHONY: debug -debug: install - ddd pidgin - -clean: - rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean" - diff --git a/configure b/configure deleted file mode 100755 index 1c22650..0000000 --- a/configure +++ /dev/null @@ -1,5019 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for telegram-purple 0.2. -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, -$0: including any error possibly output before this -$0: message. Then install a modern shell, or manually run -$0: the script under such a shell if you do have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='telegram-purple' -PACKAGE_TARNAME='telegram-purple' -PACKAGE_VERSION='0.2' -PACKAGE_STRING='telegram-purple 0.2' -PACKAGE_BUGREPORT='' -PACKAGE_URL='' - -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_subst_vars='LTLIBOBJS -EXTRA_LIBS -LIBOBJS -EGREP -GREP -CPP -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -with_progname -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CPP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures telegram-purple 0.2 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/telegram-purple] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of telegram-purple 0.2:";; - esac - cat <<\_ACEOF - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) ---with-progname= - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CPP C preprocessor - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to the package provider. -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -telegram-purple configure 0.2 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by telegram-purple $as_me 0.2, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -# Checks for programs. -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff. -CPPFLAGS="$CPPFLAGS -I/usr/local/include" -LDFLAGS="$LDFLAGS -L/usr/local/lib" - -# Checks for libraries. - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 -$as_echo_n "checking for sqrt in -lm... " >&6; } -if ${ac_cv_lib_m_sqrt+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lm $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char sqrt (); -int -main () -{ -return sqrt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_m_sqrt=yes -else - ac_cv_lib_m_sqrt=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5 -$as_echo "$ac_cv_lib_m_sqrt" >&6; } -if test "x$ac_cv_lib_m_sqrt" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBM 1 -_ACEOF - - LIBS="-lm $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 -$as_echo_n "checking for library containing clock_gettime... " >&6; } -if ${ac_cv_search_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char clock_gettime (); -int -main () -{ -return clock_gettime (); - ; - return 0; -} -_ACEOF -for ac_lib in '' rt; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_clock_gettime=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_clock_gettime+:} false; then : - break -fi -done -if ${ac_cv_search_clock_gettime+:} false; then : - -else - ac_cv_search_clock_gettime=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 -$as_echo "$ac_cv_search_clock_gettime" >&6; } -ac_res=$ac_cv_search_clock_gettime -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5 -$as_echo_n "checking for library containing backtrace... " >&6; } -if ${ac_cv_search_backtrace+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char backtrace (); -int -main () -{ -return backtrace (); - ; - return 0; -} -_ACEOF -for ac_lib in '' execinfo; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_backtrace=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_backtrace+:} false; then : - break -fi -done -if ${ac_cv_search_backtrace+:} false; then : - -else - ac_cv_search_backtrace=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5 -$as_echo "$ac_cv_search_backtrace" >&6; } -ac_res=$ac_cv_search_backtrace -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflate in -lz" >&5 -$as_echo_n "checking for inflate in -lz... " >&6; } -if ${ac_cv_lib_z_inflate+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lz $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char inflate (); -int -main () -{ -return inflate (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_z_inflate=yes -else - ac_cv_lib_z_inflate=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflate" >&5 -$as_echo "$ac_cv_lib_z_inflate" >&6; } -if test "x$ac_cv_lib_z_inflate" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBZ 1 -_ACEOF - - LIBS="-lz $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for AES_set_encrypt_key in -lcrypto" >&5 -$as_echo_n "checking for AES_set_encrypt_key in -lcrypto... " >&6; } -if ${ac_cv_lib_crypto_AES_set_encrypt_key+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lcrypto $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char AES_set_encrypt_key (); -int -main () -{ -return AES_set_encrypt_key (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_crypto_AES_set_encrypt_key=yes -else - ac_cv_lib_crypto_AES_set_encrypt_key=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_AES_set_encrypt_key" >&5 -$as_echo "$ac_cv_lib_crypto_AES_set_encrypt_key" >&6; } -if test "x$ac_cv_lib_crypto_AES_set_encrypt_key" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBCRYPTO 1 -_ACEOF - - LIBS="-lcrypto $LIBS" - -fi - - -EXTRA_LIBS="" - -#check for custom prog name - -# Check whether --with-progname was given. -if test "${with_progname+set}" = set; then : - withval=$with_progname; - if test "x$with_progname" = "xno" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 -$as_echo "default" >&6; } - elif test "x$with_progname" = "xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 -$as_echo "default" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_progname\"" >&5 -$as_echo "\"$with_progname\"" >&6; } - -cat >>confdefs.h <<_ACEOF -#define PROG_NAME "$with_progname" -_ACEOF - - fi - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 -$as_echo "default" >&6; } - -fi - - -# Checks for header files. -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -for ac_header in execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -# Checks for typedefs, structures, and compiler characteristics. -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 -$as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if ${ac_cv_type_uid_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uid_t" >/dev/null 2>&1; then : - ac_cv_type_uid_t=yes -else - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 -$as_echo "$ac_cv_type_uid_t" >&6; } -if test $ac_cv_type_uid_t = no; then - -$as_echo "#define uid_t int" >>confdefs.h - - -$as_echo "#define gid_t int" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 -$as_echo_n "checking for inline... " >&6; } -if ${ac_cv_c_inline+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_inline=$ac_kw -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_inline" != no && break -done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -$as_echo "$ac_cv_c_inline" >&6; } - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - - -# Checks for library functions. -for ac_header in stdlib.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" -if test "x$ac_cv_header_stdlib_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_STDLIB_H 1 -_ACEOF - -fi - -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 -$as_echo_n "checking for GNU libc compatible malloc... " >&6; } -if ${ac_cv_func_malloc_0_nonnull+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_malloc_0_nonnull=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined STDC_HEADERS || defined HAVE_STDLIB_H -# include -#else -char *malloc (); -#endif - -int -main () -{ -return ! malloc (0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_malloc_0_nonnull=yes -else - ac_cv_func_malloc_0_nonnull=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 -$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } -if test $ac_cv_func_malloc_0_nonnull = yes; then : - -$as_echo "#define HAVE_MALLOC 1" >>confdefs.h - -else - $as_echo "#define HAVE_MALLOC 0" >>confdefs.h - - case " $LIBOBJS " in - *" malloc.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS malloc.$ac_objext" - ;; -esac - - -$as_echo "#define malloc rpl_malloc" >>confdefs.h - -fi - - -for ac_header in stdlib.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" -if test "x$ac_cv_header_stdlib_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_STDLIB_H 1 -_ACEOF - -fi - -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 -$as_echo_n "checking for GNU libc compatible realloc... " >&6; } -if ${ac_cv_func_realloc_0_nonnull+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_func_realloc_0_nonnull=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#if defined STDC_HEADERS || defined HAVE_STDLIB_H -# include -#else -char *realloc (); -#endif - -int -main () -{ -return ! realloc (0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_realloc_0_nonnull=yes -else - ac_cv_func_realloc_0_nonnull=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 -$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } -if test $ac_cv_func_realloc_0_nonnull = yes; then : - -$as_echo "#define HAVE_REALLOC 1" >>confdefs.h - -else - $as_echo "#define HAVE_REALLOC 0" >>confdefs.h - - case " $LIBOBJS " in - *" realloc.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS realloc.$ac_objext" - ;; -esac - - -$as_echo "#define realloc rpl_realloc" >>confdefs.h - -fi - - -for ac_func in alarm endpwent memset memmove mkdir select socket strdup strndup uname -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - - -ac_config_files="$ac_config_files Makefile" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Transform confdefs.h into DEFS. -# Protect against shell expansion while executing Makefile rules. -# Protect against Makefile macro expansion. -# -# If the first sed substitution is executed (which looks for macros that -# take arguments), then branch to the quote section. Otherwise, -# look for a macro that doesn't take arguments. -ac_script=' -:mline -/\\$/{ - N - s,\\\n,, - b mline -} -t clear -:clear -s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g -t quote -s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g -t quote -b any -:quote -s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g -s/\[/\\&/g -s/\]/\\&/g -s/\$/$$/g -H -:any -${ - g - s/^\n// - s/\n/ /g - p -} -' -DEFS=`sed -n "$ac_script" confdefs.h` - - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by telegram-purple $as_me 0.2, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - -Configuration files: -$config_files - -Report bugs to the package provider." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -telegram-purple config.status 0.2 -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - - -eval set X " :F $CONFIG_FILES " -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - - - - esac - -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 5e3408b..0000000 --- a/configure.ac +++ /dev/null @@ -1,51 +0,0 @@ -AC_PREREQ([2.68]) -AC_INIT([telegram-purple], [0.2]) - -# Checks for programs. -AC_PROG_CC - -# BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff. -CPPFLAGS="$CPPFLAGS -I/usr/local/include" -LDFLAGS="$LDFLAGS -L/usr/local/lib" - -# Checks for libraries. -AC_CHECK_LIB([m], [sqrt]) -AC_SEARCH_LIBS([clock_gettime], [rt]) -AC_SEARCH_LIBS([backtrace], [execinfo]) -AC_CHECK_LIB([z], [inflate]) -AC_CHECK_LIB([crypto], [AES_set_encrypt_key]) - -EXTRA_LIBS="" - -#check for custom prog name -AC_ARG_WITH(progname,[--with-progname=], - [ - if test "x$with_progname" = "xno" ; then - AC_MSG_RESULT([default]) - elif test "x$with_progname" = "xyes" ; then - AC_MSG_RESULT([default]) - else - AC_MSG_RESULT(["$with_progname"]) - AC_DEFINE_UNQUOTED([PROG_NAME], ["$with_progname"], [Use custom prog name]) - fi - ],[ - AC_MSG_RESULT([default]) - ]) - -# Checks for header files. -AC_CHECK_HEADERS([execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_TYPE_SIZE_T -AC_TYPE_UID_T -AC_C_INLINE - -# Checks for library functions. -AC_FUNC_MALLOC -AC_FUNC_REALLOC -AC_CHECK_FUNCS([alarm endpwent memset memmove mkdir select socket strdup strndup uname]) - -AC_SUBST(EXTRA_LIBS) -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT - diff --git a/net.h b/net.h index 305b2ed..ee537d0 100644 --- a/net.h +++ b/net.h @@ -32,8 +32,6 @@ struct dc; #define TG_PORT 443 #define TG_APP_HASH "99428c722d0ed59b9cd844e4577cb4bb" #define TG_APP_ID 16154 -#define TG_BUILD "0" -#define TG_VERSION "0.2.0" #define ACK_TIMEOUT 1 #define MAX_DC_ID 10 From 30f6f0d38132dae8fa2e59eae1ed4c12777df57e Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 14:17:36 +0200 Subject: [PATCH 407/465] Add makefile --- .gitignore | 2 - Makefile | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 524af2b..293b9fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,6 @@ telegram *.o *.so *.a -/Makefile -autom4te.cache config.h config.log config.status diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..08317a9 --- /dev/null +++ b/Makefile @@ -0,0 +1,115 @@ +# +# Telegram Flags +# +VERSION=0.2.0 +BUILD=1 + +srcdir=. +CFLAGS=-g +LDFLAGS=-L/usr/local/lib +CPPFLAGS=-I/usr/local/include +DEFS=-DTG_VERSION=\"${VERSION}\" -DTG_BUILD=\"${BUILD}\" +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +EXTRA_LIBS=-lcrypto -lz -lm +LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} +LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} + +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h + +INCLUDE=-I. -I${srcdir} +CC=cc +OBJECTS=loop.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o msglog.o telegram.o +.SUFFIXES: + +.SUFFIXES: .c .h .o + + +# +# Plugin Flags +# + +LIBS_PURPLE = $(shell pkg-config --libs purple) +CFLAGS_PURPLE = $(shell pkg-config --cflags purple) +PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple) +DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple) + +ARCH = "" +ifeq ($(ARCH),i686) + ARCHFLAGS = -m32 +else ifeq ($(ARCH),x86_64) + ARCHFLAGS = -m64 +else + ARCHFLAGS = +endif + +LD = $(CC) +PRPL_C_SRCS = purple-plugin/telegram-purple.c +PRPL_C_OBJS = $(PRPL_C_SRCS:.c=.o) +PRPL_LIBNAME = telegram-purple.so +PRPL_INCLUDE = -I. -I./purple-plugin +PRPL_LDFLAGS = $(ARCHFLAGS) -shared +STRIP = strip +PRPL_CFLAGS = \ + $(ARCHFLAGS) \ + -fPIC \ + -DPURPLE_PLUGINS \ + -DPIC \ + -DDEBUG \ + -g \ + $(CFLAGS_PURPLE) + +# +# Telegram Objects +# + +.c.o : + ${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ + +${OBJECTS}: ${HEADERS} + +telegram: ${OBJECTS} + ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ + +# +# Plugin Objects +# + +$(PRPL_C_OBJS): $(PRPL_C_SRCS) + $(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $< + +$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) + $(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $(PRPL_C_OBJS) $(OBJECTS) + +plugin: $(PRPL_LIBNAME) + +.PHONY: strip +strip: $(PRPL_LIBNAME) + $(STRIP) --strip-unneeded $(PRPL_LIBNAME) + +# TODO: Find a better place for server.pub +install: $(PRPL_LIBNAME) + install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) + install -D tg-server.pub /etc/telegram/server.pub + install -D purple-plugin/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png + install -D purple-plugin/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png + install -D purple-plugin/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png + +.PHONY: uninstall +uninstall: $(PRPL_LIBNAME) + rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) + rm -f /etc/telegram/server.pub + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png + rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png + +.PHONY: run +run: install + pidgin -d | grep 'telegram\|plugin\|proxy' + +.PHONY: debug +debug: install + ddd pidgin + +clean: + rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean" + From 4f711c16d79cfb9eba548cd9b6b0a0f2f5155013 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 17:11:42 +0200 Subject: [PATCH 408/465] Update README --- README.md | 58 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index d002016..d48b5ba 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,27 @@ -telegram-purple +Telegram-Purple =============== Telegram-purple is a Libpurple plugin that adds support for the Telegram messenger. Its still in an early (pre-alpha) development stage, but already provides basic chat functionality and group chats. -This plugin is based on the great [Telegram-cli](http://github.com/vysheng/tg), a full-featured terminal-based client for Telegram created by [Vysheng](http://github.com/vysheng). +This plugin is based on [Telegram-cli](http://github.com/vysheng/tg), a full-featured terminal-based client for Telegram created by [Vysheng](http://github.com/vysheng). -# Features -Our long-term plan is to implement all major features of the Telegram protocol, but at the moment only a subset of the chat features is working. +# Version 0.2.0 -## Already Implemented +Warning, this version is mainly for development and testing and NOT for productive use.Even though it already provides basic features, you should still expect bugs and crashes when running it. - - Group chats - - Multiple accounts - - Complies with proxy settings +When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace of the crashed application [https://developer.pidgin.im/wiki/GetABacktrace] -## Planned +## Already Implemented: + + - Chats/Group-Chats + * Send/receive messages + * Discover buddies/chats + * Discover buddy state and info + - Profile Pictures + * Download and use profile pictures + +## TODO: The following features are currently planned and will probably be added in the future: @@ -23,55 +29,51 @@ The following features are currently planned and will probably be added in the f - Picture, audio and video messages - File transfers - Geo-locations - - Emojie + - Multiple accounts on one client + - Respect libpurple proxy settings (implemented but untested) - Adium Plugin + ## Platform Support -Currently we can only provide an installation guide for Linux, even though it should be possible to compile this plugin on all platforms. If someone manages to create a working Windows or OSX build, please let us know. - - -# A Word of Warning - -This is a very early (pre-alpha) version for development and testing and NOT for productive use. -Even though it already provides basic features, you should still expect bugs and crashes when running it. - -When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace [https://developer.pidgin.im/wiki/GetABacktrace] +Currently we can only provide an installation guide for Linux, even though it should be possible to compile this plugin on other platforms. If someone manages to create a working Windows, BSD or OSX build, please let us know. # Installation Instructions Unfortunately there are currently no packages, so you need to compile it yourself: -## Get this repository either from Bitbucket or from the Github mirror. +## 1. Get this repository either from Bitbucket or from the Github mirror. git clone https://bitbucket.org/telegrampurple/telegram-purple +## 2. Fetch all needed dependencies - -## Fetch all needed dependencies - -This plugin depends on a working libpurple client and the following packages: +This plugin depends on a working libpurple client (like Pidgin or Finch) and the following packages: - glib-2.0 - - libcrypto + - libssl - libpurple - libzlib +### Fedora On Fedora you can install all dependencies with: sudo yum install gcc openssl-devel glib2-devel libpurple-devel +### Debian -And on Debian/Ubuntu you can use: +On Debian-based systems you can use: sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev -## Compile and install +NOTE: Ubuntu is currently not working, since libpurple doesn't seem to find libssl when loading the plugin. It will compile, but will not be loaded by Pidgin. + + +## 3. Compile and install - ./configure make sudo make install From 30ebe78fcac3ab52beb8db740b09333b272df8d8 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 17:32:37 +0200 Subject: [PATCH 409/465] Avoid invalid cast warning --- queries.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/queries.c b/queries.c index 915796f..e0a720e 100644 --- a/queries.c +++ b/queries.c @@ -1778,11 +1778,17 @@ void print_user_info (struct user *U) { //print_end (); } +struct show_info_extra { + int show_info; +}; + int user_info_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); + struct show_info_extra *extra = q->extra; struct user *U = fetch_alloc_user_full (mtp); - event_user_info_received_handler (mtp->instance, U, (int)q->extra); + event_user_info_received_handler (mtp->instance, U, extra->show_info); + tfree (extra, sizeof(struct show_info_extra)); //print_user_info (U); return 0; } @@ -1793,6 +1799,8 @@ struct query_methods user_info_methods = { void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo) { logprintf ("do_get_user_info\n"); + struct show_info_extra *extra = talloc(sizeof(struct show_info_extra)); + extra->show_info = showInfo; struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); @@ -1807,7 +1815,7 @@ void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo) { out_int (mtp, CODE_input_user_contact); out_int (mtp, get_peer_id (id)); } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, (void*)showInfo); + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, extra); logprintf ("do_get_user_info ready\n"); } /* }}} */ From 598559105f41ae887f96b8df6c0325b8f5c0bce1 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 23:10:23 +0200 Subject: [PATCH 410/465] Fix importAuthorization --- queries.c | 13 ++++++++++--- telegram.c | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/queries.c b/queries.c index e0a720e..ff27ec2 100644 --- a/queries.c +++ b/queries.c @@ -2144,8 +2144,10 @@ struct query_methods export_auth_methods = { }; void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra) { - struct dc *DC_working = telegram_get_working_dc(instance); + logprintf ("do_export_auth(num=%d)\n", num); + struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; + instance->export_auth_str = 0; clear_packet (mtp); out_int (mtp, CODE_auth_export_authorization); @@ -2185,7 +2187,12 @@ struct query_methods import_auth_methods = { }; void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra) { - struct mtproto_connection *mtp = instance->connection; + logprintf ("do_import_auth(num=%d, our_id=%d, export_auth_str=%s)\n", num, instance->our_id, instance->export_auth_str); + struct dc *DC_working = instance->auth.DC_list[num]; + assert (DC_working); + assert (DC_working->sessions[0]->c); + struct mtproto_connection *mtp = DC_working->sessions[0]->c->mtconnection; + struct import_info *info = talloc0(sizeof (struct import_info)); info->cb = cb; info->extra = extra; @@ -2195,7 +2202,7 @@ void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra) out_int (mtp, instance->our_id); out_cstring (mtp, instance->export_auth_str, instance->export_auth_str_len); - send_query (instance, instance->auth.DC_list[num], mtp->packet_ptr - mtp->packet_buffer, + send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &import_auth_methods, info); } /* }}} */ diff --git a/telegram.c b/telegram.c index 60c8739..4bf757b 100755 --- a/telegram.c +++ b/telegram.c @@ -413,7 +413,7 @@ void telegram_dl_connected (struct proxy_request *req) */ void telegram_dl_add (struct telegram *instance, struct download *dl) { - logprintf ("telegram_connect_dl(dc=%d)\n", instance->auth.DC_list[dl->dc]); + logprintf ("telegram_connect_dl(dc_num=%d, dc=%d)\n", dl->dc, instance->auth.DC_list[dl->dc]); if (!instance->dl_queue) { instance->dl_queue = g_queue_new (); } @@ -435,7 +435,7 @@ void telegram_dl_next (struct telegram *instance) req->data = dl; instance->dl_curr = dl; - logprintf ("telegrma_dl_start(): starting new download..\n"); + logprintf ("telegrma_dl_start(workin_dc=%d, ): starting new download..\n", instance->auth.dc_working_num); if (dl->dc == instance->auth.dc_working_num) { logprintf ("is working DC, start download...\n"); assert (telegram_get_working_dc(instance)->sessions[0]->c); From 1082e4d18a6acd6a1f54350f84c2c9a8e1c882d2 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 2 Oct 2014 23:10:45 +0200 Subject: [PATCH 411/465] Add install instruction for openSuse --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d48b5ba..ebb851b 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,12 @@ On Debian-based systems you can use: sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev +### OpenSUSE + + + sudo zypper install gcc glib glib-devel libpurple libpurple-devel zlib-devel openssl libopenssl-devel + + NOTE: Ubuntu is currently not working, since libpurple doesn't seem to find libssl when loading the plugin. It will compile, but will not be loaded by Pidgin. From c870e967db1046bc7f6e7ef28c123d8e5a144fcf Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 3 Oct 2014 00:14:57 +0200 Subject: [PATCH 412/465] Send bytes to correct connection on importAuth --- queries.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/queries.c b/queries.c index ff27ec2..764cda7 100644 --- a/queries.c +++ b/queries.c @@ -2144,11 +2144,8 @@ struct query_methods export_auth_methods = { }; void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra) { - logprintf ("do_export_auth(num=%d)\n", num); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - instance->export_auth_str = 0; + struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); out_int (mtp, CODE_auth_export_authorization); out_int (mtp, num); @@ -2156,7 +2153,9 @@ void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export struct export_info *info = talloc0(sizeof(struct export_info)); info->cb = cb; info->extra = extra; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, info); + + send_query (instance, telegram_get_working_dc(instance), + mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, info); } /* }}} */ @@ -2188,22 +2187,22 @@ struct query_methods import_auth_methods = { void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra) { logprintf ("do_import_auth(num=%d, our_id=%d, export_auth_str=%s)\n", num, instance->our_id, instance->export_auth_str); - struct dc *DC_working = instance->auth.DC_list[num]; - assert (DC_working); - assert (DC_working->sessions[0]->c); - struct mtproto_connection *mtp = DC_working->sessions[0]->c->mtconnection; - struct import_info *info = talloc0(sizeof (struct import_info)); info->cb = cb; info->extra = extra; - clear_packet (mtp); - out_int (mtp, CODE_auth_import_authorization); - out_int (mtp, instance->our_id); - out_cstring (mtp, instance->export_auth_str, instance->export_auth_str_len); + struct dc *target_dc = instance->auth.DC_list[num]; + assert (target_dc); + struct mtproto_connection *dc_conn = target_dc->sessions[0]->c->mtconnection; + assert (dc_conn); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, - mtp->packet_buffer, &import_auth_methods, info); + clear_packet (dc_conn); + out_int (dc_conn, CODE_auth_import_authorization); + out_int (dc_conn, instance->our_id); + out_cstring (dc_conn, instance->export_auth_str, instance->export_auth_str_len); + + send_query (instance, target_dc, dc_conn->packet_ptr - dc_conn->packet_buffer, + dc_conn->packet_buffer, &import_auth_methods, info); } /* }}} */ From 334101c406a8b7b4fa7e9ef5560e28ed01fc9098 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 3 Oct 2014 14:23:15 +0200 Subject: [PATCH 413/465] Improve logging system --- binlog.c | 12 +- loop.c | 24 +-- msglog.c | 85 ++++++---- msglog.h | 16 +- mtproto-client.c | 138 ++++++++-------- mtproto-client.h | 6 +- mtproto-common.c | 8 +- net.c | 31 ++-- purple-plugin/telegram-purple.c | 84 +++++----- queries.c | 279 +++++++++++++++++--------------- structures.c | 72 ++++----- telegram.c | 68 ++++---- tools.c | 20 +-- 13 files changed, 432 insertions(+), 411 deletions(-) diff --git a/binlog.c b/binlog.c index dc820bc..214c284 100644 --- a/binlog.c +++ b/binlog.c @@ -55,7 +55,7 @@ void replay_log_event (struct telegram *instance) { int op = *bl->rptr; if (verbosity >= 2) { - logprintf ("log_pos %lld, op 0x%08x\n", bl->binlog_pos, op); + debug ("log_pos %lld, op 0x%08x\n", bl->binlog_pos, op); } self->in_ptr = bl->rptr; @@ -73,7 +73,7 @@ void replay_log_event (struct telegram *instance) { int l2 = prefetch_strlen (self); char *ip = fetch_str (self, l2); int port = fetch_int (self); - logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + debug ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); alloc_dc (instance->auth.DC_list, id, tstrndup (ip, l2), port); } bl->rptr = self->in_ptr; @@ -1046,19 +1046,19 @@ void replay_log_event (struct telegram *instance) { bl->rptr = self->in_ptr; break; default: - logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(bl->rptr - 1), op, *(bl->rptr + 1), bl->binlog_pos); + debug ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(bl->rptr - 1), op, *(bl->rptr + 1), bl->binlog_pos); assert (0); } if (verbosity >= 2) { - logprintf ("Event end\n"); + debug ("Event end\n"); } bl->in_replay_log = 0; bl->binlog_pos += (bl->rptr - start) * 4; } void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int len) { - logprintf ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); + debug ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); assert (!(len & 3)); if (bl->in_replay_log) { return; } bl->rptr = (void *)data; @@ -1067,7 +1067,7 @@ void add_log_event (struct binlog *bl, struct mtproto_connection *self, const in int *end = self->in_end; replay_log_event (self->connection->instance); if (bl->rptr != bl->wptr) { - logprintf ("Unread %lld ints. Len = %d\n", (long long)(bl->wptr - bl->rptr), len); + debug ("Unread %lld ints. Len = %d\n", (long long)(bl->wptr - bl->rptr), len); assert (bl->rptr == bl->wptr); } if (bl->binlog_enabled) { diff --git a/loop.c b/loop.c index d9a7d21..3977266 100644 --- a/loop.c +++ b/loop.c @@ -50,7 +50,7 @@ int zero[512]; void write_dc (int auth_file_fd, struct dc *DC) { - logprintf("writing to auth_file: auth_file_fd: %d, port: %d, ip: %s\n", auth_file_fd, DC->port, DC->ip); + debug("writing to auth_file: auth_file_fd: %d, port: %d, ip: %s\n", auth_file_fd, DC->port, DC->ip); assert (write (auth_file_fd, &DC->port, 4) == 4); int l = strlen (DC->ip); assert (write (auth_file_fd, &l, 4) == 4); @@ -67,7 +67,7 @@ void write_dc (int auth_file_fd, struct dc *DC) { } void write_auth_file (struct authorization_state *state, const char *filename) { - logprintf("Writing to auth_file: %s\n", filename); + debug("Writing to auth_file: %s\n", filename); int auth_file_fd = open (filename, O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); int x = DC_SERIALIZED_MAGIC_V2; @@ -119,7 +119,7 @@ void empty_auth_file (const char *filename) { struct authorization_state state; memset(state.DC_list, 0, 11 * sizeof(void *)); - logprintf("empty_auth_file()\n"); + debug("empty_auth_file()\n"); alloc_dc (state.DC_list, 1, tstrdup (TG_SERVER), 443); state.dc_working_num = 1; state.auth_state = 0; @@ -134,15 +134,15 @@ void empty_auth_file (const char *filename) { * path */ struct authorization_state read_auth_file (const char *filename) { - logprintf("read_auth_file()\n"); + debug("read_auth_file()\n"); struct authorization_state state; memset(state.DC_list, 0, 11 * sizeof(void *)); int auth_file_fd = open (filename, O_RDWR, 0600); - logprintf("fd: %d\n", auth_file_fd); + debug("fd: %d\n", auth_file_fd); if (auth_file_fd < 0) { - logprintf("auth_file does not exist, creating empty...\n"); + debug("auth_file does not exist, creating empty...\n"); empty_auth_file (filename); } auth_file_fd = open (filename, O_RDWR, 0600); @@ -153,7 +153,7 @@ struct authorization_state read_auth_file (const char *filename) { // magic number of file unsigned m; if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) { - logprintf("Invalid File content, wrong Magic numebr\n"); + debug("Invalid File content, wrong Magic numebr\n"); close (auth_file_fd); empty_auth_file (filename); return state; @@ -171,11 +171,11 @@ struct authorization_state read_auth_file (const char *filename) { assert (read (auth_file_fd, &y, 4) == 4); if (y) { read_dc (auth_file_fd, i, m, state.DC_list); - logprintf("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n", + debug("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n", i, state.DC_list[i]->port, state.DC_list[i]->ip, state.DC_list[i]->auth_key_id, state.DC_list[i]->server_salt, state.DC_list[i]->has_auth); } else { - logprintf("loaded dc[%d] - NULL\n", i); + debug("loaded dc[%d] - NULL\n", i); } } int l = read (auth_file_fd, &state.our_id, 4); @@ -187,12 +187,12 @@ struct authorization_state read_auth_file (const char *filename) { if (m == DC_SERIALIZED_MAGIC) { DC_working->has_auth = 1; } - logprintf("loaded authorization state - our_id: %d, auth_state: %d, dc_working_num: %d \n", state.our_id, state.auth_state, state.dc_working_num); + debug("loaded authorization state - our_id: %d, auth_state: %d, dc_working_num: %d \n", state.our_id, state.auth_state, state.dc_working_num); return state; } struct protocol_state read_state_file (const char *filename) { - logprintf("read_state_file()\n"); + debug("read_state_file()\n"); struct protocol_state state = {0, 0, 0, 0}; int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600); @@ -214,7 +214,7 @@ struct protocol_state read_state_file (const char *filename) { state.seq = x[2]; state.last_date = x[3]; close (state_file_fd); - logprintf("loaded session state - pts: %d, qts: %d, seq: %d, last_date: %d.\n", state.pts, + debug("loaded session state - pts: %d, qts: %d, seq: %d, last_date: %d.\n", state.pts, state.qts, state.seq, state.last_date); return state; } diff --git a/msglog.c b/msglog.c index cbbbcc2..a2c59f2 100644 --- a/msglog.c +++ b/msglog.c @@ -1,18 +1,14 @@ #include #include +#include "debug.h" +#include "purple-plugin/telegram-purple.h" -#define COLOR_RED "\033[0;31m" -#define COLOR_REDB "\033[1;31m" -#define COLOR_NORMAL "\033[0m" -#define COLOR_GREEN "\033[32;1m" #define COLOR_GREY "\033[37;1m" #define COLOR_YELLOW "\033[33;1m" -#define COLOR_BLUE "\033[34;1m" -#define COLOR_MAGENTA "\033[35;1m" -#define COLOR_CYAN "\033[36;1m" -#define COLOR_LCYAN "\033[0;36m" - -#define COLOR_INVERSE "\033[7m" +#define COLOR_RED "\033[0;31m" +#define COLOR_REDB "\033[1;31m" +#define COLOR_GREEN "\033[32;1m" +#define COLOR_NORMAL "\033[0m" /** * Log a message to the telegram-cli message log, by @@ -20,9 +16,7 @@ */ void log_printf(const char *format, va_list ap) { - printf (COLOR_GREY " *** "); - vprintf (format, ap); - printf (COLOR_NORMAL); + vprintf (format, ap); } /** @@ -36,39 +30,60 @@ void (*log_cb)(const char* format, va_list ap) = log_printf; */ void set_log_cb(void (*cb)(const char*, va_list ap)) { - log_cb = cb; -} - -/** - * Log a message to the current message log - */ -void logprintf(const char *format, ...) -{ - va_list ap; - va_start (ap, format); - log_cb(format, ap); - va_end (ap); + log_cb = cb; } void hexdump (int *in_ptr, int *in_end) { - int *ptr = in_ptr; - while (ptr < in_end) { printf (" %08x", *(ptr ++)); } - printf ("\n"); + int *ptr = in_ptr; + while (ptr < in_end) { printf (" %08x", *(ptr ++)); } + printf ("\n"); } -/* -TODO: implement different log levels - -void log_debug(const char* format, ...) +void log_level_printf (const char* format, va_list ap, int level, char *color) { + char buffer[256]; + vsnprintf(buffer, sizeof(buffer), format, ap); + purple_debug(level, PLUGIN_ID, "%s%s%s ", color, buffer, COLOR_NORMAL); } -void log_warning(const char* format, ...) +void debug(const char* format, ...) { + va_list ap; + va_start (ap, format); + log_level_printf (format, ap, PURPLE_DEBUG_MISC, COLOR_NORMAL); + va_end (ap); } -void log_error(const char* format, ...) +void info(const char* format, ...) { + va_list ap; + va_start (ap, format); + log_level_printf (format, ap, PURPLE_DEBUG_INFO, COLOR_GREEN); + va_end (ap); +} + +void warning(const char* format, ...) +{ + va_list ap; + va_start (ap, format); + log_level_printf (format, ap, PURPLE_DEBUG_WARNING, COLOR_YELLOW); + va_end (ap); +} + +void failure(const char* format, ...) +{ + va_list ap; + va_start (ap, format); + log_level_printf (format, ap, PURPLE_DEBUG_ERROR, COLOR_YELLOW); + va_end (ap); +} + +void fatal(const char* format, ...) +{ + va_list ap; + va_start (ap, format); + log_level_printf (format, ap, PURPLE_DEBUG_FATAL, COLOR_REDB); + va_end (ap); + info ("\n"); } -*/ diff --git a/msglog.h b/msglog.h index 9d52637..952b61c 100644 --- a/msglog.h +++ b/msglog.h @@ -5,17 +5,11 @@ * to stdout */ void set_log_cb(void (*cb)(const char*, va_list ap)); - -/** - * Log a message to the current message log - */ -void logprintf(const char *format, ...); - void hexdump (int *in_ptr, int *in_end); -/* -void log_debug(const char* format, ...); -void log_warning(const char* format, ...); -void log_error(const char* format, ...); -*/ +void debug(const char* format, ...); +void info(const char* format, ...); +void warning(const char* format, ...); +void failure(const char* format, ...); +void fatal(const char* format, ...); diff --git a/mtproto-client.c b/mtproto-client.c index 812eb89..4dd20f5 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -126,17 +126,17 @@ static int rsa_load_public_key (const char *public_key_name) { pubKey = NULL; FILE *f = fopen (public_key_name, "r"); if (f == NULL) { - logprintf ( "Couldn't open public key file: %s\n", public_key_name); + debug ( "Couldn't open public key file: %s\n", public_key_name); return -1; } pubKey = PEM_read_RSAPublicKey (f, NULL, NULL, NULL); fclose (f); if (pubKey == NULL) { - logprintf ( "PEM_read_RSAPublicKey returns NULL.\n"); + debug ( "PEM_read_RSAPublicKey returns NULL.\n"); return -1; } - logprintf ( "public key '%s' loaded successfully\n", rsa_public_key_name); + debug ( "public key '%s' loaded successfully\n", rsa_public_key_name); return 0; } @@ -167,7 +167,7 @@ int encrypt_packet_buffer_aes_unauth (struct mtproto_connection *self, const cha int rpc_send_packet (struct connection *c) { - logprintf("rpc_send_packet()\n"); + debug("rpc_send_packet()\n"); struct mtproto_connection *self = c->mtconnection; int len = (self->packet_ptr - self->packet_buffer) * 4; @@ -201,7 +201,7 @@ int rpc_send_packet (struct connection *c) { int rpc_send_message (struct connection *c, void *data, int len) { struct mtproto_connection *self = c->mtconnection; - logprintf("rpc_send_message(...)\n"); + //debug("rpc_send_message(...)\n"); assert (len > 0 && !(len & 0xfc000003)); int total_len = len >> 2; if (total_len < 0x7f) { @@ -241,7 +241,7 @@ unsigned long long gcd (unsigned long long a, unsigned long long b) { //typedef unsigned int uint128_t __attribute__ ((mode(TI))); int process_respq_answer (struct connection *c, char *packet, int len) { - logprintf ( "process_respq_answer(), len=%d\n", len); + debug ( "process_respq_answer(), len=%d\n", len); struct mtproto_connection *self = c->mtconnection; int i; @@ -264,7 +264,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { self->p1 = 0, self->p2 = 0; - logprintf ( "%lld received\n", self->what); + debug ( "%lld received\n", self->what); int it = 0; unsigned long long g = 0; @@ -309,7 +309,7 @@ int process_respq_answer (struct connection *c, char *packet, int len) { unsigned t = self->p1; self->p1 = self->p2; self->p2 = t; } - logprintf ( "Calculated primes: self->p1 = %d, self->p2 = %d, %d iterations\n", self->p1, self->p2, it); + debug ( "Calculated primes: self->p1 = %d, self->p2 = %d, %d iterations\n", self->p1, self->p2, it); /// ++p1; /// @@ -317,15 +317,15 @@ int process_respq_answer (struct connection *c, char *packet, int len) { int fingerprints_num = *(int *)(from + 4); assert (fingerprints_num >= 1 && fingerprints_num <= 64 && len == fingerprints_num * 8 + 8 + (from - packet)); long long *fingerprints = (long long *) (from + 8); - logprintf("Got %d fingerprints\n", fingerprints_num); + debug("Got %d fingerprints\n", fingerprints_num); for (i = 0; i < fingerprints_num; i++) { if (fingerprints[i] == pk_fingerprint) { - logprintf ( "found our public key at position %d\n", i); + debug ( "found our public key at position %d\n", i); break; } } if (i == fingerprints_num) { - logprintf ( "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); + debug ( "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); exit (2); } // create inner part (P_Q_inner_data) @@ -490,7 +490,7 @@ int check_g (unsigned char p[256], BIGNUM *g) { ok = 1; break; } else if (s[i] > p[i]) { - logprintf ("i = %d (%d %d)\n", i, (int)s[i], (int)p[i]); + debug ("i = %d (%d %d)\n", i, (int)s[i], (int)p[i]); return -1; } } @@ -507,10 +507,10 @@ int check_g_bn (BIGNUM *p, BIGNUM *g) { } int process_dh_answer (struct connection *c, char *packet, int len) { - logprintf ( "process_dh_answer(), len=%d\n", len); + debug ( "process_dh_answer(), len=%d\n", len); struct mtproto_connection *self = c->mtconnection; if (len < 116) { - logprintf ( "%u * %u = %llu", self->p1, self->p2, self->what); + debug ( "%u * %u = %llu", self->p1, self->p2, self->what); } assert (len >= 116); assert (!*(long long *) packet); @@ -550,7 +550,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { GET_DC(c)->server_time_delta = server_time - time (0); GET_DC(c)->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); - //logprintf ( "server time is %d, delta = %d\n", server_time, server_time_delta); + //debug ( "server time is %d, delta = %d\n", server_time, server_time_delta); // Build set_client_DH_params answer clear_packet (self); @@ -606,7 +606,7 @@ int process_dh_answer (struct connection *c, char *packet, int len) { int process_auth_complete (struct connection *c, char *packet, int len) { - logprintf ( "process_auth_complete(), len=%d\n", len); + debug ( "process_auth_complete(), len=%d\n", len); struct mtproto_connection *self = c->mtconnection; assert (len == 72); assert (!*(long long *) packet); @@ -628,7 +628,7 @@ int process_auth_complete (struct connection *c, char *packet, int len) { assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)self->server_nonce ^ *(long long *)self->new_nonce; - logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); + debug ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); //kprintf ("OK\n"); //c->status = conn_error; @@ -636,7 +636,7 @@ int process_auth_complete (struct connection *c, char *packet, int len) { self->c_state = st_authorized; //return 1; - logprintf ( "Auth success\n"); + debug ( "Auth success\n"); self->auth_success ++; GET_DC(c)->flags |= 1; @@ -696,7 +696,7 @@ int aes_encrypt_message (struct mtproto_connection *self, struct dc *DC, struct sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); //printf ("enc_len is %d\n", enc_len); if (verbosity >= 2) { - logprintf ( "sending message with sha1 %08x\n", *(int *)sha1_buffer); + debug ( "sending message with sha1 %08x\n", *(int *)sha1_buffer); } memcpy (enc->msg_key, sha1_buffer + 4, 16); init_aes_auth (self, DC->auth_key, enc->msg_key, AES_ENCRYPT); @@ -707,7 +707,7 @@ int aes_encrypt_message (struct mtproto_connection *self, struct dc *DC, struct long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful) { struct connection *c = self->connection; - logprintf("encrypt_send_message(...)\n"); + //debug("encrypt_send_message(...)\n"); struct dc *DC = GET_DC(c); struct session *S = c->session; assert (S); @@ -746,7 +746,7 @@ void fetch_pts (struct mtproto_connection *self) { if (p <= self->pts) { return; } if (p != self->pts + 1) { if (self->pts) { - //logprintf ("Hole in pts p = %d, pts = %d\n", p, pts); + //debug ("Hole in pts p = %d, pts = %d\n", p, pts); // get difference should be here self->pts = p; @@ -764,7 +764,7 @@ void fetch_qts (struct mtproto_connection *self) { if (p <= self->qts) { return; } if (p != self->qts + 1) { if (self->qts) { - //logprintf ("Hole in qts\n"); + //debug ("Hole in qts\n"); // get difference should be here self->qts = p; } else { @@ -787,7 +787,7 @@ void fetch_date (struct mtproto_connection *self) { void fetch_seq (struct mtproto_connection *self) { int x = fetch_int (self); if (x > self->seq + 1) { - logprintf ("Hole in seq: seq = %d, x = %d\n", self->seq, x); + debug ("Hole in seq: seq = %d, x = %d\n", self->seq, x); //do_get_difference (); //seq = x; } else if (x == self->seq + 1) { @@ -867,11 +867,11 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { struct binlog *bl = self->bl; unsigned op = fetch_int (self); - logprintf("work_update(): OP:%d\n", op); + debug("work_update(): OP:%d\n", op); switch (op) { case CODE_update_new_message: { - logprintf ("CODE_update_new_message\n"); + debug ("CODE_update_new_message\n"); struct message *M UU = fetch_alloc_message (self, tg); assert (M); fetch_pts (self); @@ -883,7 +883,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { }; case CODE_update_message_i_d: { - logprintf ("CODE_update_message\n"); + debug ("CODE_update_message\n"); int id = fetch_int (self); // id int new = fetch_long (self); // random_id struct message *M = message_get (bl, new); @@ -894,7 +894,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { break; case CODE_update_read_messages: { - logprintf ("CODE_update_read_message\n"); + debug ("CODE_update_read_message\n"); assert (fetch_int (self) == (int)CODE_vector); int n = fetch_int (self); int i; @@ -918,7 +918,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { break; case CODE_update_user_typing: { - logprintf ("CODE_update_user_typing\n"); + debug ("CODE_update_user_typing\n"); peer_id_t id = MK_USER (fetch_int (self)); peer_t *U UU = user_chat_get (bl, id); event_update_user_typing (tg, U); @@ -1220,7 +1220,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { struct secret_chat *E = fetch_alloc_encrypted_chat (self); if (verbosity >= 2) { - logprintf ("Secret chat state = %d\n", E->state); + debug ("Secret chat state = %d\n", E->state); } //print_start (); //push_color (COLOR_YELLOW); @@ -1370,13 +1370,13 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { } break; default: - logprintf ("Unknown update type %08x\n", op); + debug ("Unknown update type %08x\n", op); ; } } void work_update_short (struct connection *c, long long msg_id) { - logprintf ("work_update_short\n"); + debug ("work_update_short\n"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (self) == CODE_update_short); @@ -1385,7 +1385,7 @@ void work_update_short (struct connection *c, long long msg_id) { } void work_updates (struct connection *c, long long msg_id) { - logprintf ("work_updates(\n)"); + debug ("work_updates(\n)"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (c->mtconnection) == CODE_updates); @@ -1410,7 +1410,7 @@ void work_updates (struct connection *c, long long msg_id) { } void work_update_short_message (struct connection *c UU, long long msg_id UU) { - logprintf ("work_update_short_message(\n)"); + debug ("work_update_short_message(\n)"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (c->mtconnection) == (int)CODE_update_short_message); @@ -1425,7 +1425,7 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) { } void work_update_short_chat_message (struct connection *c, long long msg_id UU) { - logprintf ("work_update_chat_message(\n)"); + debug ("work_update_chat_message(\n)"); struct mtproto_connection *self = c->mtconnection; assert (fetch_int (self) == CODE_update_short_chat_message); @@ -1440,7 +1440,7 @@ void work_update_short_chat_message (struct connection *c, long long msg_id UU) } void work_container (struct connection *c, long long msg_id UU) { - logprintf ( "work_container: msg_id = %lld\n", msg_id); + debug ( "work_container: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == CODE_msg_container); int n = fetch_int (c->mtconnection); int i; @@ -1461,30 +1461,30 @@ void work_container (struct connection *c, long long msg_id UU) { } void work_new_session_created (struct connection *c, long long msg_id UU) { - logprintf ( "work_new_session_created: msg_id = %lld\n", msg_id); + debug ( "work_new_session_created: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == (int)CODE_new_session_created); fetch_long (c->mtconnection); // first message id //DC->session_id = fetch_long (); fetch_long (c->mtconnection); // unique_id GET_DC(c)->server_salt = fetch_long (c->mtconnection); - logprintf ("new server_salt = %lld\n", GET_DC(c)->server_salt); + debug ("new server_salt = %lld\n", GET_DC(c)->server_salt); } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { - logprintf ( "work_msgs_ack: msg_id = %lld\n", msg_id); + debug ( "work_msgs_ack: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == CODE_msgs_ack); assert (fetch_int (c->mtconnection) == CODE_vector); int n = fetch_int (c->mtconnection); int i; for (i = 0; i < n; i++) { long long id = fetch_long (c->mtconnection); - logprintf ("ack for %lld\n", id); + debug ("ack for %lld\n", id); query_ack (c->instance, id); } } void work_rpc_result (struct connection *c UU, long long msg_id UU) { - logprintf ( "work_rpc_result: msg_id = %lld\n", msg_id); + debug ( "work_rpc_result: msg_id = %lld\n", msg_id); assert (fetch_int (c->mtconnection) == (int)CODE_rpc_result); long long id = fetch_long (c->mtconnection); int op = prefetch_int (c->mtconnection); @@ -1497,7 +1497,7 @@ void work_rpc_result (struct connection *c UU, long long msg_id UU) { #define MAX_PACKED_SIZE (1 << 24) void work_packed (struct connection *c, long long msg_id) { - logprintf ("work_packet()\n"); + debug ("work_packet()\n"); assert (fetch_int (c->mtconnection) == CODE_gzip_packed); static int in_gzip; static int buf[MAX_PACKED_SIZE >> 2]; @@ -1514,7 +1514,7 @@ void work_packed (struct connection *c, long long msg_id) { c->mtconnection->in_ptr = buf; c->mtconnection->in_end = c->mtconnection->in_ptr + total_out / 4; if (verbosity >= 4) { - logprintf ( "Unzipped data: "); + debug ( "Unzipped data: "); hexdump_in (c->mtconnection); } rpc_execute_answer (c, msg_id); @@ -1524,7 +1524,7 @@ void work_packed (struct connection *c, long long msg_id) { } void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { - logprintf ("work_bad_server_salt()\n"); + debug ("work_bad_server_salt()\n"); assert (fetch_int (c->mtconnection) == (int)CODE_bad_server_salt); long long id = fetch_long (c->mtconnection); query_restart (c->instance, id); @@ -1535,14 +1535,14 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { } void work_pong (struct connection *c UU, long long msg_id UU) { - logprintf ("work_pong()\n"); + debug ("work_pong()\n"); assert (fetch_int (c->mtconnection) == CODE_pong); fetch_long (c->mtconnection); // msg_id fetch_long (c->mtconnection); // ping_id } void work_detailed_info (struct connection *c UU, long long msg_id UU) { - logprintf ("work_detailed_info()\n"); + debug ("work_detailed_info()\n"); assert (fetch_int (c->mtconnection) == CODE_msg_detailed_info); fetch_long (c->mtconnection); // msg_id fetch_long (c->mtconnection); // answer_msg_id @@ -1551,7 +1551,7 @@ void work_detailed_info (struct connection *c UU, long long msg_id UU) { } void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { - logprintf ("work_new_detailed_info()\n"); + debug ("work_new_detailed_info()\n"); assert (fetch_int (c->mtconnection) == (int)CODE_msg_new_detailed_info); fetch_long (c->mtconnection); // answer_msg_id fetch_int (c->mtconnection); // bytes @@ -1560,7 +1560,7 @@ void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { void work_updates_to_long (struct connection *c UU, long long msg_id UU) { assert (fetch_int (c->mtconnection) == (int)CODE_updates_too_long); - logprintf ("updates to long... Getting difference\n"); + debug ("updates to long... Getting difference\n"); do_get_difference (c->instance, 0); } @@ -1569,12 +1569,12 @@ void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { long long m1 = fetch_long (c->mtconnection); int s = fetch_int (c->mtconnection); int e = fetch_int (c->mtconnection); - logprintf ("bad_msg_notification: msg_id = %lld, seq = %d, error = %d\n", m1, s, e); + debug ("bad_msg_notification: msg_id = %lld, seq = %d, error = %d\n", m1, s, e); } void rpc_execute_answer (struct connection *c, long long msg_id UU) { if (verbosity >= 5) { - logprintf ("rpc_execute_answer: fd=%d\n", c->fd); + debug ("rpc_execute_answer: fd=%d\n", c->fd); hexdump_in (c->mtconnection); } int op = prefetch_int (c->mtconnection); @@ -1625,7 +1625,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { work_bad_msg_notification (c, msg_id); return; } - logprintf ( "Unknown message: \n"); + debug ( "Unknown message: \n"); hexdump_in (c->mtconnection); c->mtconnection->in_ptr = c->mtconnection->in_end; // Will not fail due to assertion in_ptr == in_end } @@ -1633,7 +1633,7 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) { int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { const int MINSZ = offsetof (struct encrypted_message, message); const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - logprintf ( "process_rpc_message(), len=%d\n", len); + debug ( "process_rpc_message(), len=%d\n", len); assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); struct dc *DC = GET_DC(c); assert (enc->auth_key_id == DC->auth_key_id); @@ -1659,7 +1659,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, } double st = get_server_time (DC); if (this_server_time < st - 300 || this_server_time > st + 30) { - logprintf ("salt = %lld, session_id = %lld, msg_id = %lld, seq_no = %d, st = %lf, now = %lf\n", + debug ("salt = %lld, session_id = %lld, msg_id = %lld, seq_no = %d, st = %lf, now = %lf\n", enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); c->mtconnection->in_ptr = enc->message; c->mtconnection->in_end = c->mtconnection->in_ptr + (enc->msg_len / 4); @@ -1668,7 +1668,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, assert (this_server_time >= st - 300 && this_server_time <= st + 30); //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); - logprintf ( "received mesage id %016llx\n", enc->msg_id); + debug ( "received mesage id %016llx\n", enc->msg_id); hexdump_in (c->mtconnection); c->mtconnection->server_last_msg_id = enc->msg_id; @@ -1693,7 +1693,7 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int rpc_execute (struct connection *c, int op, int len) { - logprintf ("outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); + debug ("outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); struct mtproto_connection *self = c->mtconnection; struct telegram *instance = c->instance; @@ -1705,19 +1705,19 @@ int rpc_execute (struct connection *c, int op, int len) { */ if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - logprintf ( "answer too long (%d bytes), skipping\n", len); + debug ( "answer too long (%d bytes), skipping\n", len); return 0; } int Response_len = len; if (verbosity >= 2) { - logprintf ("Response_len = %d\n", Response_len); + debug ("Response_len = %d\n", Response_len); } assert (read_in (c, Response, Response_len) == Response_len); Response[Response_len] = 0; if (verbosity >= 2) { - logprintf ( "have %d Response bytes\n", Response_len); + debug ( "have %d Response bytes\n", Response_len); } int o = c->mtconnection->c_state; @@ -1732,14 +1732,14 @@ int rpc_execute (struct connection *c, int op, int len) { case st_client_dh_sent: process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); self->queries_num --; - logprintf ("queries_num=%d\n", c->mtconnection->queries_num); + debug ("queries_num=%d\n", c->mtconnection->queries_num); if (self->on_ready) { self->on_ready(self, self->on_ready_data); } return 0; case st_authorized: if (op < 0 && op >= -999) { - logprintf ("Server error %d\n", op); + debug ("Server error %d\n", op); char code[12] = {0}; snprintf (code, 12, "%d", op); c->mtconnection->c_state = st_error; @@ -1749,7 +1749,7 @@ int rpc_execute (struct connection *c, int op, int len) { } return 0; default: - logprintf ( "fatal: cannot receive answer in state %d\n", c->mtconnection->c_state); + debug ( "fatal: cannot receive answer in state %d\n", c->mtconnection->c_state); exit (2); } @@ -1758,12 +1758,12 @@ int rpc_execute (struct connection *c, int op, int len) { int tc_close (struct connection *c, int who) { - logprintf ( "outbound http connection #%d : closing by %d\n", c->fd, who); + debug ( "outbound http connection #%d : closing by %d\n", c->fd, who); return 0; } int tc_becomes_ready (struct connection *c) { - logprintf ( "outbound connection #%d becomes ready\n", c->fd); + debug ( "outbound connection #%d becomes ready\n", c->fd); char byte = 0xef; assert (write_out (c, &byte, 1) == 1); flush_out (c); @@ -1775,7 +1775,7 @@ int tc_becomes_ready (struct connection *c) { switch (o) { case st_init: c->mtconnection->queries_num ++; - logprintf ("queries_num=%d\n", c->mtconnection->queries_num); + debug ("queries_num=%d\n", c->mtconnection->queries_num); send_req_pq_packet (c); break; case st_authorized: @@ -1783,7 +1783,7 @@ int tc_becomes_ready (struct connection *c) { //telegram_change_state (c->instance, STATE_AUTHORIZED, NULL); break; default: - logprintf ( "c_state = %d\n", c->mtconnection->c_state); + debug ( "c_state = %d\n", c->mtconnection->c_state); assert (0); } return 0; @@ -1860,7 +1860,7 @@ void mtproto_connect(struct mtproto_connection *c) * cleanup tasks */ void mtproto_close(struct mtproto_connection *mtp) { - logprintf ("closing mtproto_connection...\n"); + debug ("closing mtproto_connection...\n"); mtp->destroy = 1; // send all pending acks on this connection so the server won't @@ -1882,7 +1882,7 @@ void mtproto_close(struct mtproto_connection *mtp) { * Close the underlying file descriptor */ void mtproto_destroy (struct mtproto_connection *self) { - logprintf("destroying mtproto_connection: %p\n", self); + debug("destroying mtproto_connection: %p\n", self); self->instance->config->proxy_close_cb(self->handle); fd_close_connection(self->connection); tfree(self, sizeof(struct mtproto_connection)); @@ -1896,7 +1896,7 @@ void mtproto_close_foreign (struct telegram *instance) if (c && !c->destroy && c->connection->session->dc->id != instance->auth.dc_working_num) { - logprintf ("closing connection for working_dc=%d, dc=%d\n", + debug ("closing connection for working_dc=%d, dc=%d\n", instance->auth.dc_working_num, c->connection->session->dc->id); mtproto_close (c); } @@ -1911,11 +1911,11 @@ void mtproto_free_closed (struct telegram *tg) { for (i = 0; i < 100; i++) { if (tg->Cs[i] == NULL) continue; struct mtproto_connection *c = tg->Cs[i]; - logprintf ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", + debug ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", i, c->c_state, c->destroy, c->queries_num); if (c->destroy == 0) continue; if (c->connection->out_bytes > 0) { - logprintf ("still %d bytes ouput left, skipping connection...\n", c->connection->out_bytes); + debug ("still %d bytes ouput left, skipping connection...\n", c->connection->out_bytes); continue; } mtproto_destroy (c); diff --git a/mtproto-client.h b/mtproto-client.h index f6dfc35..d90a748 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -337,7 +337,7 @@ extern int verbosity; static inline char *fetch_str (struct mtproto_connection *self, int len) { assert (len >= 0); if (verbosity > 6) { - logprintf ("fetch_string: len = %d\n", len); + debug ("fetch_string: len = %d\n", len); } if (len < 254) { char *str = (char *) self->in_ptr + 1; @@ -431,14 +431,14 @@ int fetch_bignum (struct mtproto_connection *self, BIGNUM *x); static inline int fetch_int (struct mtproto_connection *self) { assert (self->in_ptr + 1 <= self->in_end); if (verbosity > 6) { - logprintf ("fetch_int: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); + debug ("fetch_int: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); } return *(self->in_ptr ++); } static inline int fetch_bool (struct mtproto_connection *self) { if (verbosity > 6) { - logprintf ("fetch_bool: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); + debug ("fetch_bool: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); } assert (self->in_ptr + 1 <= self->in_end); assert (*(self->in_ptr) == (int)CODE_bool_true || *(self->in_ptr) == (int)CODE_bool_false); diff --git a/mtproto-common.c b/mtproto-common.c index 362fecd..e2db1a5 100644 --- a/mtproto-common.c +++ b/mtproto-common.c @@ -15,7 +15,7 @@ int get_random_bytes (unsigned char *buf, int n) { r = read (h, buf, n); if (r > 0) { if (verbosity >= 3) { - logprintf ( "added %d bytes of real entropy to secure random numbers seed\n", r); + debug ( "added %d bytes of real entropy to secure random numbers seed\n", r); } } else { r = 0; @@ -96,14 +96,14 @@ void prng_seed (struct mtproto_connection *self, const char *password_filename, if (password_filename && password_length > 0) { int fd = open (password_filename, O_RDONLY); if (fd < 0) { - logprintf ( "Warning: fail to open password file - \"%s\", %m.\n", password_filename); + debug ( "Warning: fail to open password file - \"%s\", %m.\n", password_filename); } else { unsigned char *a = talloc0 (password_length); int l = read (fd, a, password_length); if (l < 0) { - logprintf ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename); + debug ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename); } else { - logprintf ( "read %d bytes from password file.\n", l); + debug ( "read %d bytes from password file.\n", l); RAND_add (a, l, l); } close (fd); diff --git a/net.c b/net.c index 8cdc646..296199f 100644 --- a/net.c +++ b/net.c @@ -64,12 +64,12 @@ void start_ping_timer (struct connection *c); int ping_alarm (struct connection *c) { assert (c->state == conn_ready || c->state == conn_connecting); if (get_double_time () - c->last_receive_time > 20 * PING_TIMEOUT) { - logprintf ( "fail connection: reason: ping timeout\n"); + warning ( "fail connection: reason: ping timeout\n"); c->state = conn_failed; fail_connection (c); } else if (get_double_time () - c->last_receive_time > 5 * PING_TIMEOUT && c->state == conn_ready) { - logprintf ("sending PING...\n"); + debug ("sending PING...\n"); int x[3]; x[0] = CODE_ping; *(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 (); @@ -239,7 +239,7 @@ void restart_connection (struct connection *c) { c->last_connect_time = time (0); int fd = socket (AF_INET, SOCK_STREAM, 0); if (fd == -1) { - logprintf ("Can not create socket: %m\n"); + debug ("Can not create socket: %m\n"); exit (1); } assert (fd >= 0 && fd < MAX_CONNECTIONS); @@ -261,7 +261,7 @@ void restart_connection (struct connection *c) { if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { if (errno != EINPROGRESS) { - logprintf ( "Can not connect to %s:%d %m\n", c->ip, c->port); + debug ( "Can not connect to %s:%d %m\n", c->ip, c->port); start_fail_timer (c); close (fd); return; @@ -301,13 +301,13 @@ void fail_connection (struct connection *c) { c->out_bytes = c->in_bytes = 0; close (c->fd); Connections[c->fd] = 0; - logprintf ("Lost connection to server... %s:%d\n", c->ip, c->port); + debug ("Lost connection to server... %s:%d\n", c->ip, c->port); restart_connection (c); } extern FILE *log_net_f; int try_write (struct connection *c) { - logprintf ( "try write: fd = %d\n", c->fd); + debug ( "try write: fd = %d\n", c->fd); int x = 0; while (c->out_head) { int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); @@ -341,7 +341,7 @@ int try_write (struct connection *c) { delete_connection_buffer (b); } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - logprintf ("fail_connection: write_error %m\n"); + debug ("fail_connection: write_error %m\n"); fail_connection (c); return 0; } else { @@ -349,7 +349,7 @@ int try_write (struct connection *c) { } } } - logprintf ( "Sent %d bytes to %d\n", x, c->fd); + debug ( "Sent %d bytes to %d\n", x, c->fd); c->out_bytes -= x; return x; } @@ -417,7 +417,7 @@ void try_rpc_read (struct connection *c) { } void try_read (struct connection *c) { - logprintf ( "try read: fd = %d\n", c->fd); + debug ( "try read: fd = %d\n", c->fd); if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } @@ -449,7 +449,7 @@ void try_read (struct connection *c) { c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - logprintf ("fail_connection: read_error %m\n"); + debug ("fail_connection: read_error %m\n"); fail_connection (c); return; } else { @@ -457,7 +457,8 @@ void try_read (struct connection *c) { } } } - logprintf ( "Received %d bytes from %d\n", x, c->fd); + debug ( "Received %d bytes from fd=#%d and DC %d(%s, %d)\n", x, + c->fd, c->session->dc->id, c->session->dc->ip, c->session->dc->port); c->in_bytes += x; if (x) { try_rpc_read (c); @@ -465,9 +466,9 @@ void try_read (struct connection *c) { } int send_all_acks (struct session *S) { - logprintf ("send_all_acks()\n"); + info ("send_all_acks(dc=%d)\n", S->dc->id); if (!S->c) { - logprintf ("WARNING: cannot send acks, session has no active connection"); + warning ("WARNING: cannot send acks, session has no active connection"); return -1; } struct mtproto_connection *mt = S->c->mtconnection; @@ -487,7 +488,7 @@ int send_all_acks (struct session *S) { void insert_msg_id (struct session *S, long long id) { if (!S->ack_tree) { - logprintf ("Creating ack_tree pointing to session %p\n"); + debug ("Creating ack_tree pointing to session %p\n"); S->ev.alarm = (void *)send_all_acks; S->ev.self = (void *)S; S->ev.timeout = get_double_time () + ACK_TIMEOUT; @@ -525,7 +526,7 @@ struct connection *fd_create_connection (struct dc *DC, int fd, c->methods = methods; c->instance = instance; c->last_receive_time = get_double_time (); - logprintf ( "connect to %s:%d successful\n", DC->ip, DC->port); + debug ( "connect to %s:%d successful\n", DC->ip, DC->port); if (!DC->sessions[0]) { struct session *S = talloc0 (sizeof (*S)); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 7ebeb01..f18ff45 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -98,7 +98,7 @@ static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *val */ static PurpleConversation *chat_show (PurpleConnection *gc, int id) { - logprintf ("show chat"); + debug ("show chat"); telegram_conn *conn = purple_connection_get_protocol_data(gc); PurpleConversation *convo = purple_find_chat(gc, id); @@ -159,7 +159,7 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info { purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); - logprintf ("purple_buddy_get_protocol_data: %s\n", buddy->name); + debug ("purple_buddy_get_protocol_data: %s\n", buddy->name); peer_id_t *peer = purple_buddy_get_protocol_data(buddy); if(peer == NULL) { @@ -184,11 +184,11 @@ static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition co { mtproto_handle *conn = data; if (!conn->mtp) { - logprintf ("connection no loner existing, do nothing. \n"); + debug ("connection no loner existing, do nothing. \n"); return; } if (mtp_write_output(conn->mtp) == 0) { - logprintf("no output, removing output...\n"); + debug("no output, removing output...\n"); purple_input_remove(conn->wh); conn->wh = 0; } @@ -199,7 +199,7 @@ static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition co */ static void tgprpl_has_output(void *handle) { - logprintf("tgprpl_has_output(%p)\n", handle); + debug("tgprpl_has_output(%p)\n", handle); mtproto_handle *conn = handle; if (! conn->wh) { conn->wh = purple_input_add(conn->fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, handle); @@ -212,9 +212,9 @@ static void tgprpl_has_output(void *handle) static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition cond) { mtproto_handle *conn = data; - logprintf("tgprpl_input_cb()\n"); + debug("tgprpl_input_cb()\n"); if (!conn->fd) { - logprintf("conn for handle no longer existing, not reading input\n"); + debug("conn for handle no longer existing, not reading input\n"); return; } mtp_read_input(conn->mtp); @@ -234,11 +234,11 @@ static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition con */ static void tgprpl_has_input(void *handle) { - logprintf("tgprpl_has_input()\n"); + debug("tgprpl_has_input()\n"); mtproto_handle *conn = handle; if (! conn->rh) { conn->rh = purple_input_add(conn->fd, PURPLE_INPUT_READ, tgprpl_input_cb, handle); - logprintf("Attached read handle: %u ", conn->rh); + debug("Attached read handle: %u ", conn->rh); } } @@ -268,7 +268,7 @@ void telegram_on_proxy_request(struct telegram *tg, struct proxy_request *req) void telegram_on_proxy_close(void *handle) { mtproto_handle *conn = handle; - logprintf ("Closing proxy-handles - fd: %d, write-handle: %d, read-handle: %d\n", + debug ("Closing proxy-handles - fd: %d, write-handle: %d, read-handle: %d\n", conn->fd, conn->wh, conn->rh); if (conn->rh) { purple_input_remove (conn->rh); @@ -315,13 +315,13 @@ void client_registration_canceled (gpointer data) } gboolean queries_timerfunc (gpointer data) { - logprintf ("queries_timerfunc()\n"); + debug ("queries_timerfunc()\n"); telegram_conn *conn = data; work_timers (conn->tg); telegram_flush (conn->tg); if (conn->updated) { - logprintf ("State updated, storing current session...\n"); + debug ("State updated, storing current session...\n"); conn->updated = 0; telegram_store_session (conn->tg); } @@ -386,7 +386,7 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa struct telegram *tg = req->tg; if (fd == -1) { - logprintf("purple_proxy_connect failed: %s\n", error_message); + failure("purple_proxy_connect failed: %s\n", error_message); telegram_destroy(tg); return; } @@ -400,7 +400,7 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa void telegram_on_disconnected (struct telegram *tg) { - logprintf ("telegram_on_disconnected()\n"); + debug ("telegram_on_disconnected()\n"); assert (0); } @@ -493,14 +493,14 @@ static int chat_add_message(struct telegram *tg, struct message *M) void message_allocated_handler(struct telegram *tg, struct message *M) { - logprintf ("message_allocated_handler\n"); + debug ("message_allocated_handler\n"); telegram_conn *conn = tg->extra; PurpleConnection *gc = conn->gc; if (M->service) { // TODO: handle service messages properly, currently adding them // causes a segfault for an unknown reason - logprintf ("service message, skipping...\n"); + debug ("service message, skipping...\n"); return; } @@ -510,12 +510,12 @@ void message_allocated_handler(struct telegram *tg, struct message *M) char *to = g_strdup_printf("%d", to_id.id); switch (to_id.type) { case PEER_CHAT: - logprintf ("PEER_CHAT\n"); + debug ("PEER_CHAT\n"); chat_add_message(tg, M); break; case PEER_USER: - logprintf ("PEER_USER\n"); + debug ("PEER_USER\n"); if (M->from_id.id == tg->our_id) { serv_got_im(gc, to, M->message, PURPLE_MESSAGE_SEND, time((time_t *) &M->date)); } else { @@ -605,10 +605,10 @@ void peer_allocated_handler(struct telegram *tg, void *usr) peer_t *user = usr; gchar *name = peer_get_peer_id_as_string(user); //g_strdup_printf("%d", get_peer_id(user->id)); - logprintf("Allocated peer: %s\n", name); + debug("Allocated peer: %s\n", name); switch (user->id.type) { case PEER_USER: { - logprintf("Peer type: user.\n"); + debug("Peer type: user.\n"); // TODO: this should probably be freed again somwhere char *alias = malloc(BUDDYNAME_MAX_LENGTH); if (user_get_alias(user, alias, BUDDYNAME_MAX_LENGTH) < 0) { @@ -638,7 +638,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) } break; case PEER_CHAT: { - logprintf("Peer type: chat.\n"); + debug("Peer type: chat.\n"); PurpleChat *ch = blist_find_chat_by_id(gc, name); if (!ch) { gchar *admin = g_strdup_printf("%d", user->chat.admin_id); @@ -646,7 +646,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) g_hash_table_insert(htable, g_strdup("subject"), user->chat.title); g_hash_table_insert(htable, g_strdup("id"), name); g_hash_table_insert(htable, g_strdup("owner"), admin); - logprintf("Adding chat to blist: %s (%s, %s)\n", user->chat.title, name, admin); + debug("Adding chat to blist: %s (%s, %s)\n", user->chat.title, name, admin); ch = purple_chat_new(pa, user->chat.title, htable); purple_blist_add_chat(ch, NULL, NULL); } @@ -668,7 +668,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) // peer_id_t u = MK_USER (cu->user_id); // peer_t *uchat = user_chat_get(u); const char *cuname = g_strdup_printf("%d", cu->user_id); - logprintf("Adding user %s to chat %s\n", cuname, name); + debug("Adding user %s to chat %s\n", cuname, name); purple_conv_chat_add_user(purple_conversation_get_chat_data(conv), cuname, "", PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), FALSE); } @@ -676,13 +676,13 @@ void peer_allocated_handler(struct telegram *tg, void *usr) } break; case PEER_GEO_CHAT: - logprintf("Peer type: geo-chat.\n"); + debug("Peer type: geo-chat.\n"); break; case PEER_ENCR_CHAT: - logprintf("Peer type: encrypted chat.\n"); + debug("Peer type: encrypted chat.\n"); break; case PEER_UNKNOWN: - logprintf("Peer type: unknown.\n"); + debug("Peer type: unknown.\n"); break; } } @@ -699,7 +699,7 @@ PurpleNotifyUserInfo *create_user_notify_info(struct user *usr) void user_info_received_handler(struct telegram *tg, struct user *usr, int show_info) { - logprintf("Get user info. \n %d", show_info); + debug("Get user info. \n %d", show_info); char *who = g_strdup_printf("%d", usr->id.id); if (usr->photo.sizes_num == 0 && show_info) { @@ -718,7 +718,7 @@ void user_info_received_handler(struct telegram *tg, struct user *usr, int show_ void download_finished_handler(struct telegram *tg, struct download *D) { - logprintf("download_finished_handler %s type %d\n", D->name, D->type); + debug("download_finished_handler %s type %d\n", D->name, D->type); //TODO: We need a type for user-photos! if(D->type == 0) { @@ -729,7 +729,7 @@ void download_finished_handler(struct telegram *tg, struct download *D) GError *err = NULL; g_file_get_contents(D->name, &data, &len, &err); int imgStoreId = purple_imgstore_add_with_id(g_memdup(data, len), len, NULL); - logprintf("Imagestore id: %d\n", imgStoreId); + debug("Imagestore id: %d\n", imgStoreId); //Create user info char *who = g_strdup_printf("%d", usr->id.id); telegram_conn *conn = tg->extra; @@ -1018,32 +1018,32 @@ static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) char *id = g_hash_table_lookup(data, "id"); if (!id) { - logprintf ("Got no chat id, aborting...\n"); + debug ("Got no chat id, aborting...\n"); return; } if (!purple_find_chat(gc, atoi(id))) { - logprintf ("chat now known\n"); + debug ("chat now known\n"); char *subject, *owner, *part; do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); telegram_flush (conn->tg); } else { - logprintf ("chat already known\n"); + debug ("chat already known\n"); serv_got_joined_chat(conn->gc, atoi(id), groupname); } } void on_chat_joined (struct telegram *instance, peer_id_t chatid) { - logprintf ("on_chat_joined(%d)\n", chatid.id); + debug ("on_chat_joined(%d)\n", chatid.id); telegram_conn *conn = instance->extra; peer_t *peer = user_chat_get (instance->bl, chatid); if (!peer) { - logprintf ("ERROR: chat with given id %d is not existing.\n", chatid.id); + warning ("WARNING: chat with given id %d is not existing.\n", chatid.id); return; } if (!peer->id.type == PEER_CHAT) { - logprintf ("ERROR: peer with given id %d and type %d is not a chat.\n", peer->id.id, peer->id.type); + warning ("WARNING: peer with given id %d and type %d is not a chat.\n", peer->id.id, peer->id.type); return; } PurpleConversation *conv = serv_got_joined_chat(conn->gc, chatid.id, peer->chat.title); @@ -1054,7 +1054,7 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) peer_id_t part_id = MK_USER((curr + i)->user_id); char *name = g_strdup_printf ("%d", part_id.id); int flags = PURPLE_CBFLAGS_NONE | peer->chat.admin_id == part_id.id ? PURPLE_CBFLAGS_FOUNDER : 0; - logprintf ("purple_conv_chat_add_user (..., name=%s, ..., flags=%d)", name, flags); + debug ("purple_conv_chat_add_user (..., name=%s, ..., flags=%d)", name, flags); purple_conv_chat_add_user( purple_conversation_get_chat_data(conv), name, @@ -1064,14 +1064,14 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) ); } struct message *M = 0; - logprintf ("g_queue_pop_head()\n"); + debug ("g_queue_pop_head()\n"); while (M = g_queue_pop_head (conn->new_messages)) { - logprintf ("adding msg-id\n"); + debug ("adding msg-id\n"); int id = get_peer_id(M->from_id); if (!chat_add_message(instance, M)) { // chat still not working? - logprintf ("WARNING, chat %d still not existing... \n", chatid.id); + warning ("WARNING, chat %d still not existing... \n", chatid.id); break; } } @@ -1215,7 +1215,7 @@ static void tgprpl_init(PurplePlugin *plugin) int len = strlen (dir) + strlen (pw->pw_dir) + 2; tgconf.base_config_path = talloc (len); tsnprintf (tgconf.base_config_path, len, "%s/%s", pw->pw_dir, dir); - logprintf ("base configuration path: %s", tgconf.base_config_path); + debug ("base configuration path: %s", tgconf.base_config_path); } PurpleAccountOption *option; @@ -1263,7 +1263,7 @@ static GList *tgprpl_actions(PurplePlugin * plugin, gpointer context) return (GList *)NULL; } -static PurplePluginInfo info = { +static PurplePluginInfo plugin_info = { PURPLE_PLUGIN_MAGIC, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, @@ -1293,5 +1293,5 @@ static PurplePluginInfo info = { }; -PURPLE_INIT_PLUGIN(telegram, tgprpl_init, info) +PURPLE_INIT_PLUGIN(telegram, tgprpl_init, plugin_info) diff --git a/queries.c b/queries.c index 764cda7..ff37c91 100644 --- a/queries.c +++ b/queries.c @@ -90,7 +90,7 @@ struct query *query_get (struct telegram *instance, long long id) { int alarm_query (struct query *q) { assert (q); struct mtproto_connection *mtp = query_get_mtproto(q); - logprintf ("Alarm query %lld\n", q->msg_id); + debug ("Alarm query %lld\n", q->msg_id); q->ev.timeout = get_double_time () + QUERY_TIMEOUT; insert_event_timer (mtp->connection->instance, &q->ev); @@ -119,8 +119,7 @@ void query_restart (struct telegram *instance, long long id) { } struct query *send_query (struct telegram *instance, struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { - logprintf("send_query(...)\n"); - logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port); + info ("SEND_QUERY() size %d to DC %d(%s:%d)\n", 4 * ints, DC->id, DC->ip, DC->port); struct query *q = talloc0 (sizeof (*q)); q->data_len = ints; q->data = talloc (4 * ints); @@ -128,18 +127,18 @@ struct query *send_query (struct telegram *instance, struct dc *DC, int ints, vo q->msg_id = encrypt_send_message (DC->sessions[0]->c->mtconnection, data, ints, 1); q->session = DC->sessions[0]; q->seq_no = DC->sessions[0]->seq_no - 1; - logprintf ( "Msg_id is %lld %p\n", q->msg_id, q); + //debug ( "Msg_id is %lld %p\n", q->msg_id, q); q->methods = methods; q->DC = DC; if (instance->queries_tree) { if (verbosity >= 2) { - logprintf ( "%lld %lld\n", q->msg_id, instance->queries_tree->x->msg_id); + debug ( "%lld %lld\n", q->msg_id, instance->queries_tree->x->msg_id); } } instance->queries_tree = tree_insert_query (instance->queries_tree, q, lrand48 ()); struct mtproto_connection *mtp = query_get_mtproto(q); - logprintf("queries_num: %d\n", ++ mtp->queries_num); + ++ mtp->queries_num; q->ev.alarm = (void *)alarm_query; q->ev.timeout = get_double_time () + QUERY_TIMEOUT; @@ -166,21 +165,21 @@ void query_error (struct telegram *instance, long long id) { assert (fetch_int (mtp) == CODE_rpc_error); int error_code = fetch_int (mtp); int error_len = prefetch_strlen (mtp); - char *error = fetch_str (mtp, error_len); - logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); + char *err = fetch_str (mtp, error_len); + failure ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, err); if (!q) { - logprintf ( "No such query\n"); + failure ( "No such query\n"); } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { remove_event_timer (instance, &q->ev); } instance->queries_tree = tree_delete_query (instance->queries_tree, q); - logprintf("queries_num: %d\n", -- mtp->queries_num); + -- mtp->queries_num; if (q->methods && q->methods->on_error) { - q->methods->on_error (q, error_code, error_len, error); + q->methods->on_error (q, error_code, error_len, err); } else { - logprintf ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error); + failure ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, err); } tfree (q->data, q->data_len * 4); tfree (q, sizeof (*q)); @@ -193,9 +192,9 @@ void query_result (struct telegram *instance, long long id UU) { struct query *q = query_get (instance, id); struct mtproto_connection *mtp = query_get_mtproto(q); - logprintf ( "result for query #%lld\n", id); + debug ( "result for query #%lld\n", id); if (verbosity >= 4) { - logprintf ( "result: "); + debug ( "result: "); hexdump_in (mtp); } @@ -213,19 +212,19 @@ void query_result (struct telegram *instance, long long id UU) { mtp->in_ptr = instance->packed_buffer; mtp->in_end = mtp->in_ptr + total_out / 4; if (verbosity >= 4) { - logprintf ( "Unzipped data: "); + debug ( "Unzipped data: "); hexdump_in (mtp); } } if (!q) { - logprintf ( "No such query\n"); + warning ( "No such query\n"); mtp->in_ptr = mtp->in_end; } else { if (!(q->flags & QUERY_ACK_RECEIVED)) { remove_event_timer (instance, &q->ev); } instance->queries_tree = tree_delete_query (instance->queries_tree, q); - logprintf("queries_num: %d\n", -- mtp->queries_num); + debug("queries_num: %d\n", -- mtp->queries_num); if (q->methods && q->methods->on_answer) { q->methods->on_answer (q); @@ -242,12 +241,12 @@ void query_result (struct telegram *instance, long long id UU) { void insert_event_timer (struct telegram *instance, struct event_timer *ev) { - // logprintf ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + // debug ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); instance->timer_tree = tree_insert_timer (instance->timer_tree, ev, lrand48 ()); } void remove_event_timer (struct telegram *instance, struct event_timer *ev) { - // logprintf ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); + // debug ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); instance->timer_tree = tree_delete_timer (instance->timer_tree, ev); } @@ -257,7 +256,7 @@ double next_timer_in (struct telegram *instance) { } void work_timers (struct telegram *instance) { - logprintf ("work_timers ()\n"); + debug ("work_timers ()\n"); double t = get_double_time (); while (instance->timer_tree) { struct event_timer *ev = tree_get_min_timer (instance->timer_tree); @@ -265,7 +264,7 @@ void work_timers (struct telegram *instance) { if (ev->timeout > t) { break; } remove_event_timer (instance, ev); assert (ev->alarm); - logprintf ("Alarm\n"); + debug ("Alarm\n"); ev->alarm (ev->self); } } @@ -275,7 +274,7 @@ void free_timers (struct telegram *instance) while (instance->timer_tree) { struct event_timer *ev = tree_get_min_timer (instance->timer_tree); assert (ev); - logprintf ("freeing event timer with timeout: %d\n", ev->timeout); + debug ("freeing event timer with timeout: %d\n", ev->timeout); remove_event_timer (instance, ev); //tfree (ev, sizeof(struct event_timer)); } @@ -286,7 +285,7 @@ void free_queries (struct telegram *instance) while (instance->queries_tree) { struct query *q = tree_get_min_query (instance->queries_tree); assert (q); - logprintf ("freeing query with msg_id %d and len\n", q->msg_id, q->data_len); + debug ("freeing query with msg_id %d and len\n", q->msg_id, q->data_len); tfree (q->data, 4 * q->data_len); instance->queries_tree = tree_delete_query (instance->queries_tree, q); //tfree (q, sizeof (struct query)); @@ -328,6 +327,7 @@ void do_insert_header (struct mtproto_connection *mtp) { /* {{{ Get config */ void fetch_dc_option (struct telegram *instance) { + info ("fetch_dc_option()\n"); struct mtproto_connection *mtp = instance->connection; assert (fetch_int (mtp) == CODE_dc_option); @@ -337,7 +337,7 @@ void fetch_dc_option (struct telegram *instance) { int l2 = prefetch_strlen (mtp); char *ip = fetch_str (mtp, l2); int port = fetch_int (mtp); - logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); + debug ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); bl_do_dc_option (mtp->bl, mtp, id, l1, name, l2, ip, port, instance); } @@ -354,7 +354,7 @@ int help_get_config_on_answer (struct query *q UU) { assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false); assert (test_mode == CODE_bool_false || test_mode == CODE_bool_true); int this_dc = fetch_int (mtp); - logprintf ( "this_dc = %d\n", this_dc); + debug ( "this_dc = %d\n", this_dc); assert (fetch_int (mtp) == CODE_vector); int n = fetch_int (mtp); assert (n <= 10); @@ -366,7 +366,7 @@ int help_get_config_on_answer (struct query *q UU) { if (op == CODE_config) { instance->max_bcast_size = fetch_int (mtp); } - logprintf ( "max_chat_size = %d\n", instance->max_chat_size); + debug ( "max_chat_size = %d\n", instance->max_chat_size); telegram_change_state(instance, STATE_CONFIG_RECEIVED, NULL); return 0; @@ -377,9 +377,10 @@ struct query_methods help_get_config_methods = { }; void do_help_get_config (struct telegram *instance) { + info ("do_help_get_config()\n"); struct mtproto_connection *mtp = instance->connection; - logprintf ("mtp: %p:%p\n", mtp->packet_ptr, mtp->packet_buffer); + debug ("mtp: %p:%p\n", mtp->packet_ptr, mtp->packet_buffer); clear_packet (mtp); out_int (mtp, CODE_help_get_config); struct dc *DC_working = telegram_get_working_dc(instance); @@ -398,7 +399,7 @@ int send_code_on_answer (struct query *q UU) { int l = prefetch_strlen (mtp); char *phone_code_hash = tstrndup (fetch_str (mtp, l), l); instance->phone_code_hash = phone_code_hash; - logprintf("telegram: phone_code_hash: %s\n", phone_code_hash); + debug("telegram: phone_code_hash: %s\n", phone_code_hash); fetch_int (mtp); fetch_bool (mtp); instance->want_dc_num = -1; @@ -407,7 +408,7 @@ int send_code_on_answer (struct query *q UU) { } else if (instance->session_state == STATE_CLIENT_CODE_REQUESTED) { telegram_change_state(instance, STATE_CLIENT_CODE_NOT_ENTERED, NULL); } else { - logprintf("send_code_on_answer(): Invalid State %d ", instance->session_state); + debug("send_code_on_answer(): Invalid State %d ", instance->session_state); telegram_change_state(instance, STATE_ERROR, NULL); } return 0; @@ -427,7 +428,7 @@ int send_code_on_error (struct query *q UU, int error_code, int l, char *error) tg->auth.dc_working_num = want_dc_num; telegram_change_state(tg, STATE_ERROR, error); } else { - logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); + fatal ( "error_code = %d, error = %.*s\n", error_code, l, error); assert (0); } return 0; @@ -439,9 +440,9 @@ struct query_methods send_code_methods = { }; void do_send_code (struct telegram *instance, const char *user) { + info ("do_send_code()\n"); struct mtproto_connection *mtp = instance->connection; - logprintf ("sending code\n"); instance->suser = tstrdup (user); instance->want_dc_num = 0; clear_packet (mtp); @@ -453,14 +454,14 @@ void do_send_code (struct telegram *instance, const char *user) { out_string (mtp, TG_APP_HASH); out_string (mtp, "en"); - logprintf ("send_code: dc_num = %d\n", instance->auth.dc_working_num); + debug ("send_code: dc_num = %d\n", instance->auth.dc_working_num); send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_code_methods, instance); if (instance->session_state == STATE_PHONE_NOT_REGISTERED) { telegram_change_state(instance, STATE_PHONE_CODE_REQUESTED, NULL); } else if (instance->session_state == STATE_CLIENT_NOT_REGISTERED) { telegram_change_state(instance, STATE_CLIENT_CODE_REQUESTED, NULL); } else { - logprintf("do_send_code() Invalid State %d, erroring\n", instance->session_state); + debug("do_send_code() Invalid State %d, erroring\n", instance->session_state); telegram_change_state(instance, STATE_ERROR, NULL); } // TODO: Phone Code Hash @@ -475,7 +476,7 @@ int phone_call_on_answer (struct query *q UU) { } int phone_call_on_error (struct query *q UU, int error_code, int l, char *error) { - logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); + debug ( "error_code = %d, error = %.*s\n", error_code, l, error); assert (0); return 0; } @@ -488,7 +489,7 @@ struct query_methods phone_call_methods = { void do_phone_call (struct telegram *instance, const char *user) { struct mtproto_connection *mtp = instance->connection; - logprintf ("calling user\n"); + debug ("calling user\n"); instance->suser = tstrdup (user); instance->want_dc_num = 0; clear_packet (mtp); @@ -497,7 +498,7 @@ void do_phone_call (struct telegram *instance, const char *user) { out_string (mtp, user); out_string (mtp, instance->phone_code_hash); - logprintf ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); + info ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &phone_call_methods, instance); } /* }}} */ @@ -516,7 +517,7 @@ int check_phone_on_answer (struct query *q UU) { fetch_bool (mtp); assert (mtp->connection->instance->session_state == STATE_CONFIG_RECEIVED); - logprintf ("check_phone_result=%d\n", check_phone_result); + debug ("check_phone_result=%d\n", check_phone_result); telegram_change_state (mtp->connection->instance, check_phone_result ? STATE_CLIENT_NOT_REGISTERED : STATE_PHONE_NOT_REGISTERED, NULL); return 0; @@ -542,7 +543,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error //check_phone_result = 1; } else { - logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); + failure ( "error_code = %d, error = %.*s\n", error_code, l, error); telegram_change_state(instance, STATE_ERROR, error); } telegram_change_state(instance, @@ -577,7 +578,7 @@ int nearest_dc_on_answer (struct query *q UU) { assert (fetch_int (mtp) == (int)CODE_nearest_dc); char *country = fetch_str_dup (mtp); - logprintf ("Server thinks that you are in %s\n", country); + debug ("Server thinks that you are in %s\n", country); fetch_int (mtp); // this_dc instance->nearest_dc_num = fetch_int (mtp); assert (instance->nearest_dc_num >= 0); @@ -585,7 +586,7 @@ int nearest_dc_on_answer (struct query *q UU) { } 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); + fatal ("error #%d: %.*s\n", error_code, l, error); assert (0); return 0; } @@ -610,7 +611,7 @@ void do_get_nearest_dc (struct telegram *instance) { /* {{{ Sign in / Sign up */ int sign_in_on_answer (struct query *q) { - logprintf ("sign_in_on_answer()\n"); + info ("sign_in_on_answer()\n"); struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = mtp->connection->instance; @@ -622,7 +623,7 @@ int sign_in_on_answer (struct query *q) { instance->our_id = get_peer_id (instance->User.id); bl_do_set_our_id (mtp->bl, mtp, instance->our_id); } - logprintf ( "telegram: authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", + debug ( "telegram: authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", instance->User.first_name, instance->User.last_name, instance->User.phone, (int)(expires - get_double_time ())); DC_working->has_auth = 1; @@ -632,9 +633,9 @@ int sign_in_on_answer (struct query *q) { } int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { - logprintf ("sign_in_on_error()\n"); + info ("sign_in_on_error()\n"); struct mtproto_connection *mtp = query_get_mtproto(q); - logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error); + failure ( "error_code = %d, error = %.*s\n", error_code, l, error); telegram_change_state (mtp->connection->instance, STATE_CLIENT_CODE_NOT_ENTERED, NULL); return 0; } @@ -645,7 +646,7 @@ struct query_methods sign_in_methods = { }; void do_send_code_result (struct telegram *instance, const char *code) { - logprintf ("do_send_code_result()\n"); + info ("do_send_code_result()\n"); struct mtproto_connection *mtp = instance->connection; assert (instance->session_state == STATE_CLIENT_CODE_NOT_ENTERED); @@ -795,7 +796,7 @@ void encr_finish (struct mtproto_connection *mtp, struct secret_chat *E) { int msg_send_encr_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); assert (fetch_int (mtp) == CODE_messages_sent_encrypted_message); - logprintf ("Sent\n"); + debug ("Sent\n"); struct message *M = q->extra; //M->date = fetch_int (mtp); fetch_int (mtp); @@ -846,14 +847,14 @@ int msg_send_on_answer (struct query *q UU) { } //print_start (); //push_color (COLOR_YELLOW); - logprintf ("Link with user "); + debug ("Link with user "); //print_user_name (U->id, (void *)U); - logprintf (" changed\n"); + debug (" changed\n"); //pop_color (); //print_end (); } } - logprintf ("Sent: id = %d\n", id); + debug ("Sent: id = %d\n", id); bl_do_set_message_sent (mtp->bl, mtp, M); return 0; } @@ -861,7 +862,7 @@ int msg_send_on_answer (struct query *q UU) { int msg_send_on_error (struct query *q, int error_code, int error_len, char *error) { struct mtproto_connection *mtp = query_get_mtproto(q); - logprintf ( "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error); + debug ( "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error); struct message *M = q->extra; bl_do_delete_msg (mtp->bl, mtp, M); return 0; @@ -924,17 +925,17 @@ void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, if (get_peer_type (id) == PEER_ENCR_CHAT) { peer_t *P = user_chat_get (mtp->bl, id); if (!P) { - logprintf ("Can not send to unknown encrypted chat\n"); + warning ("Can not send to unknown encrypted chat\n"); return; } if (P->encr_chat.state != sc_ok) { - logprintf ("Chat is not yet initialized\n"); + warning ("Chat is not yet initialized\n"); return; } } long long t; secure_random (&t, 8); - logprintf ("t = %lld, len = %d\n", t, len); + debug ("t = %lld, len = %d\n", t, len); bl_do_send_message_text (mtp->bl, mtp, t, instance->our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); struct message *M = message_get (mtp->bl, t); assert (M); @@ -947,7 +948,7 @@ void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, void do_send_text (struct telegram *instance, peer_id_t id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { - logprintf ("No such file '%s'\n", file_name); + warning ("No such file '%s'\n", file_name); tfree_str (file_name); return; } @@ -955,7 +956,7 @@ void do_send_text (struct telegram *instance, peer_id_t id, char *file_name) { int x = read (fd, buf, (1 << 20) + 1); assert (x >= 0); if (x == (1 << 20) + 1) { - logprintf ("Too big file '%s'\n", file_name); + warning ("Too big file '%s'\n", file_name); tfree_str (file_name); close (fd); } else { @@ -1022,12 +1023,12 @@ void do_mark_read (struct telegram *instance, peer_id_t id) { peer_t *P = user_chat_get (mtp->bl, id); if (!P) { - logprintf ("Unknown peer\n"); + debug ("Unknown peer\n"); return; } if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) { if (!P->last) { - logprintf ("Unknown last peer message\n"); + debug ("Unknown last peer message\n"); return; } do_messages_mark_read (instance, id, P->last->id); @@ -1060,7 +1061,7 @@ int get_history_on_answer (struct query *q UU) { int x = fetch_int (mtp); if (x == (int)CODE_messages_messages_slice) { fetch_int (mtp); - logprintf ("...\n"); + debug ("...\n"); } else { assert (x == (int)CODE_messages_messages); } @@ -1191,15 +1192,15 @@ int get_dialogs_on_answer (struct query *q UU) { switch (get_peer_type (plist[i])) { case PEER_USER: UC = user_chat_get (mtp->bl, plist[i]); - logprintf ("User "); + debug ("User "); //print_user_name (plist[i], UC); - logprintf (": %d unread\n", dlist[2 * i + 1]); + debug (": %d unread\n", dlist[2 * i + 1]); break; case PEER_CHAT: UC = user_chat_get (mtp->bl, plist[i]); - logprintf ("Chat "); + debug ("Chat "); //print_chat_name (plist[i], UC); - logprintf (": %d unread\n", dlist[2 * i + 1]); + debug (": %d unread\n", dlist[2 * i + 1]); break; } } @@ -1380,7 +1381,7 @@ void send_part (struct telegram *instance, struct send_file *f) { } out_cstring (mtp, buf, x); if (verbosity >= 2) { - logprintf ("offset=%lld size=%lld\n", f->offset, f->size); + debug ("offset=%lld size=%lld\n", f->offset, f->size); } if (f->offset == f->size) { close (f->fd); @@ -1549,7 +1550,7 @@ void send_file_thumb (struct telegram *instance, struct send_file *f) { void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name) { int fd = open (file_name, O_RDONLY); if (fd < 0) { - logprintf ("No such file '%s'\n", file_name); + warning ("No such file '%s'\n", file_name); tfree_str (file_name); return; } @@ -1557,7 +1558,7 @@ void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char * fstat (fd, &buf); long long size = buf.st_size; if (size <= 0) { - logprintf ("File has zero length\n"); + debug ("File has zero length\n"); tfree_str (file_name); close (fd); return; @@ -1575,7 +1576,7 @@ void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char * if (f->part_size > (512 << 10)) { close (fd); - logprintf ("Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000); + failure ("Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000); tfree (f, sizeof (*f)); tfree_str (file_name); return; @@ -1640,7 +1641,7 @@ void do_forward_message (struct telegram *instance, peer_id_t id, int n) { struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT) { - logprintf ("Can not forward messages from secret chat\n"); + warning ("Can not forward messages from secret chat\n"); return; } clear_packet (mtp); @@ -1702,21 +1703,21 @@ void print_chat_info (struct chat *C) { //print_start (); //push_color (COLOR_YELLOW); - logprintf ("Chat "); + debug ("Chat "); //print_chat_name (U->id, U); - logprintf (" members:\n"); + debug (" members:\n"); int i; for (i = 0; i < C->user_list_size; i++) { - logprintf ("\t\t"); + debug ("\t\t"); //print_user_name (MK_USER (C->user_list[i].user_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].user_id))); - logprintf (" invited by "); + debug (" invited by "); //print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].inviter_id))); - logprintf (" at "); + debug (" at "); //print_date_full (C->user_list[i].date); if (C->user_list[i].user_id == C->admin_id) { - logprintf (" admin"); + debug (" admin"); } - logprintf ("\n"); + debug ("\n"); } //pop_color (); //print_end (); @@ -1734,13 +1735,13 @@ struct query_methods chat_info_methods = { }; void do_get_chat_info (struct telegram *instance, peer_id_t id) { - logprintf ("do_get_chat_info (peer_id=%d)", id.id); + debug ("do_get_chat_info (peer_id=%d)", id.id); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; if (offline_mode) { peer_t *C = user_chat_get (mtp->bl, id); if (!C) { - logprintf ("No such chat\n"); + warning ("No such chat\n"); } else { //print_chat_info (&C->chat); } @@ -1762,17 +1763,17 @@ void print_user_info (struct user *U) { //print_start (); //push_color (COLOR_YELLOW); - logprintf ("User "); + debug ("User "); //print_user_name (U->id, C); - logprintf (":\n"); - logprintf ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); - logprintf ("\tphone: %s\n", U->phone); + debug (":\n"); + debug ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); + debug ("\tphone: %s\n", U->phone); if (U->status.online > 0) { - logprintf ("\tonline\n"); + debug ("\tonline\n"); } else { - logprintf ("\toffline (was online "); + debug ("\toffline (was online "); //print_date_full (U->status.when); - logprintf (")\n"); + debug (")\n"); } //pop_color (); //print_end (); @@ -1798,7 +1799,7 @@ struct query_methods user_info_methods = { }; void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo) { - logprintf ("do_get_user_info\n"); + info ("do_get_user_info\n"); struct show_info_extra *extra = talloc(sizeof(struct show_info_extra)); extra->show_info = showInfo; struct dc *DC_working = telegram_get_working_dc(instance); @@ -1816,7 +1817,7 @@ void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo) { out_int (mtp, get_peer_id (id)); } send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, extra); - logprintf ("do_get_user_info ready\n"); + debug ("do_get_user_info ready\n"); } /* }}} */ @@ -1859,11 +1860,11 @@ void end_load (struct telegram *instance, struct download *D) { instance->cur_downloaded_bytes -= D->size; //update_prompt (); close (D->fd); - logprintf ("Done: %s\n", D->name); + debug ("Done: %s\n", D->name); event_download_finished_handler(instance, D); instance->dl_curr = 0; if (D->dc != telegram_get_working_dc(instance)->id) { - logprintf ("%d Not the working dc %d, closing...\n", D->dc, + debug ("%d Not the working dc %d, closing...\n", D->dc, telegram_get_working_dc(instance)->id); } if (D->iv) { @@ -1939,7 +1940,7 @@ void load_next_part (struct telegram *instance, struct download *D) { l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", instance->download_path, D->id); } if (l >= (int) sizeof (buf)) { - logprintf ("Download filename is too long"); + fatal ("Download filename is too long"); exit (1); } D->name = tstrdup (buf); @@ -1949,7 +1950,7 @@ void load_next_part (struct telegram *instance, struct download *D) { if (D->offset >= D->size) { instance->cur_downloading_bytes += D->size; instance->cur_downloaded_bytes += D->offset; - logprintf ("Already downloaded\n"); + info ("Already downloaded\n"); end_load (instance, D); return; } @@ -1959,6 +1960,7 @@ void load_next_part (struct telegram *instance, struct download *D) { instance->cur_downloaded_bytes += D->offset; //update_prompt (); } + info ("do_upload_get_file()\n"); clear_packet (mtp); out_int (mtp, CODE_upload_get_file); if (!D->id) { @@ -1988,7 +1990,7 @@ void load_next_part (struct telegram *instance, struct download *D) { void do_load_photo_size (struct telegram *instance, struct photo_size *P, void *extra) { if (!P->loc.dc) { - logprintf ("Bad video thumb\n"); + failure ("Bad video thumb\n"); return; } assert (P); @@ -2144,6 +2146,7 @@ struct query_methods export_auth_methods = { }; void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra) { + info ("do_export_auth(num=%d)\n", num); instance->export_auth_str = 0; struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); @@ -2186,7 +2189,7 @@ struct query_methods import_auth_methods = { }; void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra) { - logprintf ("do_import_auth(num=%d, our_id=%d, export_auth_str=%s)\n", num, instance->our_id, instance->export_auth_str); + info ("do_import_auth(num=%d, our_id=%d, export_auth_str=)\n", num, instance->our_id); struct import_info *info = talloc0(sizeof (struct import_info)); info->cb = cb; info->extra = extra; @@ -2214,9 +2217,9 @@ int add_contact_on_answer (struct query *q UU) { assert (fetch_int (mtp) == CODE_vector); int n = fetch_int (mtp); if (n > 0) { - logprintf ("Added successfully"); + debug ("Added successfully"); } else { - logprintf ("Not added"); + debug ("Not added"); } int i; for (i = 0; i < n ; i++) { @@ -2230,27 +2233,27 @@ int add_contact_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user (mtp); //print_start (); //push_color (COLOR_YELLOW); - logprintf ("User #%d: ", get_peer_id (U->id)); + debug ("User #%d: ", get_peer_id (U->id)); //print_user_name (U->id, (peer_t *)U); //push_color (COLOR_GREEN); - logprintf (" ("); - logprintf ("%s", U->print_name); + debug (" ("); + debug ("%s", U->print_name); if (U->phone) { - logprintf (" "); - logprintf ("%s", U->phone); + debug (" "); + debug ("%s", U->phone); } - logprintf (") "); + debug (") "); //pop_color (); if (U->status.online > 0) { - logprintf ("online\n"); + debug ("online\n"); } else { if (U->status.online < 0) { - logprintf ("offline. Was online "); + debug ("offline. Was online "); //print_date_full (U->status.when); } else { - logprintf ("offline permanent"); + debug ("offline permanent"); } - logprintf ("\n"); + debug ("\n"); } //pop_color (); //print_end (); @@ -2293,7 +2296,7 @@ void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, i struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; if (get_peer_type (id) == PEER_ENCR_CHAT) { - logprintf ("Can not search in secure chat\n"); + warning ("Can not search in secure chat\n"); return; } clear_packet (mtp); @@ -2332,11 +2335,11 @@ int contacts_search_on_answer (struct query *q UU) { //push_color (COLOR_YELLOW); for (i = 0; i < n; i++) { struct user *U = fetch_alloc_user (mtp); - logprintf ("User "); + debug ("User "); //push_color (COLOR_RED); - logprintf ("%s %s", U->first_name, U->last_name); + debug ("%s %s", U->first_name, U->last_name); //pop_color (); - logprintf (". Phone %s\n", U->phone); + debug (". Phone %s\n", U->phone); } //pop_color (); //print_end (); @@ -2367,17 +2370,17 @@ int send_encr_accept_on_answer (struct query *q UU) { if (E->state == sc_ok) { //print_start (); //push_color (COLOR_YELLOW); - logprintf ("Encrypted connection with "); + debug ("Encrypted connection with "); ////print_encr_chat_name (E->id, (void *)E); - logprintf (" established\n"); + debug (" established\n"); //pop_color (); //print_end (); } else { //print_start (); //push_color (COLOR_YELLOW); - logprintf ("Encrypted connection with "); + debug ("Encrypted connection with "); ////print_encr_chat_name (E->id, (void *)E); - logprintf (" failed\n"); + debug (" failed\n"); //pop_color (); //print_end (); } @@ -2390,17 +2393,17 @@ int send_encr_request_on_answer (struct query *q UU) { if (E->state == sc_deleted) { //print_start (); //push_color (COLOR_YELLOW); - logprintf ("Encrypted connection with "); + debug ("Encrypted connection with "); //print_encr_chat_name (E->id, (void *)E); - logprintf (" can not be established\n"); + debug (" can not be established\n"); //pop_color (); //print_end (); } else { //print_start (); //push_color (COLOR_YELLOW); - logprintf ("Establishing connection with "); + debug ("Establishing connection with "); //print_encr_chat_name (E->id, (void *)E); - logprintf ("\n"); + debug ("\n"); //pop_color (); //print_end (); @@ -2512,13 +2515,13 @@ void do_create_keys_end (struct telegram *instance, struct secret_chat *U) { sha1 ((void *)U->key, 256, sha_buffer); long long k = *(long long *)(sha_buffer + 12); if (k != U->key_fingerprint) { - logprintf ("version = %d\n", instance->encr_param_version); + debug ("version = %d\n", instance->encr_param_version); hexdump ((void *)U->nonce, (void *)(U->nonce + 256)); hexdump ((void *)U->g_key, (void *)(U->g_key + 256)); hexdump ((void *)U->key, (void *)(U->key + 64)); hexdump ((void *)t, (void *)(t + 256)); hexdump ((void *)sha_buffer, (void *)(sha_buffer + 20)); - logprintf ("!!Key fingerprint mismatch (my 0x%llx 0x%llx)\n", (unsigned long long)k, (unsigned long long)U->key_fingerprint); + failure ("!!Key fingerprint mismatch (my 0x%llx 0x%llx)\n", (unsigned long long)k, (unsigned long long)U->key_fingerprint); U->state = sc_deleted; } @@ -2688,7 +2691,7 @@ int get_state_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = q->extra; - logprintf("get_state_on_answer()\n"); + debug("get_state_on_answer()\n"); assert (fetch_int (mtp) == (int)CODE_updates_state); bl_do_set_pts (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); @@ -2704,7 +2707,7 @@ int get_difference_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); struct telegram *instance = q->extra; - logprintf("get_difference_on_answer()\n"); + debug("get_difference_on_answer()\n"); instance->get_difference_active = 0; unsigned x = fetch_int (mtp); if (x == CODE_updates_difference_empty) { @@ -2738,13 +2741,13 @@ int get_difference_on_answer (struct query *q UU) { } assert (fetch_int (mtp) == CODE_vector); n = fetch_int (mtp); - logprintf("Found %d chats\n", n); + debug("Found %d chats\n", n); for (i = 0; i < n; i++) { fetch_alloc_chat (mtp); } assert (fetch_int (mtp) == CODE_vector); n = fetch_int (mtp); - logprintf("Found %d users\n", n); + debug("Found %d users\n", n); for (i = 0; i < n; i++) { fetch_alloc_user (mtp); } @@ -2754,7 +2757,7 @@ int get_difference_on_answer (struct query *q UU) { bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); instance->unread_messages = fetch_int (mtp); - logprintf ("UNREAD MESSAGES: %d\n", ml_pos); + debug ("UNREAD MESSAGES: %d\n", ml_pos); //write_state_file (); for (i = 0; i < ml_pos; i++) { event_update_new_message (instance, instance->ML[i]); @@ -2781,7 +2784,7 @@ struct query_methods get_difference_methods = { }; void do_get_difference (struct telegram *instance, int sync_from_start) { - logprintf ("do_get_difference()\n"); + info ("do_get_difference()\n"); struct mtproto_connection *mtp = instance->connection; struct dc *DC_working = telegram_get_working_dc(instance); @@ -2789,7 +2792,7 @@ void do_get_difference (struct telegram *instance, int sync_from_start) { //difference_got = 0; clear_packet (mtp); do_insert_header (mtp); - logprintf("do_get_difference(pts:%d, last_date:%d, qts: %d)\n", instance->proto.pts, instance->proto.last_date, instance->proto.qts); + debug("do_get_difference(pts:%d, last_date:%d, qts: %d)\n", instance->proto.pts, instance->proto.last_date, instance->proto.qts); if (instance->proto.seq > 0 || sync_from_start) { if (instance->proto.pts == 0) { instance->proto.pts = 1; } if (instance->proto.qts == 0) { instance->proto.qts = 1; } @@ -2801,7 +2804,7 @@ void do_get_difference (struct telegram *instance, int sync_from_start) { out_int (mtp, instance->proto.qts); send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); } else { - logprintf("do_updates_get_state()\n", + debug("do_updates_get_state()\n", instance->proto.pts, instance->proto.last_date, instance->proto.qts); out_int (mtp, CODE_updates_get_state); send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, instance); @@ -2817,7 +2820,7 @@ void do_visualize_key (struct binlog *bl, peer_id_t id) { peer_t *P = user_chat_get (bl, id); assert (P); if (P->encr_chat.state != sc_ok) { - logprintf ("Chat is not initialized yet\n"); + warning ("Chat is not initialized yet\n"); return; } unsigned char buf[20]; @@ -2830,12 +2833,12 @@ void do_visualize_key (struct binlog *bl, peer_id_t id) { for (j = 0; j < 4; j ++) { ////push_color (colors[x & 3]); ////push_color (COLOR_INVERSE); - //logprintf (" "); + //debug (" "); ////pop_color (); ////pop_color (); x = x >> 2; } - if (i & 1) { logprintf ("\n"); } + if (i & 1) { debug ("\n"); } } //print_end (); } @@ -2848,7 +2851,7 @@ int get_suggested_on_answer (struct query *q UU) { assert (fetch_int (mtp) == CODE_contacts_suggested); assert (fetch_int (mtp) == CODE_vector); int n = fetch_int (mtp); - logprintf ("n = %d\n", n); + debug ("n = %d\n", n); assert (n <= 200); int l[400]; int i; @@ -2866,7 +2869,7 @@ int get_suggested_on_answer (struct query *q UU) { peer_t *U = (void *)fetch_alloc_user (mtp); assert (get_peer_id (U->id) == l[2 * i]); //print_user_name (U->id, U); - logprintf (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); + debug (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); } //pop_color (); //print_end (); @@ -2894,6 +2897,7 @@ struct query_methods add_user_to_chat_methods = { }; void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit) { + info ("do_add_user_to_chat()\n"); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); @@ -2915,6 +2919,7 @@ void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_ } void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id) { + info ("do_del_user_from_chat()\n"); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); @@ -2939,11 +2944,12 @@ void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_i char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); void do_create_secret_chat (struct telegram *instance, peer_id_t id) { + info ("do_create_secret_chat()\n"); struct mtproto_connection *mtp = instance->connection; assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (mtp->bl, id); if (!U) { - logprintf ("Can not create chat with unknown user\n"); + warning ("Can not create chat with unknown user\n"); return; } @@ -2957,11 +2963,12 @@ struct query_methods create_group_chat_methods = { }; void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic) { + info ("do_create_group_chat()\n"); struct mtproto_connection *mtp = instance->connection; assert (get_peer_type (id) == PEER_USER); peer_t *U = user_chat_get (mtp->bl, id); if (!U) { - logprintf ("Can not create chat with unknown user\n"); + warning ("Can not create chat with unknown user\n"); return; } clear_packet (mtp); @@ -2990,7 +2997,7 @@ int delete_msg_on_answer (struct query *q UU) { assert (fetch_int (mtp) == CODE_vector); int n = fetch_int (mtp); fetch_skip (mtp, n); - logprintf ("Deleted %d messages\n", n); + debug ("Deleted %d messages\n", n); return 0; } @@ -2999,6 +3006,7 @@ struct query_methods delete_msg_methods = { }; void do_delete_msg (struct telegram *instance, long long id) { + info ("do_delete_msg()\n"); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); @@ -3018,7 +3026,7 @@ int restore_msg_on_answer (struct query *q UU) { assert (fetch_int (mtp) == CODE_vector); int n = fetch_int (mtp); fetch_skip (mtp, n); - logprintf ("Restored %d messages\n", n); + debug ("Restored %d messages\n", n); return 0; } @@ -3027,6 +3035,7 @@ struct query_methods restore_msg_methods = { }; void do_restore_msg (struct telegram *instance, long long id) { + info ("do_restore_msg()\n"); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); @@ -3049,6 +3058,7 @@ struct query_methods update_status_methods = { }; void do_update_status (struct telegram *instance, int online UU) { + info ("do_update_status()\n"); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; clear_packet (mtp); @@ -3067,6 +3077,7 @@ struct query_methods update_typing_methods = { }; void do_update_typing (struct telegram *instance, peer_id_t id) { + info ("do_update_typing()\n"); struct dc *DC_working = telegram_get_working_dc(instance); struct mtproto_connection *mtp = instance->connection; diff --git a/structures.c b/structures.c index b637259..d7feadb 100644 --- a/structures.c +++ b/structures.c @@ -49,7 +49,7 @@ int verbosity; void fetch_skip_photo (struct mtproto_connection *mtp); -#define code_assert(x) if (!(x)) { logprintf ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } +#define code_assert(x) if (!(x)) { fatal ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } #define code_try(x) if ((x) == -1) { return -1; } /* @@ -304,7 +304,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U if (x == CODE_encrypted_chat_discarded) { if (new) { - logprintf ("Unknown chat in deleted state. May be we forgot something...\n"); + warning ("Unknown chat in deleted state. May be we forgot something...\n"); return; } bl_do_encr_chat_delete (mtp->bl, mtp, U); @@ -322,7 +322,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U int user_id = fetch_int (mtp) + admin_id - instance->our_id; if (x == CODE_encrypted_chat_waiting) { - logprintf ("Unknown chat in waiting state. May be we forgot something...\n"); + warning ("Unknown chat in waiting state. May be we forgot something...\n"); return; } if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { @@ -332,7 +332,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U int l = prefetch_strlen (mtp); char *s = fetch_str (mtp, l); - if (l != 256) { logprintf ("l = %d\n", l); } + if (l != 256) { debug ("l = %d\n", l); } if (l < 256) { memcpy (g_key + 256 - l, s, l); } else { @@ -341,7 +341,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U /*l = prefetch_strlen (mtp); s = fetch_str (mtp, l); - if (l != 256) { logprintf ("l = %d\n", l); } + if (l != 256) { debug ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); } else { @@ -353,7 +353,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } if (x == CODE_encrypted_chat) { - logprintf ("Unknown chat in ok state. May be we forgot something...\n"); + warning ("Unknown chat in ok state. May be we forgot something...\n"); return; } @@ -363,11 +363,11 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U bl_do_set_encr_chat_access_hash (mtp->bl, mtp, U, fetch_long (mtp)); bl_do_set_encr_chat_date (mtp->bl, mtp, U, fetch_int (mtp)); if (fetch_int (mtp) != U->admin_id) { - logprintf ("Changed admin in secret chat. WTF?\n"); + failure ("Changed admin in secret chat. WTF?\n"); return; } if (U->user_id != U->admin_id + fetch_int (mtp) - instance->our_id) { - logprintf ("Changed partner in secret chat. WTF?\n"); + failure ("Changed partner in secret chat. WTF?\n"); return; } if (x == CODE_encrypted_chat_waiting) { @@ -383,7 +383,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U int l = prefetch_strlen (mtp); char *s = fetch_str (mtp, l); - if (l != 256) { logprintf ("l = %d\n", l); } + if (l != 256) { debug ("l = %d\n", l); } if (l < 256) { memcpy (g_key + 256 - l, s, l); } else { @@ -392,7 +392,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U /*l = prefetch_strlen (mtp); s = fetch_str (mtp, l); - if (l != 256) { logprintf ("l = %d\n", l); } + if (l != 256) { debug ("l = %d\n", l); } if (l < 256) { memcpy (nonce + 256 - l, s, l); } else { @@ -602,7 +602,7 @@ void fetch_photo_size (struct mtproto_connection *mtp, struct photo_size *S) { unsigned x = fetch_int (mtp); assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); S->type = fetch_str_dup (mtp); - logprintf("s->type %s\n", S->type); + debug("s->type %s\n", S->type); if (x != CODE_photo_size_empty) { fetch_file_location (mtp, &S->loc); S->w = fetch_int (mtp); @@ -668,7 +668,7 @@ void fetch_photo (struct mtproto_connection *mtp, struct photo *P) { fetch_geo (mtp, &P->geo); assert (fetch_int (mtp) == CODE_vector); P->sizes_num = fetch_int (mtp); - logprintf("sizes_num %d \n", P->sizes_num); + debug("sizes_num %d \n", P->sizes_num); P->sizes = talloc (sizeof (struct photo_size) * P->sizes_num); int i; for (i = 0; i < P->sizes_num; i++) { @@ -784,7 +784,7 @@ void fetch_message_action (struct mtproto_connection *mtp, struct message_action char *s = fetch_str (mtp, l); int l2 = prefetch_strlen (mtp); // checkin char *s2 = fetch_str (mtp, l2); - logprintf ("Message action: Created geochat %.*s in address %.*s\n", l, s, l2, s2); + debug ("Message action: Created geochat %.*s in address %.*s\n", l, s, l2, s2); } break; case CODE_message_action_geo_chat_checkin: @@ -951,7 +951,7 @@ void fetch_message_media (struct mtproto_connection *mtp, struct message_media * memcpy (M->data, fetch_str (mtp, M->data_size), M->data_size); break; default: - logprintf ("type = 0x%08x\n", M->type); + debug ("type = 0x%08x\n", M->type); assert (0); } } @@ -995,7 +995,7 @@ void fetch_skip_message_media (struct mtproto_connection *mtp) { } break; default: - logprintf ("type = 0x%08x\n", x); + debug ("type = 0x%08x\n", x); assert (0); } } @@ -1069,7 +1069,7 @@ void fetch_skip_message_media_encrypted (struct mtproto_connection *mtp) { fetch_skip (mtp, 1); break; default: - logprintf ("type = 0x%08x\n", x); + debug ("type = 0x%08x\n", x); assert (0); } } @@ -1218,7 +1218,7 @@ void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct messa M->user_id = fetch_int (mtp); break; default: - logprintf ("type = 0x%08x\n", x); + debug ("type = 0x%08x\n", x); assert (0); } } @@ -1230,7 +1230,7 @@ void fetch_skip_message_action_encrypted (struct mtproto_connection *mtp) { fetch_skip (mtp, 1); break; default: - logprintf ("x = 0x%08x\n", x); + debug ("x = 0x%08x\n", x); assert (0); } } @@ -1243,7 +1243,7 @@ void fetch_message_action_encrypted (struct mtproto_connection *mtp, struct mess M->ttl = fetch_int (mtp); break; default: - logprintf ("x = 0x%08x\n", x); + debug ("x = 0x%08x\n", x); assert (0); } } @@ -1389,7 +1389,7 @@ int decrypt_encrypted_message (struct secret_chat *E) { sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer); if (memcmp (sha1a_buffer + 4, msg_key, 16)) { - logprintf ("Sha1 mismatch\n"); + failure ("Sha1 mismatch\n"); return -1; } return 0; @@ -1409,7 +1409,7 @@ void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) peer_t *P = user_chat_get (bl, chat); if (!P) { - logprintf ("Encrypted message to unknown chat. Dropping\n"); + warning ("Encrypted message to unknown chat. Dropping\n"); M->flags |= FLAG_MESSAGE_EMPTY; } @@ -1421,7 +1421,7 @@ void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) int ok = 0; if (P) { if (*(long long *)decr_ptr != P->encr_chat.key_fingerprint) { - logprintf ("Encrypted message with bad fingerprint to chat %s\n", P->print_name); + warning ("Encrypted message with bad fingerprint to chat %s\n", P->print_name); P = 0; } decr_ptr += 2; @@ -1525,7 +1525,7 @@ static int id_cmp (struct message *M1, struct message *M2) { struct user *fetch_alloc_user (struct mtproto_connection *mtp) { struct binlog *bl = mtp->instance->bl; - logprintf("fetch_alloc_user()\n"); + debug("fetch_alloc_user()\n"); int data[2]; prefetch_data (mtp, data, 8); peer_t *U = user_chat_get (bl, MK_USER (data[1])); @@ -1549,7 +1549,7 @@ struct user *fetch_alloc_user (struct mtproto_connection *mtp) { struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp) { struct binlog *bl = mtp->bl; - logprintf("fetch_alloc_encrypted_chat()\n"); + debug("fetch_alloc_encrypted_chat()\n"); int data[2]; prefetch_data (mtp, data, 8); peer_t *U = user_chat_get (bl, MK_ENCR_CHAT (data[1])); @@ -1679,7 +1679,7 @@ void free_message_media (struct message_media *M) { case 0: break; default: - logprintf ("%08x\n", M->type); + debug ("%08x\n", M->type); assert (0); } } @@ -1813,7 +1813,7 @@ void message_del_peer (struct message *M) { struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct telegram *instance) { struct binlog *bl = mtp->bl; - logprintf("fetch_alloc_message()\n"); + debug("fetch_alloc_message()\n"); int data[2]; prefetch_data (mtp, data, 8); struct message *M = message_get (bl, data[1]); @@ -1832,7 +1832,7 @@ struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct tele } struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct telegram *instance) { - logprintf("fetch_alloc_geo_message()\n"); + debug("fetch_alloc_geo_message()\n"); struct message *M = talloc (sizeof (*M)); M->instance = instance; fetch_geo_message (mtp, M); @@ -1859,7 +1859,7 @@ struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, struct telegram *instance) { struct binlog *bl = mtp->bl; - logprintf("fetch_alloc_encrypted_message()\n"); + debug("fetch_alloc_encrypted_message()\n"); int data[3]; prefetch_data (mtp, data, 12); struct message *M = message_get (bl, *(long long *)(data + 1)); @@ -1871,7 +1871,7 @@ struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, message_insert_tree (M); mtp->bl->messages_allocated ++; assert (message_get (bl, M->id) == M); - logprintf ("id = %lld\n", M->id); + debug ("id = %lld\n", M->id); } fetch_encrypted_message (mtp, M); return M; @@ -1914,12 +1914,12 @@ struct message *fetch_alloc_message_short_chat (struct mtproto_connection *mtp, struct chat *fetch_alloc_chat (struct mtproto_connection *mtp) { struct binlog *bl = mtp->bl; - logprintf("fetch_alloc_chat()\n"); + debug("fetch_alloc_chat()\n"); int data[2]; prefetch_data (mtp, data, 8); peer_t *U = user_chat_get (bl, MK_CHAT (data[1])); - logprintf("id %d\n", U->id.id); - logprintf("type %d\n", U->id.type); + debug("id %d\n", U->id.id); + debug("type %d\n", U->id.type); if (!U) { bl->chats_allocated ++; U = talloc0 (sizeof (*U)); @@ -2020,7 +2020,7 @@ void message_remove_unsent (struct message *M) { } void __send_msg (struct message *M) { - logprintf ("Resending message...\n"); + debug ("Resending message...\n"); //print_message (M); assert(M->instance); @@ -2033,13 +2033,13 @@ void send_all_unsent (struct binlog *bl) { void peer_insert_name (struct binlog *bl, peer_t *P) { //if (!P->print_name || !strlen (P->print_name)) { return; } - //logprintf ("+%s\n", P->print_name); + //debug ("+%s\n", P->print_name); bl->peer_by_name_tree = tree_insert_peer_by_name (bl->peer_by_name_tree, P, lrand48 ()); } void peer_delete_name (struct binlog *bl, peer_t *P) { //if (!P->print_name || !strlen (P->print_name)) { return; } - //logprintf ("-%s\n", P->print_name); + //debug ("-%s\n", P->print_name); bl->peer_by_name_tree = tree_delete_peer_by_name (bl->peer_by_name_tree, P); } @@ -2055,7 +2055,7 @@ void free_messages (struct binlog *bl) while (bl->message_tree) { struct message *M = tree_get_min_message (bl->message_tree); assert (M); - logprintf ("freeing message: %lld\n", M->id); + debug ("freeing message: %lld\n", M->id); bl->message_tree = tree_delete_message (bl->message_tree, M); bl->messages_allocated --; free_message (M); diff --git a/telegram.c b/telegram.c index 4bf757b..24772c8 100755 --- a/telegram.c +++ b/telegram.c @@ -108,20 +108,20 @@ int telegram_is_registered(struct telegram *tg) { void telegram_change_state (struct telegram *instance, int state, void *data) { instance->session_state = state; - logprintf("on_state_change: %d\n", state); + debug("on_state_change: %d\n", state); switch (state) { case STATE_ERROR: { const char* err = data; if (err == NULL) { err = ""; } - logprintf("telegram errored: %s\n", err); + debug("telegram errored: %s\n", err); mtproto_close (instance->connection); } break; case STATE_AUTHORIZED: - logprintf("requesting configuration\n"); + debug("requesting configuration\n"); telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); if (telegram_is_registered(instance)) { telegram_change_state (instance, STATE_READY, NULL); @@ -131,36 +131,36 @@ void telegram_change_state (struct telegram *instance, int state, void *data) break; case STATE_CONFIG_RECEIVED: - logprintf("received network configuration, checking whether phone is registered.\n"); + debug("received network configuration, checking whether phone is registered.\n"); telegram_store_session(instance); do_auth_check_phone(instance, instance->login); break; case STATE_PHONE_NOT_REGISTERED: - logprintf("phone is not registered, need to register phone number.\n"); + debug("phone is not registered, need to register phone number.\n"); do_send_code(instance, instance->login); break; case STATE_PHONE_CODE_NOT_ENTERED: - logprintf("phone authenticion, user needs to enter code, first and last name.\n"); + debug("phone authenticion, user needs to enter code, first and last name.\n"); assert (instance->config->on_phone_registration_required); instance->config->on_phone_registration_required (instance); break; case STATE_CLIENT_NOT_REGISTERED: - logprintf("phone is already registered, need to register client.\n"); + debug("phone is already registered, need to register client.\n"); do_send_code(instance, instance->login); break; case STATE_CLIENT_CODE_NOT_ENTERED: - logprintf("client authentication, user needs to enter code.\n"); + debug("client authentication, user needs to enter code.\n"); assert (instance->config->on_client_registration_required); instance->config->on_client_registration_required (instance); // wait for user input ... break; case STATE_READY: - logprintf("telegram is registered and ready.\n"); + debug("telegram is registered and ready.\n"); telegram_store_session (instance); instance->config->on_ready (instance); break; @@ -170,7 +170,7 @@ void telegram_change_state (struct telegram *instance, int state, void *data) // the current mtproto_connection to be disconnected int target_dc = *(int*) data; - logprintf ("Disconnected: Migrate to data center %d\n", target_dc); + debug ("Disconnected: Migrate to data center %d\n", target_dc); // close old connection and mark it for destruction mtproto_close (instance->connection); @@ -203,12 +203,12 @@ struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_ this->state_path = telegram_get_config(this, "state"); this->secret_path = telegram_get_config(this, "secret"); - logprintf("%s\n", this->login); - logprintf("%s\n", this->config_path); - logprintf("%s\n", this->download_path); - logprintf("%s\n", this->auth_path); - logprintf("%s\n", this->state_path); - logprintf("%s\n", this->secret_path); + debug("%s\n", this->login); + debug("%s\n", this->config_path); + debug("%s\n", this->download_path); + debug("%s\n", this->auth_path); + debug("%s\n", this->state_path); + debug("%s\n", this->secret_path); telegram_change_state(this, STATE_INITIALISED, NULL); return this; @@ -265,7 +265,7 @@ void free_auth (struct dc* DC_list[], int count) void assert_file_usable(const char *file) { - logprintf ("assert_file_usable (%s)\n", file); + debug ("assert_file_usable (%s)\n", file); assert(access(file, W_OK | R_OK | F_OK) != -1); } @@ -341,7 +341,7 @@ void on_authorized(struct mtproto_connection *c, void* data); void telegram_main_connected (struct proxy_request *req) { struct telegram *instance = req->data; - logprintf("Authorized... storing current session %d.\n", + debug("Authorized... storing current session %d.\n", instance->connection->connection->session[0]); telegram_store_session(instance); telegram_change_state(instance, STATE_AUTHORIZED, NULL); @@ -352,9 +352,9 @@ void telegram_main_connected (struct proxy_request *req) */ void telegram_connect (struct telegram *instance) { - logprintf ("telegram_network_connect()\n"); + debug ("telegram_network_connect()\n"); if (! instance->auth.DC_list) { - logprintf("telegram_network_connect(): cannot connect, restore / init a session first.\n"); + debug("telegram_network_connect(): cannot connect, restore / init a session first.\n"); assert(0); } struct dc *DC_working = telegram_get_working_dc (instance); @@ -372,7 +372,7 @@ void telegram_connect (struct telegram *instance) void on_auth_imported (void *extra) { - logprintf ("on_auth_imported()\n"); + debug ("on_auth_imported()\n"); struct download *dl = extra; struct mtproto_connection *c = dl->c; struct telegram *tg = c->instance; @@ -384,7 +384,7 @@ void on_auth_imported (void *extra) void on_auth_exported (char *export_auth_str UU, int len UU, void *extra) { - logprintf ("on_auth_exported()\n"); + debug ("on_auth_exported()\n"); struct download *dl = extra; do_import_auth (dl->c->instance, dl->dc, on_auth_imported, extra); telegram_flush (dl->c->instance); @@ -392,7 +392,7 @@ void on_auth_exported (char *export_auth_str UU, int len UU, void *extra) void telegram_dl_connected (struct proxy_request *req) { - logprintf ("telegram_dl_connected(dc=%d)\n", req->DC->id); + debug ("telegram_dl_connected(dc=%d)\n", req->DC->id); struct telegram *tg = req->tg; // TODO: error handling @@ -413,7 +413,7 @@ void telegram_dl_connected (struct proxy_request *req) */ void telegram_dl_add (struct telegram *instance, struct download *dl) { - logprintf ("telegram_connect_dl(dc_num=%d, dc=%d)\n", dl->dc, instance->auth.DC_list[dl->dc]); + debug ("telegram_connect_dl(dc_num=%d, dc=%d)\n", dl->dc, instance->auth.DC_list[dl->dc]); if (!instance->dl_queue) { instance->dl_queue = g_queue_new (); } @@ -435,23 +435,23 @@ void telegram_dl_next (struct telegram *instance) req->data = dl; instance->dl_curr = dl; - logprintf ("telegrma_dl_start(workin_dc=%d, ): starting new download..\n", instance->auth.dc_working_num); + debug ("telegrma_dl_start(workin_dc=%d, ): starting new download..\n", instance->auth.dc_working_num); if (dl->dc == instance->auth.dc_working_num) { - logprintf ("is working DC, start download...\n"); + debug ("is working DC, start download...\n"); assert (telegram_get_working_dc(instance)->sessions[0]->c); req->conn = instance->connection; dl->c = req->conn; telegram_dl_connected (req); } else { - logprintf ("is remote DC, requesting connection...\n"); + debug ("is remote DC, requesting connection...\n"); instance->config->proxy_request_cb (instance, req); } } else { - logprintf ("telegrma_dl_start(): no more downloads, DONE!\n"); + debug ("telegrma_dl_start(): no more downloads, DONE!\n"); mtproto_close_foreign (instance); } } else { - logprintf ("telegrma_dl_start(): download busy...\n"); + debug ("telegrma_dl_start(): download busy...\n"); } } @@ -461,7 +461,7 @@ void telegram_dl_next (struct telegram *instance) int telegram_login(struct telegram *instance) { if (instance->session_state != STATE_AUTHORIZED) { - logprintf("Cannot log in, invalid state: %d \n", instance->session_state); + debug("Cannot log in, invalid state: %d \n", instance->session_state); return -1; } do_help_get_config(instance); @@ -471,7 +471,7 @@ int telegram_login(struct telegram *instance) void on_authorized(struct mtproto_connection *c UU, void *data) { - logprintf ("on_authorized()...\n"); + debug ("on_authorized()...\n"); struct proxy_request *req = data; assert (req->done); req->done (req); @@ -510,18 +510,18 @@ int telegram_authenticated (struct telegram *instance) void telegram_flush (struct telegram *instance) { - logprintf ("telegram flush()\n"); + debug ("telegram flush()\n"); int i; for (i = 0; i < 100; i++) { struct mtproto_connection *c = instance->Cs[i]; if (!c) continue; if (!c->connection) continue; if (c->connection->out_bytes) { - logprintf ("connection %d has %d bytes, triggering on_output.\n", + debug ("connection %d has %d bytes, triggering on_output.\n", i, c->connection->out_bytes); instance->config->on_output(c->handle); } else { - logprintf ("connection %d has no bytes, skipping\n", i); + debug ("connection %d has no bytes, skipping\n", i); } } } diff --git a/tools.c b/tools.c index 5291d4f..130c3cb 100644 --- a/tools.c +++ b/tools.c @@ -76,14 +76,14 @@ void tfree (void *ptr, int size __attribute__ ((unused))) { total_allocated_bytes -= size; ptr -= RES_PRE; if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { - logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); + debug ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); } assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); assert (*(int *)(ptr + 4) == size); int block_num = *(int *)(ptr + 4 + RES_PRE + size); if (block_num >= used_blocks) { - logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); + debug ("block_num = %d, used = %d\n", block_num, used_blocks); } assert (block_num < used_blocks); if (block_num < used_blocks - 1) { @@ -182,7 +182,7 @@ char *tstrndup (const char *s, size_t n) { void ensure (int r) { if (!r) { - logprintf ("Open SSL error\n"); + debug ("Open SSL error\n"); ERR_print_errors_fp (stderr); assert (0); } @@ -206,12 +206,12 @@ int tinflate (void *input, int ilen, void *output, int olen) { if (err == Z_OK || err == Z_STREAM_END) { total_out = (int) strm.total_out; if (err == Z_STREAM_END && verbosity >= 2) { - logprintf ( "inflated %d bytes\n", (int) strm.total_out); + debug ( "inflated %d bytes\n", (int) strm.total_out); } } if (err != Z_STREAM_END) { - logprintf ( "inflate error = %d\n", err); - logprintf ( "inflated %d bytes\n", (int) strm.total_out); + debug ( "inflate error = %d\n", err); + debug ( "inflated %d bytes\n", (int) strm.total_out); } inflateEnd (&strm); return total_out; @@ -234,25 +234,25 @@ void tcheck (void) { for (j = 0; j < l; j++) { if (*(char *)(ptr + 4 + j)) { hexdump (ptr + 8, ptr + 8 + l + ((-l) & 3)); - logprintf ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr); + debug ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr); assert (0); } } } - logprintf ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt); + debug ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt); } void texists (void *ptr, int size) { ptr -= RES_PRE; if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { - logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); + debug ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); } assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); assert (*(int *)(ptr + 4) == size); int block_num = *(int *)(ptr + 4 + RES_PRE + size); if (block_num >= used_blocks) { - logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); + debug ("block_num = %d, used = %d\n", block_num, used_blocks); } assert (block_num < used_blocks); } From e3d6f02a67348e41c0bb0650ca77ca138ed3aa3f Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 3 Oct 2014 17:34:10 +0200 Subject: [PATCH 414/465] Add form for phone registratrion --- purple-plugin/telegram-purple.c | 49 +++++++++++++++++++++++---------- queries.c | 7 +++-- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f18ff45..1b9d9aa 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -281,24 +281,45 @@ void telegram_on_proxy_close(void *handle) tfree (conn, sizeof(mtproto_handle)); } -void telegram_on_phone_registration (struct telegram *instance) +void phone_registration_entered (PurpleConnection* gc, PurpleRequestFields* fields) { - // TODO: Query first and last name from user and start phone registration - telegram_conn *conn = instance->extra; - - purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); - const char *first_name = purple_account_get_string(conn->pa, "first_name", NULL); - const char *last_name = purple_account_get_string(conn->pa, "last_name", NULL); - const char *code = purple_account_get_string(conn->pa, "verification_key", NULL); - - if (!first_name || !last_name || !strlen(first_name) > 0 || !strlen(last_name) > 0) { - purple_notify_message(_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, "Registration Needed", - "Enter your first and last name to register this phone number with the telegram network.", - NULL, NULL, NULL); + telegram_conn *conn = purple_connection_get_protocol_data(gc); + const char* first = purple_request_fields_get_string(fields, "first_name"); + const char* last = purple_request_fields_get_string(fields, "last_name"); + const char* code = purple_request_fields_get_string(fields, "code"); + if (!first || !last || !code) { + telegram_on_phone_registration (conn->tg); return; } - do_send_code_result_auth (instance, code, first_name, last_name); + do_send_code_result_auth (conn->tg, code, first, last); + telegram_flush (conn->tg); +} + + +void telegram_on_phone_registration (struct telegram *instance) +{ + telegram_conn *conn = instance->extra; + + purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); + + PurpleRequestFields* fields = purple_request_fields_new(); + PurpleRequestField* field = 0; + + PurpleRequestFieldGroup* group = purple_request_field_group_new("Registration"); + field = purple_request_field_string_new("first_name", "First Name", "", 0); + purple_request_field_group_add_field(group, field); + field = purple_request_field_string_new("last_name", "Last Name", "", 0); + purple_request_field_group_add_field(group, field); + purple_request_fields_add_group(fields, group); + + group = purple_request_field_group_new("Authorization"); + field = purple_request_field_string_new("code", "Telegram Code", "", 0); + purple_request_field_group_add_field(group, field); + purple_request_fields_add_group(fields, group); + + purple_request_fields(conn->gc, "Register", "Please register your phone number.", NULL, fields, "Ok", + G_CALLBACK( phone_registration_entered ), "Cancel", NULL, conn->pa, NULL, NULL, conn->gc); } void client_registration_entered (gpointer data, const gchar *code) diff --git a/queries.c b/queries.c index ff37c91..3d83789 100644 --- a/queries.c +++ b/queries.c @@ -464,7 +464,6 @@ void do_send_code (struct telegram *instance, const char *user) { debug("do_send_code() Invalid State %d, erroring\n", instance->session_state); telegram_change_state(instance, STATE_ERROR, NULL); } - // TODO: Phone Code Hash } @@ -636,7 +635,11 @@ int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { info ("sign_in_on_error()\n"); struct mtproto_connection *mtp = query_get_mtproto(q); failure ( "error_code = %d, error = %.*s\n", error_code, l, error); - telegram_change_state (mtp->connection->instance, STATE_CLIENT_CODE_NOT_ENTERED, NULL); + int state = STATE_CLIENT_CODE_NOT_ENTERED; + if (mtp->instance->session_state == STATE_PHONE_CODE_NOT_ENTERED) { + state = STATE_PHONE_CODE_NOT_ENTERED; + } + telegram_change_state (mtp->connection->instance, state, NULL); return 0; } From 84e549fc96b400611f32cae036e03201ba04b263 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 3 Oct 2014 18:19:50 +0200 Subject: [PATCH 415/465] Use correct DC number for our updated application configuration --- loop.c | 5 +++-- net.h | 6 ++++-- purple-plugin/telegram-purple.c | 13 ++----------- telegram.c | 3 +-- telegram.h | 3 +-- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/loop.c b/loop.c index 3977266..b20ad5b 100644 --- a/loop.c +++ b/loop.c @@ -120,8 +120,8 @@ void empty_auth_file (const char *filename) { memset(state.DC_list, 0, 11 * sizeof(void *)); debug("empty_auth_file()\n"); - alloc_dc (state.DC_list, 1, tstrdup (TG_SERVER), 443); - state.dc_working_num = 1; + alloc_dc (state.DC_list, TG_DC_NUM, tstrdup (TG_SERVER), TG_PORT); + state.dc_working_num = TG_DC_NUM; state.auth_state = 0; write_auth_file (&state, filename); } @@ -162,6 +162,7 @@ struct authorization_state read_auth_file (const char *filename) { assert (x <= MAX_DC_ID); assert (read (auth_file_fd, &state.dc_working_num, 4) == 4); assert (read (auth_file_fd, &state.auth_state, 4) == 4); + debug ("dc_working_num=%d, auth_state=%d \n", state.dc_working_num, state.auth_state); if (m == DC_SERIALIZED_MAGIC) { state.auth_state = 700; } diff --git a/net.h b/net.h index ee537d0..e6ddd63 100644 --- a/net.h +++ b/net.h @@ -27,11 +27,13 @@ struct dc; #include "telegram.h" #include "queries.h" -#define TG_SERVER "149.154.167.50" +#define TG_SERVER "149.154.167.50" +#define TG_DC_NUM 2 #define TG_SERVER_TEST "149.154.167.40" -#define TG_PORT 443 +#define TG_TEST_DC_NUM 2 #define TG_APP_HASH "99428c722d0ed59b9cd844e4577cb4bb" #define TG_APP_ID 16154 +#define TG_PORT 443 #define ACK_TIMEOUT 1 #define MAX_DC_ID 10 diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 1b9d9aa..3128480 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -184,7 +184,7 @@ static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition co { mtproto_handle *conn = data; if (!conn->mtp) { - debug ("connection no loner existing, do nothing. \n"); + debug ("connection no longer existing, do nothing. \n"); return; } if (mtp_write_output(conn->mtp) == 0) { @@ -242,13 +242,6 @@ static void tgprpl_has_input(void *handle) } } -static void init_dc_settings(PurpleAccount *acc, struct dc *DC) -{ - DC->port = purple_account_get_int(acc, "port", TG_PORT); - DC->ip = g_strdup(purple_account_get_string(acc, "server", TG_SERVER)); - DC->id = 0; -} - /** * Telegram requests a new connectino to our configured proxy */ @@ -453,11 +446,9 @@ static void tgprpl_login(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); char const *username = purple_account_get_username(acct); - struct dc DC; - init_dc_settings(acct, &DC); // create a new instance of telegram - struct telegram *tg = telegram_new (&DC, username, &tgconf); + struct telegram *tg = telegram_new (username, &tgconf); telegram_restore_session(tg); // create handle to store additional info for libpurple in diff --git a/telegram.c b/telegram.c index 24772c8..8dee7d1 100755 --- a/telegram.c +++ b/telegram.c @@ -188,11 +188,10 @@ void telegram_change_state (struct telegram *instance, int state, void *data) } } -struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_config *config) +struct telegram *telegram_new(const char* login, struct telegram_config *config) { struct telegram *this = talloc0(sizeof(struct telegram)); this->protocol_data = NULL; - this->auth.DC_list[0] = DC; this->bl = talloc0 (sizeof(struct binlog)); this->config = config; diff --git a/telegram.h b/telegram.h index 407f9b4..736f11e 100644 --- a/telegram.h +++ b/telegram.h @@ -294,11 +294,10 @@ struct telegram { /** * Create a new telegram application * - * @param DC The initial data center to use * @param login The phone number to use as login name * @param config Contains all callbacks used for the telegram instance */ -struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_config *config); +struct telegram *telegram_new(const char* login, struct telegram_config *config); void telegram_restore_session(struct telegram *instance); void telegram_store_session(struct telegram *instance); From 83c09aeed35f05110763be4861c9e7905325d74c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 3 Oct 2014 18:24:16 +0200 Subject: [PATCH 416/465] Remove useless protocoll options --- purple-plugin/telegram-purple.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 3128480..7e51fe0 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -1250,22 +1250,6 @@ static void tgprpl_init(PurplePlugin *plugin) option = purple_account_option_list_new("Verification type", "verification_type", verification_values); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_string_new("First Name", "first_name", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - - option = purple_account_option_string_new("Last Name", "last_name", NULL); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - - - // TODO: Path to public key (When you can change the server hostname, - // you should also be able to change the public key) - - option = purple_account_option_string_new("Server", "server", TG_SERVER); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - - option = purple_account_option_int_new("Port", "port", TG_PORT); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - _telegram_protocol = plugin; } From cf1bd2376275fd4ef826e089d58acef6eb863bbe Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 3 Oct 2014 18:42:25 +0200 Subject: [PATCH 417/465] Add manual for installing Emojis --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index ebb851b..f65684e 100644 --- a/README.md +++ b/README.md @@ -96,3 +96,9 @@ The username is your current phone number, including your full country prefix in Now you should be able to see all your contacts and chats in your buddy list and send/receive messages. + +# Unicode Emojis for Pidgin + +The Telegram phone applications for iOS and Android make use of standardized Unicode smileys (called [Emojis](https://en.wikipedia.org/wiki/Emoji)). Pidgin +does not display those smileys natively, but you can install a custom smiley theme like [https://github.com/stv0g/unicode-emoji] or [https://github.com/VxJasonxV/emoji-for-pidgin] and activate it under Settings > Themes > Smiley Theme. + From da8ff5782c3df3ce3d91f2296e7368082bcbaf3d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 3 Oct 2014 18:50:09 +0200 Subject: [PATCH 418/465] Move Ubuntu note to Debian --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f65684e..79c2ac0 100644 --- a/README.md +++ b/README.md @@ -69,14 +69,15 @@ On Debian-based systems you can use: sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev +NOTE: Ubuntu is currently not working, since libpurple doesn't seem to find libssl when loading the plugin. It will compile, but Pidgin won't be able to load it. + + ### OpenSUSE sudo zypper install gcc glib glib-devel libpurple libpurple-devel zlib-devel openssl libopenssl-devel -NOTE: Ubuntu is currently not working, since libpurple doesn't seem to find libssl when loading the plugin. It will compile, but will not be loaded by Pidgin. - ## 3. Compile and install From cc09ab19e04ec4a68249cc4ee0d13a1251d156ef Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 4 Oct 2014 12:19:43 +0200 Subject: [PATCH 419/465] Fix errors in README --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 79c2ac0..86180e5 100644 --- a/README.md +++ b/README.md @@ -36,16 +36,18 @@ The following features are currently planned and will probably be added in the f ## Platform Support -Currently we can only provide an installation guide for Linux, even though it should be possible to compile this plugin on other platforms. If someone manages to create a working Windows, BSD or OSX build, please let us know. +We only provide an installation guide for Linux right now, even though it should be possible to compile this plugin on other platforms. If someone manages to create a working Windows, BSD or OSX build, please let us know. # Installation Instructions -Unfortunately there are currently no packages, so you need to compile it yourself: +Unfortunately there are no packages right now, so you need to compile it yourself: -## 1. Get this repository either from Bitbucket or from the Github mirror. +## 1. Get this repository + + + git clone https://github.com/majn/telegram-purple - git clone https://bitbucket.org/telegrampurple/telegram-purple ## 2. Fetch all needed dependencies @@ -101,5 +103,5 @@ Now you should be able to see all your contacts and chats in your buddy list and # Unicode Emojis for Pidgin The Telegram phone applications for iOS and Android make use of standardized Unicode smileys (called [Emojis](https://en.wikipedia.org/wiki/Emoji)). Pidgin -does not display those smileys natively, but you can install a custom smiley theme like [https://github.com/stv0g/unicode-emoji] or [https://github.com/VxJasonxV/emoji-for-pidgin] and activate it under Settings > Themes > Smiley Theme. +does not display those smileys natively, but you can install a custom smiley theme like (https://github.com/stv0g/unicode-emoji) or (https://github.com/VxJasonxV/emoji-for-pidgin) and activate it under Settings > Themes > Smiley Theme. From 706a28a4e66a7585cbe24628b3a01d1d185d90a3 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 6 Sep 2014 20:59:57 +0200 Subject: [PATCH 420/465] Add xCode project files for an Adium telegram plugin --- net.c | 5 +- telegram-adium/AdiumTelegramAccount.h | 14 + telegram-adium/AdiumTelegramAccount.m | 61 +++ telegram-adium/TelegramPlugin.h | 16 + telegram-adium/TelegramPlugin.m | 26 + telegram-adium/TelegramService.h | 14 + telegram-adium/TelegramService.m | 98 ++++ .../telegram-adium.xcodeproj/project.pbxproj | 454 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/telegram-adium.xccheckout | 41 ++ .../UserInterfaceState.xcuserstate | Bin 0 -> 42507 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 37 ++ .../xcschemes/telegram-adium.xcscheme | 59 +++ .../xcschemes/xcschememanagement.plist | 22 + .../telegram-adium/en.lproj/InfoPlist.strings | 2 + .../telegram-adium/telegram-adium-Info.plist | 48 ++ .../telegram-adium/telegram-adium-Prefix.pch | 14 + 17 files changed, 915 insertions(+), 3 deletions(-) create mode 100644 telegram-adium/AdiumTelegramAccount.h create mode 100644 telegram-adium/AdiumTelegramAccount.m create mode 100644 telegram-adium/TelegramPlugin.h create mode 100644 telegram-adium/TelegramPlugin.m create mode 100644 telegram-adium/TelegramService.h create mode 100644 telegram-adium/TelegramService.m create mode 100644 telegram-adium/telegram-adium.xcodeproj/project.pbxproj create mode 100644 telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout create mode 100644 telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme create mode 100644 telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 telegram-adium/telegram-adium/en.lproj/InfoPlist.strings create mode 100644 telegram-adium/telegram-adium/telegram-adium-Info.plist create mode 100644 telegram-adium/telegram-adium/telegram-adium-Prefix.pch diff --git a/net.c b/net.c index 296199f..89dfc50 100644 --- a/net.c +++ b/net.c @@ -314,11 +314,10 @@ int try_write (struct connection *c) { // Log all written packages if (r > 0 && log_net_f) { - fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); + // fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); int i; for (i = 0; i < r; i++) { - - fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); + // fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); } fprintf (log_net_f, "\n"); fflush (log_net_f); diff --git a/telegram-adium/AdiumTelegramAccount.h b/telegram-adium/AdiumTelegramAccount.h new file mode 100644 index 0000000..540743d --- /dev/null +++ b/telegram-adium/AdiumTelegramAccount.h @@ -0,0 +1,14 @@ +// +// AdiumTelegramAccount.h +// telegram-adium +// +// Created by Matthias Jentsch on 06.09.14. +// Copyright (c) 2014 Matthias Jentsch. All rights reserved. +// + +#import +#import + +@interface AdiumTelegramAccount : CBPurpleAccount + +@end diff --git a/telegram-adium/AdiumTelegramAccount.m b/telegram-adium/AdiumTelegramAccount.m new file mode 100644 index 0000000..608d03a --- /dev/null +++ b/telegram-adium/AdiumTelegramAccount.m @@ -0,0 +1,61 @@ +// +// AdiumTelegramAccount.m +// telegram-adium +// +// Created by Matthias Jentsch on 06.09.14. +// Copyright (c) 2014 Matthias Jentsch. All rights reserved. +// + +#import "AdiumTelegramAccount.h" + +@implementation AdiumTelegramAccount + +- (const char*)protocolPlugin +{ + return "prpl-telegram"; +} + +- (BOOL)connectivityBasedOnNetworkReachability +{ + return YES; +} + +- (NSString *)host +{ + return @"173.240.5.1"; +} + +- (int)port +{ + return 443; +} + +/* +- (NSString *)encodedAttributedString:(NSAttributedString *)inAttributedString forListObject:(AIListObject *)inListObject +{ + NSString *temp = [AIHTMLDecoder encodeHTML:inAttributedString + headers:YES + fontTags:NO + includingColorTags:NO + closeFontTags:NO + styleTags:NO + closeStyleTagsOnFontChange:NO + encodeNonASCII:NO + encodeSpaces:NO + imagesPath:nil + attachmentsAsText:YES + onlyIncludeOutgoingImages:NO + simpleTagsOnly:YES + bodyBackground:NO + allowJavascriptURLs:NO]; + return temp; +} +*/ + +- (BOOL)canSendOfflineMessageToContact:(AIListContact *)inContact +{ + return YES; +} + + +@end diff --git a/telegram-adium/TelegramPlugin.h b/telegram-adium/TelegramPlugin.h new file mode 100644 index 0000000..bb0e985 --- /dev/null +++ b/telegram-adium/TelegramPlugin.h @@ -0,0 +1,16 @@ +// +// TelegramPlugin.h +// telegram-adium +// +// Created by Matthias Jentsch on 06.09.14. +// Copyright (c) 2014 Matthias Jentsch. All rights reserved. +// + +#import +#import + +@interface TelegramPlugin : NSObject { + id service; +} + +@end diff --git a/telegram-adium/TelegramPlugin.m b/telegram-adium/TelegramPlugin.m new file mode 100644 index 0000000..96bc7b9 --- /dev/null +++ b/telegram-adium/TelegramPlugin.m @@ -0,0 +1,26 @@ +// +// TelegramPlugin.m +// telegram-adium +// +// Created by Matthias Jentsch on 06.09.14. +// Copyright (c) 2014 Matthias Jentsch. All rights reserved. +// + +#import "telegram-purple.h" +#import "TelegramPlugin.h" +#import "TelegramService.h" + +@implementation TelegramPlugin + +- (void) installPlugin +{ + purple_init_telegram(); + service = [[TelegramService alloc] init]; +} + +- (void) uninstallPlugin +{ + service = nil; +} + +@end diff --git a/telegram-adium/TelegramService.h b/telegram-adium/TelegramService.h new file mode 100644 index 0000000..48b8ed6 --- /dev/null +++ b/telegram-adium/TelegramService.h @@ -0,0 +1,14 @@ +// +// TelegramService.h +// telegram-adium +// +// Created by Matthias Jentsch on 06.09.14. +// Copyright (c) 2014 Matthias Jentsch. All rights reserved. +// + +#import +#import + +@interface TelegramService : PurpleService + +@end diff --git a/telegram-adium/TelegramService.m b/telegram-adium/TelegramService.m new file mode 100644 index 0000000..21ee175 --- /dev/null +++ b/telegram-adium/TelegramService.m @@ -0,0 +1,98 @@ +// +// TelegramService.m +// telegram-adium +// +// Created by Matthias Jentsch on 06.09.14. +// Copyright (c) 2014 Matthias Jentsch. All rights reserved. +// + +#import "TelegramService.h" +#import "AdiumTelegramAccount.h" + +@implementation TelegramService + +- (Class)accountClass{ + return [AdiumOkCupidAccount class]; +} + +/* +- (AIAccountViewController *)accountViewController { + return [OkCupidAccountViewController accountViewController]; +} + */ + +- (BOOL)supportsProxySettings{ + return YES; +} + +- (BOOL)supportsPassword +{ + return NO; +} + +- (BOOL)requiresPassword +{ + return NO; +} + +- (NSString *)UIDPlaceholder +{ + return @"Telegram"; +} + +//Service Description +- (NSString *)serviceCodeUniqueID{ + return @"prpl-telegram"; +} +- (NSString *)serviceID{ + return @"Telegram"; +} +- (NSString *)serviceClass{ + return @"Telegram"; +} +- (NSString *)shortDescription{ + return @"Telegram"; +} +- (NSString *)longDescription{ + return @"Support for the protocol of the Telegram messenger."; +} + +- (BOOL)isSocialNetworkingService +{ + return NO; +} + + +- (NSCharacterSet *)allowedCharacters{ + return [[NSCharacterSet illegalCharacterSet] invertedSet]; +} +- (NSCharacterSet *)ignoredCharacters{ + return [NSCharacterSet characterSetWithCharactersInString:@""]; +} +- (BOOL)caseSensitive{ + return NO; +} +- (AIServiceImportance)serviceImportance{ + return AIServiceSecondary; +} +- (NSImage *)defaultServiceIconOfType:(AIServiceIconType)iconType +{ + NSImage *image; + NSString *imagename; + NSSize imagesize; + + if (iconType == AIServiceIconLarge) + { + imagename = @"telegram"; + imagesize = NSMakeSize(48,48); + } else { + imagename = @"telegram16"; + imagesize = NSMakeSize(16,16); + } + + image = [NSImage imageNamed:(imagename)]; // TODO: forClass:[self class] loadLazily:YES] + [image setSize:imagesize]; + return image; +} + +@end diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5800016 --- /dev/null +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -0,0 +1,454 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410948919BB2D7D0083BF3F /* CoreFoundation.framework */; }; + C410949019BB2D7D0083BF3F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C410948E19BB2D7D0083BF3F /* InfoPlist.strings */; }; + C410949B19BB337A0083BF3F /* TelegramPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = C410949A19BB337A0083BF3F /* TelegramPlugin.m */; }; + C410949D19BB34BE0083BF3F /* Adium.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410949C19BB34BE0083BF3F /* Adium.framework */; }; + C410949F19BB36A70083BF3F /* AdiumLibpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410949E19BB36A70083BF3F /* AdiumLibpurple.framework */; }; + C4877C1819BB37EA006FA91F /* TelegramService.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1719BB37EA006FA91F /* TelegramService.m */; }; + C4877C1A19BB3D91006FA91F /* telegram-purple.c in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1919BB3D91006FA91F /* telegram-purple.c */; }; + C4877C1E19BB676B006FA91F /* AdiumTelegramAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */; }; + C4877C2419BB6D11006FA91F /* telegram.svg in Resources */ = {isa = PBXBuildFile; fileRef = C4877C1F19BB6D11006FA91F /* telegram.svg */; }; + C4877C2519BB6D11006FA91F /* telegram.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2019BB6D11006FA91F /* telegram.png */; }; + C4877C2619BB6D11006FA91F /* telegram16.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2119BB6D11006FA91F /* telegram16.png */; }; + C4877C2719BB6D11006FA91F /* telegram22.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2219BB6D11006FA91F /* telegram22.png */; }; + C4877C2819BB6D11006FA91F /* telegram48.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2319BB6D11006FA91F /* telegram48.png */; }; + C4BF98FF19BB75260038D507 /* libglib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4BF98FE19BB75250038D507 /* libglib.framework */; }; + C4BF990119BB87C00038D507 /* libpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4BF990019BB87C00038D507 /* libpurple.framework */; }; + C4BF991C19BB8B4D0038D507 /* binlog.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990419BB8B4D0038D507 /* binlog.c */; }; + C4BF991D19BB8B4D0038D507 /* loop.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990519BB8B4D0038D507 /* loop.c */; }; + C4BF991E19BB8B4D0038D507 /* msglog.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990619BB8B4D0038D507 /* msglog.c */; }; + C4BF991F19BB8B4D0038D507 /* mtproto-client.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990719BB8B4D0038D507 /* mtproto-client.c */; }; + C4BF992019BB8B4D0038D507 /* mtproto-common.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990819BB8B4D0038D507 /* mtproto-common.c */; }; + C4BF992119BB8B4D0038D507 /* net.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990919BB8B4D0038D507 /* net.c */; }; + C4BF992219BB8B4D0038D507 /* queries.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990A19BB8B4D0038D507 /* queries.c */; }; + C4BF992319BB8B4D0038D507 /* structures.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990B19BB8B4D0038D507 /* structures.c */; }; + C4BF992419BB8B4D0038D507 /* telegram.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990C19BB8B4D0038D507 /* telegram.c */; }; + C4BF992519BB8B4D0038D507 /* tools.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990D19BB8B4D0038D507 /* tools.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + C410948619BB2D7D0083BF3F /* telegram-adium.AdiumPlugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "telegram-adium.AdiumPlugin"; sourceTree = BUILT_PRODUCTS_DIR; }; + C410948919BB2D7D0083BF3F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + C410948D19BB2D7D0083BF3F /* telegram-adium-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "telegram-adium-Info.plist"; sourceTree = ""; }; + C410948F19BB2D7D0083BF3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + C410949119BB2D7D0083BF3F /* telegram-adium-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "telegram-adium-Prefix.pch"; sourceTree = ""; }; + C410949919BB337A0083BF3F /* TelegramPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramPlugin.h; sourceTree = ""; }; + C410949A19BB337A0083BF3F /* TelegramPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramPlugin.m; sourceTree = ""; }; + C410949C19BB34BE0083BF3F /* Adium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Adium.framework; sourceTree = ""; }; + C410949E19BB36A70083BF3F /* AdiumLibpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AdiumLibpurple.framework; sourceTree = ""; }; + C4877C1619BB37EA006FA91F /* TelegramService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramService.h; sourceTree = ""; }; + C4877C1719BB37EA006FA91F /* TelegramService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramService.m; sourceTree = ""; }; + C4877C1919BB3D91006FA91F /* telegram-purple.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "telegram-purple.c"; path = "../purple-plugin/telegram-purple.c"; sourceTree = ""; }; + C4877C1B19BB3DA9006FA91F /* telegram-purple.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "telegram-purple.h"; path = "../purple-plugin/telegram-purple.h"; sourceTree = ""; }; + C4877C1C19BB676B006FA91F /* AdiumTelegramAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdiumTelegramAccount.h; sourceTree = ""; }; + C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdiumTelegramAccount.m; sourceTree = ""; }; + C4877C1F19BB6D11006FA91F /* telegram.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = telegram.svg; path = "../purple-plugin/telegram.svg"; sourceTree = ""; }; + C4877C2019BB6D11006FA91F /* telegram.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram.png; path = "../purple-plugin/telegram.png"; sourceTree = ""; }; + C4877C2119BB6D11006FA91F /* telegram16.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram16.png; path = "../purple-plugin/telegram16.png"; sourceTree = ""; }; + C4877C2219BB6D11006FA91F /* telegram22.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram22.png; path = "../purple-plugin/telegram22.png"; sourceTree = ""; }; + C4877C2319BB6D11006FA91F /* telegram48.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram48.png; path = "../purple-plugin/telegram48.png"; sourceTree = ""; }; + C4BF98FE19BB75250038D507 /* libglib.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libglib.framework; sourceTree = ""; }; + C4BF990019BB87C00038D507 /* libpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libpurple.framework; sourceTree = ""; }; + C4BF990419BB8B4D0038D507 /* binlog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = binlog.c; path = ../binlog.c; sourceTree = ""; }; + C4BF990519BB8B4D0038D507 /* loop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loop.c; path = ../loop.c; sourceTree = ""; }; + C4BF990619BB8B4D0038D507 /* msglog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = msglog.c; path = ../msglog.c; sourceTree = ""; }; + C4BF990719BB8B4D0038D507 /* mtproto-client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mtproto-client.c"; path = "../mtproto-client.c"; sourceTree = ""; }; + C4BF990819BB8B4D0038D507 /* mtproto-common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mtproto-common.c"; path = "../mtproto-common.c"; sourceTree = ""; }; + C4BF990919BB8B4D0038D507 /* net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net.c; path = ../net.c; sourceTree = ""; }; + C4BF990A19BB8B4D0038D507 /* queries.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = queries.c; path = ../queries.c; sourceTree = ""; }; + C4BF990B19BB8B4D0038D507 /* structures.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = structures.c; path = ../structures.c; sourceTree = ""; }; + C4BF990C19BB8B4D0038D507 /* telegram.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = telegram.c; path = ../telegram.c; sourceTree = ""; }; + C4BF990D19BB8B4D0038D507 /* tools.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tools.c; path = ../tools.c; sourceTree = ""; }; + C4BF990E19BB8B4D0038D507 /* binlog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = binlog.h; path = ../binlog.h; sourceTree = ""; }; + C4BF990F19BB8B4D0038D507 /* constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = constants.h; path = ../constants.h; sourceTree = ""; }; + C4BF991019BB8B4D0038D507 /* include.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = include.h; path = ../include.h; sourceTree = ""; }; + C4BF991119BB8B4D0038D507 /* LICENSE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LICENSE.h; path = ../LICENSE.h; sourceTree = ""; }; + C4BF991219BB8B4D0038D507 /* loop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = loop.h; path = ../loop.h; sourceTree = ""; }; + C4BF991319BB8B4D0038D507 /* msglog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = msglog.h; path = ../msglog.h; sourceTree = ""; }; + C4BF991419BB8B4D0038D507 /* mtproto-client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mtproto-client.h"; path = "../mtproto-client.h"; sourceTree = ""; }; + C4BF991519BB8B4D0038D507 /* net.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = net.h; path = ../net.h; sourceTree = ""; }; + C4BF991619BB8B4D0038D507 /* no-preview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "no-preview.h"; path = "../no-preview.h"; sourceTree = ""; }; + C4BF991719BB8B4D0038D507 /* queries.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = queries.h; path = ../queries.h; sourceTree = ""; }; + C4BF991819BB8B4D0038D507 /* structures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = structures.h; path = ../structures.h; sourceTree = ""; }; + C4BF991919BB8B4D0038D507 /* telegram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = telegram.h; path = ../telegram.h; sourceTree = ""; }; + C4BF991A19BB8B4D0038D507 /* tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tools.h; path = ../tools.h; sourceTree = ""; }; + C4BF991B19BB8B4D0038D507 /* tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tree.h; path = ../tree.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C410948319BB2D7D0083BF3F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C410949F19BB36A70083BF3F /* AdiumLibpurple.framework in Frameworks */, + C4BF990119BB87C00038D507 /* libpurple.framework in Frameworks */, + C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */, + C4BF98FF19BB75260038D507 /* libglib.framework in Frameworks */, + C410949D19BB34BE0083BF3F /* Adium.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C410947D19BB2D7D0083BF3F = { + isa = PBXGroup; + children = ( + C4BF992619BB8B530038D507 /* telegram */, + C4BF990319BB8B200038D507 /* telegram-purple */, + C410948B19BB2D7D0083BF3F /* telegram-adium */, + C410948819BB2D7D0083BF3F /* Frameworks */, + C410948719BB2D7D0083BF3F /* Products */, + C4877C2919BB6D22006FA91F /* Resources */, + C410949919BB337A0083BF3F /* TelegramPlugin.h */, + C4877C1619BB37EA006FA91F /* TelegramService.h */, + C4877C1719BB37EA006FA91F /* TelegramService.m */, + C4877C1C19BB676B006FA91F /* AdiumTelegramAccount.h */, + C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */, + C410949A19BB337A0083BF3F /* TelegramPlugin.m */, + ); + sourceTree = ""; + }; + C410948719BB2D7D0083BF3F /* Products */ = { + isa = PBXGroup; + children = ( + C410948619BB2D7D0083BF3F /* telegram-adium.AdiumPlugin */, + ); + name = Products; + sourceTree = ""; + }; + C410948819BB2D7D0083BF3F /* Frameworks */ = { + isa = PBXGroup; + children = ( + C4BF990019BB87C00038D507 /* libpurple.framework */, + C4BF98FE19BB75250038D507 /* libglib.framework */, + C410949E19BB36A70083BF3F /* AdiumLibpurple.framework */, + C410949C19BB34BE0083BF3F /* Adium.framework */, + C410948919BB2D7D0083BF3F /* CoreFoundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + C410948B19BB2D7D0083BF3F /* telegram-adium */ = { + isa = PBXGroup; + children = ( + C410948C19BB2D7D0083BF3F /* Supporting Files */, + ); + path = "telegram-adium"; + sourceTree = ""; + }; + C410948C19BB2D7D0083BF3F /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C410948D19BB2D7D0083BF3F /* telegram-adium-Info.plist */, + C410948E19BB2D7D0083BF3F /* InfoPlist.strings */, + C410949119BB2D7D0083BF3F /* telegram-adium-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + C4877C2919BB6D22006FA91F /* Resources */ = { + isa = PBXGroup; + children = ( + C4877C1F19BB6D11006FA91F /* telegram.svg */, + C4877C2019BB6D11006FA91F /* telegram.png */, + C4877C2119BB6D11006FA91F /* telegram16.png */, + C4877C2219BB6D11006FA91F /* telegram22.png */, + C4877C2319BB6D11006FA91F /* telegram48.png */, + ); + name = Resources; + sourceTree = ""; + }; + C4BF990319BB8B200038D507 /* telegram-purple */ = { + isa = PBXGroup; + children = ( + C4877C1B19BB3DA9006FA91F /* telegram-purple.h */, + C4877C1919BB3D91006FA91F /* telegram-purple.c */, + ); + name = "telegram-purple"; + sourceTree = ""; + }; + C4BF992619BB8B530038D507 /* telegram */ = { + isa = PBXGroup; + children = ( + C4BF990419BB8B4D0038D507 /* binlog.c */, + C4BF990519BB8B4D0038D507 /* loop.c */, + C4BF990619BB8B4D0038D507 /* msglog.c */, + C4BF990719BB8B4D0038D507 /* mtproto-client.c */, + C4BF990819BB8B4D0038D507 /* mtproto-common.c */, + C4BF990919BB8B4D0038D507 /* net.c */, + C4BF990A19BB8B4D0038D507 /* queries.c */, + C4BF990B19BB8B4D0038D507 /* structures.c */, + C4BF990C19BB8B4D0038D507 /* telegram.c */, + C4BF990D19BB8B4D0038D507 /* tools.c */, + C4BF990E19BB8B4D0038D507 /* binlog.h */, + C4BF990F19BB8B4D0038D507 /* constants.h */, + C4BF991019BB8B4D0038D507 /* include.h */, + C4BF991119BB8B4D0038D507 /* LICENSE.h */, + C4BF991219BB8B4D0038D507 /* loop.h */, + C4BF991319BB8B4D0038D507 /* msglog.h */, + C4BF991419BB8B4D0038D507 /* mtproto-client.h */, + C4BF991519BB8B4D0038D507 /* net.h */, + C4BF991619BB8B4D0038D507 /* no-preview.h */, + C4BF991719BB8B4D0038D507 /* queries.h */, + C4BF991819BB8B4D0038D507 /* structures.h */, + C4BF991919BB8B4D0038D507 /* telegram.h */, + C4BF991A19BB8B4D0038D507 /* tools.h */, + C4BF991B19BB8B4D0038D507 /* tree.h */, + ); + name = telegram; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C410948519BB2D7D0083BF3F /* telegram-adium */ = { + isa = PBXNativeTarget; + buildConfigurationList = C410949419BB2D7D0083BF3F /* Build configuration list for PBXNativeTarget "telegram-adium" */; + buildPhases = ( + C410948219BB2D7D0083BF3F /* Sources */, + C410948319BB2D7D0083BF3F /* Frameworks */, + C410948419BB2D7D0083BF3F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "telegram-adium"; + productName = "telegram-adium"; + productReference = C410948619BB2D7D0083BF3F /* telegram-adium.AdiumPlugin */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C410947E19BB2D7D0083BF3F /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0510; + ORGANIZATIONNAME = "Matthias Jentsch"; + }; + buildConfigurationList = C410948119BB2D7D0083BF3F /* Build configuration list for PBXProject "telegram-adium" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C410947D19BB2D7D0083BF3F; + productRefGroup = C410948719BB2D7D0083BF3F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C410948519BB2D7D0083BF3F /* telegram-adium */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + C410948419BB2D7D0083BF3F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C410949019BB2D7D0083BF3F /* InfoPlist.strings in Resources */, + C4877C2619BB6D11006FA91F /* telegram16.png in Resources */, + C4877C2519BB6D11006FA91F /* telegram.png in Resources */, + C4877C2419BB6D11006FA91F /* telegram.svg in Resources */, + C4877C2819BB6D11006FA91F /* telegram48.png in Resources */, + C4877C2719BB6D11006FA91F /* telegram22.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C410948219BB2D7D0083BF3F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C4BF992219BB8B4D0038D507 /* queries.c in Sources */, + C4BF991C19BB8B4D0038D507 /* binlog.c in Sources */, + C4877C1819BB37EA006FA91F /* TelegramService.m in Sources */, + C4BF992519BB8B4D0038D507 /* tools.c in Sources */, + C4BF991F19BB8B4D0038D507 /* mtproto-client.c in Sources */, + C4877C1A19BB3D91006FA91F /* telegram-purple.c in Sources */, + C4BF992319BB8B4D0038D507 /* structures.c in Sources */, + C4BF992019BB8B4D0038D507 /* mtproto-common.c in Sources */, + C4BF992419BB8B4D0038D507 /* telegram.c in Sources */, + C4BF991D19BB8B4D0038D507 /* loop.c in Sources */, + C410949B19BB337A0083BF3F /* TelegramPlugin.m in Sources */, + C4877C1E19BB676B006FA91F /* AdiumTelegramAccount.m in Sources */, + C4BF991E19BB8B4D0038D507 /* msglog.c in Sources */, + C4BF992119BB8B4D0038D507 /* net.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + C410948E19BB2D7D0083BF3F /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + C410948F19BB2D7D0083BF3F /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C410949219BB2D7D0083BF3F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + C410949319BB2D7D0083BF3F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + SDKROOT = macosx; + }; + name = Release; + }; + C410949519BB2D7D0083BF3F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "telegram-adium/telegram-adium-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/libglib.framework/Headers/", + "$(PROJECT_DIR)/libpurple.framework/Headers/", + "$(PROJECT_DIR)/..", + ); + INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; + INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = AdiumPlugin; + }; + name = Debug; + }; + C410949619BB2D7D0083BF3F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + "FRAMEWORK_SEARCH_PATHS[arch=*]" = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "telegram-adium/telegram-adium-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/Frameworks/libglib.framework/Headers/", + "$(PROJECT_DIR)/libpurple.framework/Headers/", + "$(PROJECT_DIR)/..", + ); + INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; + INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = AdiumPlugin; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C410948119BB2D7D0083BF3F /* Build configuration list for PBXProject "telegram-adium" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C410949219BB2D7D0083BF3F /* Debug */, + C410949319BB2D7D0083BF3F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C410949419BB2D7D0083BF3F /* Build configuration list for PBXNativeTarget "telegram-adium" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C410949519BB2D7D0083BF3F /* Debug */, + C410949619BB2D7D0083BF3F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C410947E19BB2D7D0083BF3F /* Project object */; +} diff --git a/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..595620b --- /dev/null +++ b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout new file mode 100644 index 0000000..790fe0a --- /dev/null +++ b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 1C5A3335-4726-410A-8E70-801C8879E269 + IDESourceControlProjectName + telegram-adium + IDESourceControlProjectOriginsDictionary + + 075EDEE1-AF43-4A9A-8B99-96488680535F + ssh://bitbucket.org/telegrampurple/telegram-purple.git + + IDESourceControlProjectPath + telegram-adium/telegram-adium.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 075EDEE1-AF43-4A9A-8B99-96488680535F + ../../.. + + IDESourceControlProjectURL + ssh://bitbucket.org/telegrampurple/telegram-purple.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + 075EDEE1-AF43-4A9A-8B99-96488680535F + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 075EDEE1-AF43-4A9A-8B99-96488680535F + IDESourceControlWCCName + telegram-purple + + + + diff --git a/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..a04539bfbc9a47c08a71a9394f0ac6275bc142b2 GIT binary patch literal 42507 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 SXwl-o``(=Y?*HHP;r|5_VqSCr literal 0 HcmV?d00001 diff --git a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..833b1a9 --- /dev/null +++ b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,37 @@ + + + + + + + + + + + + + diff --git a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme new file mode 100644 index 0000000..8b109a8 --- /dev/null +++ b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/xcschememanagement.plist b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..6742db5 --- /dev/null +++ b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + telegram-adium.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + C410948519BB2D7D0083BF3F + + primary + + + + + diff --git a/telegram-adium/telegram-adium/en.lproj/InfoPlist.strings b/telegram-adium/telegram-adium/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/telegram-adium/telegram-adium/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/telegram-adium/telegram-adium/telegram-adium-Info.plist b/telegram-adium/telegram-adium/telegram-adium-Info.plist new file mode 100644 index 0000000..5f9b01b --- /dev/null +++ b/telegram-adium/telegram-adium/telegram-adium-Info.plist @@ -0,0 +1,48 @@ + + + + + AIMinimumAdiumVersionRequirement + 1.4 + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + org.telegram-purple.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + AdIM + CFBundleVersion + 1 + CFPlugInDynamicRegisterFunction + + CFPlugInDynamicRegistration + NO + CFPlugInFactories + + 00000000-0000-0000-0000-000000000000 + MyFactoryFunction + + CFPlugInTypes + + 00000000-0000-0000-0000-000000000000 + + 00000000-0000-0000-0000-000000000000 + + + CFPlugInUnloadFunction + + NSHumanReadableCopyright + Copyright © 2014 Matthias Jentsch. All rights reserved. + + diff --git a/telegram-adium/telegram-adium/telegram-adium-Prefix.pch b/telegram-adium/telegram-adium/telegram-adium-Prefix.pch new file mode 100644 index 0000000..6f065c1 --- /dev/null +++ b/telegram-adium/telegram-adium/telegram-adium-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#ifdef __OBJC__ + #import + #import +#endif + +#ifndef __ADIUM_ + #define __ADIUM_ +#endif \ No newline at end of file From d3d8903b49ba930159005822a04a272f3cbe641c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 6 Sep 2014 21:04:34 +0200 Subject: [PATCH 421/465] Add a nicer description --- purple-plugin/telegram-purple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 7e51fe0..e3cc4ab 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -1272,7 +1272,7 @@ static PurplePluginInfo plugin_info = { "Telegram", "0.1", "Telegram protocol", - "Adds support for the telegram protocol to libpurple.", + "Support for the protocol of the Telegram messenger.", "Christopher Althaus , Markus Endres , Matthias Jentsch ", "https://bitbucket.org/telegrampurple/telegram-purple", NULL, // on load From f58302be5ef5b2b6bd1dc7e05d56a2b2793a79c4 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 6 Sep 2014 21:07:41 +0200 Subject: [PATCH 422/465] Ignore XCode xcuserstate file and remove it from cache --- .gitignore | 1 + .../UserInterfaceState.xcuserstate | Bin 42507 -> 0 bytes 2 files changed, 1 insertion(+) delete mode 100644 telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/.gitignore b/.gitignore index 293b9fa..76e328d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ app-hash.png .gdbinit core core* +telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index a04539bfbc9a47c08a71a9394f0ac6275bc142b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42507 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 SXwl-o``(=Y?*HHP;r|5_VqSCr From f16f32d8c4cc7b208393ba17b5e6e493ee4cc84b Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 6 Sep 2014 21:33:46 +0200 Subject: [PATCH 423/465] Rename struct user to struct tgl_user to avoid namespace collisions with osx system headers --- binlog.c | 20 ++++++++++---------- binlog.h | 18 +++++++++--------- mtproto-client.c | 4 ++-- queries.c | 10 +++++----- structures.c | 12 ++++++------ structures.h | 12 ++++++------ telegram.h | 2 +- 7 files changed, 39 insertions(+), 39 deletions(-) diff --git a/binlog.c b/binlog.c index 214c284..e49e655 100644 --- a/binlog.c +++ b/binlog.c @@ -273,7 +273,7 @@ void replay_log_event (struct telegram *instance) { } else { assert (!(_U->flags & FLAG_CREATED)); } - struct user *U = (void *)_U; + struct tgl_user *U = (void *)_U; U->flags |= FLAG_CREATED; if (get_peer_id (id) == instance->our_id) { U->flags |= FLAG_USER_SELF; @@ -1114,7 +1114,7 @@ void bl_do_new_user (struct binlog *bl, struct mtproto_connection *self, int id, add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct user *U) { +void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U) { if (U->flags & FLAG_DELETED) { return; } int *ev = alloc_log_event (bl, 8); ev[0] = CODE_binlog_user_delete; @@ -1122,7 +1122,7 @@ void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, stru add_log_event (bl, self, ev, 8); } -void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, +void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long photo_id, struct file_location *big, struct file_location *small) { if (photo_id == U->photo_id) { return; } if (!photo_id) { @@ -1169,7 +1169,7 @@ void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection } } -void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, +void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll) { if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) && (U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) { @@ -1183,7 +1183,7 @@ void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, st add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long access_token) { +void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long access_token) { if (U->access_hash == access_token) { return; } int *ev = alloc_log_event (bl, 16); ev[0] = CODE_binlog_set_user_access_token; @@ -1192,7 +1192,7 @@ void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection * add_log_event (bl, self, ev, 16); } -void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct user *U, +void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *p, int pl) { if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) { return; @@ -1204,7 +1204,7 @@ const char *p, int pl) { add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); } -void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct user *U, int friend) { +void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int friend) { if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; } int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_set_user_friend; @@ -1242,7 +1242,7 @@ void bl_do_set_working_dc (struct binlog *bl, struct mtproto_connection *self, i add_log_event (bl, self, ev, 8); } -void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, const int *start, int len) { +void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const int *start, int len) { if (U->photo.id == *(long long *)(start + 1)) { return; } int *ev = alloc_log_event (bl, len + 8); ev[0] = CODE_binlog_user_full_photo; @@ -1251,7 +1251,7 @@ void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *se add_log_event (bl, self, ev, len + 8); } -void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct user *U, int blocked) { +void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int blocked) { if (U->blocked == blocked) { return; } int *ev = alloc_log_event (bl, 12); ev[0] = CODE_binlog_user_blocked; @@ -1260,7 +1260,7 @@ void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, add_log_event (bl, self, ev, 12); } -void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll) { +void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll) { if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) && (U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) { return; diff --git a/binlog.h b/binlog.h index 1f6b1ed..ac4b7b1 100644 --- a/binlog.h +++ b/binlog.h @@ -93,15 +93,15 @@ void bl_do_dc_option (struct binlog *bl, struct mtproto_connection *self, int id void bl_do_set_our_id (struct binlog *bl, struct mtproto_connection *self, int id); void bl_do_new_user (struct binlog *bl, struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); -void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct user *U); -void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long photo_id, struct file_location *big, struct file_location *small); -void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); -void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct user *U, long long access_token); -void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *p, int pl); -void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct user *U, int friend); -void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct user *U, const int *start, int len); -void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct user *U, int blocked); -void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct user *U, const char *f, int fl, const char *l, int ll); +void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U); +void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long photo_id, struct file_location *big, struct file_location *small); +void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll); +void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long access_token); +void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *p, int pl); +void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int friend); +void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const int *start, int len); +void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int blocked); +void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll); void bl_do_encr_chat_delete (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U); void bl_do_encr_chat_requested (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); diff --git a/mtproto-client.c b/mtproto-client.c index 4dd20f5..30c6a11 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -806,7 +806,7 @@ void work_update_binlog (struct mtproto_connection *self) { peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *UC = user_chat_get (bl, user_id); if (UC) { - struct user *U = &UC->user; + struct tgl_user *U = &UC->user; if (U->first_name) { tfree_str (U->first_name); } if (U->last_name) { tfree_str (U->last_name); } if (U->print_name) { @@ -829,7 +829,7 @@ void work_update_binlog (struct mtproto_connection *self) { peer_t *UC = user_chat_get (bl, user_id); fetch_date (self); if (UC) { - struct user *U = &UC->user; + struct tgl_user *U = &UC->user; unsigned y = fetch_int (self); if (y == CODE_user_profile_photo_empty) { diff --git a/queries.c b/queries.c index 3d83789..63a57fe 100644 --- a/queries.c +++ b/queries.c @@ -835,7 +835,7 @@ int msg_send_on_answer (struct query *q UU) { if (b == CODE_contacts_foreign_link_requested) { fetch_bool (mtp); } - struct user *U = fetch_alloc_user (mtp); + struct tgl_user *U = fetch_alloc_user (mtp); U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); if (a == CODE_contacts_my_link_contact) { @@ -1760,7 +1760,7 @@ void do_get_chat_info (struct telegram *instance, peer_id_t id) { /* {{{ User info */ -void print_user_info (struct user *U) { +void print_user_info (struct tgl_user *U) { // TODO: use peer peer_t *C UU = (void *)U; @@ -1790,7 +1790,7 @@ int user_info_on_answer (struct query *q UU) { struct mtproto_connection *mtp = query_get_mtproto(q); struct show_info_extra *extra = q->extra; - struct user *U = fetch_alloc_user_full (mtp); + struct tgl_user *U = fetch_alloc_user_full (mtp); event_user_info_received_handler (mtp->instance, U, extra->show_info); tfree (extra, sizeof(struct show_info_extra)); //print_user_info (U); @@ -2233,7 +2233,7 @@ int add_contact_on_answer (struct query *q UU) { assert (fetch_int (mtp) == CODE_vector); n = fetch_int (mtp); for (i = 0; i < n ; i++) { - struct user *U = fetch_alloc_user (mtp); + struct tgl_user *U = fetch_alloc_user (mtp); //print_start (); //push_color (COLOR_YELLOW); debug ("User #%d: ", get_peer_id (U->id)); @@ -2337,7 +2337,7 @@ int contacts_search_on_answer (struct query *q UU) { //print_start (); //push_color (COLOR_YELLOW); for (i = 0; i < n; i++) { - struct user *U = fetch_alloc_user (mtp); + struct tgl_user *U = fetch_alloc_user (mtp); debug ("User "); //push_color (COLOR_RED); debug ("%s %s", U->first_name, U->last_name); diff --git a/structures.c b/structures.c index d7feadb..ed30181 100644 --- a/structures.c +++ b/structures.c @@ -164,7 +164,7 @@ char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const * */ -long long fetch_user_photo (struct mtproto_connection *mtp, struct user *U) { +long long fetch_user_photo (struct mtproto_connection *mtp, struct tgl_user *U) { unsigned x = fetch_int (mtp); code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); if (x == CODE_user_profile_photo_empty) { @@ -199,7 +199,7 @@ int user_get_alias(peer_t *user, char *buffer, int maxlen) } } -int fetch_user (struct mtproto_connection *mtp, struct user *U) { +int fetch_user (struct mtproto_connection *mtp, struct tgl_user *U) { struct telegram *instance = mtp->instance; unsigned x = fetch_int (mtp); @@ -408,7 +408,7 @@ void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U } void fetch_notify_settings (struct mtproto_connection *mtp); -void fetch_user_full (struct mtproto_connection *mtp, struct user *U) { +void fetch_user_full (struct mtproto_connection *mtp, struct tgl_user *U) { assert (fetch_int (mtp) == CODE_user_full); fetch_alloc_user (mtp); unsigned x; @@ -1522,7 +1522,7 @@ static int id_cmp (struct message *M1, struct message *M2) { else { return 0; } } -struct user *fetch_alloc_user (struct mtproto_connection *mtp) { +struct tgl_user *fetch_alloc_user (struct mtproto_connection *mtp) { struct binlog *bl = mtp->instance->bl; debug("fetch_alloc_user()\n"); @@ -1587,7 +1587,7 @@ void insert_chat (struct binlog *bl, peer_t *P) { bl->Peers[bl->peer_num ++] = P; } -struct user *fetch_alloc_user_full (struct mtproto_connection *mtp) { +struct tgl_user *fetch_alloc_user_full (struct mtproto_connection *mtp) { struct binlog *bl = mtp->bl; int data[3]; prefetch_data (mtp, data, 12); @@ -1607,7 +1607,7 @@ struct user *fetch_alloc_user_full (struct mtproto_connection *mtp) { } } -void free_user (struct user *U) { +void free_user (struct tgl_user *U) { if (U->first_name) { tfree_str (U->first_name); } if (U->last_name) { tfree_str (U->last_name); } if (U->print_name) { tfree_str (U->print_name); } diff --git a/structures.h b/structures.h index 00bef50..cc4ce08 100644 --- a/structures.h +++ b/structures.h @@ -142,7 +142,7 @@ struct user_status { int when; }; -struct user { +struct tgl_user { peer_id_t id; int flags; struct message *last; @@ -229,7 +229,7 @@ typedef union peer { struct file_location photo_small; struct photo photo; }; - struct user user; + struct tgl_user user; struct chat chat; struct secret_chat encr_chat; } peer_t; @@ -337,9 +337,9 @@ struct message { int fetch_file_location (struct mtproto_connection *mtp, struct file_location *loc); int fetch_user_status (struct mtproto_connection *mtp, struct user_status *S); -int fetch_user (struct mtproto_connection *mtp, struct user *U); -struct user *fetch_alloc_user (struct mtproto_connection *mtp); -struct user *fetch_alloc_user_full (struct mtproto_connection *mtp); +int fetch_user (struct mtproto_connection *mtp, struct tgl_user *U); +struct tgl_user *fetch_alloc_user (struct mtproto_connection *mtp); +struct tgl_user *fetch_alloc_user_full (struct mtproto_connection *mtp); struct chat *fetch_alloc_chat (struct mtproto_connection *mtp); struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp); struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp); @@ -358,7 +358,7 @@ void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct messa void fetch_message_action (struct mtproto_connection *mtp, struct message_action *M); void message_insert_tree (struct message *M); -void free_user (struct user *U); +void free_user (struct tgl_user *U); void free_chat (struct chat *U); char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); diff --git a/telegram.h b/telegram.h index 736f11e..9e14021 100644 --- a/telegram.h +++ b/telegram.h @@ -251,7 +251,7 @@ struct telegram { long long cur_downloading_bytes; long long cur_downloaded_bytes; int our_id; - struct user User; + struct tgl_user User; BN_CTX *ctx; int encr_root; unsigned char *encr_prime; From de826544345a5aa7b94885fd6ea3ac1f5f8502c8 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 7 Sep 2014 00:54:47 +0200 Subject: [PATCH 424/465] Ignore more XCode userdata --- .gitignore | 1 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 37 ------------------- 2 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist diff --git a/.gitignore b/.gitignore index 76e328d..851e8a3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ app-hash.png core core* telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate +telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad diff --git a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index 833b1a9..0000000 --- a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - From c5d7fdb89cc30eba7a647e23f7356380b2d49852 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 7 Sep 2014 00:57:42 +0200 Subject: [PATCH 425/465] Fix build process by adjusting search path and adding missing libraries Add openssl and libz, don't warn about deprecated functions and add purple and glib to the search path so we don't need to change the includes in our other files --- telegram-adium/libcrypto.a | Bin 0 -> 3455640 bytes .../telegram-adium.xcodeproj/project.pbxproj | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 telegram-adium/libcrypto.a diff --git a/telegram-adium/libcrypto.a b/telegram-adium/libcrypto.a new file mode 100644 index 0000000000000000000000000000000000000000..234df55380da0e03e73e02322692a5ec8d31b08d GIT binary patch literal 3455640 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ℜ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�e2qhbDx#`!b+G*lisPaR=~$48j!8Aeb%<}{JvWCR&WMv(vslBLMf zWDFTg#*y)40tu0cWD;41OeW1_Su%x$$yBl&S)NQIE07h*N+d$26I=6{WMwjotU_j! zC|Q-PMph?lkTuC#WDbduwaGeUU9ujTOV%eFkT~If@ysI|k&VeFWK*&kNs!IS7Gz7Z z71^3>L$)PJvK`r;yOsOU%l+r&{_}GGdAaYr+;stlZm-dX`jQ&!XztTP=?(=VhUxJl(*wpD90g zx_>#cJmF$~F6IB-i9FZwKDEC32HZPrKHHA%dX6o>4X8}91Krf()61}4b-j8QGEVOm z$FYODESKelcwF_Jr?>iM-dlYu@2$R(_XhNgTUUKjud6<(*Hxd?c{e)qG~fK0^Jm(- zT6 zv3#Te+6}O=?S>d_N7ZOMAV%B!Fxsw%(e^uxW4S53!{w~e&L-Pgvz;~BncvQqwX-R9 z7Phmgb~fD3mb0_v?aXIq4R$u(&L-HI*UswfY_y$)>};Z)O|r9P?5y6-f_Ao)olUc| z73^$9J6nl6*ypvgdOPDD_xc*_jE%wTYqT@Joi*9na621eXCpcM;%RA~+S0t%j0OIM zS8d7bKQH}*ll4QBzWN(hZK(G)dBt(!bg?==r18pPy*NSSh)z>W^W>K1<{1knExc;u z$~kW+$|K%TR5(nmykX#J;rzRJet)8^?b@9^d`@wZ1wD|h!gQLDK z^3t$+&zu=&*7J^pv!?P?efiv1KCd*x%hO}Z=VQy~hkrv856 zQMDxI`Q(jrcn$LGvskrGwq8wSg<2Bx>^?JZ6^G}SH^<@GvMh0jH(cK44sQhW?QdfL zzEkUDpIx%QiTxXOt&{y7>~CWKc2w&WV5WKYIiOl6`z)Gy_L;p}C;QBmd3)B9m}j3; zGjDH)XP;j)&pyvp>okU$wr$O?B{6R-vA^-b4$rnv`}-c{@a!|#=AGp5CdjjYldE+K zG1Hc3pHZlFn#fG^uBat3Z<4&C!&`>=cE8-}@Fp|guGc>ER_kPsTYC&YR7+ysvhwWn zE45Bjm}$#V zmc+bS#MbXihv#}ds9t|e+3TrYuYH!S*2zBOXDxIx`y7@1-BJ$E zK3`>C+TpE-vm~dvOCsT{zl7cfOX$V%Y`f1mZpVf=c0V8L@aAcG_PMfJr;X&D=qt;v0vX@58SOk}Ooe#|t_KL1$jv_CV=v(H=pPn>MO$d+fHzpQo2Fw>q- z?emtkP6sm6mS>-vtaUnwndaH&C~KV#W~O=e8OmCxLzrpXseQJy*6Gk%GZ&e6*do)l zCJ(PQbCG%W*=t)r`^;yp(-F+H_b>At-jTHyvdBE!Pqn|BeHOOX>1bx!_1foKYn_f^ zrY+AtC;LBfI*x_du^RilYpqk3ndSFk4)6F{3t42|35!hEnmn=A%thwee!krf`@D3m z)5**nK@M|xr{LIjf4svx700gkB!`#7vA^%>4(~J^yPwZ-c&E#|$l)!JccsHSL*Dfc z?@W2OI=r*+>=@hK4)1Jv4?Dazc~3dKbL73`@XnR@hQm7#&z?8_=I|Ec*!J>?!#iKz zXAbWId0#lZ3-Rpv;NK1}k7Iw2?;PGm@_cqXAyes9|e^*@Vbd@~&Zv$$bu9j!t z*HG(p4Kr;!wf~Nw*6BCQH19NrcP)|csJuM$>|m(yS=YCme(%tO^0`@ybm1SZSp>Kc(>!( z-|cIMcZZf&ev{Aiubu8>hApbeb_Qyke#boXMmoH^aO`z;w8JaO8}IP$#>2JI=tWGEy?MAB-;g@>sa0cICej;@9;Ws>~&^ChxZ_ky&u}t;XQ<7 z_w!Z`?_qg6I=n~l>~XZa!}|k{ZO{8Vyhr67?(iOycf7;vl()d)JudHjhxdfMD;(Y* zDK6QA1k~iS+o|ji| z50V~T55Uc73Y{?0t}#yh+ZXAIV$U z;q}RzZr@XBl-pBG%4(}6r`#QW&Dt|ujKH)lJ~H~`?tKO9p2aSUUqoj$a~A-4aob*;e9Lb3y1feydNFj_wxMq zCcnn%2jN(O&A6@K1`f}QXYY%*aCr9JHKuIu@a%hQ zOxeZZ`Q)V?o_%kQDf1nkeLs;YhdI1PdB-?Bzr2$io_%h^lm!mYzK_Y2a~+<2|Bopb zIlPhb3Jz}+p8b8Vb9nZBMCRS%@a(&b%)86s1?4^9@RpMIn8UNrz1a0WC8z=8whc{l{M-Fd-yw4n7NZvONZ=$^aIJ`;n8tqQ3ak9@1nKIhpO_n#o;Wf*f z;_#N0x01t~B5$_C3(K41@TSV!z~L6>6Z%e%$lZ6oh4hqtY~2OM5f-eV5WKDTSz%QFsddwDN8ydC7d?(lY$_pZZh zk@u0q+ezMM4sU09-#9$`oU+|7|8aP`$ZNEJWTX(q zHCFwcr&2}s=EpLv)+gsiS4sRcMn>oCF!`olpUJma7dGj6Ke0hgE zyo|i#9NvNQPIY(($vfNO9W3uchj)m)D;(aTc=iyw&fy&c*n{6*5PIG?4Q8u>>yT+)A4wANPd{Z zI|0u=iZsIEoruT(J)<1nNm^dO;hl_U|K1&Rc&Fgm?H%LrPL(&o;pOBlxDZp55N#9o|LqPI7n`%RANK zT_W#vhj%I7lAJEXv+eIp$MP=6vqNy_I=n07UF7fz@(K>`N<91fUgz+xl6Q;4yIS5| z4(}Ry4>-Kv$a~D;T`TVyhj*R4mmFRZ&;A~-JG|@h>~Zvt!@EJ=M-K0|^736jl+9Y-pvm0FY-zb?=^W3IlR~9J?Zdz|dtcsa4)1UB)^m6t$lKK6{as$t z;e9A?SBLkJy!{+rpS;5y-aq7J9o|3Xo$l~HmbcL1eIoC2hxe(xqQm=_yxSb!XY%fI zc>VGob$Fl4>vDKs$a}@%eJSrPhxe7d4;|jW<@GzfujPH`@V>#b_ou$mwIAmLc(&i& z=y%TiW4$k7w`iLk{l;c~czTk9c-_S9Ewk$(!!*Sk#i8IM`{&J6Cor z&x>U1w~E8F?~O2TRfktEZw-fMzgcC=o8$28dnn9X$Kl!UWtlhE;n{CB+3~fw!?WLV zGH+vtXTSSoUc%wo??jommBX{&jWRFk@a%V`%-hl7*>6vomvVUaeH!NN?(jy-OFKOK z?Jry2ehzObc^QXi-{WD+JH+AH?`xUY>hSEhxy(D-;n{C>nU{5V_I)4bo#gQBx6#bY zIXwIQH1p1IcoXHdIXwGaG+W+6hiAW+W?tUm+4qr{cd5g(-+nW%;PC9X;mo_n;o0|= zm{)XoVR<(?Jo`;KTVA`vv+qGM?+%A&zei_Y$>G^=)|q#o!?WMDGq1zp*>BgG_lU!@ z?`biw)8W}~;FBxiaCisEd&J?*m)Gg=?0e1Z@A0I=J5XMi!#hac^A7J| zdEE~05P7dUyhG*nI6V7)HoLuVIlRN=^*X#(JUf2%fx|mO-aj1Pk@EiK@Q#xArNcW~ z-hjh9M&6GO?^t9R)yonC)M0ryjo_+tGZ7(Z0 zyp!ckcX+4Bo8|CMmA9(H%gI~Q;hiRLZHIR{o^8)_9o_;w`@FzBhj#{^eO_P-hj%94 zlAO+3Lho!m4z+rAa9nR2o_$_mM~8QgygeP>xl6cy=PjYPa0$Khm(aUl3B3!K(918O zchM4h7cZfA$r5^(;@R=yjN|WinY@D?-sO1q?*@lCyeshR@o|j9E66+9;aw^3Oow+B zp55N_9p2SiUf$tdgJ+N5g2Vfbyz3p_weoIrc-P6h*WnfAJ>u}Lm-m#zyFuQI4)3?} zUUzsm;@R_1ufw|u&;D-jIlP%_D7Yj-%j$K~Da@Sc!&zr*{ZyoVj$lkz$p-c$0Pa(GY6d(PoKBkv`L z*Cp>&hxe?!Hyqw`^4@WHf0Fk%hxfd^K8N>$yiXn8i}Jp3crVHO#^H6#`@!M8EYCZp z#*;m>UXeG<;r&_O2#5Eoyr9GTi@b3T?=^Xo9Nz2lrZ~JFdD9%;8}g<*yuZp@#o@gv zZ*_s z_IG$6$~(y6eI)O2hu0_XXovR?dB;1vf8yEkl2aVs$9VRB_jHH%iM%r%-lup=a{AX2 zdY|Fhf3nl&xZZwwmpHu777M<=OG#@BW9Dx1`tW=X&k_EB{bzjSDr&^N+0|F>AQIpu-y> zFXZq>$_qQZQSu@V&wf|K_T!@tZ?wF%9bQn^JI~=QC2tFdw=|wT?{4q##>m^l;f=+! z+naHCD|aZ&`T{I=m_J9(QR}Y(M^U zhqt1y58>{UPPXE99LfBG+kb!!9EZ0$o;`2Ob$DyY+t}f)DQ`=MXTN)7*So#Lnyv+9V+{~ zUFY!T$-CL%Z6xnbhqtl3`yAdT@*Z}0o638_;cX`GS%;U9*X{5&m-o8E+d|$u4sT0& ze|LEHyI}Tr`^4dGE$>T*w~f5-9NxC_yyLm@8mFW@zr))O&)&a`c6i&%o8a(vkT=EQ z?I>?0hu0!+w!_;=-W-SL`kl7wU7BKf_I_gn$MSZ;jLp7M5gczem)%i*Qv?c?zFmbbsd+eco;;q5E$V28J#yu%#c{_>7+cn8Qk z+TqQYcbvn^$UDK|9VqW)hj);?oWna<-U5erh`h5L-l6i&ad?NxTj=l(mv^DVYn6Ag z!#hIWWe)F1c?E}el)S4Q-qG@|b$G|fyWZg)EAK{!cbvRi9G?BIB>(r^=J1Y}cc;TU zL0-w>oha{Khj)^^`yJlNcy`?4L5Ft=-jbY7#k1FiCmqYn$$P=!ohI)!hj+TXcOBjW zd3_G=40)eByffu}=kU&wS3jZly?C~~kq)m7Z%Iz)ETMPq5_;$1+4eHdv3?8Xg&p4c z@@6``3-IjUXV!9f7vkCWw~oWh%iGA|U4*wJr;C@+yJQKyOPA2QYze)~m(aTc&+fmi ze&v3dTDddqqhbGbifWXt@E7w-nyN zKWsZooa}jQaq~<1KHAT47B|0W4@yq`WO4JW-&3{{2c;G_zxp|smAU*>Pu(xqU!Rk> z`q!4PfBy*l%Iz!a53|*;-2eT0{TmUk&$O5Wht6fMTH-*S!1v+cips(SP66|J&h1mc?XbV^NN#s^dG>fH zpQ_8-VnO4=Vdpno;In7a%5vAk&p%zcfAsiR?CstUFY-*q)8k~Z-a@=id3wD3!n5_X z?*L47RhDOuoARl;o?HL-dYW(FS(JLV;@jiszx?Dc{juEkj^``BJ+A)CU(E71#?QV` z@$GTu@{h)ky;$+>ara;T&(_DbFZ;}G?A3~Ix2Jrn-rkKC`0O>%di!iuT%J81%crWh znDw@Q3ogmG$EVA;W7qk=RMx{Dum9!$Y`txLY+t+ddd0WLZ~0VXeeAtKuBYPL@QgJYakqhT-QSk7o+}Q0(D(WNF5aLY{J)e-DF< z?}YqT?W`N%yFSmXb739hEcD?WF75$C^z-0Sa7}2-nWWy{SB|HD3QlP7%(eI5!x-EC z&POcQjz^4R{4Gxm#{0#!MEiG?v0UyoXqS5w+H!h%{gVSc-{_rng~s;Z zk=pXNfg|Ww*LV^f#rP-wJNuFF8))7o(9if|zJJNCzX0v;a0;~hFD-5dZM`;!<}Cx4 zgFWbKC_dy!q9niKj`yCZq&SlWY_ylO)_R!X2w)iarTR;2# zBI|GGj8$wt3EK5;3GI4Uh5WzydlqW`7tqEf$f`7-2F*`G^Z&r}mpz{LfadK4xyt6X zpn1*Ey!UvYW4HSm$VHoP6)%D29R|%yLtD-^B9GDX<+#n|%kfw#^A%{9yA#^wiqI~1 zfoQ*PZr3*t+VxEnmxgw^PkHXJ%k@IL+>4^Uy4n41uMmP;>GY*M<^#cn%o`>lB;e)Ujn%@mO7(dK=$G8XboDk@Mcfb<7 z9TuT^d3YP+HZiL{18=2Ii%Ioy*iIi4BkDu&7W$y*QQv>A$8$4%pV$NKdb{9F^qpc! zeG%SBUl7~WXW?(@Tg9~cB)ow>A;#24;Pv!jF{s`Hd2S30oKs;RwDswM*U@*2o$5>Q zTKaaepuP?MhCU~@s!zjf=u=`seGFbr9~HyugYYVPzc|oVS)V?5C4H~ht-cc$=sU!A z^#ynZeO}C|Z-tlBXT+5H1iXwsE=JXd;idE;(XW2sY>(#>`hKw&+WpoIFQ)GjJJh$s zi|C7DUVRSc>9b-+eF|PkpA_Tjqmb9IKtv3w_rvq)Jz_sksJ1@6a3Ot<*rmP$o=0C2 zi|X_6T>3UKt3CtIp-+oR^>Nrn9}^?$L-1_+AUq3t)c2psZ%#1ogJ-}VSl<5O0>+*2 zbXbI^!2-;|HfUZJp31lto&wYAlkjB533w8WsgJ-D8HeEsFsR-Gk7qn^2K#2P58Cp3 z;Bkz*;jyq&eF+}JxE&r13+mh8QH*n9tNJuNl0GFS)W_fv^ieUaJ_tEh6!41!3o7f= z2M?$36}#1U!o%o0#CG)scqn~d%&BjMhtOxll==ibm_9B>)ra9h^dZr&e&BSE=Ro>? zu@~C?)(tcCU1Ep&b~vBDDCX7Y-~semF{3^O_oq*aarIHSAALj&srSQu={;iqX_fWq zh5OL=h+XPC;NJ8lv8X-|)AVg(R(%HUMV}Uv>f>-v`j{9|AA)<(2Stzi{v7+e^nGFv zEN}O4H~LPoq`nAur7wtW>a%bc`c^TmJ_%Fw2{EQV0(Yhli$V1sxD)*VZ@7$ou)O`l z7RKFhN7$*p1b1NE4!4H|^=)uF#yOaTt?JWoTgEB44UEC9VN?u5yS^aYirx>mgafBk z`aZY?<6gKq>{j0i6O23HX0Tm-0dC4T4>y51^{sGY#u>N~OsP-6d5q(5Ll{*bhH=Ir zxB>L5A2`|LS)Xyg*bB?sJ)BG5C3dK9hwIT7#k~3)T$es8X4I$PI`l~~u09IarjLjr z^?n$m_lW%`Ro15$&Y|xSyVQ5UwdhM?QGFh+N#7=B)o0)u^l34vJ`Pu>kBJfWA-EcS zQ1qzpKaua&rSB7aV0pWTQTk4?q`nAe(-*`x^;x(IeXE#OpMPv7seLIZ6g8DYN662iMsy+=@q))*WU_yNiPGcN}%fqnx zAY6{IA5Mh>$5+;;4~7}{!YQy@eJ5O&aR+RM?dl6~GUGg42Ikba!byxXa3V~pPrwl4 zIGg}`+2Ja0&u~2BE;tV6)#u>#7-SrQqhUzB9|jnE;3(LC zT;+Ou;Yh|ka0Kj9-vNg+F2N?4hkn=w8({_xgK5|R_66HJF0;` z_@8>N2mS;*;g7Hc?S3f29~c+l_pnWU7JkRL6@ClT>XUGQaRPn=W9lRDYsO*tZx~eX zfnPBmIL71o686FJb_l;<+zmg6o$5=lpK&|<3>MV4!GAH%L5^7jTGglFCyZ0@V;F<~ zgi-hp7=(S$4?ltfM^~=D4}QqF7ycb~tM7y#Fz$eVgYD`I@O{R4_#VuuZ-pE?31q~S z`UHHJJ}ySphv7T)A(dKgqwf*B)OWzY(3ixb`aFD-k&%i&^r^TfD zIDCaZCPvhU;LG$u(WAcq2#!HXrs;g$92gMXy&6}#1U!YAlE#CG)s_&9xD%&BjMo%9(or9J^4 zqmPSG^{8zWe@|Z$i|X_6KKeE>t3CtorB91V^>KI) zeN2p~55c?XgQ7=${~;U)qVE%Xpxtj>@GkmJv828Te@9;s+tg>_o%F3@T744UL7xy~ z>Lc)W`mh*O?}4|`4;)-!A1rVG@K*Y6u~U5sw$rzZ1@&$47W$mnsy+>Grca3p^)Yx8 zeN+sq55gPi{o=qumG$X^zoqXLyVZBX8|XX4cJ&2#J$+uxsc(fv`iz)TpMclV$Hl1n zFuayNB>L449LRAc`hKw&mbZU+4Sko`p}rknOT~ca`YgN>X4I!(fpHRE0pseU zkk7sZBJeU8QtyYCGWI||lN0FARMw{#@>!lh59G5yfiCqOFweLI`L}~WQGFg>z_<;b z53}ksa3SL~rr=R929JbMcmxc>R_KR^!@m7FE&_Yup|BGk z0z2TrumBH&d3YeqLAzgCVTN%A&W9=W33veGINTpb)raAJj6-l=IIthb8(=@&8+OAq z?1Fp24rtfY4)Hls*l4R>0@vQ7*QXB+cOTr?Vv|}|2`ZqVB80{ zg*~vmeZp-RcfzeOF8X`hmSG z?1Q#GJ#bU{Zn0B+32s8)E*8|c!Hwy2VypTz+=xB}=fQ;f7~GI?R1B*R!Z^JjZU6_; zmG$X^>oe{ZyVZBXx%3@kyZQoLk3KKv)VIQQ=`&(VeFCmS9~YzQ!*Ff-kmy%GuouT6 z==;T9X!lz;oI~FwcBpTMYta|Qy!sqmlRhhE)TiJY^hq(UJ_=W-kBA}lez+RFN9^CT zvOc|VRr(&WOMM57(wE?DSX7^ft1xa8v+6T&7JXVws*l5!>0@F+kgAv#R%iBL(iE*b`QeT8C(ig-w^;x(AeXE#OpM=xs6Jkt#1TIe>7K7?Na5?&c z-7D;avuN$C5< zURd7#;aK`Eu|s`397A6e^XhYOY5J^~QJ*r>C&jq>C=Aj^#E^PF98K>L`**3VPcID6 z_lRBUJK!k#l2}xqha>6R#H{)Z96_HJlj`GeIDJfvs1Ly=`k?4h-=E?*4t<~41Iyb# zY^3iLOX`bo7=1x(Q=f$m^sQoAeG>ZU6Jkt#1lH4s#h`i*tfL>;xxzkJ-u|JNzFX{6 zUxFU`cCnzo4f0(kft=W?J`MRUlt4;MsE z!t(YHzoPFFJJh$sFX@Y7UVRSoT|j}Xm{FgCe3wulDaO@DA>Tz5h=?Kee#mzj1w3N^ zj+OQ4g?txMphxUd-vRk9r9eq6s?Wnu=-b4s`V9P-J}oBI$06SZ6^Mxu^&!Z2NdnztM-q zpn4DFyTAei+gI2J%iBNXvq^z&u~U5s_R_bD1@&!^?=lPI#8&lb$akRyQer}V4DwxS zfv6Z(AB1nw`^ACnD(lk+-=yyqyVZBXztVSz?dl7V?~)7T#hm(9$am2NGGa=70`gsU zfw&k|ABKDvULYj;)ej^&zDM6L_QIv?{SSPVz6<^tcBpTMeCJ=FDCX7YAm14n$ch>D zDadyY29oe47*`*Ke79jB0{Je)KuEnGKF`<#{{*|Xt*lQ6CBBz-6RBP^*eLcWtT zP!QYHXCdF|8E6&L>XWdOJ|V``N8n@hVKJ!Q10SUy*t)_#XzSAh|3Kd@cB(JIN9fzd zg8DZ2FnvyJRiB1@b}x_;6Y68|LHei|Rv&~N^nP(*tIGQH!3XGj#cuVT@P7IZv0Z%u z@>#(^Ud*X)h4;~C#FY93yq7*MM%9PmJ@g^buYO=lj7+m)N1c9o|J> z6!YqH@OSiCF{3^O@1#$ParIGn2Yo~gsrSR%={;iq7M1nsg}2f7h+XPC;H~r}v8X-| z+v(fHtojVRg+47N)yLt@^f57_J_K)~4~ic3{hOCRpC9NGdtiC{hrh+|6ie!h@CN#V z*rq-UucvPn)9RD3NS_d6>Lc(v`mh*O?}69S4{MTZ*U-0%1@&$4 zYWkemsy+>`qECql^)YxQeN+sq55fYyUmV!1vOazA3i@7nIqX*72`^*ZA-1b8z)R`# z@Di9)-wH2goDoy%6YwJXxENI*hI#ss=vP0mDaY^V`^8>Z-u~eQ^j%_y`gV9eeNoJ- z&%uTCSuvwN1<#{TigEQ(crJZJ45|0SbLc%{|0b37>4k0dJz|&o4#;PQ10}JjJ`c~L zZxgfXGw@9Mw3t*MhiA~o#EAM3TtFWbJ?i^6=C~q#pV$M-+dn*wzEdozFTxysL2Of> zg{RWDifQ#pcnW<&jH!>nlj*}^P`wA9L_e@mg?+HR{lgRKyTwlRC3pgTJ3Jm1)VIMb z;~YE=wyICVV;QI5F)*P%29IVOg-5}#`XD@#u^%1*2j*4Qrw_I=?uCcLZuOn;FvcD5 zP}r`%01siDhX=!)`c`-l;|x3yrqm~3hH)Iuhf(!mcmU%N+#mYY4{XTsPR9LkU)T%F z+dtfgaTnYhcBpTMX~spk7tE{A!95vg;T|xfJ_UDYoP@iNkFvZv- z_Qxyh(+hW|?-9Gycfg(KOJY%d9=6c8iCOg-xFda9OsbE=9q40XM12TuPahOL>iaj~ zxF>y|*aOSkKTOhhiY4_$xGjA_Y*U|w+t9a)Y4u6CHGKkZ1tV}>7#4%juFnIvq#szH z=y^-R@SEv#_4ZeH5hln)nSMFcDNejqL^2ogR9bKVH9T6r{HYHNw^A( ztB=B2j3aPm7*g+tGZ}l}4A{SJWqo?#bjCd}0=v|Az?B%6;EJ%QJ`Y!5+y%48w@}5S+p|2$zK(_5JH`Jdbgo*aPi;>w=T%JH?XvB3y>P04KpV z^;tNPajTeCpM)X$gcwsFffMM%a6AmE_rP(C2iE3z9PEST?H-O{+zpq8o$5##M>VvR}u^;;3K&-MpeXx;nFB}HD)px=M z#vRZH+tn9fJ>$HXQ{M{f=rdwUeFA#v<6=~O7<%YKqF?>M9FAjo+0MjXSl<5OPxM`4 zhx&H-BYjcKtIxq7=(A!*eF}b0pA_TjqwqWWh!|4uhu_kB#QwD^>(dJd=zGMX`aJxG zzD>-k&%m$g(_&J69R8a=CPvhU;8*lP(WAb9O^##H_lZ5Qyq&`@=sU%d`Xcj?}UG+?-1M77vKlKH z75{j0ipQ7&&+tnA~lk|Bpr@j^b zkv;>TfGPC}_&DP@?1WMEVfYy15PTH+)ep?#xEJGo_z3KUcE5GQhZ%Q?9qQZRL-a*4 zuRaGKq|b^O^(ojvpA_TjqwoRxh!|4uhxgNa#Qv2l>(dK=Pv0YUsqcXI(U-)c`aHas zz75_3v+6VOZpLXbsXh)%^f57_J_PTg4~ic3{WCd^Mc*g(!1DGF@1*Y(OX`d84*G)F zralXAr*9S0>XYy``h*x$AAz^hhsB_J4{WC&m{DOLEN}nt7W!_nQ+)~EOy4dR)VIN# z=yPJL`ZT-k z&p^JvCXg1B>f`W2`j{9|AA%Rq2Stzi{uMdCMc*g(!1DGF7t(i%CG|yk9(_SkH9wiuozVDfoIbXtWaSeEN}ntEc$M-Q+)}ZN#8CO)VIMi=yPJL z`ZQcXpAr-5WAJqPs2Elsgs0K_#er#+_348-`d+bHeJ4DXzC&zRUx263=f#}*R(LXf zMog(sz?10XVpM$?o=6`O{ptsn=lB+Vzt{`Q+dn*>zDw*--ww0%MKP~F2aluAiW&7O zcr1NVjH{2rW9TDdNWC8(P45x=m#eH#FFcCAN9hsB_J51daw5U#KfmbZU+0DZUEslEjFr*9Vv>f7Lc^f|FreH!jdpAr-5 zV{jk(s2ElsgnQHb#epf6_349Y`d+bHeJ9+DzC&zRUx0hk=f#}*R=5X!Mog(sz}@NN zVpM$??nWOH{ptsn<@h3fzt{_xviCo57y2%-Lw!3;(HF(M`W)PuJ}YL_r{GTXNinWI z3R~zSVo1Fo?nv(u`5wXf?LxEMUVRa$sBK_?}J;y9%%Pl7u_ri@$RCNK#% zh6%V4j6qv&1kPg|h8x15dixT#IOBn3I9>?*p!q#;ea78lr}`3{OWzLHg9Y_%a9zeZ zu~mHMx-zk>V z7vV(ug4m|sz85S+-zuinC*cJ81RM`z>LYL*WBWeTu`sCK1II8P7|-!bXx|@J-tLWz zyI~M^s<-b49?iHN2B3Z4viWUr6l44T>XEQjeHxBnoPxt)LVXN2F^)n%466^qM#g?P z3=WK|EWZynFz$suXumsP*V_r}8F#=s*sk7w*TKs;4?Qraz7_t5%VpqCFr_{Le`Fko zKftK^F#Miz2!03s>IcSh9FcK99Du#h)~6eO1H0hYutR-2{5NC!9?Gv^UVRRJ$v6wY zfcAS!wwx6F9428ujH{2r&lpGGzhFqcAAZW%BleG}ET@kRe4B9rz6I0jlkiQ(3HVnSQy+nEFb=~W7*y|puQMLt%3gy#@Gr0%z6v`b z{|}Tn`!j5ZuR!~qcI(?Xdl}}$H0)-af-k`sd=WpM^IvZiT;vY4u5X1LFj|9>&y1V3BbcUI&Bf zJ@8t_10y-U0Q;b=PY=8XcEhV-r}`4SigCNx2CrnCg9X?M?eb}O1x&%qVM2WjUdA{I zFNIN-V$G|^E8>D}C*wOIM zq|Kmz3TzSl_cyogc33ITCfHH1)wE^wm+w4|g#TjNh4h~bI|BYQX{XS?5Oz5HhtURM z3&Gj21+ba0l3xbw^{{EM`LO$&+5X#MuLEy`y%x3%_8Qowuvfz_hL!yn!VZI-4|^5t zO!`lOy%IbYHV-xiI}|ntb_i@H>=m%>VK0Z>-xT*pur;uQV7I|a`qi+P!B)Wzgk20f z0Co{hm&4nEcEBg(Djlm9v?FX9;+ZVPwY!nvX;Y0=)V*;2fPIK64*ubpAUO6crNTku+!;37WP7LA?;xL=fGY7{~&F5`nQKY zAO0D%DfF*N#eEO_x6^KdmE){}4Z@buE}{P-*Z}+&($1y-bXY(9r_dJCe=w{M{xRAh z{ky|@;h#yHLH`t35B&EZhx;Vh?XXgwO|S-RHEcF)8U2^Qo(EnGdoJuk`p<>!1)d3e z4(t^A7sB=g4}(1$Hb(y-Y!7fYY; zuw7sm(|;lC8Q}S_S+FzdKLs`uJQlVy>@fPrU^{_xU^~KQ(?1io1Gqix>9A?^-=Bi} z7H|#iHdv{*YS>d@t6nfDqCDnvfOuz3kyqM!T2#@^qGav*x^?Qqc4;7-{SDiF^iYXvbl&X z--i)5Nf_x}#`JC?4mX;@|TMfagQ?5b5ElPR&l3S6lA)ibxBzGcDCd>EtW&fMW+2q^FA@W`1-sF49{mBoK zhms#7%XhIQ{in&J$uE#6lb4dGlgr6>kXMuMCa)*oPyU4b2>C1WQ{;b<|A)Mf{2KWP zS+2jNyv;Glh+9QYCx1Y0N8Up2O#YJGjr<+?Jn~+0fP92}0a>mOCI3svZOHw|r;)EC zcOlDjZ*k|4r;&Z+JIEK4?;-ai|A9Q1{3r6&vb?7d_dfY1@u2CHEm`kq45`B40)B zNghu2lE;%TC6|z|Am2{TC!6FV^8MtS$&ZrnB0o)jl>8$3N%EWI7s>CC%gJlW?~*r@ zx01gg?;w9iK1kk2ZkcISUy7@ReLlL7Tata`lgWe0oyqy+9^|QH4|yi}BJzXee&nag zmy^rL*OFJ0i^yBZlga-i-$G8yO0nE5avO3f`84u_9LHOY&3X9po3t|02Im z-bbz=r*^UPe~)}Tc_X$SNM1(1nY@yG2f3OYCx1+Sfcz!-G4j92&ye?% zUnU>d)vo`y$TIIlTqQY+ypG(9yoKy1e?`88yo-D(`6u#~&bJ-Tgdm4w~`+s z?*N>78^~{xx02r>A0V$KH|b`Ve>3@X@)zW@ z$={LBC+{QoCcEU}3yvp`+>$(+d@}hqa%b{A)Rk<-bkJ?!H@l`QjG#dRT{MearJLk^HH zBZtXXllzlLk@LvY$pz%Q$m7V5kc-LBl4p?1$aj(7Bi~2Pb8T;8kvxZdEBPVv9P*3gd&%#S zA0q#g`~ZRh_cxhwe{^2Ow}kL1V6Ka-y&r@HOqdzIXR{5Cm*yo%h8yq?^N z{3-cN@;Bu3$-Bve$Op-z$W7&?8qUux?0SG!{iy{!Q{Kh*OTufPb5D~{tfvlvPph{{0H*u)lP@6W zk)z}Z7V@9TUy=Vt-bG$Z{)zk@IaOXx<9r;C$pzw0Aa^FWBcD&sA`c?> zB#$8b$dk#JknbetlK)5^LS9VHC%-`+L#`&@NdAg^D|sJz4!IR3QHZ;j+?o6k*++hY zd@1>P^7Z7`$WzJXAg*~k`}{Nw+T4bG zI{9>RkbEY&KlwcJ_2dwFD!C6?zK0-gAo&sURph^shm+-d3*yF;zb2QE50h^vx5OkE zaVEJP`F`@b`6F^?@(ywja_af^@p#BB$rq7NCHEtDBVSIwfP5|aQgRWwfIOKz ziF^xr7I_xgB$tx!AwNi#?~RCiocsj&S@QGbSIKXX-zKjjuOjatuP1*;{*=6%{0;d> z@^11^;jz50YOXFCxEAeu7*?$ayj{P z@=Eef@>cSX1&qs^XINp#?B6lWtB=;nDBVR-|$nrfPaTk!~J3->2?asl}(@(pB}ha<;VLjH+7lbm|G9WLL45_bYwz7r*`9r;;u7Wp-D zPjUs>M_x<5guI2EOa6vDguI8GPd-8(LvDGoU7j1s?Z`53M~<%xc@FtJ^1b8>$TCky z;`bvzK^{Vuc{>tbKz@xpo?K48nY@NPi~JG!Uh-D*!{i<0r^zx;NAi1_e2Dxuxp@aW zd=0q`c`NyJ@{i;*$t^Ci>+3vnXL5)fBKIL*Ngha^K)#ARn>?IslE;%v$tC3b$TIIo zj_*OTN&YMOe)8MoN6FP>ndc+>e?oqd{4M!SaeBl%f!H}b3GbI5O#z2sHoe&qG! zJo2aHBJwxnY2@AHIpl-nhsaGk+4c1VIi0+Od@8w|+=X0C?nT~24v@bihsk@%{mDnj zdE^$o?fNSqpG+P{K8svT_K|0h`;qS==aKItk0(D&o=JX+yny@y`5E%-& zkvEYylD{B-PTou2Np980KHeY6XONGOz2p|1?emjEK8f6y+>tEb0~ObeJdtdWZz5kn zzMUK;-$x!qew=(Yc`11$c^!Eo`75%_OA`IAnzfMBp)JABR9{okM}OJ z%+r$g_%Qi&@(biM$z|m8$RChH^j4)|B2+5a@?8_283-;vjon_OzA zFZ0@@KIHrG;=UpGAnzt$Kt4zwKyKQ_-oJ>PPQHVDD*2D(F66(Gdy(HF%RDtH&l+-= z`~|r``3G_y`MCae`3uMyr=yUCxEn+&k?+eto!{3F>QA0b~%Zqd~~zRSobk;juel4p>+ zk>`;O@*?sD?ZmM}B~uM}CYv zhWrfqH)NUjCg*z|`7QFF$d%+*$?M3KWSQqC`)?(GMgE?=i=29yeLO#rJCak+wD<2x zK7o8bxgB{BIg4CC?nxd?_K|NSUqb#JIhQ<-JcRsvaz6Rb+TvdpWK`n;6<8u==6Ie8R$4f#g$N95bcTgh?q4)Q|s9`aM< zL*$pp&CjyS^ESB+`CanqvH?}_mNK^ySmxsmA`8wt|eLi?vc2Y$rq42lZTLdkgq3u$TyKMBHuyoM}CNW zIe8KJTJqE6BJ%%`CzD?#-$GtSo<*)8my%bLA0)3MKTh63ewMtK{3`hX`EBxXSJ?Hl zirk63o_rShQ}VgwZ^(Y~ZgQA>kUW6gw7Y$Nt|F(CN03h?Pb7CCPbc>x&msrN_mIQn zhsgcOPm=S2&cakq7|41H2K0+QrZqdU|Zvy!w@=fH9(zX@}J02@?!EJ@=Iiyw<*W7j69OOl01=IO}?4@G5HSim*hD4U*reK`^k@yj~i;A zk7vlO$S;#mA-_e=Bv+EpCa)uV$y>-5lfNRz$h*h|!Xx>0{KaDJMx=k znKvr+_W`*lc?a1?mXAk>yM!!%Z%|w=S^gfOxFO^iIiGw5c?@|J`9^Xv`Bw7XPr z$@h|9B|k*2AU{D~O@5xdiToOQE4iFpLtaC6U1=ZBN8}U9TghF>JIG%09&(g?h#H#AIWa=v*e4&%g8bEdt{k6D(Ckz^7Z6hrC3z(I6!JuJ7WoeHIphW80Qt}4-sCsQ1Ih1`<$LQ^eUe9#caSHM zn_OcT_ZD&o@@#TX^1bBq$$up0lAj_Ml9!N6$ZwMGBCjMrL|#XJmi!6%E%Ge^Qwgxlg}bABOBy(jDxAXfexhMHm@-T84c@B9E`G3e8$ZN=-lWWM| zl20zM^V>&0pL|@lU7rQy6UcXw+ml})cOh>ipG)3L4v{+++WAGu5%M7Nc=9#m2gpU_ zx5-n;>&Ul~zb5~Vyq|m@`GnyqmV1PpNq(9fCci|!l>8QX1i6Ylk-VOK7x^>tbL1W5 zE#x1_$BnSdbA;?6A8*+8e>wSN@^8qQ(3ld&p;yA0lUypCtDuzd*j0{04ap`5p2d;OA%9K& zJ9#&`nk@71rM|u*H+S27h?(c@^8o`rofkUt_nPToO&j(m{(8ab`VKHlZz_T=}-=a4s%bI4zi zW8{C4hmmETztmSgxrxW-5oDS7FX2fZP(ZRko%C|CJ!R7CSObbh&+b8 zja*FLNxq%DmwZ3j<+bbUX>u#_o8)%nwPaamAocq-xfgjSS^gfEgx8S!kPnhCBR3sm z*U#1DHsn#{j^xSY9^~JUedIah-sJh@LF9+YMdZJbZzaD-zK^_&{4}|e{1*8G@_O>8 z56B@cuen zS%+V$!*A5#59;vzIy|J#@!V5~7uVrAbr^pGxYqICSchG8ct)N4@eTZ1`}eEExLv6g z9<0NU*5Mg-ctst4v`%^U)(OWq^K0ezXdO-|7&*3R6H-S9BA~Kd{jI{yUYc}<9_2Dv=qlVl2Pt)wfB*fiznH+$@YY#Z7BwFO(`fSD4sSP zwLfy~_<}Jd!>6K(dgt|p=hO)!r`(caZ4{yGy)Uz>?dHi=jLW1#EzjbjX$9&zp?K`L z(MS}Li%Ui%{6|c3k19fC_RbxI5>1&pZql^TRxJB$C6{6J@Nqb`PNnE68&O;|eCo)t z1$K}_Mbqgqa%$1=X+^AxVmqTTMbofV5Gfixykx?(D@rC64VXM~_ykm4LBYh~#p9>K z$4<`PyLLNr{LtJ`7h{JPkFC{C&n*H=DcMw&+0c{|ZB4y!P;$0waq*;DI3a;@rm%+w zv#luGXIRlb$%;JB%CdKIYEDgR1jhqatA4d>w~n`kILacl99D)=Fd!Bl5-W%d3J(~d zzU~HnJ+*yRr&fwqXJDr#38qLBEV8uAz4{CqI5=fM!MQj^DWY%L0Vf^*bE|j~Hzshy zj%;uzH?4=(OY4K8ZyG+Kq^Ou4e%b(SkTyhXWIG#9(uR|^;UsQ2sT)2gvXiXgq-!_{ z8&1k@CuO&jvfD}7?WF8>Qg%BjyPcHXPRed4Ww(>E$4S}aq>NibyM8=Q${r_WkCU>; zN!jD1>~T`|I4OIbl)X;MUMFR*ld{)I+3Te2byD^^DSMriy-vzLCuN_Lvd>8w>#gm= z`<#@0PRc$fWvmHh94BR;ld|7Q8P6l^IDRK(zmu}xN!jnD>~~W3J1P5}l>JW10Vm~v zlXAdGIpCy>#n5)9SVhbYC*^>Xa==MB;G`UMQVu#P2c49IPRh9bu@l7KOXh}?a?nW` zOG_E#q>P7Pwok}OIpm}qa#9XCDTkbtLr%&eC*_cnGFE%q2^!f>(nhwEwvp{5Zs2a& ziRUD5WIO2_*-i#Vwv&T_zuWEXp?M_9QS(R$GNH(XBomr6G>?QT6S7oY8Y)afm1(Fn z4b`Th;xts9hRV}WeHtoILltVML=Dxbp&~U@rH0DXP@NhoR6~_&s8kKrs-a>vRIP@} z)lj_}Dp*4mYp7%m)vTeSHB_~R%GOZb8Y)~vm20SU4b`rp;x$yghELDA>eo;K8>(PK zC2XjM4HdDWDmGNchU(Z*Aseb>L#1q}mJJoNp=vf%&W7sQ2xz-fMH?zYTHn88$s2F%G*$V8!B)^6>g}+4b`}zA~#g!hRWPfox4@% zZq>P4b?#Q3yR#jgyH)3I)wx@B?pB?fEh5cdO3bs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%j zI(Mti-Kul9>fEh5cdO3bs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%jI(Mti-Kul9 z>fEh5cdO3bs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%jI(Mti-Kul9>fEh5cdO3b zs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%jI(Mti-Kul9>fEh5cdO3bs&lvM+^sry ztIpl3bGPc;tvYwB&fThWkLui`I`^o~J*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rW zqdNDf&ONGgkLui`I`^o~J*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGg zkLui`I`^o~J*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~ zJ*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~J*sn$>fEC` z_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~J*sn$>fEC`_o&W2s&kL( z+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~J*soB>fEb3_o~jls&lXE+^ahGs?NQt zbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p z&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^Z zI`^v1y{dDs>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs z>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jl zs&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jls&k*}+^0JC zsm^_>bD!$mr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$m zr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zL zpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zLpX%JFI`^s0 zeX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~ z_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*} z+^0JCsm^_>bHD1`uR8au&i$%$zv|qtI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZ zbHD1`uR8au&i$%$zv|qtI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au z&i$%$zv|qtI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au&i$%$zv|qt zI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au&i$%$zv|qtI`^y2{i<`n z>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au&i$%$zv|qtI`^y2{i<`n>fEn7_p8qR zs&l{U+^;(KtIqwZbHD1`uR8au&i$(Mfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!c zsLlhb^ML9+pgIqz&I79Rfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+ zpgIqz&I79Rfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79R zfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79Rfa*M;IuEGM z1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79Rfa*M;IuEGM1FG|Y>O7!2 z52(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79Rfa*M;IuEGM1FG|&>O81A530_Cs`H@g zJg7Pks?LL|^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL| z^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d- z&V#D+pz1uRIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d-&V#D+pz1uR zIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO z>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO>O81A530_C zs`HTQJfu1gsm?>H^N{L1q&g3&&O@s6km@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1g zsm?>H^N{L1q&g3&&O@s6km@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1 zq&g3&&O@s6km@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1q&g3&&O@s6 zkm@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1q&g3&&O@s6km@|7IuEJN zL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1q&g3&&O@s6km@|7IuEJNL#p$T>O7=6 z52?;Ws`HTQJfu1gsm?>HbIg-TOq5Zj!#6QiMzs!K=OsEe6SHMh?(j{_mr=pP*LjnU zxj2d3RP*pn;;G4)z z`vCYRa?@S_bBYqVX+HqpL~hy>z&DYb_66`wfan5z625wD$WDC|eTk9iON>Nc zVkG(!Bhi-_iN3^0^d&~3FEJ8*iIM0_k|yFM&BRNZikCDOFKIGf(rmn>>3B)=@scLw zCC$i7nv$0^CogGIUec_*q-l9c^YW4=<|WO{OPZROG&e74a$eHxyrk)QN%QlPCg>&2 z&`X-4mo!H&X_8*jEWM;@dP(#2k|ydU&D2Yps+TlZFKMz~(rmq?>3T+@FG-rPmo#H9 zY06&GoV}z;dr7nQlBVq?&D%?wxR*3@FKOyt(%ikI$$Lq&_mZaXCC%SUn!sly`jVt6 zd`WZok|yyb&EiX%#+NjYFKHrQ(oDXjseDGFFG-rrmo%HtNc1I1^ZAk{^d-&cOPbP` zG^a0VQeV=nzNBe=iFtjHoAxD%nSJopz9ccX55C%$Bxd))SNoF0{66?Ful8JtsebU)o+~lg5B-PslZokm@J-~FxGqV|_(O!m zu_dlcWYS+WhV@9pC*tz}4X%^0)=_W)MXjY0$pN)iOC(laSPLE!>m(Wskfjn5kkZ9C z&z+r_aOhZY`H1O@q0CIY@bXotM}etno_8#1HON{N@TD#Vx`5F>x8R4$E>w`Egk!mhDU{!iptz1qDN+!-gvA z#vbM+>B+uj_|IAz+9YMBM#4rx!AL9{88>MRJ?p0Dq{C&CDXC6D7@x(}B$3|aiBpD; zoK{dW>E>~hMimqch-jc}aEBavW*|MOt0`F5$)H+E78DeXwOfq6L*4S_F!mItH<;-W zQ?Q&BXFK5}dVBn4BEJ)02RFl-QCL~_Iv7835=VY=s0g;|ALbXiyqNh__^R-g;k@wB zA%kP)!Kkq}HfKxvY+0zfw@;=keRfl9ZI?uI&6NY^>`kBj6Sm{GwvClyZE;G<8?uCw z;gtjD97&)3GdyDP;`XsQd#AOEjU3W;fO*7>B0t58rMKdQoXUbr&dB|#rtH=syYEh&D=RW*Zgefb+J-89Vu_8;lIBZ z;lDS8!%O9)SQ+i~*N+mmqD*z7pq8eggm$G2F!x#eq2dRaHL+PM(yk3(7tRk~A1=tR zXf&xmk@{-oE`0edu@tfM`%ev&09?Q+@{0gUA7%5(k ztHw!QH%v}-Z72TXy4a>(IG1UsxPEg*ifej?E2CBOwE2jI&q}3qz;Dr^BbIa0NeQ>k z_}y`RPH1-NtmgBYl{USn$-N@0l&<&}|EyXB5`y!0}@q=(a<(jEUs`tG|w4BvH4^f3Z1b(~gsV-x^yDdx%i7yK#x9Zho^g-Ik4_-$WtNgM%IY=~o){5pmnRWqZP_dJGiBj;$<(5hl1bwyO}=?jCRPKdh^!L}ur1`e zZV8btM(kzbfl=!N0k~)@nr?YvXE#>tOQ>vOeA8_#>aXpnA2y*x*wMzZu81Pz*s#O) zz~typ$1x_64V#YszB?=u@0dkC%?|G?wSXfkC>tV2n z(>ewVUAGRxqUp8n4vVJPTG}L^8vePfTPL^?2TseO7ogYV+l8lUd zj?2MDI>HyxuN^okIOW_rY=7`!!sOwjtcCvey#f}O%OEqlWYS3cI}q}90J(>-ysgN! zBG%nqM;pYlQkjMnrI`uiBL>BjCl&KCnsYzx+;BQ~($0;obD!zl(mHp~&QrLgAuQ#1 zxL-PsVKR9zc^sQQwPluZ2KWE|@*d=!@{4Gzw^-*ea*$E-03;m10T z9bjIP9@=$EHN=o58PprcMxv6ZNr>g@-d9 zeVdVMZpbzFnKP;f#LtwZa^n|vjg{tGw>}+W=4ac*b57ax3<)q-T8N>vq#K9M0i{;G zy&_Eay4;a9i^rOT&Ggr$CUBn%&PfZK&CDv?lV!*~nRQ2&-gzd% zQ>^k`DP_ydH4n#1quXL;bdy=~rJ1)q7Vjugc>9?ZD=pdPl&>v3o#G*WtaRX}ojq%p zF;+TblU>dw@X|Z^Vc#E*v8imWeHhg`4#b|Norgxq#dE4dF z`}(l?L)bh#z`oANopnh{N#|Ipb9e21{>K`3CgPfTAMz01 zma2W@Dg4KBS6InznRZ>o^hC^&P2$lH%|0l*bv9!0VB*wGGjijX00)={t$pW|4TxLU zK+`gFkBj)xxx6PyH+t*di<2Vbgd%E%~Y)+4do5bR$^z7ZF zq**+i*0XmS>MdRVHk^dx`A4lYcM^}vK9)*L7PVuvsud)+?#b!dS8Iv%WAT5Vf4q6m zX89F3G&t#3B}0*C8h+9T$@ba!_270GHiz52VZ~p1%D(vJ;MWJgLj2^OPWBy(pQIz7 zZo3h`9Q-7{++)hN_}`3Q34RiP9;(@epKLFJ&4FDA`^a%%{KQ|rC-peD{{;JIZa)V5 z1h?DCfxyYW?US}o#kRx|fB8-6i+__LV)KhwTKo5u2%k=v5LB%ebL(ne?p)5=32>l$Gscc6I) zwoS_>jFkvm#7(&_%t|?~UU&|DxEBY_@&t2WwlB> zA?N=xhT}3qT)q9P8%e*Wk^S4+=^pht*WjP*`va*z%Q?@j`p;@MPoHuno^zEkzSL)} z`2A)zxd-j@9C%9G4j!=6m3pwwzMV7{#X2Gf%^xc?aPoq%{w`Hq&}N}MlTTl88Ci~F-) z55wYEE-Hn^Am2-#m!S{scnd79Z7-5*TZ!KuHWN03wi&|@AE zqqPk#D^V%<*K8X+#Fo)6qMb=wNSi~ONeg4`C-=E>f9zcB8p8NF{XniTPMC8)a1Fzq zex#V}^lP`12TPi8rZ5^pp>?H$F^Az!KlMjpG$`l#`$=-P4E%5}lZTPZ$cxGEk*mq_ zTwK!IPac6Z8awkj3K*B+%NpNxnU2@8Eopuiow>Zb_st z-A+OtB*^nFD}5`WhMt-uqbViwJwt31Po9eJHP(AjZWqx0I-^9NJcZxVltNnH+?1^9 z9E(2NNb+YPHAqXRK8dU>FW_X`%y=s}po^vc_dW*Q%Qluvr91BrCcB!lZJ3?d6IbwLO zA+E+YDZ}uv)Q!v$ZPr@( z)ST9JSnjM9jD=&iV(mP^*^0UlVW||l?gM}ZpM%8ae2_kS44O~OoG~}vuT^|dS|pwx ziT7)QoAlXIW`yJ|jbCiecsG7!6Fk=lo9~B>mC>w~^1ti-uqbe-z5x7;$ZiU)kNvdn9W9i2S0)JK?N%@V{$a#I+-SoS*zuLS9KJ7$BVPgl7;4K$=6sO$y#nK54-l7D9r|hdCii=5p%g@ zX{?T9eQ&IG)r8IOt^I;#$$T6XGSuVR9X5Y-t;2p7nk9>@>>|eZS*!7182e!_WP;?P z=8CM<;TG?PvsQ##d>BbBdADEblir7Jx$~NE`HIx2`E|tn2hLuk#d7T1;``L-iqZwg zNpSh{reSk~Ssl&#I?`fWB&#gaq9)>6RXQ)t3N6Q@wfD`caMp$v)sd`i2t=LsEqx`$ zPI~1DQL`pu)`YXFT2y6KM_QCcQj0$9Tl!>XBI|7tb6Yg42D@feAwp_ib?Jf(&AM8$ zM!LuvQOY8&pOUk#lB}zlby?K40a<4sHS2iZlBnz7=kEIW-(()2@d&bi#Xjf ztHL7j8H>WEopwW_L!QByiQLwr*Q zuCUru3$!OR#nO4lTX9pP3kR5=Nh2(8iIx;GRwMP}BnVX;F;^k=bfY|Cl=nti#M`wW zZLGXJ6)}y~j9OmSB9c0Afr++=wEHq`E6LR8d`q#$+TNuLno9!Z%hOW_ei$*=8kNSz z(s}8YUwLY3^hs#VSZk~;oo&an60JtOjYcI3Wkp1BTBhbLwv((ZUC@pxLW>by%kf$hOLaGwx1a*o$iXwIue?C#sJrm zzsntPtcU$*-%0_Ge=&4eBZ6@xx3tM6f0tn?)&rwSrR9q`W@ewkm~dwH8CrLb%0AXu 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 z zsoQCi9`KY=OS_ELYJc-^Zo6gq!o}sK(OXyDeCrLRrQv`CbFSGsoeZ5X5BZe52tK>* zKp%>Il_dkRc^jy-l&M`_h!f92uK6<=4wCLM*b8E*S7FE(SC zeK#RCW4L|ijm;Q=LDI>O477CQ#AamMzMdGP?6-}IU2XU)+J6%uSKTcgk}F>_Ek8Z` ztI&7RJ27CdH>$n?u_EzhxfA>q*)pg&KbIu~b93{gr)SZl{cWf_kn0U$emaWz>2%q& zr>Vo8ml?=g>1q_>?)`869UN0Li@oQ>&s$!0aECt@&K(_QqnW0?h5o#7E?bAleV*Kp zvF|6y{a6N@b5FG+=EyyJKS&}BMFw)6kI8*bFt0rKj7Ap9W^@);>^mBBK9`eMGDyeC zD`6L5J9{Nr1=5K|8YrstJXU|*76 z;>veAH}&IZ_v7aK7wEoR`nWy&xiC)Cs`js8M~P2l()>T0@ma8l3_i``Ly>w|qpQ9+ zn!_NAM?Q>o0&@ymB4f=lyGy(Q>tN+OLn{v&SP8fZ#0tuDt$ofoIO`Ken8Vt(WR1vR z(2XeyO_hh4Q_;NQ9pmX)hB=H4rkiBai*4?z-bEFM*c%+WvMpb$%gikCn!ivb&ycwT zm=sF9_7sD=|BbL#bUh;%8$xR1p*@6SjtsdB){#gT>W7dp`U#RWgod= zm51DF+d;N59%>fIx+Z1rXX9eoDP7F{vf1xu4@SzyP-U`<>>I19dq+29xR*iAig4zy zR93BIK(+;D0Gd@iR);)9Fu1Lf>|(W8vFfL&X$3SmifNU^ zu#0{yMO2o!m(_+F(&_)0&50-p1_+%9rLC0@Xnc_LFbE}McA93U!9t;27G~ChRG{zO*^{8Qxp8>SSA*xKEnnB+gX+>W+dB+8GnN5Xac6AJeaT@ zCOlg+p_GM6hCLa`Wb=iH41m-HnGykj`78G+UVIx~JgA*hbI(sS_oS{< zI<8&aj9ASK24Q_{u-7UD7}$-MfM_zTUXsTuse}H5TZ*ISThYgQxT#qN7$Vk7>?IYk z-i${dli>paH|wLycZXJf1U~_7#X#Fc>oDBZTi%nvx5Fu%v;t0InDM0WZ8~ACH4g=1 z(MPGDP}85Y%2$!;FsB&E?DhDK4M;6EJNE3B?5nX6rYNCR+OtBg%^}w&-&S_tQVdmI zsO8ysdP*iVc-eG4XS()dUv#tGPx+a$cTUq@cX-%-zT;-H3P|0`w5#Zg5TjGf*5Kof z4cL_fHPJ`Qzc2Z)ZiMwyz^4M40Dq|eo{B%b;sYvPa6uMbs%Zzk(4!F4MlMO44@ufm zyD9YT;U_<9;A~Voyy890K?nPAkPSeMsVsy#Qt*?ynkzMZ$4=_M)<1U+`jB-I!aro! zVV@DgKALs*`42V~M}2Awex(hWd%=7R$isx8YwH5B$WLJ5KurYTy0(rfgM#oG9&lj4 zb;j+xUuG0Bg)3;!XgrYmOW_MzY|NC9c~<+Gi6nF>0kMVEQ{@3HvpPkp)x1*Z&Xn+1m>GW_F4B)RiRrpUCz`uByik>0+hV+-doPQ(N zrTjjN9XXfq*!MDO57>56O`l$SBYtv8xB$O;9Zu8fm~djJUB*vlkjW+VQkP@D?8k2W z5CMv{U03Lr7QP=l@HPU}>HT+vo+k=_ga8eCeWlR%MByiq=cHo??wkKU`4PIzCrp{% ze^=1DnEB?;Dwf{%^JA5eXn8bgz zwi5)kzas~uw7;|e%pKa_;qz(Q-_-GWOtX`2m1ojls{7|+XO#RGH57C!x|$HLcRj!aLl zuc{1LI zb3lJ>RO{WfCFAq0doAeQ-+A>HxW99o#*w6EBIo(@+Q)86Ne?LKy^dX{c3k_|Qk{-h zr!axU5R;5rT%A=N!VYjE`&dkeHg$TYPES7$Xdm04!?og0C9tTczVT)+ljNnJIQK+%*M`Tf^cF1%McCp2t5GvqUC0c)>0(-9lI(rAq zICdpwiIXH9Mdso$=ZjvQ3WlYC=SJz(@k}Ew=vEt1v-_q+y~qg#(y3#@pocXoO^41o z|8Dh7W@aTggT-fOoX@kIYzLe1GGm_(uDx%*@X@hpY2&<+!kzDVtf!}$CK}?U<8$2up@`a zb=ThA|61+%5mqYC8lxfM)}9q{>z$rOCam_QVXaEP!Mbo<4K53Q-ltDH)PGAN@z5u zHb8q=Q{=P1cGro<=jZ8mfg|5N+ir;-3BTZ;~;v$*T)5F1>h)y&G2l=c7BoBV{;)-v+rE=n{iD zm)9w?es*xxd400u4$1(p(-Tvym&O&4bj-MekXvY5jK54tsl}a(n~GaJs!ROk_j#^4 z^hd+S(=&{4;_M3Q(S+rEzYoNc0rt3I@j^?JnCZjuzz}zst(Pj^>Y^*!Ijq-C+|-dJ z`)afODks~8SoRPu2z<2EP;V3+euxuZ($^6P z-T4T(cCvww4cMCt(vnm|Mr+7m6Wkft84Q!IBHvAJPJL|!$U zItlTdDyf|O7N1@xp_mp=3iT@F++0_9*sk=%I4F(;8&uE*F%oUmK?n7dDhA%^Njp^x zZ_`_K(9C{P%^}q`J5>z5*YDOrv-(NZORDX5s&%B=p@RyN)=!kw&okyy(?NoP@>O37ZyPs6cNVUvPwVhO#>YyY0 zNp&fyF1J%fWn8~n2OZTigHN0-fYUj| zo^KZ^7!`_t%NrwrNZbN}kb>+Xu{Ol z`^mFuG~xSOf;RJ`t-pM?ip;+ccJq64iE(M5nJ||Io*OOyUz70S^9teLBC+3-*vcdP z``~$gn|O=w$}agRv!Yja4R&sd@M`DHA&KysM8N-pZTfASgd_IKHi^m22YY%R4jA7* zo!<&OR(%-`G#bYv0 z#skLk?N`Zvcr{>ruwDMKNu}^m|NL`lK#H}pYd|i#G$18b9CkcjS`rjiCMkzW(#zeG znHLFo+YSo8@)fuI|5*Nia9IBB?;+0JZ?TU9uRbGj9KsA#*5j1&gymx}+Nl0FaLcX% z#W9Lm{y!iS>B6m^ddHCaJSzDyMvcrKF?^VN=#ar#nS&Uqq1-7~bDubUAEiH(a(Tzu z554H_v|ToF!kGaMpWgKAv;y z8F{DdAM@1c+dYM+emwTs)9yUIxNu$3rptz0YF=4$#kQ%VE}wnzeV4p+(P>lW`F@o5 zTK-oG%5on$|Lw1R^{Y$I`;T+q_g*-D`PYAX!G{wsp0IlIGn0;7c*Qp=mQVXm*2*m_ zVykA}o?X5@T6^a;-ygf?ui0ytCRj6KcmRc}sz%l*!C@2>yj zRd0Jf*!kxN-v8F0aynk!`%vfg?|DCc^T=aImvm3~_`OdaKYZ(!r;-FdM1m36x}y*lLg=Ib?YZ2QBg*Jl6jzL#Hm>9pU@Yx~iT*LHnnXW8aQHod*& zt1U~L|6}9(O&2DYKmXI`K5V^s>*{UKyl~{jE4EksU|Ma~eOvC2Jvj3pvVXY!f!cq* z=AXts^zx54Z1|i1GwvT>|506H(fZtb-nqBF=I`Q@tUt#ZDp#zVQgLu?W7T)7r`~<^ zuH?TDst^3fUH{qo-@|_r{;zu;Z~M1X{&ntS5B|&Ux-%c1|L8wG(*Cn^pSt1cfBkvK zPrv@;vM2t#q3f6V&y+Vl{fk4-Uizy$e)H>J&oKRSOz)E0R(Nf@&m^xs-Y~--nd4pb z_ui=smoHy&Tk&nnZ@hKo%4HYcw&JEM()PP{GyVn7pY3P-OWY69CF063j<{m(QR6r~ z$Tf|hJST}Km%L83hxwdm?LS^Wdq`hhDf7GgpS{ie#!{0L9 zBO%lZXP&B)KQ*t0dAu_3&5vo%9gMGX`>j6&C;r8V zq1Q4lD`j@@;X6-Z9E1b+R4%aOx3O0X7Ed&O)xQvk%}FEi?A&ntYev;y_-e@dI26A! zn3&#ubz=S|H=A_$4yK=L#{TR3%=lOe7#+**N@pb5hp+RrUY*N3jvq6gX1lDdY`Mht z>>o1s#9wqUx>>d{{~;goB?CnVjH>hbe#C0?^RZAO+~f`==5AsDfSq4Zx;^vs0*PDM z@L{TpeOJuH_Zi%oI*2Kt?x?%+sEeRc7M5?HmB?meuCUw9&4=N{d^h&amd+_=LXAED zM%eV%vM%PC8~EpMY~;V92Mem}xQ|$Gbq>8ck`hteks&0f6>nJZ?IAJ4mZ2NXc|4JER->3KtDWl=_SIP+-^bw6MI`|o!V$L50GxyI5a>7h?L zKQIW!mNfAa_hr+_*UMoee84oquLk1Zc1IT9=?-4DEI0d(GyRDu6Sd#9d7_6O#tT1K z%iyGmpRztU96v7R6Ry4W*!?=|0vND3!wEZ7dzyczm~OkSEuweZJoF3fS-MF#EkRmvnU2A!Bs- z5PJi)WU-l;oMX3}DSh?^kddOM@~^3Rz1@sXj%JHLw`pM>hqM0FIcjE0)+g%w)<@kl z+^IFzw=UA>ecPDv5wPK}{Jtk6Ug9Y~y_)gI-612`5;lULFtk}dpJN9)hq7q`B6OV} zJ7s*OyQs^Ebonp4J)1dgcf!3NDMGVhpd7aPcWO}cb@j@ImdjFrg8(51RyvEA&&y7b z8wr*YgmegXUeLPL(|LLdD)DlZgE#(XrNC_e(5Hl2S1!gg?UFI1e%I6LP_hoNzwx>T zttIZ{bN%_}Y0z#bo&Nj>8t=;`yfns(KUUM8x+Q<=a^?Z)^_`P=8Q|Bb!%05X<%H{J zepERDHt6-BlJ66R7sl?;rc7So*T6?51;7D z=%S2LnEuAq%NO2y14p9=ueqjld9=Lr#uY1WTcNy&RJ!W66*sI@X{ZQxnrfDfPNe5v zTAH%jj`swW+b?9@SwY?+Oy8{=WWm4nUWsWs16fSo#tcb z)f~4y>!jnfXYYZ@Q!hu1op&c{&&G7VygI@L(nG{D+WCOypR^=T)Sj)^>6tpcMxCC1 z9I!px!S`exTMokf8g75>S;>gdPH&~a-N|2R?E{8*>xrs%ZMl)T7fi?gt!gqH^~Zzm z>g1hcn4G>L6pv(>l~bG8o>LZR_zwohW<`gw3hCgCv03GVRm&9p=Enab{Hv4f2NPxH z4ZCgF?Oz&tv77K=FfQh_GaQ$J;JTFi4ZZhGvLtIXo2m4^dPUkE(pD{}YVbCyzReB$ zkks+*GW&J|x7W(8rIsI|D?5ZbR#VgAbDH*^>0S{;fn{5|$~6yUh_`MZFy3ZV1%+Vo zM7?`PiaqWBZ^K4l7I?9tp)KCyb{L?XbS<9dB5Mi z*PdG@pyxfG-~0aY?oTG`*?X_O_Wic@+IvxIbKK4O?&wi`NbpXIW@fBSe+bWwcjBMb z^g8~lgmv18p*t2)t)?wWtZHK6<&ZPg5=|!)PYW|YQ{eRsqS6J&d-tV>%*vwE3u}05 zuW>7|N$6T#z-*{!C5?&zmtgepS5J0Xk?F4R=3Zs(tE#EpJUYHP>UWlHcUNssY%7ME z;W00}5EHgcx>W5q3?YP%mn1gZuWJv!6s8K%UDqh&QEvWfs6N77%Di?EaR3`fm(@$L zo!Mm-A8f5qu7PSqlm7w{{Jn8%TNSfIZINmD#m(42Aj{Yf*i|q2tMRfKQk@TZttcP+ z4EB#sJ&q-|KQaVPzbNPGV7uRbRK3|(4S5DU+}pda5>K#Kt;2Gxz`C@ez_KS5RE(RN zUu7Sz8HR^mtmxfXG2>w6MU{hjwdT!(c7GmYHA#} z6pvTBYc571HsTS%8Su5=u41p-p~&D8WEEc8j3^&P?IBRJe^CiU!M76Is;ZAni4Ho# z))u-2xl)(d^c!VZ;wvG#$S>F~v9eQS+5K)~yPz(x$mx(OLn~+G66qKIR&Ef{9`!?K z5k(TW28#KkCjeEZg0pZv1OjWTn*4|HLMLB- zZ^ezm4QM{B!%92mKa6`aW!slsp0OX|vKLCL`}oIAJaA8;-+5$NL1lDxqOv&V55Ix! z#`fiJ`4f274tx2TwS4-_9~l>jTwWP@oF(M5->o#eoXDxz#Ozar7;a@sq%b2<){iPn z)L9U32k#^jH%nj_*!zqR#xh+Zyab7uYUAJGe}4k+G^xVS?y3ZI6;#?+CYte9AtV?! zca=4}>t9!IVTaa1ZUozi$jpY-o~WN2M!b2CW(#E@$<1P0eGHpLTwAN(iy~%C28UEc zRuy1eh^T=~B`bWt%Mr};+4mQ)IR%R?MS1nG6xBd?s^|>ZlIZQC8c;ev$Kn=kO0^fu zm1wgqAmE}(dVA`83P`dtsYbgI!+HGMtn0a6=XznR+#fLOfaH2Q>s^~`Kp%6Zw?81) zz00v~#JuVKJ|NbP-pc^NH0CN2uW6uH~^^angcYE-vxL%i^Bk*rP!qo5mGa!=WeN5mwfgB0w zUI&P*c$We)eE?ja^w|!`b-F2!U9=-FW*q{YjCK0+w8K9JVl<>r9AiBANVjLNv#-zc zFUzuz%Ci44%YJK?9eK})&zEHnW!e8N%f2AX&T>mn|LQEeT7YAftk?Z!xj*rS8PqVl z43COneNNk*^Yr)P(4tv*Y(%f|7cQT_;10NF?FA5|dI{g{;M#s(P;Ck_HxJ2+2j~b` z{ikgk7}vbT*oMFdPn#GY*fO^l%Oq+56#yxz1ZP+k51om|6u5_-O==w zbZT4oHzH29e{h_yLv{#(0?@;d;h0~d-{-(5dS}X@NZ>BMxV z*^8KJ-E}Q=v0JfPiG4(1 zv6$hk(t=rhVR%)0FHYk%KfuDEO-*y^yclyjUiriG*9P-4M3h`;Vckusdp=@-i}RfZ zXJDdb+{|_?7;9q4hl(mP6PiNBQd#z85P8ND#4z=Ao+A~nf%{gNw!+f-Aj0<|H|If% zBQtYOc(uzJ$`7wDaD@6Cnt368v3H2E`Z3uTcLswBH7@tnY)#(oZ z;e%*2@sjSu??4Pz(_BLwDo#6JhD8FK{R%7p=V;1!Ox0cYJA6RX3F-;!LS2I?hzk=* zH(WKBZ;-{Vaf8EMcPEJBI>mamt-OU6(&lWBohLV^>N*0MwymMjD!&S$L?K`W`Wfy* z9b!$Kx zpU5CyG{tEWnjtSoD-^|hR&5zsZp7;o8{Bo%fd2<42&&9-GxAPoalE`c;R{rD-a#Wp zmLX^JoC|qnV9@&bOac2wY@;w1{@>UlMmZg`A zWpTJ~=>acB3VSY41Vb^Ppl9mxtp6cLHg50rkisLj@Rqb&@tyF( z&Ku)|K7`ZCY}HV~mH>L(x?(TT9>UYAF;y{JgMLNLjA`)zoP#sE*U^tan+5KVUW>NH z%x2Wl+rhaYf$D?kdzEeys?`LmbSmN%752_}d9H>PyhxP+u97!$tDD`fa899`Q@z@& z@&*qX1sGfVa+@Pu+S zNdSRMK?4j9cilCb2HAvsq!Bx8CJd*%)GhpI1Cz`5M51f)1!Aa2?Cq13NXA{)7c`#X zjs;uh^}xI8ml%}RT>K0h#8sc;-g*ya$1?~9w?g+rJMe)j1doN$ z`1z;q!}N^QDGCCpF-oyk&ezYfLQuUC%1O? zZd)Nr$w?7_C8}#8qS_!8+eK7q=E&LaSnl?r#E#Z_W}gwD1Aw0;=?cvcZ=#1IGyy5u zfG;wOxRmKuNOLtQ@?b~eGXa$`X@r8YcoAd?5SP0yKZo~wmG)DtKRxV(H!=Ucnvfhv z&GnKmAGlE9F{@)pjRt}%FVjmxyoF_wdCj}I2?(pTcA;nyF(KKS**Y#83eF75~o zwjX6KL641$!|ec7Ht{}54>m>R7Kv)qFvaZ*Xh|njghHb90LbNsKdJ^n$gKr{s075r}t!RK03kWTyTU%fTf2GR) zZH|L;fyN@Lj6S&*pPU=)FC}@Q<>5{AcZB@tU5wZahgec)7TGLKvHp-QFzg`Uz(FyM zTySIj-1@y50nNx==gon`*2Sdj*(bb-CDO}!7AbVp1SDJFp(DpKKW$>_>-Vk%Zyu)! zlJa1I&+haU?^Cna4rhh^iIsRE@uF{>s=`D8;3=AE~lZ;V|Ygi@_3I{LI_PrwRz@yk zdIHoES^>>_ieuoeyA`x>1j924ims!p~{KeaWHTd`vR*C!?&rD114sWIJ$}t_C57?8(a}iOnzNeJ$Z+)gYX*dmp6UK2h4P|42i`7Ng;Uul zd5VIC3UgIieK6eB2eL^I9Cad$`{$eMwm;1=#_em<2Q_MK^6I;tcMK#w<6 zG(p&}a=Wv+l1Ef|N|qhTXOg2U%ax9)HP`v8vB-l|QL`H=9uN3=6tpFNQ^vZu22shn z_-1r_DYDMLf|r%KE^g^;ft#pY*vOr)!c{}}^|~rN%ocXe;eA(QZ8-wAXUaj|U;H98 zMFgTXMW}&QxMls(d4cAH$8eD#UZyT6tF&K5M!PEWfV&FH+*N%{iRS+ubPzgPz$mKq z&d07Vq|N=iX6Ov9bnXY4CKSa1z{b{!^$gKk5hK8Jnor=jrL|%Mtx5H25`wZU)PS9XzM@6H;9IZ+OjSE-}wV;V@ zoIe_BEJe%2qV93F96T_pu+XEgK`f1GlzRhP#DIw*) zc0rBU+A8~#Rp%glQ(AaAy4HcQW5p3AHzV&Fhem&OXuaa(q&eb#HkmD7RM~%rG9zr> zYgOq!#rW`0TSf8=aaGgPtXT4m%)@Ai!%QpKxn|*SEmsiYA*ba}fTdpfzte zQ^;nbGR(m9(hD8u-taL`&5J5fDt_h~ zr<=g)DGeNq($j#}kNa5EAN4;Gzg}XUD1M$^q{mN=`u|+~tjQDSAN?pj{u5>TX`bAr zr8TRpS#mv>Ge*~LVa<*(y=|~voS6eRRi_w2PY}<59ASHk=j)cS9pOL3s1m;GJ;B z$CBqT`0U4@#&^O!4f8ao=8EXT;Z8KAb!eP*NIc614+`s}k4e!nORdCC2x>zDdkq*r zYTe>1?ii`&va0Gs7S2}C4?D*qs)!mjE%!9ARj>}@yo%L7XS?7fey#92qUKls;XVFn zrMnz&ZVoL+I}SBHIONQR!T!YNN@ph?JIA}mYUI|Wf}?WtJoiKY z7Yj5}&sBy0Fy6h0s#1y8I44@qsbMlYuSrjsWV<4fx@~05dhWVsyC7(joxE8NRR?ZDKqrE6!yFIJ9u>GOo zVL5nXEx5eqU25!2efEc{`A3J$uo8HfcqcBptN|BUFLNVRwZ&~Cwd&yNy%tm-YKb0S zS!m0uGgv!@S)-O^?_hEPBgb7g0w3rC<^GYsQ01qal;3#_1r~X#0I5;q`Ga^C_Qs}$ z{9d?30A<=Z3|aOGmQCP`A6k7r?}|XeOH030AtF4!oFxHMK}>gDGg^wlPE}ac*S8$2 z0+yDdp+&^7`LQS-q1Sxw267LR{RfJ?)H;l8vFrtmS+~3E;)mFoSFJNeXW3h=Xx?p5 z@{AJnjZ-yJ^G8|b_{vs2p-QUJ^h{M!zX1&fLM!O4lE|mGHnCvR&+i_@q#SBgYUG-^ z-Yh$^>=V?F&&EUKdTq5@uaJ5x@i)bK&n}|%qV3w`EP7)jv!*H?%f|XR_FSEXDod$# zo@^LaHDG6x#pPei%Q+Bj3VP5;X0vds4=7?t|5#d+M*?Pd#O)S$ZUb@R6`i*`d)FpQ zW>k#3fs%@)dn==O(pE2nF$$G~sEikimxA@08Vt+|IaM*^*y_?M21-a1FJTW00ySI0 ztDbP&dnQVuv2<^#W-zLn;GwxJ-c=E?d@yUM^|3x_U@6@O8l7L@nN{86J3msoMezt7 z#;1tdIjVW-pehM^<_2k&a)x8hK8wjgvJlW z)X?dKN7i~En_oH>)d~4({n&dNpF%N9yC1MqOi7rf?_t&|98*!d~m02tzSIP&1+j4)Iu@ll9C^~Q>Pe(qo^AmREXi~(LeF$o z!H!yF5$og0)_SHDu8!~~rl*&+3Ez&In~^?ZDF)%EDJ)G1Ov1~NniP}pY~0}U6?aAy zwO2c!2E4ElELikA$&|7RyZ8j0_FdPZJkUAh-kT1s=mzn+fv0^U-B>uDSaeK8??q%YVYp>NzVpk_!R<| z05V^<0y19{09g(r09ih#173`Lc49v9;;$8u_Kkqd-@gH(h`qN1vcG!(Sx+B>VMzEO zAp6PH0zCqG$%6iW1&fmYPXW^YC?M@X}qAoivXGbQvq4;onX1L z-l%$y^|lm{bZ!N_2yg-*^Hl^$dU*nmU_Pb&ARx=*RX~;p??r&L_s4+DcR3*QeFY%% zJrI!X?sLp97y`X70kRyP0%U&v5s>jeAh1f{1cChl8UCX@9iI2O8SXy;8EzgR%jZgQ zA1ILbPUufIJH!7IAmbkl$owDgrSrcTkoo$P!2b~VD?sM+M}X%6{t%Gmb1fjthk``3 z|IMlGT*RWvyc7*WlkomKAhPbA56JSM{5gg?FQp(ofQ5iecYnb10Xsm3>3s>1cuxW{ z-k*y-2*`9U5O@P1(>DQ-=@HZ6|{6EaH zFUi6mm*wxzvfr3xzauOBy;=4^R(e0k^2hL&k>0Uc`0R)HOPZf#*|`}>_aBuN{-!K@ z|1A4iS@y59=&8#}xb2hcGE>jDp_12}GOk6X?mY1V)ZKU;0dT=`-kaimC}mYDp5dIl z?}YC~OXl*zk@nZ$a9b<^#9`UI>h2hF#R@d4rcJ#;5mj1}(;d=cPNAEdUyPd9tr*>% zOBT&rrf+ZEv24krY`0_#T8Z*3UKFeT;jHTUKb&=EXwEYIf`nv6g~esC#mj@i1&g3^ z83_tiFVY!Uyck%@>7F?YL-S@WSqy}9a(B#Guu%D5S21zA%G3g-MH@ttF3DU;22eZ; z@X%ZJoUD);8lR2U=!|P<)pLTudCM+K-aOMKj}5OWmsxkt3C=ed$#*b}Chy!TrV%_D z3duIbvV6g!r3-a&NXe^w^0panvayr|Gs~*WlaFlV^2l~$Q^|H?u2L0}?W@y8*KUt- zpl6C+hSJfVlu`HP#*7|)Sx@)rN=rxMS{;nKPq%Qv?LFV8>p&lMc=Ql}In=R|_8!b^ zOuouso}-yAb}oO+kM7^}eYp}$#>#*mrY*;GEJi2Nq5FM0wq}LOf3s%YP%(p(xfnyI zTn4KWELKRbCxa%qe0iGZtXV!N9!NQue95$`JkpCrqDcne{k+WdWzt)UMI8<2Lz<;n z%(DpR56c{1l_&mz-U;6yX%KoG-)R~^FWsc4mF_3IKe$fl#iU->N&1!|eONcrWRN`B z{lOX79ME)0CCtELQb;RzEa&H|5BW#pESuTqIvm#ka(yuaVS$&tKge(XIEPNc4@=x{ zZO9+5PpljmP7G~AQ**edw%Upggu4fZj~mCW;`j<2j~d6#;^v4D(6d*-9Q7 zPh{vrc~5Yt{wN7v>2KaYHn_~M-Fc4o`JgYlUNmIF8v!MVUG1lKbir*LMA z=v_{b*WQfx&6@Y)EpBZ0P&kUrh?y;iwj_en;o-^(?LugsIG{SiG3XlyRzVh40bRR1 z8ALsBOHWC9`CUIfG7B&7@fnfCi~j1C=J)#Wk&npu=KV~SbGLdEjKxu|<->2fp4W1K zKMk)Z@N{pOzj}GTzxl)7DnMm)`Jh7+2lWb_25;p8<(6=(h+O_0+Z;|6lq>YbI)iwC z19BWb=9CM|M}%l5l`_R9RoH3haGI-g47SD7+XI?PqMoizRC2nuJOc<2w+WzA9< z%E*tZuLq7})8wcbmO*kQi)5K95K$R?PlubD~#$V)flPCBox?Q4WYW?LP%CL^?e<4fERv)5_mn z;B*%R@LFJR_rPlk@RUcm*#j{J4@4f`pAsFjHSX=6GE1e5GoNZ0QWi5?0(Nuw-QMA& z&fwYMqrHLbO@t5ShSDhc;bUmI7EZwVW`PWQt z?gogoqt9L2I#IVlxu?)NQQDwx>O8Sao@Iw-^w?v(sC||E_~?ur=4!QZcUFgjK(mcg zdvsQnerdnFtmi9Rp1-PCwO^eIT$f|}O$5)9r08y2X^->S7&CCrnrcYt_fKv>nUEkZ zOS|iKqEIR#t6g}BHGefzZcerX_7+m-tzed$9*s;4=i#A~eAEu_kgrwVr{k#?zIkG| z>NYYlvyJpZ8`*(2vMbd;-35Kz1yj*JobG`E)jqbOeKbq^7_>RwJ76C~z3=NCKEirG z!g@c_J9K6sf;zXSK-)c^mYm`WMEd#d{`N#Xr8KF)o(MlB_8=W7v;RaU4~pD2s4_Ct zhvy-Ec;v_zxfu=UOuu~=bl2c@q{vPA_RaZ`n+oik(UrgJ!wW4wduqPVhRf#gyH0yg zcweu6yX9Rhl8%2_*j6P{w9d zBWe$ArF9~&l{tb#BxzOl73?kQ5T9kL?uJ16iRXAdzn2S%J-lD=Iv+`e)CO+{UEM=h z<0)n(Vm#rXilG_(aXthE+I`XLM1}o<)%vqr4Lks?YFF3T z_o}vCrpO+$Fz=q4c3m@KVSaSiJx&~Zr-~6_JAVT^=kvt&Km?O#-Y)A|ZYQk6uVudX ziwvHPMFC|J_qm|pyf2Q%{r%c-;V$%kd^6;DRCTBN%ari={f^M7fyB$WPUM70#%H*R zf|o~K@v$czW{|GhFDKW`E&3(W{4|FX3GPK07rI&mCXa72K~R(3{xd+>@Kp z$xQmxdKK;I6ik1i!3qKGz+JxzX@`^UAy@%VF2JJ<6@#}~hj&@wZO(C%3POXGOU!~C z0LB-Ltv9(=_s3giGh5WZnkxf%9}Q2gF}2C~N+F8#%Ib4fXV1fAb|xN!?$5V*2U>Vn z4bK+id-)qa8|xfJC0ReB2fom<|Axs9hw@6g>j@;&XTJwUmd)|Aea`prg0z?-27Gu=*uKdXelKPfzuCl==WE#Kf3+h}{W2f+>X)}& z%OL2h>={pVWY!<^i#j~Ca)EtNULZVZ*=<&HS09#f+2+;LAJ`WI{o)-en(~H&h{k`o zJy3msi|%202bDVt`NHTjNYWib6&y^p_cVdW?e(uf;OS=U3DVXx$@nix#cywKKH8`3 zX4mR-Ow@kVEPF&=vxWfZDSjBCYy)85S zfoiOT$8UA$u37&hq|QoUcx+zz0Xp&pEU5{QSF3c!uoi8Fen$wbsd5S35(tabT0AQQ zm+B0Z=?rW|23nK-&yVS2+?C%h{c8SI{SWKg=FhM8Cw5{DRrL1$)1u?|1)|@dUKO1`y{hbM?X{xcHPO5de_6{t<$-WZf9i;Bb)Oki?{B*c zsvPcu)7>}ka^KMIzInUl9!Q5%@#!9TDs}Q=IS#$NTaSlct+L+`H74y%RqN^Uz|nB7b$> z1Ab>)qC;sX?%(+l@}NGK;`V2Mf8<)fzw`_Lu%rG`Twa1(DI6lx%l(nN%jq=iIK6E+ zl)@o09jlhR$EJJ00*A=-5_puPd%yyR$n+8L7?JJ)3mhWTJ@9}&!c-ivz#%fd5FUl; z98Cj zJ%n!*isaWp3sX1x=KPci9_CQ*l?p`-%9$ycO8jz#Un~Aa3QHA-{*wRZ{c$OfZt;86 zZrb740{mR>+#eACVuZ{UzelkUaZZfzxzgVu{#8BDFX;mhn7`vU@Kj2uWg6;Vp}7se zT=B0J|4V!DZx{b_NrWV_joND9Yy$4N;;$9|zaV5Txx(3;5@3FbU#{?qu?)YPiIgM$ z*ApDq49QNw-=s4&vMu`0=w!z3P-dybgkNk7ktw-9*y z1y714C*Dti*DiR{?{ngj>(?OimZR{kj7i^wu`Y$`@EQc~MCJ1s@M3}|<6O6RRs92R#+N!D9PgAd^&bfLeW*_~*;0Rk6^y>;%@|?AMi9lOrb?<`)R!U1b$aw9w5X00rS{oz+VFr|0+Pz zJs*(%|ABvu?;d#4{Re<_A0+m#F^|*U4Cn{^4IsRV{uPk;j|f}=NO`%*fRh1v#g=&Q zAny$K0wC?T0n&e(*hdOvUDN+nv<=dI5s=}24@md_06YiwIe-j*ow#2G$n>2GNc@8+ zU*c~CB;KFJz6_9bX9~PXU?E@t?!Cl*0R4^j=K)#XYXOm!BHj-myi4E>0(}BG?$N)G zz;{u}w6k3xYeoMH5J@b01Q1ab{R9xGMQZ?IiYR(O|EmG%e-R-4&j5r`!?_EhfQ>+c zd!Jf?vjvt5^ayka>;N(1#{@PCtQ9z0V7Wk#K!?B%1Xke%HVUj2I9p)3K#xF&zz!rH zpM7Ei8wJ)1oGq|iphqBp3TGo9r{QPhC-{Cj?Kg;=2*)1UXNa9gleFI|cD5(VPa1iN zIPJ*WQjrts1;5i!QAzm++L2(h{w<;%__GCn4DD!eMjqjNVrS#0;ZuN=Z#3)2%?RrT z{`9l8|98dTtRLIOzgGM|1RBGe_3fkL-!AkgNqDpV%R_!hzXY9wrV>AfH~Whr5`Ju< z@^dR z#?SUfbFui(mh|!9TBT3<;;swRgYfIl(hf(&->mO{CE>e-{*T1p?2oP#{|2GYeoOjh zeSC)GZ-$g#wfLL$@rB}FEB+CoZ}wM{g#HGh&;CpLjrh^zi+_RmV@y&0F?zxrW_-xs ze#sxtgBhN}%QSzN@ErVT?iPQuKBum1hF>rK464E_Y--ch{!4{E$0y~F!Gz`yLf<3x z{}$ZnUjmvmRMVp9OZjq~Q{iR*^0xSIknlqhhW=*%{2}o{D<<*(iFSlB@>LvPiEs7` zGbKM=lAj-mzu9k8ihsNK|6bzbxJN^|aK^V=%6k{wNWVkc<6`ljF8Nsqe|RU&KW5o~ zm1X}ymi<7MT?zeBa1`8~Ig9l3`gn6c-I^vP2?0SPahj6lG%ku1#Sxdy(o&Bn7EuH( zjfRh;e5H~e)f#kX8EMI^SN_2{nHyRv3c*yIu|i4q-%BTD(A+QEp|I+`43b2 z3m9ziJP2qmxCg?RNHFNBxKaLMBeTsoAs0ze)>MA(nYV2Df+ad(sR}fbm8m*3F3D;% z4yN8zG}(^Eo~lpd!b&sWtT*$Gs#BjC^E{jYZ8i(|1RBq`tneLFPOcOM-J`L`|1&bi6 zjV7eqLCQL7{(?Ipp9}hFZVQ*J$aYFfZKo<*#iV7N(T+0fT*V|3w|n5*2+`Am#<;ywXd)mAr0J{e_m-tq!j2SzecGUWbRVs5Sfv z^+AuozJjIz<0y@>bGqOU%OPdHsl2X_fnZ3FVaH-#nLvj;M=gOdCzD?_bR>C>8_b6g zkmMS2CzW5FF6oL%h}odWDaJoQ?Jww>LGonss|7OO7RqGf!TwFAEENN?t?F4>ggB?L zm57g`xVynm^B^pz-RbzzFai8=sX%s{M1ikwZq)g;lFtf6zALgsHzFQ${_YQta|9u$ zp=GK3;rk15OzDr_U$~!fz+R&5CC2X8cE7RD*7n)PzEay)iv5|jqys6*sQNOl>yxhh zGOn?tE5D5E?xZWfj4LN*O_yKBl`r;cSAH2+7OZyVmvJ4Nbmfr3^zqMQu0aQc*JwS%wX1R(Cut4lC4f!AE%o#E(cfo0+g@0DlUi??N5P{B& z^gx;uA`VKL&qfaMs_!UNY9O-Oqk^CzDUq}}@LT);w;#0ZZ`yv`{s&sveoS|x^he|; zY(;E2QnNjf?9Rtj_l zBG-@b*S`|PvFmaV+p=Hs&W(3qi*yDfP z$ybXq8sr0ra^oWWvzlBc#>B)ios)r>CSMwvj9dl#LQmV|F%$(F!7m&%PxJU9c@IQZ zl-OVRiZ|agB{HqhZYys0m2I^r7Y4`S$=2{bytKZ#_>0u}Iuwx%@k1)nAE~WHlzwPC ze40lUaTi1se2{wIme?GE{Lkc)*2${t<&Ymt$^$~?6`f;@!(IO}XerBBSYoh1?x)Zi zH))8wo;xbj!?_#U$SaAea4F17+0J=zsKk(Knnh)_y2QLR1$V!B{sZo_)7)34+<(0m zSx9+3vtC(0Qn6G9e}uTaH#!Cd<4Xv;zb4n{lW@Q z8d6{-CKW;wB4X>{Q(dL6Bw|qXSLl!CT?e)5%_!Jl0b~q~sD5HnNqi*7V8)-(2!n8t zMtBiCRhfx=u*hO^nTqvQHPdYj6=38#7i}bcm^ux_rY-zmBCCr3-9z{eSv2ecZmx63 z7#C46VGX*`pDz30zriP0_>-NxwI9}eZ01iH!^ciLzd<)~_(h+g({uTN#6w<9uTa5cUhcltZ`pN%s@{rifBSAj-yD zsMm!>y#WWpPW^NZVpP&B!Ebu{r_X)g9Ak{Z99pqawALPq3ALJV` z-M`WGRCE&{*1X&fkC$hV48FWZW=La@10M zn|~k@pCw5no#Dd}hUt@*7Q^D8w~8{|0V+1rt%#7; z9G8B-E&rgjEFIn}{gp~Wi}ES@`SR;7<<#;g@O9!b}9oVYP9 z>&{bpY>B2vA_;J^{r(1XULy3CBHt!&B+=7;zXS2%&rxuJ!!aH)rtkMjia(5x91A%= zd~1{34^Uoqy3cO0sPFQx(2s~M-F}k8T?j5Z-^6F2`s=D_-f?%sUtuA00IKRa0Eb(? z3Pi_zML+18D}BX&Cry5L2(Iz$rXB?DQt}D{?uu>E$$8-}ym`;V3xDL+Gr>zGhqwc$il!@Z=~Ypgn$sslO9z zhj442-}!pL*$$0l6{KOeb^a0%DlxF>807LFegn7xyPye<4nHV`j~#bEQUjZ1?}1vc zgeMRU9`}?cEQKNa4Rp zx?qa!>s1gw)@xN>qBRbQVc+ONI$;eR9PODJ_4V@D$C%}|)!$dQ{#?MVnF^V64+N4u zdcTBgf%^lte}D9vzpp{zxoN*_yi`hns|{$NJ4z41q2Wp9jhCKyzNVV*pqweodehAT`9SI8#HcT7|hZDtbYD^-KBMmjEVgxRf&UMQYqE%N85Xl z!Yh+8<&9;PKk_fkUhm+QX~`SwvR}lD>~8x>m2}^gX~`Q~kZ5t+|Df}9Wm?+C7SiK> zdW2h5!X61Xqu(42IJDPUqmI@9NheoUXW>5U61YE-pyB{Yqq-r zc1@crI^Gp-MV2@m(G{D*nzjPvicZ9s=!z?FHEo5;6}^VZpsRO+cE6h7u&Q*K2E4XKFc4OLkBEsy2ag*(<_di0rvkQ1nxC~3qJxG( zK?yiUW%jDas_d_oKFN=um8Pw-dS4~pI)?t34{@JqgJmDL4nsc_FA+B3wlh@js0qk! zxh6WE0oGU9Usc(k`yz`TgH8dT{W0EmRT$CyACw-7`dpY*T<)KI#afIGcmpX)-g!`0 zFFW5=bw3l6$ve1#xPdRPhhTW~2rD)!)&?)J*aDrj4}f}@l0u>ea*25^Kxk3jAX z=&sfqfG%xUJK@gWpaIP|P`Na(Hr!R92-p7?1E82W`Tj${F`B;iHOpN-x4m=|fxv`)!I%cy@X>|M>K{qbb zQ8Gevf8uAOC}V#6b*vkp5^c=z3fvkj-L`)=cnK*hRo;Tvg&JdXsAb!|8VKl1ZxRV_ zg-e@6lRLsTS&0_2e+W^k-@^C`-9z(m`S~MUcSj4`&)D%oHSXkwS3QRIJ_LR4o#5%v z9E=yh4T4p?H9knaExp}1`J4xE1C)tDg~Sj$6iefs=424~qYVc=70%BCP-TV3`SZ5p zzU=npxJ>BV?(!!PSGg;AICBtbAu+}s9VD+5Ae$IRKuV<)@j$Jz>T>IqL+6E9m1GBE zOJw<+FyLq4a^JDG4CQhOes>GxH-Ent_yJ(@{SNZGWqcfA*?+;s*^06kEO#YF$d@YJ zmG4#9TPxgC|L%8J?x8k?hfhJ>`|OHmd2P@}Aw}|sD}B$=JXjzz&v zC{V>>wiy)?sd&~`w%_Nj+8?NX0p9JE(S^+(T>eb1hp&lLjt4WjqJ2uVW-QjdZ%1x? zNfEoo_Fc6fH*q;l+)FI*&NUW>s|>6Iz~bz2J+W{bN@HRDn}OA3g|~i1EfS-M<}qlV zEHp4yTRqeO>waVoYb3m7L~3eip<;ozGu_m5k>ZbM>>qI7e1@8N@a9DLSl>10Th84U zCxac}s$(Bf0Zp9YEi+OPC}K)MTXh^y-?!oFUnfTYM$3M)q8JSms?@5`9X3}&%@|am zR*+B#kIh5d;;Ie04xnKi)5GT=vW`0d-c7f^EQZFp<39TfQNx6qSR2g`v{tNTuaSx3 zogH&B^FzrJ(oaXpYXUnc* zQ1lHYFE=(-lwr_pv)omii+6|07>8B-hE=?W)R+TgX`Q{N!fsb7kLI0&i}o|oa=1L& ziQ%@m*4bLyZ6w)l%46$iM_dkx|3$?Ny z<#E0PL$WH6R#hM!D3kQ17ZycmUj*zu}$AdgkptEm|d^C0F+EbR2`rlz*FnB=-DqvO#b5}e(( zLe-x^P_rA_8kV%iNoF@Yp6pdrym3_OnFSfSu|0UH^HqQKizw6Hc~JA4_tNrnc?yI! z=iA~^%j?wmmOkI54O}hHqk_(tAI}!jf2-imU#|J55XyyeypoiT)3KTOia<7)S zcLO!A$u8Gymev zCoq>@SDW*%a88FMytL7;F@ZjSbXegRj^pk#wohBIee#hVGZnMqjZUbt9KPR-E6~fZ z`X=}spevRu80v*k^u`2U61Wn6UG(cRA*|@k594AKe*T|f-!iV|i@r?OLsawPV@)1|ksv15<7jH8S9>dZnAh#am(6k%X z3sYJ};|ARY2I0XV2JPH{;uW8hQd0x8{YCtev;a`S1f+jH>Ds^ zrc=OW{faFdnCv#Si@}O$ReJ~gdKs@j{_B`RlQi-3(_WAc?!`Myz=7TU&`0b>(R;weoaCfOZ_S^q zbWe-<-BZ7;#MmG1_=@K_4tL#;@E>|@F=?S}*J3w#MOAeCk*esRZKVl3JFsGqAD)rW zTBPb=Aez6;U$*0(Yr!ABCK}v>>ZpQ8&9;KlZOQfRm+mFLod@tgf9Dj{KUz6WY7^D z%opQTf-zlw=z%LcT+^uv1k1ujjZg#|uwO$>p^so@&@2O}1+tuPg;#BH1kX}6!mT`p zTJ38UzYs6%?(B2!x9k_7fJ%>VY!s%%F%=~pu^u(m(BgA`$w*jlD2#UOewsBNaDx3* zWfix?^@nq}-GYHD`2E$RFr^uJI&dZVIstZ0&etmje`k>EcIy5V1I z{IcyDIYs@$%#}OeikypiZykPr5Xf)--V@0AF?)aD$KVgaqpIo^E(!|u^F{7*p;SU= zq{&{W$E`ZABQwIjv5h+^aEE;M0aOqN1hp&Bi>}JDV;E_hf&-9?CTLh|L%$7SOSDRR z!$z&z^{=?=j&W^|tVYTUtV<^sRM>y3DE`ErP!PHf3nW*lGJIdY8!WRmr$1MKE}(XbxP&B}P{WEB^PH-uN294?TXe zk6q4Q^cV*)zAp6sN*AVLMF2|Z6QO=c{sv`Dv^@iAj)vw}-%Dl*OEUFr7?LxBQI);D zreE32$J`I|eL-PLphz}YhGXj4Hi-0qtG@hv@(_3oswI4Zm^1XV2SvcRgBl6P+ob%4RfpWe53@cnn=Z#aTD@a z4@Ox=xM$O^7-0z1#Ti@(1bc$ZuS!xA23Pm5*b|t|07hoK+k&00H|ocOI@`1!#M3g? z7isSUwbjS)J`f}-Rr^7SHTlbq2ldFCEI%K0b8qpdwxBK1F?us0g|-?@(wrq0eCDL3 z6~qSaTa*;@hccMt>O2EWGn8|hc^<7l*FE?c+-bh($sh6`G>5Q=$Q8b$zxJoRL@xjG zeC^M7b#wX8hL8)*7x?A$=V2ra=a*dm9v)P}3`RP0`I~!R7lC`5%O5fz%JihaspLHr zB@D|?86&?lCG%b_<$Wsgi;3POmZvf&z^?(qTDkAf^3A}{y4OtlPvB?nm$ST;G4ylb z^N4kW-19c?8YktXa^UkFfJV7T%=%E~1oX!Pe<>fHVfkd^=O`Z@zB>3wFbwNUnG?|e zIq(ZaPZaC#MEEOlzV3!x&DDTKfJFj7!M!mw5$}6|kaPF01H_rPcOfA0rUF6)-aAn2 z@xj{t2|&sRtpmi>GOsPr59oot2$13T6l%PUfRulF1Q37TI}ivYy)yyN1-wG+=L+mA z@Bk7;|5pHszX3!De+fwU1!BKl?3ar@ACUPyh(r>;49IjnC-A3$48Ka?bppo;>@Vx}GXDQ1_U{7{uKjm<@3Gtr9 zILY+6j&>8w!m_M9)SQV z+-T6{{b?h=G8n`t7iPxk3*qmEzn>AqAa3Pv<|!U3)4vOimF75p3~%NEo_o{3P{PN> ze>U19jZ^&hqw~`I1wR!(3Xx{N&~Fm|xp1Sundi6`ApIHQ|D5=nd2WaJH;Dg4@sG)P zNAVVhA0hs*D*6D*@NAs^ZIZtwuoK4^j=Aafi?i%^WZ7@Xvh$D}e@U|(U+MPCvg|ck z_EWRM`?Ks%WZ^%OWxp}Y{;yef3`-g5QCHTMhi>Nu*W?9D2t?C~w?FmGyE${`W+Tuk zg+SdLP;(K&6->FpNtfy+i*BDYRz*SU;w8&)hc)fWDFv@_(=#jTWXLhekeLy6k6Kaa z9zSjb=13J?O;V5oMwh%!$mB?55aENDlJx5)_9vo)BIT#V1VJhNnr+6#LPaF0qb4b3 zD8-!0z7hq5Yi4m9S0*%>$8<-XnRJ)T@<{i|D3WZC?u1w{3QLy;KU23I|2uj}#$0~s z2VC9PIOJxJ_!%7<9P6c!5I2~^j_mu8BfyhHI_0V-|}9g zp@Zo}nb(oYbc5kC!<R41N2x{F+Fe6DTCz6B?wqbGLgCp>|-D|{>OW|V4^R12HL+~x|HtyT)gJ478WVTf6UfvGI z9QM{~lZ;CxL&EnLKvy#}5iG!+odPhD{93I>{0#jlE@X1l%iH2inG*YLDrQf<@1E$$ z!3V$L`YJGic}jmwMTXrl;=3F`Qt}2;Vidb4Q^IL1nUXV1N>0aamOI&;=`bFNj^sH6 z@98BYwww9(a_|DhUes^b*T)pob|rWLl9}wgWZn7t|6j{b5o=CmBiK_mlI3B}CHPJ{ zl$e8!3yA=*6LAd)(n+F3*+8&dD@s4*J)zaQ$g03y7@%0bnjaVkA4f|&pxSPM7G^wh zPPV)az1}!zCXcs6+SdkWuvE7yHUeoifo#nI4|MIF#Ecw!g$H9w8{+<)3{ zh5rr(;QFE#P6N@_GT&zIRzKHI57;|Zd&lw8QPaGOGTU0J$#yaoqTsv z_Bb>{2Quv!DzMppO;6J8*W@%;PfBmUU8b2rffq-ArjhL@yhVN`xj!cAZPQ@)NgTAt3mU|kG8*nP}Ayl~!RymQ9zSm0Zj1QLh?KjfBZnKJY zATy4vWI8|t<6$};G^!`o)ajF(_$ei7?m@DimB|tR zOTcRvdaUmZysUco^C?%>* zcC;AupdcOl?IKB(Ucp3nSw*ZiMvjEQn{2n0rDwhM2k3un4 z@?G9W*)cs&0g_ImwqM0}s7Pm?_;a6M4Er#^5rBL%?n1y1P>2lI4#@cb0LXBUYIpBU z@t-9A2&??d5gvbiJOXKzkH2VmO{8G5vtlLo* zioa3I05CyB#(RNFWuI{g+{j-cF`BUWH;O+m1JK`$KYc)-;my6pHiV(S8Q48C z6aO~J-+b{mKM-i>BMN`A=0@{=2inH)h$(v+&nv`EzfU9-ozEpOR(2KFdBMi@suYq%_JJy|!Q{ zDIah)6r@_!tnXQOhZa=-Q2B<8SMq_ekRiZ;S>I^^>1&ua$@`XyByHw8r@=5Pfs+gw zGC4?JR0Z>U;qv(l?g*AD8tLC@erfT8eU!|e##UDIAX_R>TA0)oRrOpO(qMQ;X_4kq zhpb9D$(%u2QEFLM9Zk9;$}Y>=9S7x;fphn=bgPs?4yW#vG;Vj)6lRXAu13G@=n_xL zoJ_y%Wn;#U(b$Twv~(FB?b4hjG+3Bi{H3)RiyR*MYW~s)+Iuhsm>g*~2#(Q@&S8ST zKJ!GUo6ONP#HP0sNF2b46Eoh9;@GWF7C>doalSv10~ zcQD^fUr**_dUH)VdC~}^(@P(Fh;lOi*GfsB8MHAxT5xDW7T;<^3)$hID*#zCYil2`6`AJ3C8GXY9VLFe zpQ3E5tD*D<+zwIcI<$^tAc?%W3YvhP9*b}CTOdC&B@%qSi^{{?e|p<~qud^alBf+nJ^6%gzA{Z{ZsGIeGy0O5@m{#i{`_^%SL zHK!TIT!x&8$-lY>f-?9@1&HRALs!v){dWSl((d#(cU~Q6{`y?Y`Lch(?pLdBhhWxj zD4f08-+b%>XUl}BZ)7jrh*=Q(^6c$D#0H!A@IKGk79IbB3#q7#UWNaTjocMMy2F&{ zr0Bwtr)=cj)<+>-<-9*{R*_+5bHgJIMK9$IvU zbF0Iv5g@7!O~ANgfe#jMiofZ94hgmM&TD-z6+>U#Eph39AzZkt01pfyt3M4mUx56c zzxeGyWLg(+aLf4&CIkEm^R8UtMMXYEzZM5={^$>!p+imVSyg3+gGYS5q_NysHe3QPG<<;nfH#tKODhJMU*we zZR1X)@WI}thw5S>sOEdWa}Vs}y&>G4YEkzPp{~!`G!D5)vb^@Jb^i$p<+l10&5%gW zJLFsYJ!j~XNzu8NCw%t2mmow8&4&qh-6O0X+z~=S;ttAT>+m~PVn=1q7}NkZe+D&l_~ra@Wy8U61+#9|8MC2t4QEnwv$D0O&1zC8Ir9;RIw@j~{+L;GTNGXCE#; zoY)F6(Pa7it6SaA<@IjZT)Vlw_GrHq?r^Lj5j=TEGN9vIHAx zC4gty6;MoC;kaWh^fq=lLivHjOSrW$oQfMig^tHc-shO-il2l0vo^zJj?i~iLB!9p zS}R=0D5VH-*QcVO(k}Kz=Dnl^%F-`QCH2as^pJtSoYp>gCjMY=(62*P)al024~@fU z_1tGY$JPOEbE-ThKmqnhlu;n@0~98Z?Iy)!rWWSoW4qJ~X3p1pXwF06hA+>%KyaKKqbq68Pw2java3!mia2nNQ&0 zK!w8Lgc1wnJ_>FR_O6Qsmj$Z-;$N^`4~jed&7WaVJaV4%;19Q*UcCKj&Q`^{AcN`K zjyxhtRX*252R-I@KL;&wbEmf_n!`s<51pGnhUjD?VlWX^#0Xfr?ZMt4fo|1Ic|psb zTwvj8HV6owpArxZ^mcQ;$(9QQva8C*^LcoR!QK)d2yzMqgQ<>6*JCC(J#Bnb^9S{S zLzn9D+Hqd!e~m78#(U$;r}ld#p|c*G z$4!J*s{oaupXoF66X)kc=I#!pqgCGZ!*40gZTg58_@3U{XpYb&t*1Z|IYH8XJweOVpk#fYE{D6-#Q&u+UEDfRGh4uJ z)(ih?$N39Gj`K@O%K*HN5~vp&asJ#<=g%!hC}m1YM_)STvdga+TV_p|=&K+*C&PRR zTP{AYS$FcCt6Y5I>9Tk{rw9L~s{9;|7UV8h_;TSp%trjV_|%4PGpnccx!?h_55HXW z4~Tz-!ZNwh7XCjOA9=pW7qWbm$-%$$!K3^T>oSpGIc4DGkXs}ldA9JUS#BBlS$y14 z@O%uv>B667IVxk)k%d1Tp0D9|K=`S%6*B%A{IqxPIHZnX%Y$M0Dr4}{_`~EQ^R74z z%Q*utD}RiiGD4oOHNKR4Dt-xm3HCLp`Xau^On&1)KvY#xe{oO1f<0#RkcNvk0Fp2J z&wwCbbc5I@1EPr)jTHNL0rOz*1o3l#|2E*6fUg2#Z{mF#a0uY<0gC|d2gLfoOZhg4 zba{&a!DIApLgXI6KL8?6ULPRp!h0Iv`GCg|>4kvf0f~PpBBlQ^^auL$y$SkL|Hnx1 zRga;bna@Lja4O>aa*@yai30*nMJW{uurmvF{dpmDoFIM;V*_^+B9W&k}#L>0c-Q>%>1U^v!tLApT3m ze*o_Pi{67ckTD7iHN;X5qh@G|g@`-Chz zn?*W4#)1s{kF)H*%d#t8Bve1lpSRL6>%w7^RR zLedhYXo4<)7K;oAYB~_i%eu?|eJeigrI%fypC#0K4VKNp1Bgq|){M!;r#--i>(Lk| zlLPF+7(-Kl@s7sWIn42gAyb)e%BOu%0+1d*T^LV?lft*;(;7N5ygBwtI#puuPm*h_ zC*_0gmUMMUi2b04>BT|)ax$c6kUSY5vt#D{s? zLHX=Pgyrx$9X}dokw4~{JO{A2zqR2$%WkuGK~B#;j<@^ln0_nW$i!Bp$w{d5AW4u7v+5pG3H$3y(nH zqIfjmY)T-luXbRQZuVP0hJ#PIHCkB6UH2Eb*)yN;M=3C-8GFxR#pQ6{oaBvR=gaGR zT!iBOD{j4lMP#n)3AugvLHOXV94=<#9g)yrm1^)U znqK|Ta{sAszXMi7-^i*b;$x71z|bkygMH%{5&;s9gA&`GW7A8+jh||5?d!B^r#Wjk zIKdG+yvzNk*swNG0ox>>tRm>Jw`%kILf9@@yySa4s-*A&)x0CDl5LcimW^W<;}c zoU)=gj3}qO?(}X*I%ye5e3pu-<{Nw2ss2%CJA8XeIG2t(;r{`wtp3UNqw8NEilj9G zEJ@UKSB>l^4aZOz_PY$@5!)0Dw7K^2OJ#KDIu52=__ZhT-yr@y#osReyFfWt{2OHc z=_&q`@exMI{$1klwjajcQR#p72p-Ep8M7bHvCk(Tpu{Zwv5B z1n)%Y`~-N0Z@}_W#-uX`KVS%Ob_+kCr*yWWe351EIzYtjT@8p}MGF9NHtW3>5Qi|{ ztHnM_>}QMp9gLt1_W~fp{TCp^{Roiz`f7m{fW#XKNW3CI)SWjU@N~cfNCc+#qE0{; z;1)op>o@oZSiWifsd(DE{k$X$AJW-?aaGX-Aow^%3Q#Xz!Bs68R0ZH*%o^^9%gAZ(R$TG#uq9&oo{9qj01DQt|IE z{v*Vn0}K64|5E#Egl`vrcqxAXWsc*&lGl>-JV`sl3;hzIzf!`_g+FN+!*WlzZ_Bbj zn`IxLW$(zc*Jjzd_DiQ9$g*?opY9KyR)&2>mc2O3&iz1oc(rfgFxzdH8eFgl8?x)H zsXi@vq`sCepBI|DWY+EX2IuJ=T52bmrDjo~r|^tI#FOfDlo)i9)YceL1=UQDOe<}7 z>fK^$yA0fv&OL={q>GIFQyS?s3TlqQ?vFdVG>re7w>N={^2+jtt5}P*KtMo53IPGJ zgklj85eleSrQi}{jBN}Of=j#LQWdq0K|Y{kO{Jol#L>KIU(J_xVkYC5jN_=WjS$ z&1g8i)jU)d=wXOgbRd14E-wMe!^8HAV!Z3%^oSo#^n~eazjz(-g}_rQ28Q1Py6+dM zAJY${6!0d}g|A09Y(FT@{Y-^lnR9LBVR$$w%(hgeFM1y5qc>g%>4tWot}8^;b?c%L zn5|p|uPVnNz3qAC`-RA!Ud_L-je}6l9!lwpy)RXTKbngS>~Q$* zi-V-QQrMhWpkPTliiEZmD8+%y0>6V|{-xelk&I#+1D#Pm4@@?w+WFXc;#;$i(HeOd z+s!oS!i&~?bo ziV%Ae_d{Iyem;iX^`X0eHhq}29EyN$>D%rn=-aLiFeq;stlwcH?^j`4p(?lMrWP#? zeqk`~PeCw42&Oo1)to^Y;}n*>Vu#-W#Z9d^cCARiQf`k-HKc!UwBf!`k+JrqvEAnk z$`q&N=gigY9*zk?KP-h+`p0@}hXEH4YumA<#33kZwhL-@+g$pdnDVAm6>HjzryRzB zK^1F`7*Bm|v_1*Bo=@;=y@N|RbgAY{=S>h~7Scw&qL-zUGGavIc(;dL5>LKM$9s*7yeP*A4f2@RlS>>NBhpR|Q;ex}^KtvD0;iK@VIeD!8i8FWD zhR7v1Vl%g)_H#dm$}3zvYk-pCzd5y#)27c>sw%TrYLw6ksr*`Rtx~a8u{?unqU~#M zllK$_D7xr1jZ|0yscm&1fe^@b3L$Gk9{dlF_B7FYN_r>*8ZwC$Gyv*up**Oq+fQ$+ zOjhX&kFWB9xZEJu?pica^h_tCpy@)Z^^5d2Yt?6aN>PI8hp}lD8|A$vWb=ix4Vn{0 zJB4%_KK-f+|6)$({pztWL(xJSi%3?Z3z9t^gOMf3@iL1T@?uS<+O8_-GlnY38&$SJ z2HO+KstW7Liu4~0)`cot)n{OsEHK#$jHj+O{h-ua|7bRu>`&iNLDy4MbM=L^yDV$;85`LahsXC~>TyS+{wR?&4`9TwcBSBLxD#J|d$kT(1T+UIUs zE>&4ip<|m0AE=w>AZ|%cF$=2up@=HSglu*H!Sa1)6`W8Dl0gSz26oH{`-AxC?R;I# zXV>B0+rGDzx+6?EI#F-#;vPj8{PpI}_b+|k(<_l8yiV$Rl%1H{y>eHV)X%bP z;td8)9{Z(d2#5O~z8-pvyNi1JC+=R#!_)qP=!8wofiwRTy{UTTH<#3z_l^Kx?bEZaDTjA^33RYY$9ax`kba%>3d4(OOE8`TF#@s zV1D+xJ$FQb+q#_&+}xM#y~^Wnp@Pxi2Sepv;89S_+W9Yy?{{0dAAyT?JDMFckGgLE z7aoAx=+NDEP5dG@vwDv0VM`T^mF1n zh`f<~U+Zkz$AHhHSVxO#~hqZ`KOY;UD8)kqJ>8fz!0*!|@fA+zUi zw7+opj;_^h-mbLySE_&8s)00I*KJJfnhNMO4d{?ih!oRoPWl|r%z&oK3b*^~?42uV z(F=)LV|zPAsc!x+Bo)U&O${Uk{SFW@1M5F31qM~qn9NM4{tSLU1h{cCo6WE|kB|tM zmzip-RhY7{n1v*{r2}hRJQ;D0q>$LUeY|a$jwvmb*veQLo76i<%+{EG9Dc`IeRR-6 ze5V@^-!z=!vUIWChauo)z;<3-7vxR%|? zLe~D^F5g>tV$~3nZG_P_3d(vf8I|{pv1g4?KWb89$(M|GB20KQ>3^1d?#M3ugJrnB z=t;Jd3dOuH-%3IM26i%dEqlB*`3}p1i1(mddl2g~cE15Fi0Ab!B+URBQCuQ0Cra{; zqs4`MadbmC^?JuLr;YU!(#(0=T*r^cgox;M$7J0}J+?z8TM4}jtTqGAZVEqlH@I}CI&JSZ-3f0Peqgg@E(g#6R`XA57?P`;QE{$=;6 zli~PV{AP0gJmr%a;h)O^lD|*!Q}Kl*<(CK@LJ#$hcI+b;*PJ7;WK4;fefd0n|t^TGMufO=zgYCG{{XF$#o^u zsYs^e}8rF9%8724>h(unbQ7qs@t`oe-jCZAwTrP zxg4F*v9ST*XBja+GJQn+MF}ogbKogZ`jFNwY-W@$PpF&!1`A_*IZFhfk)i`E<&ae# z@GOp}aj4;tGDZF|m@=r6AS(;HdWHKylIR0wTBFt5Jce%Igo_mgvn*Gcu?FOfV)9iU zW7gEX)Ioal<&nQg&-{ z7E=A89{==vUd4YFhv(z&~k%+GbVHr>J9C7)zV4P2p#=@+-lOT8>lkj|;wx|7mtYbZ7FzgUJ) z*p@{OvxmF|^}i42v5dEhjDvAi02)|_I>zYReMk&n0m@2Cj?p$QhApmssNzrd!5>yo z8lw#r(8Ccfe$w(u-!v*&V^I+`5QBJ^OTU#TAJf@>1s|TjD}rlWM zHWe=|NbmW8f@PSLsFZFD4>(qsZ)xa0X#NGW^rUO~2z+K6qDC6(t85dDRbWicVt%HE z;oc}!PnGpbH|_(eTMi=$bZfcg2>a-^)Zm@T&NnF=(yinJ)J;EHjej35#y|a@8k7c$ zm2Te#qN`elBZy-j{p%SE^NG|yL%wUNW6wcKT%C<_>Vdg+OSrjpOEDgxQY(9?Z==XN z>EEB}-+B7?CH*^%b05)OXnzA`Ww?a~5vK^+!lg((W>C}0f^Ks$>jqL|;djo)!JlK8 zM?pMC1tE0?${Nca6wf7M00N4-ABRe#eXeNzDCG665Rr4=sr*EHMjEjrl6d2IQm#m0 zPLvWkfF%+)h|yQ2M4}*2u$d0e8_>Na5I!B{JcW{AAq~6zjo9&s7L3NiCG@ClddWqF zy5fo?sprmsr~Mk0FZcyUzAwf()p%-RCLtf{QGRu<@^cDr>00Te&3Uds^h|i}4r=9) zKO6<&r2{l&&>bs{EL@K7k?8XJH`>N%5Q&qYVYDvu#O-6!Jlt(#NMNN~^0{ zs%v4Up+oexKbr}AGQYr2sZer^S+RdK5|Q~Ue!Ycn<*N;P__(+I;dQ?7qS>go{oguY zqOMT<4!_>Q3pp4A^MxeJj5t@W>cjoIpX7jL4VfO{+2RlmeYp$1a9{2kzE14RJ?kOv zeeG{)A4+SdJN#Z8)gLorzu3z@v=ScD_`Nu)PiBPwvL?2aA-c4`75C?;UYQa8WOT{@ zZ}H3G=L}TO%n1Lo^MhnKeuiHb-)~dBGb8-F-HZDX4r2dK_0Np(C)<}3U7GuZ93F2E zJ@)(LkM7Tj`*yrt^y=>g_*=vG`Mmym_4ix&Tl5J2K83%h9>L$=;7`aM{#3jJQPx6E zurGh#pna!fUw>3;=kdP>OayM{_Di|_d~Tn`VK^Y#m-c(~KMMbu)DPo-4>$n$F9C^8 z6?f0!?g`v|pO17;Zztd&_}j|i1`e$pE(C;(mbLfNL0n-3? z0BQh9?l1{(0$@Dg7(j|A8E`OQFo*Q62eu%LFGA^^51e2rAjLNXkm4gfV#u;~hf+%S zTYyCGH4a-iT*e`3P@wQyKnhQb#}wcsi%H=~CXgVFC+d2I;oc`N9yqHhE z;qLEqcj8YG{Z^s@6VBafe@~_m_S}i#iTLl1m&tH)ba(%Q%>5l1zEg(pli}$ye4GqN zAM}XtnhgI^hSMJ2J$;OyR#s^mUtt>O! z(gif>KAp$KL77-4s5oPBUMO_hSQg>xnj~21w5wfG2RnLnpk{%S>j$owbaGm^j6s)3 zq|?jXh0oV5Sqfq-1$A}vs^`~0kg{&clKLf*W$paBnkB-5xOiYE;y9O4a7ABFbfoOb zE#aGac0Lv0^uQvQ1(NJU7^hcgxvMtMK_;K8o-18)bUG2Au@9#{tclpH`8Bg8-lGSh zUaWC9Qm`4FUa3-gSW5NM!`i)SdOAu4*OxuYp@)-HLVZ~G7QmzIdW7>Rz8k5Q;Ez^THZ%O?^ceZS==kC|3<7)7Op>uZ{`}#6QjFV&p zUsm8WOwx~rSTc`#?!F)6A{oJ#rSo#e_w41|{ipQSiFr!Hs6k!>2@z@GRvzGCeAx>; zU4kCXqm=blq>mR5_aTve7+;nJhF7EHT@eO4yeOFsrky$5i2))`EX>33M^h5X@2>-- zZ^jY@BtPOudF4|Tz8>8OK83hHiOnu#tmrnQ1_)+{p;X3{SOL^PR?x>>Ah-h|KHGJL`!VF&7f*&g;1@!`4IWE z*Fv1@tCk}#hCt`eKG5#ItyEfuFpi%3l}qqKDxo9?g;L#2Q@K-~u^al)uUWrhiN^l@ zIxrmLbM5C+dMI8C!rVTnl$d}>wRw=Pm3V;)bD+`YZNv+SO&1`=z*=I3ZB(PaX%+aG z;m|3?_{of`=}qdqD2%#!xRitnk{bPrrA(X)Q+m2Q(t`tg@scnvAL2n3UV>DC|J`9;M71J>4p^qEthdxHp@_nf z4-Zl!aF{s6yX8uYno6>%fETh^iwbn4aSs~2SWW^9N=qmt1<02bCUE;sq>1c52PFGNfat$kT1OEa0f?^8 z0jK>A0Oi+jDIl%?#kki(I1K`PP@!mO{VB||gu^|CyOZ3Vn=|cYJaF)PJ#hJYF3I6Wh$cZbvC zD9x91#5X}APV=e}@nL_jNW(end^FsjnpeR;`PoK3uNFW_Ba}6AMQ&`yd+}M5tqRQh zfZJ_Ka}b1-EGvvOZZ4(I$MET8DP@OBw=5A?C;`yYraOxnSKS~qK~9IA5Dcy$UV_pD(Yt9 zuL!oifTY3D?R%TsH!cS7(^Y7`bo<`o_T7PlOiJ%K#E*PJ8LUNmmzmq=Q2OzbG^PSX zgRAP_Lc66imk%&1VzLnPEQHok2GC&1J(w}QbVHxQRHPdO_F(Y=BHucLA3*RAso~Mx z7pxGR4*v=VC@nbLUdCp6IB!E(MwcWl{+!J+ee{Nt@9nkCcKTE2x7 zRWMa-1Qh$xbZZHfD)#kOhaZlT@SKhMzuj69DXn#M?nOYfxWZfN=KsK_Xk=(Jn~7vo zx6<+*EAoHI(V0$H5T1Hlu@7uCrgaBBVy z3ux$QT8`7%NFssNk&`S5b}>7wYK8Iv(&q7U9UQ2n!*R*0>E7e&m#1Sr()kso6wWR0 z^Wu`4M}_l^CmaO}idN{0m6b^|$xhL+E)t`(#IXZjTBK4%O4ig#|CdA?P0y9iKcS4^ zV-Mv*-TWKL#}?kqf3?GD)@=mQH5fMw0Ky6LD#KdXSE8 z?~;dc%mW%RUYbTu6d$=!@TD$lZR<>BkvqGpduJ!^naG6sS*bapH#jTfhSbZcr(%Th z=#GD4PKIqbJvUb`llz^z4vstKi z=0(b#^<%fpK{mP7va6FM>v*)%qMr4n1F$9GW!wj(7+7$RlCxZt4&P0xXicQv*T8?7T?wF34sh3Mtg_t2JPQ#eZ^1erG=4@`=%Innpc+d7!k2LG|EJv=H zCrlGW9H;xil~6D3&n;au4Cy;@*YHAh>bSslt++KqiS93`4y|pDw{hUgmUp#?&S_{J z^!Mx^?sU;^q`O%);hz0zAIo=3J;bw9B#{jWM()I_0iNA%! z5&VopnisHF&^7{MU8Oa0JOhyQHrzmOCpp$H04W|i55jt?_+J5$^kTYqLFZO6=a|_6hY9l!QSJX1) z?+hT({Q!{YZ3M)eq9r|u80fTgK1=y703^C}PJ|-RhH*&x0SUi@!XQY)Ai)b9eh!GD z*8Ucd>hGTb>67+tl-@aj6wgFJq7Oj(CqIgp_I0AY%p@FTDb~3_J@$2UH!?>Z29Fhi7}16LUf>u5|E~SL9)lklvA>VOU{*sGKXZRC=wPm4W)gKMH-n+b z!#r$%Kar=al!uxLdKkJD8VtIemIuj)?eEudddoSzEu0=lX^x69^;JlQFxeU?vxrE<0X^Ycn<0;XtSjv z%J!9DtzPZi3erp-4P>zcVNsDEFQSU43T*zsS{mSsDffe_eu&R{-&QCsWl{)-AJ$hQ zK~O_Sfe*nuY+Y%nv|cc(jR%p2|G~Q@6gQIM*eZp@-iAfX1Fw++3zClikmThgy?1m3 z5S$G5zq(~H7Ewq}u#_Biiv@U(q_m{K)=>b(80IL+v4ZdUS#0J(09*=@cKxnn3Z^IU zI@XiY5*eByWUOY-`fmJ=lFdYaKf_7M8r1hjk_)#4>u*;iNBXFnX_Z=O-MSpxBpB1i$^9$r`ZCQl0 zu&tBWEYlMW*y!+m6wWEIEMLQdvzGQQs~L!`?xI{UdwPX|YMiu*xvu4PK}H#mj#z)N zXpE$K6K~r(Th^K_^vsV4iXt!(wHN3=ZvfdZ*Q}m^viT4V?qxcrb5S?^i!D!o0`RiPVPA$sF z1zYC0)q`94qomzRmz9t!kVhp@!9#jmDjjRfOwg0c_#>$bUdBM)TNQBU1>|gPc?!YA z?sXl{(QS`9Kyka*!El7DwCYm+W>y;k@FZ%(Xxl`d>3|B4lH(}` z8a_U$;`|WE2ZQ}F7?$X)u*7q}*f6q$z=`+B4>2a<7)$Db(8;+){mQdc;5MIR3p2YWNf&3|diahR@Kc z^|mRIO<&&$__*m0e%2{ac>1H!KBW~R=g>>Ti^yEVroO+hL4tDqg>W!3hwl+3w9KqQ zhZhc+wyM?E!(E?)tp^u0rBy04yz7jsfVO#G-C{z@TaHlX8=@dkFAWeF!5sC}@?nh{ z=YyLlNVtMUVU$iL!2@R}lf(n3`_#?BG|srQ!EEUJAI`@={hnWA;lYwdL!=ay1B^vB zC{+g3ZM5(UL7e4FGi2lM*C42yVj0#Q)XlV&YMeYE|~8k(Q!%`c^;m^vb33ElBA zPr{`PFUwMLLJC_bL6uh4_)OICk-r&ec@j6UllD>`u9yKO55#R`sducBNLlbKIwQl_ zyFF<+rjU{;%OLI>`c*w5wXB0$TSuA9)|C`CZ2bqdJeHR%q?FgIx_JXxTfd_2NPS}l zT7$G;VC^4{C>v_UmDW}3Y*W@)JGwqc!(838LM3{J33u%2LcO0WDfABh)21X}o%8 z+fOqX#@Dp9uWl4=UIKtrwQ*Q}eVTh_41yE^{|XY4H} zIU%ea8d{_dhmMY4!#MwHT68DQC1W&IoPb{IrDn-Pmg zf_Mm8(U?n6$MD`c37%NCENYMZEFXfPly~@(@*;W+rj|sK*y!qvk|J>VVi6E^46a?B zzm!5#;Z@@kTt?bl)*=_~hGemN<1;cDEqI&+=3j5_50hhl1SWoGJs|j?+Q}R*cQaO-3 zKS4TnBYxx^)Gm^&?d0$rha}%m_8)V&o5O7!(sCa~qNVrVDc(dtikIa2Dc&zR{39U6 z*UI6WfE4cwfJA>0hs4h%{3#BrI4t9k^bC`GCLqQ8CHfDFPTLMh@%=j>)#J;6RE~6) zgy3jEs;6i`G!?Cq+qa_<$^A7zvR?#9be`t05Rl><&fyS1idO>&5{O!Y`9O$|EBGrE zAMtSoKLe--A2${j#K+x+Mna|F82adMqfnSi}!(@1p z4DXQPT{8T)GTbP`DRTGpeJ*nkmbur<-0d=agAAvguRHx*8NN)0m&)*+GQ3%aQ#){{ ze?^8f79|F72K(m6I=Q1lcdt8#Q}95ADhVzVC4`xXDeDwEhnrv&yEwzJbTU?5oL>({ ztW1K+`LenjBiQ-2I#fxp>sZC?|d()a~E*_NA*s`B%q>U1fN#m==0R?>1>Xf zN0r0+*p2T?Vbc;7im61QC!h8w^#ONqIy4E9xqv}Uq(!pv{QodMZ3iYTGOO8t&_lj4 zR4XoEAmDT{db!NQ__Py=*$Q)50*aX$rzj$`!5BJ+J261SG5)j5RWydq#J^#%gufnq zS{3Xt7Sp`>vkmd>jMlqG+(yr~6+$G4mWC}`0E|}qVF2s;f5(5UW*Z+wU@kV=Sb>vB zEH=h_DEsQQE%?8OO1<&HB!GtHd#LCeACOX@hIxAs3`hzg&oF(3jSt!|CN)gjLoKoK z!CFEp_E7OOKA1sB{vI0l8z0bXWDP_2&|J~@;4c0*#P30a0Yc+iLs;X3e*skghVF>l zD_Z+mTYke5`?o8w#_sD7B&!&E`ZUrY*oAB-zP%M5nJ=)j*5DgH*=~+rFsUNe@cz}X z)!WB(TU%bh7d`FVvJM}W_7o!Sh{ro5+{VWIdgvjjw6PdE&By_JWW=_MlE$rRcW-N< z!e&Wmfg)BEH={1mQa2YNV5goXnPT_jLudO7Y+}|^8{%oP{8J}Q{n*)1;XCvwFz3B>?uEU!qHey8R%EO_h!o^f z3Ya5p)Sr*(KG=AV#dbkdXXmRZsdXOlIX+ltY}!vTgO~6z3hqOAQS7CE@aGb)^( zyV0~?{Ic^KL@Aw9;CWtSyaF=Zm6ZPJfacu7iZKhw9o2f*9}RJpvbL& zIC^Q?PdyVkJc3Br*$chnqdVC%pX%nV z3B04+vILuIkCxOq4tsCuoI?~HQ6rfJls`3Zg}RwutOOOpY+m5()kFDI11k z5Etd#Xq!Y@8hMsGW`PIE1`|ATFRHQm^gZ&op9Uirn^?ae1%pz&iT^BG{$kO3O1k?P zLPB}X$KZ=~8aEsKi5S!0$g$1LKU)gU8M z2Bi$gx@FiS5MEe1R8h2@20=+SO#SjO)V@Q*hXYm(4sa`Qbm$tKX;ijtqGXG)&k0=< zQIVm;5=9CG8-GvJm>VaO5tX7NjXobZ{!_@=dY*$deFy$5z3hF=Xr0o*w4AV@Y_yX^ zFo{u*2f_TXGio`jZn=i?fGhJ=OcNuM;Z(0Z<8Dur;XeE@MILasr+JYss>A*rcYB&5 z_kkAd*Sg!&Y)OJpiiVZWIBC*k!Zi)Eop#h#_o>L=WTzcXq5EhyZ2)hGrviJetCRrNlYd830S)JDsD$dNRfiSkRXAHXZ1d88gr?C=Ea5Wt{1ii>CZ&5K z1`EqmovRU6M^B<%@3gQ_k~hZ_=s$Qt2NDzXeqC~%3Rl)Q$5U*iTZnf|$id?2dh|*c z{q7EU=s?;qwpt|FV@ZdXlp1w&Akh%)REots3Mlxqt*jZ~h!{uHIF=Rux1;JA?^2qK z_3e0z0A)kV3-E&x&3O?{d}2-YzW4?$q(#t*LeqfjHaB{b2X(VIocM@znGu8o4FaUj zffC2~?HEF?0>@z8Oi7?aa*z@l+cC4_Jag6i;H!#*W}cB$1SuvTT8 z@j4NuR*QRptrfPq-&u5>q}c&Yk}#X)b#+S!C=?q@&Oyn>Y5a++0;edKp-h_Dr>!V&S zpbmS~%TZW9tX^ow`ssRkT2?O=Rwz${UaonSwmPYygKPgaYTd0$%u^+rh@CFxNfqM9 zI%BSTW$dw4z21$t4PM8Ad|{hs*~MdQk@D^cKp8pk8VH)CZNWz74SMIIMIXeV)SC+*h`<2?(Z$qB{bX1uUV^~Fv+2;A3ja15it zeNBKSk952$o~g)F6e)@o<%%&1lVXBmvSON|Mp37jt(d1+pjfPEP&6s53Y%iRVgugk zdRy_1V!L7|G@Bk!v?&fL+7+i1=M|Tr`LskUPoY%$D?^lOWt1{j8K+E9<|y-( zh00>(IOQbebma_XjdHfKUTIOTR5mDEly>E-$~Tm6E4M0lC_hl{R_;@_DUT?RDUT~p zDbFh}D;>(4$}Z)7Wq?^J?^J z@_Nb3?)942dat*~+oSme*Y`rMItlgm=7mx_5?m zo_D@?k$18881E_G)4Zp9S9>q;UhKWpdzrV*d#(2d@3*|)_1^Bi(|fOXyZ2G=6W(XM z&wGF4eZ%{f_dW0X-u^xTK5Cy>pE#cspHv^MPl->tkHN>}Gr?zy&kUbhpSeB_K8-#$ zpVxdg`MmA(uFnTP`+eGc+I^1s9QQfxbJ54)bKj@i$J;l+H^?{KH_A8KH_kWJH{CbW zcarZ^-x2s%8f0F+c|Ec~p{tNt< z`mgY}`P=EpekTOz?6V#0o4KX0u~1>3up! z0^bPS9QbbFdx5(G_XoBG9uNE?@SDKPfmZ`>1l|nv4hj#73W^I#3Q7;s29*Sj37Ql% zHE2dqT~K|{${=fyJ?OQdH-g>_+8wkv=wQ&%pyNU3f-VMi2Hgs}7vvut6dWF$5}X;V z3)Tlu53UZb30@GqG$b^t7A#+1kgfxbIv$}>S^lf z>e=df>IU_C^;_z<)$gdct9Pn*srRW*s86ZCP%$wvo5JnkZ-&1WzBT-v@b|(Gh93$)5q>88a`?6I zTjBS@L;A({OX!!>FTGzzKV854e)@i6`c3Xv-EVQfrTtd)Th(uEzYYC%^xN5QSHHde z4)km5cdXxue&_q$@8=&85)m7b8ljEIk0_5YM3^EbL`;pC5ivVrZp4C!l@W~*FGbiQ zUX6GyVpGKCh#e98A`V8Jj`$+te1s$7YQ)WmyAjMUjTcs>o@P^CIgb z7e`tm?U8RpZjO8_@`K3Tk^3W$MxKtm6nQz)H!3J9JSsXWAu1&*Jt`wAKdLxNA5|V@ zimHyPi<%uZFKSg(LsV1L+Nf8fHblJ{wJU00R9n=csAExQqPn8|`v>$__mAiw)jzg> zT>q5*IsFU!7xy>xpU{6w|GE7a^sn!4>Hk{)4gELwf4BdR{=53`?|-oW@&2d!f6@PJ z|BL;<>F?-&wSQOtyZr;A)zL}OsnI#n`sf+awb9F>S4P{T*GIn@y*YYo^v>wL(FdZB zL?4Yl9epvnGx}!qt?2G(|CorF_?Wzy{FtJc@)%Q0Rm_x_*)fY_mc^`!X^3fwSsU|a z%%+%kVz$TZjM*F07SkScBIZoY7cu8!zKL zlLpKkFmJ%h0jmbQG{8FGwE^!8cyGY=0Ur$5JK)HG;{#3)I5XhVfSUvE4d@==8wWrZHjv*?m*n3xD#<_;=YKx7S|OQ zFfd|Z?7-B483VNga|RX3&hcuTomo-;4*EIJu-I|cZh{U`^eWEFGLgKW<>50{e zOA}Wmwj{1k+>rQI;*P|fiMtZp65A8cB%VwBCb2W|M&hl+dx_qI0|u)H#|=&#oH96L zux@bS;BkW|46YqKd+^f1mcb2!TL!;0_|?Ii25%nx_Tb%v_YXch_~PJi245ZAHP|~T zASoy*H7PwQGbtx2FUgQJDQR-jw4~akc}Y!4Ym?R|y_2*(>4T&LNr#e-B%Mw=mvkxV zTGGv=yGg#uLCMj{vB~Ml#mV~Q^5m-I>g3tU^O9F2uS#x6Zb^PK`K{y~$-9#GB_B#Y zntUwzO!61W=aSDS-%9REzL%^_@lT0JiA_mO(WMlpl&6eKnUJzHr7^{x@>z(}vUynLDI@ z$jTv&Lz;%H9rEUo%|o^i**WCkkRwBm4mmyK+>mQSZVib}jZMu<%}=dLot!!)wK{cP z>VnjzsmoFuQrD-xnYtLnjQKGPHVV-OzbM7YtoGv}veysBP$mp__*89lCGmp`piyo*Q~;sAK4jq4$PH zWTa;3GIBDCGfFbXWlYGJk})@9K}LPX$_#tPhKx5d-p<&X@ovWcjAI#>GaMN=Gwx>G z&j=W%9u_?;X;|j4ykUjI^uwkOn>K9juw}yunNu_CGcB2`G8;3SGPh>Fm$@_Z zVCM166Paf-&t+cDyqb9{^KPaxDa@B-UAfMn8>gG0tI^HY zEzm91HRxW|y`kHzdsp{??x3z+cN#AzUe$F$hjKu6RCaWBe0F+vUiP%?8QHbj^Rnx+ zE!oSmS7zI@-^kva{Z97w?48-WvyWsS%|4!eBD*vDYWB_SyV?FZDLENAnK^km`kXO2 z({rkGX6MYyS(>vVry-{)=dGN#bGGN~&1uUynsX}0k#i&GevUF%og0xGn;Vy#pKHjS zk~=lGHg|6Bg51VjTkfm58*(@0Zq411yD#@h?y201xi@mVa|80C^WyWgc{zDSdHTFb zd3Aa9d5iOw<*m$HmDiYO&s&@KM&6rwZ{_XI+n;wJ?_l2PymNV%^RDIjj_@B5J|by^ zZbaUQ{1HVXszyv0F?qza5j7*`jaV?kHe&6F?IU)K*gIn1h+`v8jJPzSb41q&WxjX5 ze|}tkNxmW9ls_SVMt)7cCBGrxp8t0KyZP_sAIU$Re?I?4{>}WZeBXkgg2aNHg1iEK z!I*+^1(OS=7E~A171S3jE?8Btw&0C|cM5hF94a_caJ=Aj!I^?{1s4l06?7LU3*!ru z3R4Qx3o{Fg3-yInh0_b?6|N{;RoGN$D}1$Zec_vhZxy~%xTA1q;l9EHg~tld6@F9b zD7;p9uh4sB#K@?T2_sWSW{lL095-^($mt_%N6sF(VC0ICFOA$f^4*cUM;;q_dgR5C z-;8vOygBmzNbjQXqPU{OqNE~iQ6V0uoLn@msJduz(aNI6B5To`MVpJZ7QIuny=ZsQ z-lBs=M~hArohiClbgAf8QFoDYRLH3CQPHCkMx~F+8&y7P!l=okrjM!{HE-17Q7xma zqc)6sXVk7y2S&AzIx*_psPm(4jOrTYT^v#zTO3!MP@Gt-EzT*|JN%+Wcc^`obb zt{q)BdfDj4(JzgDYxLgH`$r!beQ@-l(MLv~8GUy2#nG2XUmM*$I;bS1B)_Dnq_{+1 zGOeV#q^@Lk$%>LyCAN}ROSYFBC^=Sgs^nZrXNjZaM#=q>xYESZl+uh+U1>>ad8wgv zMrlpy?9v6LFO|Mp`gZBNr5}{;F5O>xw)A|dqqM8^ZfSr%NFT0`(kJS3^m+OseTjaW zzD_?+zf8YU|C;_i{cin!{Q><^{bl_%{Z0K{y>FR+S!`KCSyEYgS!P*z+2pb*Wz)-Q z%9fU`Dr+ihDYKTnTDGBVQ`xSvLuE(HPL-W2yHs|g%)eY+o=~1ro?4z$o?l*AKB0VS z`P_0_xxM_g@~!3XmhULvRlXleo{yJbEWcdtD8E{Mqx^1pKt)hRbVX7{dPPx1NrjMH6hnkv>-yj8Ka;=PLP75gg=R2-=|Q*pN9ZpFO{UqiSd!jNIm8T1B| zVX|S0p~kSxu*%S2SZjFOu-&l3u+PwL5Uc?H0sf1pnaI&QVEgtaCpQu2OJttu!~K1J z&JI~HGCk-+rimHluO3$@mxn3Cg8fzN;42xnbUwZAB5`1GiXeFdE2sDOYxZz|lul-Z zKbd?T$?2H!TXRLCOX+4t_?PJ+qICQgzdhee{&_xnq~jyxQw6!DR{+7i);0o?oYN9O zl6y)AL|(OCfFyVJ71-W{{~I95P5l}$0&p=P$-n&ufyuodko-T!@qU2h|9cQ6|6c%- z|Mh?*7xybbFn6^J03m{){RLn&U>e|HKs6xAv3(C#JfhNm&EXji4*-(;W{$rMNb+$@ z0FiX<5oD6&&;An-CVmkh>Ph=Fhei%_In;0%%;6oh7xI6BL(*SE`1>4gOva{n1XA$A%G|ftuG+5q`irHB=|Llj{_n~Z9Ip6^;IY|!2bo1l`~)>@acdg z_g4T2kqd1cAo;uFBbCop4u1n_ZLbj-*!Nl zc+%@i=^=f+l%6a=sz)0fQ&5gG0b%7=%Atls0A^46x9B)j$jb~S9C;J+DG2K!ch?FF zI$WQFOp~F529moI zwx+mN1>N zOXe=9V+vWTtCyN6l)?Ic` z+@p4v!GoPk29E^qoNrmVUz#S>wk#Jy+)s!hk|#;F&pq|CYUWD0e76b{ayZgtVajccA|mA2GP$=pxgKQHKAzA?9ei#JO0 zjnFPENjLT;*I0_NN1?$F26L?9bF}Tg49#C;W>Od!fs-};FpV(tsB(?D+&|I7@TVxn zDEu7vW(4(AIx{qUhUcuKT-Z0}1u>#1$$}e4@;KrVL*s!&l4jbuzqE z7XKERdzdW#_hs%|WbPUn{=STUt1SF#nR}Kje5nkdD8pyU@I^9wwG3Y;!)MCk?~tXh zRpvfXhIh#D3vygW?|oVPi)8+<%lxmCxhrINm<-p*@GUYtONKieqV(~cXSc#Butzsj zERo@}WcX|uj!x;(e&@>Yg);n?GJL5Fub1KTWcYj;ZkFMTWcXqkzCeb{ibqkiWOlY@ zzF7m9qjJ@bhYwMrGyNMb}A-?pCxu$-h1`8qc+*%DM%4UPP3l~|; znuYad#QL12w(dCv?m5)VpZlC^<~dGOn)1nGjb`a$tfT4_gv?zy*E|>ge}#|> z>w!v|`SH25e!j&#w|=2wk!J2v76Y4=6_l3+H49g0=9+1#1|LgZcILVTi|UuuELov> zzGlhXnrG+NEmf3_e_TJl0>JgWK&_;Jo>pTX*6!~KxI0MN=jGmMspIa8KT!ayXBTEa zS654p_?jcdLTfUpk0(p|&Nu%~651gaO-S3ip)tDPe(P^pXPn_eNng+r-Q zvdPBq)I{X3+BE(N!{g)im1H&MvFrtOU&H;Ig>-Xct1NdM1^#>;6b#jP26I_g*DP7$ zK@p0N=D}Wk6S|fwc6nYpCTk_C7fZ#`kZUY2gCv+nq_!yyU08uuf%K@>r4xIytby(0(Q3s(L0kO6VT?2@vVd!!|EIC8x0IC3=0z@5!8UeB14lMx0+C4N45bN;J z7(f(xDE!iT5K*xD_L~Ywe34SJfWdqx@kwAu=6U?+eP~iNOQr!o!lOC9hU3FI{wl}E zaQuI9ds$<8=R(%oq5P|J@w_n&TgF z+`;kV9RC}~&vN`e$G_&dAL@(fUFA6OcnFs^HK==z2cyu*ByxNp$A@x!7{_xsUe57R z92fjs1IHI~_wgJjJ&k0ha(o@fXL5WC$LDgKl(mpq!tvuAU&-?xZ)7{7>LGUCkhT8pjWEd?v>~<@g+qpXT`U9RG^rV*mCH z$L~`ez>p9w(Is)=tj74z%UoO`z7U~olYV8vLi{|3K zOer7tTDc#A)9^z-bUkJsmH$QOFJy=w>#~?|v7YFK|Mk=SB|&EKuXJX(Bo;s zNZ>LL<1cOG>DtDFJcZ1Oypa{w7IR$GT>K>!78$g5p!e;bLZ0By$zP%(qaPI^l@-=A zKihcT8*2QH=2N_kjHk2NTjE#(kt99t3m7`8YUd}b==SL=t6?cF$e9YEOYpoU$cel3 z^3Vg%i-=+ME8KW%g@Av1%cuBHB+Km;T7|XcFi?HbnBYq5ofkuKO$RsNU~`3hAe_2+ zK2oD^y05Z~VJ}waCNrnb2XJpMSCKcaYH<&hL+9i8?~0?7bmY3B2@)|MOSlKI4-gV@ zs2iYyA1`v}CL8Vc4y2-U9UO#kyxrK%qBwOyUwFt;US`kT4p)?no$^(*IM`@C{37({ z9hcHBS+gv>3vYt3EkN8xag4UH%nJhg;1>rVw0r)YG|Y2*h8Jq(^xemBvz3%F8f`vp z);43|VN0Myy8E!hPx{hZ$EZw&=grYlVNg-w27tIz>j-pNi%K*~D)?=zzVH%;v8bxU z(hv91sCl^E5Ma6WxF_t{o|?Xc{>>`fLxbwU`>6AhZsSH%d&MCtJB5i$4OH1JDuaD? zx1r_FFQyvp&!~)eE6HkUMPhJ?rNa6(i^WuncRDJLso*;X8ocO1D@!YaL4VPz4hlM& zZadja9~d`Q*++eXH|bUM9yMOCz9S=K^*1$r5~lC|)YR0jB7X?oa0ZIUI>y*@aj6U! z_P)o3<_hZ#UYRovqquMxqgA{LAo;=d8u;r zVMBE%?kM7VIPObL>8P;Yb&RR7uKE<(@iOf`ai}f3&+pkSuG)iiUCU%21r)mS?YXQH zSqW9xR(~hu*SH46Cq9~=zponpE1y`dw zuh5ks)G5UYU4QJx6B76XIsGe~SgLU&d&)L`c?#F#QHfA@4<}NO#jW+}hd>26Cn{(y z!oEUz#XJ;AReoWtJ%WsS`#|xX&mWieH`y!xh_=&ARf!vYP%T%gGUG0^ht7KDh=1jn z1$vcd;j;ss+xF%@lMnu%_u-B`D>HJw0`}sxA66KDkoXD|KQlt^q!&4rN_d!qYrbSC zJs$pLaw7N$Bdva^M4zYEcVUXuK=$=^gJJ(8@{4`8_6#8Y zwEu;F$fK6@%wwOfod`&DbbwehYX@=sd*l!MbuC@^#{OMP>v>E{+E_qrqKo?hV(!yE zKsqr+YIg!6sCGRd=0ojLKuo>bNgPiC#2l)neI~{KJ|M-v9+3RgK3)Y_#bGfZreLiG zkm4%^1PMRF2?8)!1%&nqVx9-;u`h^&g&OYf^L0Qocb|y#lOg@>gAdNai*{1L z-NX2L={InvID{FB4|kl}h&%q844)~( z`T0Hf4^E?H$qRJlwqdVqfFJX*!+l=5^P#$ZKh*@M9h;}RL((n`1pMZs#n?sn(Ah}ovNBtYGW(mp>CY&$r!S+-UP$(V z50sjlUKvSI5wz>Sx>58BE6!9^uL%FpiCc7nPTB|&j_8M>`gf$v4_*IvPS5e z9w-sYTxzsEM#;m{j(oiD^f4J44jy=smw0%gMB=VAdD-Uj5(ei=YX|K-SkcSM_sPk6 z>z@oQx7DwlL_vZan&B&~NFV#L!rIz)#jCq{f3w3w4kGLx<->wTr zE84;&Dm0amFzBGNPJ-?elp#YkK+{;MF*FNkfxhVz-t^i^kp%B$|7A%3+*~o%KI%Bi z=}!)C1C-aJkSGN9FH@22J4!S5Z73G98-qBeqQLKXnQ;*u1;H#4)6_IHI4HYfdUvQj zVIdDiy4Q`?ABD!mnYk;dA5J{cR~^YK`#PkWWURQdJy#@JRP zv_H={=%m-ff80;|*FTB2d;)nfbtM{ft!SgXrZ5`d@h9a8Q`0HzoY5fRqek>3=IxY; zx;3(lprU~)B}>*w9}9znNqLZ3HSU@#Pa2y}aQ`(bZtt`u>S3OimDXysW^#z(X>z4V zik3o1okmJ06*Z-@hiwc?iM!WI)DOICTxs{n69PChYvP%bh`YuJxBSK6#`krnsihAo;&4KnU&OU0DsX^EQ2l8UK-m!C(?5Sc7l!Adog*29*P zC$9un=RNC-%BiMj-J+0sX$J+aRwF9hI-vl0goCpRpuGVFZfg1ywRxiBR%6_j;&iKB zZc9b&))Kfa_0AWQ+QB*-{ooTX5M@i6G-FLT-x+HuAE9e{gqB(&Q-$QYtHuXAUk~iWEta*-`?L zY?&=(2Dx;%t+Xzih)BslTv&N|R1lHxS&)>co`p_%l2s6j_bHwyQC_TcjZ*0n9knB4cxS%;+yHW2`53D2&$XMOZE@XEP4* z&)E9q|DW;Rqij`3waT+ON*z4R)3VnA-_?|e3_^(F;te-UA}+H<3&7OlZpjCHY8prj zYZ_ETC|TD2i42H~Cc|wh${0^ul(z=uP5$A+%GouWHp54#ss{d zNNWN~FAG~$U?wJ_Y+-GnnHb#zLkXr&E3GH6$QZ)LY}g_7N-P3SDxBHnQ}$Gq6DvAwPtWYQpDLhb7aJ)TY;lTVLwLJ??<|j*Jybm(cZ24FL%lJu_ zU}q^hdzUCh5R;d54?mPBDdBz7q0FHvqj380gBqvl5dK8#W0Q@j0E$Bj-**L2T7R+v zKp(m0`RRiWDyfwF3q$qD8)?t7=E>@#utAEFjwJYh3}*2 zcyb?Byfm3n_BFkX1MbZf-l!z8Hu}k?Op_P<_1csv8Yz6=S*A&g{AIC1X0w%O^sEff z+sP8`f=yPgcERT=R1}-5dguYhL;=tLUyO$yYmP9{&D?5*7b9EdKf-`0MrbzB_3YQY z7+Aw`8xWmi2j(KQ5wv4Aru1yqysa`nXk#?m#h}2$dKS1yw^ZP6qm*mh?x31rQ_qZp zw3U_&@vUo=q;JjB(EUI%bZ;;`$a(4@S>pdX&JFt(--!x(=FZcs=FF~0$-0O87Ve(W zhkM6E+y%4mJMi0ki=W=5AVc@~dUIb#j5QcviC^C{eK_nOGfQ&m;m-4=ke}})BMkBG zH-5*CU%IJ$nGxqNh9>sL2c6SY;J4+f&L77qfbhfY&DoV+Sbjsyc$=~nsV+vH^kJkgZFP`_R$=`Qw^nS`;B=SIdX~|H% zFeB)>rH^Fx=J0n=sDAqL_Z-|V+?MF^dg?WOFT>wqD2pY->#K)94gBEGkNy$7fJh0p za=3-V)f~>`u#`g$hX5=byGM)i7JObhXCm1~(XP)C4tEu=0LbPtchN6Cds3ZpT7Il%Y5l;s+{juI`6MJgk$pIB{_%OISElCM=wZ6Ba#ah`XFi zg%4-43VPV&3L9tQoPL}(%#Yj256&&5cY1%;`A=>^j{N+GZi6}xfOnUT`H?)?Z%^__Dt*5K(4N6D4J3rZ^JOmc<19GoYo~uF_e2urx|M5D!6FucYxZh>& z2n;?wh*lLIw|s(-v=Ea5x`!enx|5*BEkC_8)*AU~mHm0B;#@b*Ht=s!Vk>Qt$t(g& zFnR4Y(UrC*l95{}<(gURJkoo5ye$$u`92e@{1Syg3nF!CuneZy*=^p8? zD*U7R<&l_0P~wosf+SgPa+USCBhba49~+Yrte@W*v1+}q==xqqWD%zM){rRCePHuI+{V|y#Lv`X9PO55|QO54J) zN*nefwuM;dJ(Fg%&&s-aaGkup`1Iah##&$a6o)K7ztI@+4lHX0c&LN7B5DCfWjmS` zI}oc>o=5TeP+=LZqmofq?&TrXFiPX@byml`QKHdRJh($Pu5$kIiZe3u&s?SUhS)?S zMQjub`Ej+-k3|a=O`cI_sdb}{BNd(%qAs~2-EJ{dJYZ>bi{b*cyu#z^m-A5R|F^Qj zdyQK(tgqqa4{CB}SnorZ8TBKz2hm^9S$GGh4&8Tuab{A~SEcvU$&Xxd%5}0#j`x1z z$G@xM#(O{gnch12*F z2-&x>Hgs1SVP>hXwHnzF*w*RAh8v6`8A=QQa9$W=jGKf(W<|HdDbF^R#vbbvU8=Eh zPu~bbOTVodYkT5$+Ss`HH)6(GpY949Yn|T}Gd8Z`1{|Kgoi)}r|8~LHxF>F;A?-di zTK$gEU?CX|iJAybLm49>AJ32s3}`pi^`W!W4L->?q3RXm{mn9U{Sza?2vm;H%qmki zROAxY@I-!?glPz?%*T27^BRi&n5pfe7Z2v?|B**UxARih_^5BY=v@V-sr6D-`X4ZP zjqdLkbp!|n@Axv* z?la$~t8{0plwTX|rZAeKSQthpoam_UID91e)`6i_x<6Am%(q1GGel6ObP%7-GoFE9 z10#wm-BsqB#S+eA=`9BEf}aizdqm<-tI^<|4vp!RI`W|DEd~q#ck$j!0h=-Zj1_^Y z=`$pnvVwe6S~HFI1!0xe*(z82{i&kHT7Zi8tgNV5kz<(4yxy}+c-bS9qHHR?pHr($ zO{b-FJVGI%ejEYLcL8 z*7m$;q>qU<`V2ME9z`~l8fmX>s2a`mnLEz*!zO6fOfeDmtl_D5QN7E zwdI^zi}!?E0w@MhxhceZVg%w1f`IvdzjN8VdkF!1F8|->bUxWU@67Ye%rp0yXP%jv z)8OyjDt#v_-*uR1;^k?Z=M;uQTdP-m6UXq4=JXVImea_DG|@MY#2Ak73H~~$Oq5GY0QW;WCWv4hffrm%UO|x zW}7hi*W1ftk}QgmD2dzK3L;TC$kIcc%yMf|vuTZLF+u_Kxgqqq1|JGa%`~&n+m6dD zz*ESh!ydB$RU@^)K&PC-zSzJUBcbH(X2?W8=lsi;c;}<(%&78;)OFLU_4U~9XYJpH z&Vg+{y2FHjC^d;5aKAt4-PkSx70ZdfbdTA2oYU4p%V5a>x0NNKA=!LFE4-jqfgSo`<4{)}ZS?EdZ3|JsK*JaXK*k))JDH`aA7Y`~=ggXd>plD>GXvA-&YWH>ZUAvj zopYB<>JATZjkxB9!f|6qx&7DjMw8)_=i)Auf;n@i%$_%I=EZaFy8UvVwy~v$@*}K@ zvz1sd8#?=r?r_k0_LQyDK9>R`7_Oix*NhmgfGzGYlk&U43*=oFQr4$!-%ma^Xi#n< z`PdLGAp1wI935B9qZpTM|l6Ycaz=WyxvGdSA#s|0zF>ymM^?zjFl6Gs3+#@$tg&VhC;^ zhyEp}IY#h6Qc2@iJf70F|K+nb8`X_s!et!ZiV4@BFyS(S?{^*@9=E&bE6lfQ@o#2r z3jPObv8E_pSetH>ufgHUO8grw=UmRxYvhc}S$bpKd`s~mrd!T;BzNTLCCQVGE3$Y( zYb3qx%~r8~6{bDBc5i>xBd&3rhb0hhLcHYm$$@E8?mESl&{LRLBi}QM5E-FT#mJ`a z2-iGCoOr`rfFIX9RZ7PRpHXWd99b0hWeOkBt>Btyl4Na&RDF=_N{dEBEt(?a2=n{s z6XXuLG;;5ZK2JJz;4Hmda{Qy~rMYS$;$kMiX#4kFFKPb_k3lbk9+QZoo%IsWgR@xb z0doKot(VA})+@m0DH-Fw&zHc1ucn&S6FWo>NHaPc;o(B7z}L6h3}>!qh(>kG6=TD_ zx*65qLA2T@EZq7w7}c#;7}&q4uD`e~KUxAGk zf9`w4=lFBKAU@BZ`z1td5cK7KL%bpA$7L1@`k9#%1bra0$h0;PKMmZ`|6HSbe=-AD zU|KbT$^FUbE|R|n9TNbo5lTHqBzvOwlR*P~>epa?xRF~s)j97-5@|`8yIXmIR0VIY z+PtOOybV^~I(6)=m(AM%<*jqa-ul?QWh!q-WJgS9+Pw8q-cIY-+W?!lUdmgSj=c@G zc}rE^y0+_0=KgRF-besAW{s9 zPzX&PG$SLl5Me;ZhA?JA6q#GchL^h&PyRZXVOB}H$ht3yvBo1hFH}RwJIE)PA@Yu| zX%O{-cO*{c@2HXe2Hr9&>mQTEaX)gc9AmP7uiz2|x1$5YU&e*V2#!VC@RMUv9XmJ} zs8w<7YBQ9_$s2H?bvJOqK*yx9h2AmOUTaR8K6%i<;>mL-6*|QI3Aqb$;S2Yg4aC(1 z5!2y)1%vW(ByrK{xK9>0@eauym@P+|$RLAo|Iu;gO?BX2k2Bi-ea9K?Uyn1*7_`NB z-_AHQ7xx0--V{dxl-QO5+Q%7)>Uc+s$am6wA48=TYLkg$MJA6=Zx?!HbW_UZyX4*; z-Jv=!G|#x@lC-^+||LX zy>0Y3ZUFZhNiP(Id{&(inuBH~*%z#umJid|HvW|wy^T-Fe>|U(|9Czn|M7fE{^R+S z{M-4I{7C*q9{ZAZiey+@*;CgCRG1) z5#bEFPNEs|;e1=-VlqQlw;iCfWdW0FhHlX3*?dVc#bt&jyV@%(ld&Opk?#yYg z=*-YPIN@l|7EyfD(VImTAFexyq%Cs9&BpuxuZj<)GgtF3Y8p;zpxf4Elc+gJ{^P5e ztbXy;Ojf`6Y9_0nJwIis0<)*jFneBIX!g8ef)V6lmr(^c!DE;f=C3%Y zYn5k~VPG;tUCq!~45?602;qogu%^%mZYW?=<5kmgI1ee>&ZC;mo?}}~3&C4H!{||^ zgNZa(_%%^^L%j7a$;T@n){DCp+)xFoXPbmBABE7>;3dVl?*Q94S}|L!ic5Je#jM~u zObVWnY^oGtx6`QpxU&&5(JLgqVL;QO^LU5Zb0X6FR2jqS`K$=C=ik`}AC5THV& zwP&~rHY2##Vf1Y_`hI2fJ#6&-(x_PvSBEcajj#6}U+-hS-cU zLq8*QPmU3~Ixos+aDS4o_Xc0@eZJl;zTUV(;<-!?My7SPY25-Hg{jybotC}8wa!6Bk-epAt-sCWaqO#a~7kjT`uNP3XMqNTPk!cXDn$|O!{bJG(&#O#BJg+hh z@x013#PcfC5YMYjgPm7<8tnCgqUO*XG;^5-!K!IJmzfijhIn3O8sd4CX^7`lrXikJ znTB{?Wg6_f+S6dK7r5vaX+Sq6(;!$it(P~t4u>YuQCnsyvj7h^D5I2&#O#>omYDr z?DYb(IMZ61$-CK2Yk4MhHB9TbnG*zjGP6j)XELV=_*~{(0bkBsARxwCK&1!}k<)U- z!(f6jVJF5<4jSyJ#h_6yw@Bpd83YZ&F4N0FqgmKxIyq>x2)j%l2aPIWm+9i5Q7h~s zJqGd1Wq%sF0Yf@2j*_P%uw-G9*h`5ylN-5=VO_-HPkM{Yuoq(wAo0j;;6<$Jkb-na zZo^%~?oWD0CITa&WJ)mMPudZ2CU1tMHZ?V7mN#GwP#lOD*!i&G+M~8d!G_I7VP_#O zF0v3C7dVsIBeK`e%OtRbWA}Fhx^T=Cm>3Zf+a2p{TNKe@8DN1G1bCg==rAKu+4EGi zjvLU^x@EozFDwYwFIY!9Ji-emN?v0ay ziZ~e=>$8DsBkFTVPASZg9G1{vNWOqp0xW=M5Yq8#fDD4JV!{-kaG9((*f zKJr7!t;ZpMk5(UMvSJDe3OR2QZ4gIwIJ?~KgQBZkOtadiFDzfPnUs6dmQ48D^LTJ6{+5zv?h`sG+Pxt(!=Ow4M2K6kE91QiY3&3vIH9R zS)e)K>!IqT;t^>QJSOchdu$Q+yud|pi&T?a1JRTLif(B9wfc;n4>QvHJ})~R1i_E0 zOp9VZC>t6OCSr+aW~M{r_z^Vepqn>m47KpCgRpvK!P7 z3;l!TcH!3#za0GXScS^q#i((oaRp$6vDg47hPB184jMI8DRd0=o@$*Bk#5>lULPgk z?}RV;StUF|z!HAVK{i@zOJ0Z9^XUxvC?cFmQR;JoIWu&&iKP+FwPCe|g+T}lgAf)5 zxOl=0jmhIGifK`4cuuAP;>~{0P{wtQBBU?uj6p~$*qEp|d#sJK$J#i1R&%zQ0$G<4 zY(SpiLmtIM?n;eHGn2}aHU$*hlcJ9jABDPc73q&iD`Vb*W~t~Q@v&UDyWfg-C#xTdA32Nu%m64v z22Vf+7a@bEA%o{4gBM_ub~EJm_pN1kX8+FSc~?PA7>dN_-IQ*gR}6LE8PF4+mt&rH zFGw*hU4R*cfuXuE-RB(9jNcLbHsQD3uuv30TR>Zd7)s~5K#tkC0dIwQAo&`<2{Ak~)>{FF} zqp}B-{T$>A&As@Meuc8*Q|xP`s`KjDqfn0{V}HTnA8)!no=Ld_^A^x5_SNN+i}IUC z`6my$)xpF0%6;aXIddoF;04C%fl2&!2!~t=1`0|9GVBY=3mLPckTf;9$K^f*lz?-e=z)Nw`1K%uI0M2SdH=CA7C=3b_#ilZHw{qwRWs zMC_r%{bbMe_mTBTgh#(csKneK!e)FKfi@kzTdc#u5H8FB#i#bK*wxk!-!1N^_^MYv z@(>=k$QlrV3OXvtj_!$0QT5+Yd7F+#C%4>W1lZ@9rlJynf%6^%7Z4W!7GlGPF4 z%B$21j@)~AD3S)Nnp|uI7f4O+A;Ab9tq{-}kyA5bFj#P`CL{84KD$bh2=98_+kpEU zt~Ky33Kjx*6QfSNwS#v~7S%?0RB6O>7G9j-sn{Rz`6~_u;NhS@|8U?eyxU@0IN7vI zMBIe)UdNm8ga`QCEnM*4PI@jL&M2wHQyfN!QS1~5HxHJ|{PSR58eErdd&wo1zdW3b zB7fLJuEk?Oc&!BQYKUMo#MvtS3I0mXg~e~-tm`^KWmu3{*Zb*ni@)Ndl5>FeS?|G< zK+8j}rqzVvDe0QKr?E3CCibwA!BxWk6|#}{Ni%5TKZKp(@OuZoO{-*;Dbje@2u%c= zdquc-G-%1s1zMJiCp06+o3tN~_IR9TgJ;-`!5*stnH9K2^R6KxcE3s;nLsWUQ@n-R zV;xXo27ZX_Hp2Iy)cM|s-)a#E+~4f&eaPGGfDXfBHCrPFGwXvbtU3w_obxItXzAasLdN;KpN z*^1VeMBV5Q20fN+`$$M1?5FVYoNw9A{8odA0@b4T9#6Ngw13qpwWURmpT%HGn*sPp zawIW7qKxP+;W8G#MEEjA{nK{vRSG`>Fws3`Vj%}yC4PzCsad5sYDW7^gs)Ts^TKxg ztLad?_nhrK!hCIQW%`BD_kCR%WEqP4$UK1cijMgpOai)@K%}U5ahM;%B%oUkgiF7l zqsSunmZ^Kj$j{68>34Q2W9eev!6E(U_^npqGQWh;@h70~gS=g!-q~UPMbVEAc3s*f z9J#@*E9MPouGxo?-%usV=KGZA0rI^aOfj=x1H@D|dpY2b0DlGulQ9gC{(hw3S%4^$ z?9%~p7B2f6(EFk&fyFKJ92#7gg_B=p_f1bi0LmrT>QNg_mz5_^qzXoLZ4*_C|lsz91Yk_Ru z?M6N>2c-X@fTV9iq8ZPJfK1;OK&JOEfG)t_076wJ`ze3?7 z{e{9;Df|_*Ju)Jj|hs7m`{?Y zWUoL;StMO0eQI{SCGOIc^L_WC3wt8QX=wORhmI9-0qq;ZTeKnqabbCdD}-TeMqzK4^?iptiT= z6kX)&yY^R>PJKN-G-qf;Z;=Z3(9HiYU5`%?^C{#E=InldK%Tz!v)%YtB9)>o@Dhw(R8PG%p z+0lA@)fv*$N)=ue@{!?b1N1cgO~}A8jyYO5hym7OuzDSi45ko28s-;&7za6)30Vrj zDVeDGF4v!at_Ha{#M7LI@H!{9wD81{bLmP1>(0L=#aZ#V_?m>T<@_2p5zn+Xl%9@h zty*m1B}OkUA>e}M9Z+Br?F%i!rGrC#A-w(Kt%EeuWrhn1-D<6h3A5iF8kOcAG*Zmj z-PXjE3QYMM-LEjWoDVL;|L_RB5ejK|XQOkH?MRLh%yZ!JrC?P{>*k6*i<_+*Qkrfv ztyx^Oh*`IWSYZmL_5?1&@(JrAfBtuYGciTSBbkD*DaBMzih`fsSfXI%jRjiUn&#mu zkMnsf5@onpFUBmD#kt(r{KUJSZ{aZ^WTd|sy5Ly0I?KnP;75gr5A_VY7w^OFDy6)^ zV|^#M!1`E76P)EkK*fZ(Awb4j@jZ907aP}8>ip2vcKJdR9lm03iYLEi5pD|^zIH^| z9NL;yje{I-q#(CMSYB%p(liSX@!$>BL!~#$yf1+C#al-=>l^A%onbit!u34zeuW}5!pSMlhu1it-{$VN1Fy(BAE|aeztPwCO&oapijSn?rP-1f@ib?x zcUTE3LL=YnJ*byLIyJ~yXZdZYzFw;YvTJ`8b`iNc^M|HjnTkymZ{6r{pJwE(c-d7x zuC(nK5uyBF(#y{^fo4Bbl7Z8$CX*3!8?4Rg*#Gwp__N4VS8h% zNPsWo*^y3LGcp4;aPV8Sv`EXsx3J@q%#j+Ho8L;q`>}69V{c8eCx6YtKfA-Ft$3fz zlYiJ5=8eKeag8@TyVad_+!rnZt9aS<{bSh6Yn|n55YU)#az7*?#~<#sZfv*@ zE*V0ehI{RToMg3`)MSMF?DB_GYsQB0+*1B7=Of;~`198|AHkh`{?%swF1PcMwZ8n_ z0Bd~0R&C~2!&c=jhfIHM$*n&c{};j=y)IPCwI$cU-zvUrP`m>VNevXDj_|^xX}&Pi z6CSrC&3QeZc`9%?(?&Nt(|+LWaaFUkM^9&uQ2<@}3YvTkZ4KatV8= z$+8TL#QU!MeBso0DN=$aHXd+AYTj{Y?G-2D+Rp89Kf=m2IK4+!1*>pMv>LxPs25vG zK0x!S3SF6kGW!W$O6Gg2xJ=FHY`gc;22Q=IdVP<4hM-N$7tv#gnuRtI_yJb?_RawkH0@bR&{Av?ium~3?waeilaMYe8)z*JUl?TQjLkv9MK)7nC6Fs;KLp)v=EoJms z8-x@T-RWXBQsfYXr7Q4WvCJP1KD@Kr3>T*;;j$54Bt>0D*jtG(SJ!ygvD(&nYngCe zf??x|>Lce@H=Y~zq+AiKud+G|VU7s))dE2%M*viWVqeIM4$Q%h(n6p$-jxi>`EZr< z`6@h|XN1xE`H(Ztwn_0DtIv=ZWiW7$NQ|=F!O|3m-}*RkkrJCpL1oiLNM_@25hx)C zT*9S*M$HBaNVKFGV#=4{>IlpO0qzZ4O|B8cms%=`h$jFg;#p0~(k?zIxG{T26zWo^ zC)o-@gOVcO@S4Gkf+5hP8@hx5qgy=2ZSh98@PU#V%MRQK zL+Ap=IaPgu`~7-;;R{~w2;8g-8M7P}lbY3tR-1y!fCvq#Y#Pd$kYp{E7)cTI12jDx zn$GuGKlE9+NJ}!nY4i(8Xl9xLDq}})G3aGVF*(-eD)5|0u2=|nnqQ)aOoVS%3y`}& zlL$YTMF}$vzeI9Vp0}kj@JocxQF0AWJNPn%|E3-O%TgFRnkjyX%OQ#` zM&3$3`5x{9_09v!MHn5fP42r8bajf3`+7jye+&2{ z!219x_nird`k8$xApQLWkaXPvDfgv3k?GhDNPeCJL=Tev3?SvQj{)`rAJYMukK+NE zFQ$Sc6zl@XaE_xL6Mn7WUlshLg1=XA3E+jGy9bc@WCAjsZa|pqY(VmJ4j}n)0+OF! zp-V$u%f1mX3y|;4{{(O+0{Jl@<*0P$dlw9kb&}yxPTCi+3n1myAH$L1z6Z!~%K-ZW zvX7^KGKIe`^{^9GDOjmsnSw@CXvTlf`nXp}e2b-+^&EDnzXG~h?P?jN%iekCd?4Fv(j>;5%e;mZ{MS%ugAbF#uu zPh#%!kbEU%9Dg2)mUiY6f6uzI5S1p4d`q$&be$s>ge#$?r0?)8%wkv$CO8-r8 zBaJp!;KOdujj=x&W9R0xo&MVx{2MX$J7VZ>jIm!8Lq9kM&wT*=MT|Sfer=5Zk{EpF z82g48`>QejZ;!D*5JTTL#*V%siodxr_RJXj&tvRDN~;B}lyb@|BgO3_IIKN+_H8&3 z&Y1<|(L@V+ij+@I5*-mfPnvY=&!*fpClZzxEYFkooU}a$1EKNMyXMRik!fDwRy=3! zJtA)Z*fHaT%)TALd_;mDA&hs4NaqvF>?1yf%zhG+T0CP?@w6F}ZZDa9*KLB0D1m*H zD4!NBT4%;ipFMxdUGwA~!OS)hyMA6qgeFAr_K2oVo-RfD5nkdmfDvIkV#XA3q_!Ps z6#>SVs1}vSWUh9O#A6fGN8IcZ{fMJodLMBFPjMlV^Ek&g<~1sYF}XJqC(7rhLLy3r zqVB)RRTtX0Xgbon%N^2oKLM-x-04!xpXfeJ;9E?{=uVt8+PoySu7eaP`c026W53 zxJzIKWVpD|2kYWBM)hZD6?>L+Uvgd2lBu1RjO-jp-Y_!R5!{T&P!9XTgU{Ep2*?=H z9D&o_Wn+`enmPlYv{oy-+~S@T_b#KG`fuYP1AwN@Q79EH?i;19!z_LA4*YYkz7_u) zxh3p;zBBd$(w)y=l?0Jun$Zo6kLU!a6r)=$Bog;__I0cAg-0bD#ake?F1eNZVm(FT zAvwye5_0&TBOqw-1n%%WP@D{TXfoEZSf)Z|A_%qcIxx{)^?6sf^Z9ko!T41zJ zXLxQz{L(Zeo@W-gdo}-y@N%n~db(>yroj#^tC1;$I8{dBh{zSyjEm_WF%RP_(L0Kj zisB5^yF~9OV$LZ{>^dciLtZo+UePL?RGJ$ z-8y?9I_UWE7w)%CpDhQzxzh*UDnG>p0mB7Q+NpTvl*xC=(b;>=HIt(Evt{UdI6_45 zMO)k$^nLDG8#MIN$i394pqN?>{4d>4E)>n6t-Q4T`;Is7(Ibo=Z;DX)ur530@kWOO z@51cY1CO$+>Z5EOk2ej9FPHMsg77##aJ{AKOH_~@jW;PO-wYLAIv72f@n$vR!+O(^ zf^`vhw-SvvWCTrw`ctQD^mrrnnQ_S+0>hJK&}zmOs2Li<04a8cNZ%LgddQLFEU$%= zVf~G_a2i&)N&uWpd3ZIx8b~h{lnv{#Roca>_H=vSS^gZ5ruFO!I78@}=FVSdRa+I6 zu)3Z8*RAk!BI0*-v=c@G)B4*I8~;rl$W2yO=VndhCGWEnH#}Z z$QknTK*?zg-*g8G~nNF6*ncJZ0Pqng%qU|;ob)5y0Ko&eynp1KVn z__H)e$yvCC77St^T`-8P!*-|pWj1X0c5JyEOOmP#rID!vN@28BzMs|1S&m7RV|3`b{k5=B$vpJ1 zj7soqkAT{mzSi~L{Ertt52`9Mc%nS|hm*Inovuc5ve zflCo(?TzPY2P&y2^fz`EP?K;zcsuN&3f8~;wNC%q)>=zgayLr$YD8XvPwvE_-pDS? zV}0eVXf3%g5+AmNp#3dtUC5gj;cz}eN7H2`@`UHLhQdrw#YShvuVoIdCPM8C=5A!I zx(^7C^$MFXR5m=8;8aylcNQMge2jkFt$5}O(^t9wiG3h!3W?4vT=1PIzu^VuEV`)B zV@%k>AGxhJy?Cf+Gdi)hBNE)Uto3v|;>mAXyw?*FQL3D=1fL<%J=?flbz*M6ZsV3U z#hnGc2+@nXTY2WhV|}9XCBkj63f$J8BDWvLavOYwx#|cMTARK32TDfC`n|OUtC`U9 z^=x#ua*8RWw(>>K`WkZ0VeKmE+PF!4;F!;FZ~iAGmu@{`6yp*m1cr#(4~!)!196tK ziL{29{j6pWt&<*C2p~ow)KJmbLM2f2kvcFaf2nrVbPJD7yh3V`WwJkMGQ8HuO(QrS zT+V;_{5P2YF5$nQ@ZW`Kf`l0u6QJsXZS(z2J#cKoTHn;!4gCk{Y6KUhw*g`ty1yz|3P}2ifTZV`!1d4L zfGL37d!nBG#ehs-AHW{~b^?USID~)5%gYV|f|cw#K*sZ;f-4n#OhK;akOkSd0^*#W z*he6A!On01IN$7&g@0UE>HN>39TDhxC8OuMNgKYw&UKRuOw;)Bv!TVgTDyHv44&z+ z<9`u@UlC*f&lvlG82i2$JM+UH{*Pnq(_-v@h_P>tvELA5FNv|o>XApJms}w!iL+fW z+KvRaeTj5L0v*5LqYU!yITYyHV~7{M>V>3T$|?Aas8eed>UgoMpqoE=X33OEb7o5+ z@br0Hflfl~0vRLC6mF52B9dx`9LbV|t5UQNn0C({=et}(a&jRNmB*5Eb8?0b9xUXe z>H_eh)6p&6Zom5*MV0W}aRKVP!$qu=gYL9f80j4Ozw9FUSwufD+Kz5V$U)Htg*jP0 z=N^3}J;OsYax`Z-9KWH{Dat{0IOtP^x$^?`p@3pH;z&8@?0Es3eVli~xQNx^Qhb#u zr!s^`{@ODg$yFZ*F&40CM+^g} zT(#&DtZxBb=!i0rAp1I({`q4cfnxaH=a`k;5*N`xu!_ghhmA;qAk=i4M-8XB*B!b$ z#XW3(YU$aLgM%S77dtqCfyT@DpZpmd{*QS!Z+&z)| zv7KqjyPRp}t~6&_uiehHn|DJ&w9a|`E@zKkd!0RQ-i!M|ApgwYS3()AFMnsCZ?xW` z5gNYR7&IJ;qQmzZt!wkwF2sU~hk+cmI%iOV}%uaE$w#)?z-*|U7sOfGs^6Tag$lZn#jOe+c{OeHub!pBX z$y=R0%&jQ!H7M}yCAc|rpD({9(1!&cp*KRkS`4e#5u>#RYpE}M;gMj^yUK0N#{wD$ zY_WzZS?vq`&~0sSSATcDyZXSn?xYPK>u_~z7i-bF@R(N1UzLBv+T?t&73>?u=$ammcO>?hxYhiD1fi5FMQi^^w?i(<__O%hK6s4wBA|% zdxlq&yd40GRexQ`mt3*YZ>!K76w`>-|8wh}nbZM6m~gWohdsfgHTq9Xi8@Hd3*%X6F}nw-+efq|uAOOI#CE@S%#;{Ru(tzO&BTwLDjuk(cNOvY-$ zZ+#k=9!+n3S^e$#)t@2dU%IWW?&>35f*&C9Uu124jZtSoB)0+S^Fb#&ckpJvwZ34< z5#M&4h<_*0la~v0cehppY32^tOg(aM=u%&>hH;fVIXct}Jzm|CYTxz-KYFl=Nlf*> zBUG7!8&VpVs1!u%(`Z#-if^z@uJ;CRRqc-z=ltq}=O!I?TSo-9$lx!sj<{bTx9+Sr zOzb~x|3I+Y3+&c-mNfddAH*4sv$%zmrnw!yS>Ds&#%Yt_21HWw)R<86_BLMUf!EdS zw|MfsVq56|qu38U-PFy|`EAon-&C<}aWhi3%IX2l#eO!)oUMFx|G+yOaIcR|&ROpX zU6bOi*ybz`AyzNicJVf^wcTC)VHbBR^0pkVaJTk>rqnb-oyLUBx)xvSCU1BW_Ng`+ zs|A6>Q6_3;;BC=26yY5LNk7E)2{@&yRW#a z##2#+WJ5+!Q0|$(~`QsipmJH3o!OLNOTUH~cGQI3fQ^_~2CulV79L?4ygmhag8fk8P2B2%lSquD0MwW=>;^iw^(9Vp^!Q~hsze>d zxYrFY9UnoORvN)KlRWt~Zq6?pfn+l@_z0Lqg|a5D@LBt$)VTB>S$-n^P7t!9aW}Ye z&?SG1^mp3mP@n-9i7i?MnS>egs-*B}6qLvPt48OVc@6kj%?~z{Dt@%!qjq#|YMu`l zu0bA)h|zsOLjT6XhjmJzSX_xgyb}(utibFe4ZJ#+4n|>ODg}M|(D*V)BAC;q7upYx zbQksC);?>+xsj16BD0V?LSO<;7Rl061>MvG;(TzTB`X-XSoTUyy%`mJnyqDvuMK5ChR1!^VuVF~)%}GpG>}Ec$7w=+_Tf&rJn;Ze;}D!q zT7V~M^06(RV|2rOtr-`y#{ls&^V^q}GJ5#KA(Jm5Tmz zV{pxPzTlb`7Q{ophLn&;k;2K{DmJ?D^n7VvTQ&4`mJcRJ#<$q|NDob2y-6Fryq_H^ z^qeWg9wuzo)dd&C#3;qb)i<$&CQd71=7j=WRHe74uswEVc=%JvXyxjjq!%ei7gg9+ z537N9hrB7Mb?kjCSTQ??AePl|h3csz>ji5Udh4rvq45|e$E|6>b&TN~a0$;gL-Y#p zTPCIvfgQU4srWMBgk*G4S6}g7x0U)kTo7YyJczc7Bv)AAapept<~w!O(s60khkb7kR!-keaHrFyXlSS@jNa+dE$*nGjXuZ z)_&bq4f668dtM&aJV@E8&>X21d5MetAWUUuKBO}ft$u%7X4>WlIzM}5o>G1uXMVni z{Cu49eOrG1+M9oz`MDnXdB4oh_1+5XNmesUkH=)`lC~^8s*|Hfy7+^vtgbxqrxjr+ zD&8uxvu%A4ouBG4F>#u%Oeh+~-IgOx(_s+B(HF{Kb>$T!VICYXVy(u=v@8m7zChqU zsi%sN#wb*>^s@@97c?z1G^GrkyQuRlkWWy8!F##;_b$FL+VKJaZHiX3)rDqd2s_F3=PhGjF<-zXlDg1JbBFT8NQBRtx6 z1lLB#ty)B4;i>r0#AWRSHON;(rEo{^+fED5^@U4Q!dK$_k(>%Z#2^^L?17`FRmd)7 z^|0$xOM7se&W6OjQK7DwNL~b9IPuU2g5}*+l`*tUXCT`v*#mOEV2xjbwy@f|9-(_z ziIZX86#`i?4eT4?0&LS(%*AKZ8G;>Tl{*XbR%{uJUn$oxzOXk1fz_!6W3AWvR*ctv zoB($ps!4KI{2b#UHoSe%2nc?Nr!DsQLaAsJ`DWjJMs5vQzs=7hLO4ZgVRXeFix-t~ zVqHxALz(-mV`gZW>3rrpur&`e4iUs4Typu$F+9~))PhL`j-tvVsjZtzUN@~xM)4XP zaBu3o40GG92mKZb&DeU-XAR$gnWeMhI#va6>czq0U@LSJOfc&SdDnUKaZ-2Dl0^nG zX(eB{yykQWwJt0u`A)=mRPpi4nkb(@ zI9^`S&W!fMnLqC;tZyGoLM_1F9rM|E0fUf`0U3R3#XQ+rz6^E5gKCN0B9@9T9C#bj zgW;Ia`d8q@?p8B2vCWb&O!{fTPT6NVeT`>7aByTvds(p!zo2>1Oplv)3vk?Z2ie=$2md^-jZ9B~*T`Lj&IY&2R|eQ`Or^ zC@vVp+;x9or2RN(@VnLkgl=n-F<+P(>87!qbcF`d8TgV$3RT3&@tM9>0b{X_Kn~tQ ztfp>ni{Ve718ozKg$6O&!3;mT{^;JCB2{e4p3}y|$6|HgbeaI-yr;fLQpjs<_blQH zLfaHTclsKNsndQ67X~9$LdPU>yCPD3e%mOCDj4BUx?}p&# z?bs=a&OI@JVpkReDCMk}w5d@Fq7G)#g_L*TS_i$JlS3FdouOnQET9G*nueIvU`7)d zF4nsT#OhRDhoSea1L&J0(*fL8fzDaf7M;+Rrp|~|2dAM2uOmdC@)X4vQ{MJ_FCl@F zwGz_@h{kbQUJ0_eGw%0DDjA60UXFhvR_F6O8}}j$a3y5AP#=kosu3tmCphJfKF}}I z>MUOhyhty`d_83dl$zEeblo!7Ft9-pVZm4kQ&fK^=y4z#>&Hfw{s7VNp-;9Vt9wf_ zbP~`uIRJmll!Hm_uu?O=)fYn^fbFeT2PZ6!+9d^;crO0<}o7_KUECV6k3# z78BXX+V9soPXvqT$3K!PmbhU@ul+cM5Nki&Bx_sy+3S~Hui(O-6D|LCYI%eq*MA4} z`tP?f>%T{#hojejy-mB>lH3eRS`d~lcTdZehKIf4$p+Hk8ZpgM(TE; zzZ>_Ovyh}N3mYn$VjW5e&5;)X>E0WImG<5A5V8hDvh+kZ(|8Z~R{cS2`3=hC6DL1Qh_pCNc2 zbwC{zNmMJ@M}(gk90R*Gg5We(c%k!EaK>c|kc?C}o*(w4v~F#INCBF-oU<={w6O}4 zSyp#BwUE`l@qBu+-e{x(N*t266)+t-UoaiPB}SFn%2{&c8@irIxU-zG0I@=(HZ-)x z%P!uLyDb;HII=e-ufGNr>@nF|t~iu+Lw3~5v8s2LGXhcn8DsEmW!xq5!s{2I1pG9pF!or#1o9;wpa>?kZkO3XiZjU zIrVh>K`Cc>9-Zwscq^w;sA77Qh?iToFxE6|Qd+X-JNp@L)$I)p_2 z>&}<{+sj{FUt`bL4S+Z5x7P3BB&W5N^-mamzAon69O+H`D&LdztdGKI`j~q~GJ#x( z-?H~5J?p11n%*bR?~(3F{HA>%=~z#N(R6Nkk2d3f9ltt7$NDOari+Q6^vCdP{z!() z`YX%{=m#JVaz2&xEYFVUZw5_agQREvcSO&-Hs&@;de-+S`WSs;@=qPy<^z(R^jT6dE3|K@Bxb)1NV+Fvd(S8XMB1`% z2FwC96#im`zW@*_h1op;!Cv<9AIke&ehEnXJqi{9qKnGTSNL=VKg^KfzXdoD_%(nS z3bLO8%mKU)@F##J3QkpUEFkFzD#*)Y7+)hg8zepZ4F!J#Nd9L4GTbqM4DU(>FIDgo z!2WRm>^vFndw@*uHb9KY*{cC_0e=Tb|Gxqx{d_>??`%Nk+c-ex=kL(pGJhYI{cc7O zkoh|TkbGYX$nXaMGW?!^4F4E1iQ#_@$nakPB>rCk8BYk1@!Sc>c-CTEU_39#@gd{i z0U6INfDHdKK&HPRAiQKd0kiRU9ODi1X*VG0Hvuw#Rsk~pm4J-@w}9mLEEBsW2zYvh&^#VkY+23LuWjK2Q8O}R^ z45u8B;S>WhoE$*hVC-|HvkTX z{Z+uBfKLLlTn}PCGX(aJ<-8_iJK)8zKMKfloCipMGXUxDYC!t?w^ZrxQ9#;%0Z4zN z0h#`Mz;1wn)5ZCKi~>NW>pVd6-4l@f)q^Mx@D)JTlV<_*abDtSz%1C81L80HXo|z} zQ^4B+nU6Vu43Fn~8Q!~q3~wDE{U-wof0$1){CYt0zd_C~GhBeA<9$Xf$4o$mmxII* zQfEC0=QXHBLg-Mi9v0fG6s%OROu-@r3lwxI=uog8;p4MQm4cNDmMK`IV1a@z1p$OV zz7xUayVghNDyTa;Bv)Tjpv-9JSez-W^b>WSg!hW@F0FKh4}*Z`P4v8zr~Qa;xKR2> z-U+;(moHWR7bySeP6S@h>-qR5{TmAZI~Bg3w~kifr~O!lze?fty!94^FHrbKh1c^^ z>gF>1N`+sq{i9LS%vboi3SXe`dS2d5;g_iN%~beRXsyH0W_*#|zLfYY9&ub5=@QW^DY`CjU;q|<@PT_MD{u0ffYV*I}t zW4}Gd?v1gpjj^+vweu^E>x>#Xa2B6Rh`u!oS5F88kM2yqOTNs|cI3#0jXr;*PB_IJ zS4wz7Nd!N4&dhrT>hL2G^1d$Z*v{c7`;}bMAN&klfcw6{Tjbc3jn7GZE>Q<+k4gAw zyAdnqwT##&F(N+oa}^N>T$Lq)irjUj!)$vf!%iFFg}JJ)+!6#}av<}it#nuj`jl2A z3_c?fmmZw5ia5p`)rxooO?1#mN+9AZLPpmZx;ZoFPnmRQ$>g>waTo4b6GV~IWNrQ< z)NP@ln&~S_B6LVYtXq^_SCJ@3eO4`jXI;>V=;Pdw$T&9?WFj}_P?S6DqMV`}RZ%5! ziwl6Xs=(st;U4Fv%PAou-Z7H@2_v2tLDQ$YCT7yLS6?$JaI5|Gk?(abFK0-;yf8+b z%bPuYUdQi`aE{|};Rn+jzZ0FyTXLQta}?1JjJ9{hH-8*bXioNA-kq3C(=fbbzy_?V z=FlPjTwcsMIu9Q6CZRM7R5;Dbz7z9v3}KFN)T!{&v7Tgj+MLnOxjbG9i+Q}G z;6j|wMuI>Wx$g{FChn$T(lO^2IDk_!l;ay=Q49Ehs5rOvkJ|0~um+Sggs!}ZLh8uX z1@FZ@B`#0sUcB(!U+Lgt3s7%UVM7F0mf&s}CJ_5nd-X<<5fZa0>g*5m*OfS-$6(lY zJcRfio6y+)f>PCG%Cm6A?#o5I=mZCl4wnv)=UMXi1^$e{1)lp>;u3niYKYx8DamjA z6orK|e%RlE!t>t1*x=&S&I?od-bianR^x0)T3%%tLMI5R6yb$h)i=wNwo&qIV zv76yVl?sckJbCZGad@Y3c#qK+FTUcV&g|P__WjD}wl;D0@@38xQ9e+ZT+J*){WgNb ztN9=X^s@_-a8T)BE3yc5qDnOW2C8l+-shSo>obbnhH8_SRfpoAh$pb-1vsmZLu(9>pT3M<SigOvmT{Zcnxjq#=drU7Ed&yAnI%pLY*9v4@yJh%cu zxx))HQH#eWK_B2ned^NayD2czANCyQ)34!)tIYhhcX#)NC#Iu5A75qUAD!PX_Yn2Y zpe5+}CY`#1-}G~4dA?cY%rd{Jf|euBUVd5fz5(^!{4W9njIjC5DqnaUNQ3K+yR*KI z=vDBX2aaz*9acQ5@_NbsU`uDKdT}4#KZ3@yN>r+t#uHI1MNKuVO>PS(Gv0TJV;fQ# zl??_*b+E~4y$Q7|U-d^WU$?i|1mIk2Sh(2`*#-T$>Q8{!E83amUxF>;GMtIP;TJz% z*YPex_Be2)1aUy^v-$&<*=-FJTPvY_1;yj>%U+O0!5w$mD@D9~2roGGBeh&D>^S?E zL^y=zta?Yo<{z274BBZjm{5h(sP$qin0x0XmDodHg71}fABq}ikTsE#Z{lQmD+LiM zGiolmRAG)tXS+sS93@ip0@H>}Xyq$A)kj=l?=;~2I9bIm;sP<&;KZD%zPeTE<`OE=ynhjQ zNagRtwK;)nPpyCP025fiJkuwVy^2F+aHG29A#I)-$lwuNK&RpDOOh;bU^ z)kfA4oZr2{NZN`K8;$q~S?&X!m@0Ix?C8S7Z$cKCS>V6c%p(5=_)ls<;C)n^zv5)u zylrgfTjlcVKeTo3DLUBJwNnReJvtm;@w;LQpxe69y4kn@D-qNQ%m(DV(G1VBb*P70 zw~MC!dUR87F#CQXo4S~vVSp3!GYoLdXf$_l-f89vhCYopi zT4recIyC)4M5MZg>(B*YVj|}HyN#qZCLW|qLV7sRE zSjhW~V2=}eBWo7|z6Z4EB}AWs=FgP_XtxR~B;|;ih0~s6fDyc7KC}qAi_EGL3xJ(u zo&D%YFeJjrl$m%$1b`^feR1gkX9jRfKkC~-tu*N?EL1}Nm+{}kiY4nPvb!I;y#efj z7!pZDok|UFnHR8g~=#EAAMn&-*lwX9ZCL>(NbQIRf zbyClA=BPNq#P1*Jr_f)Ch65UOSoPt!+Hs%!SyZftZ&*|FTKI_Qi^T8RQ3X=S}{E-+Gv?rgE*h5?S{n+ zEZ${?^Oi|88DR^g9QvuSSm~oIe^nJ$dAh#_rx8y_O5d(ld?x z(b&VG8UcSac6X>xP%lLoySoy9MrgGiiqyg&hY}i%*GO%TrPp=}9_&W361AtN!yp~; zc0TPmjVF!fm*4jAHO+~_pkKRxdmQ{GE*5GxhHIzS@xfUb($URMV~m;)Txtkp1i+y zC}R?&)FWbC#oezW!uIekl?CnLsSiZc9=DRf>+~AdF5&0)1KDxvTY{SuP#Xdq7|I zxl9+!sU!LT=nIrSG0UwZ`X@nOrSx}Mjwhmj_Xkp+?R7xto@A^CL>v5)dq9JO)U8zB0f|peJ_^Aoc8KD0~qh=_df9Ze&~rNVLUtb^8F4V`CcpS*{c+O zg>=8{X9~`fFuO?M2P=Db1?w>oBfRWK73>7abe)09A?gn@o9WpIDC!R&`Fj!&)ivWW zKv91H$>%+QOwSC3F9Ia}1VAJu<1#?f{Q-#u|Je@%f|ZPrvh(_W+NtkHK7J3#{Jjd0 z{GFy6!8F(pT`w`86fE^0Fl&;I{-;H3XtsqI;Wz3 zT?7bLGN^8ds4~DiO~y|AgDOJzD!?BAt_17>$Z*pD7XUf|ivYXh&j3sX%mF+dkZJ-b zN1#MHySorL{<`oVVLjXls}!tMuuQ=s1q&2(DF`6^6@Y2#jcR>~amv07Ow&*=l=zj( zzEIh#lzo}9?^Jf4aUgxOvcFC{%CJ%mD7zFsMcI>pBcA%yH2kK2m%g|O&%q6L`fpbBZ)&{ar(W3$Rrp^hd!^DV?Sx7| zy;`k*fwB;Kks>nu8xIGeH>vb92!!6GBABc2Eeel1EATFb4=KD$>1p~Dp7n!<7a%fx zL*XaGjo}v%2~(}`a~1v`xDj6{unxz&3co_(*-nUeA)PeT-(~o<3Qs*r;>%P8Pexf0 z-=gq52SdD`e~5Qwf$yjEgg7RO@KO0`1}Og%6n+idKoT)e$JjT=*dL3re;#9B6=Q!O z#?CR_9v|DQ-TqCC{i7JWP^i0oN+4$vRjVe=y=(fcDU)*ZrSfB}`@n&N6VeYHGBlz4 zpuEKNLk8vwdJ!d6*F=PN)y}r-?IYTNvuA@cT17N+MSVn3vQ4j4zAYi&ZJjk`RxzJV zwQG9ncSrH?DpWfooQNdCukBsdD6~pxgkC2x;-J$On|DZ})~ky}Ai9C&=6ICY0P2^>ao6gQi zyi7+74V*H&vz4s40H)2^fPapGWV_y-}9?v2j#*K zhQmgly~7f&ZU0ixztU7G8f|Cy&7bP#Pg*}SRfWUwF!VY2PAj^1TFMBt=}7-EO@&jW zJk)_t^3sfdiYLXnBe=M3JDxJZQ%%)GuqLAq>csVTaH@5IzZ4x#zqFoALf@L zuS7cWeJUpI9s{@awi_4HSVwETqD&x*hTaG77xCBOGAZZ*mh_c(BR4P}acxmE)K7A^ z;a(^=m$nXE=@9l;VPgq59eJ$J1ReDYtDVcC7`O+|t-fE?wCm4os2LBsp=Ia(4n0bn%62?dPHKMdt6xjX%85&Yo!$BB*f8|io3@MRs~t2)4w#}kI%0iKzDBLB?O z6XH=PB6#o`+56h)-2Ft~X=?_r+i+{B?A<i@ys_T1*c5B;N5?F_K`lfes!Iz;+mHpe>fBz`|>3tUtTz1RIi-&F*_Tl4q4@mER zf9Ky^6nx_Iu1`GlxAha7=a|=Q+}nTip@%1&lb-*uZ{cST-|_KT+kTwB;@i{G&bsTt z8y|S)kG$bG%KV>7{~y<7KRf80Gm{H{HfZJezJJ=+=f>KU$GIVb8(SANcIf>nCs~d%6wU@x!Id>qlQW`LQh@Zu{}M+YZe5;*xK>?0O*Oww?1k z&AYtzj@zy|zkm8U_qtMFdjFj3e>QpI%)7fSsd{nO$PZFJ7+V?m_)obb_S|%={&?Dh zSN(je>kmKOwkay}VfknN{}1MW-;|_t?;8GtfB(fNJC@w}>$F#1yy?e}uDvMzj;}u$ ze(v&VgP%X^jNKOo8#n#rEwf?IOKbKd?|tyd#Sb3qb^fcHp6<8shEZc?R84&JKOY%e zxoqtd7YzIT{a4@g>HhO4XU*O6!H&PIKJUHxedii|>bm^PMQ^XV@elv{+-EDo54~4? zf9v1hUG{XrQ2S+A-E}N!&Sfhym{bf zXKlSJqx084-?3$O;JZU_-!k`-ktNE{Qm9G z-`DS+|4rc^FMHtp*P5Gpzy2Tp*7NO~cVD;h^NYWHWMJOnh8?qqCr?Yh{Gq8=7)1wu z@LKjwX9NQ8e6sw=4`;nzkonL0|IhmWf42U=+T(`6zx{H~55D{OqrAHpKL3Y-`H3xDUeH`Kc;2zwW`344f65Rvp!{HMaGdo8NDa&Fa7<0yq)$+>8JjA-+nb??GN94V%m^pBfoC? z#qWMu&}~G>=reQ2l3zP6e)~XP|Bb!ReEL|Y*`pqw@X@I2?r!|!<2i*N%)f5=zS{Gz zYbbkR_MJr=%ideDfBQb&{<%h?pJldi;ZXmnsD-6)aP*NWlUHT?zsSe^0@Fqze?r?SRD*d#+f@QuXh%k9xzYuo5&PYO z+Tr+^cHoPY+=*=1<+z&_K2PDb9Jc`O!oUOlFH!hw;Yj~Q66-im;a4gA423UK_@N5F zQ{jUOU#alChl$}!VV`^xo8ea}yto$&__*b|SU$5|dRh9k=6`th_r#3SQySJ0> znp!+?a8AD3F28hWo{;O_I(_!QTW32GP~_%t=Un+5G-TjVz0p2o5O&Vv-3R6jMv(FD zgK{p#&V0N(cu5!zq_zp;&BK;yB%J7!2>G#!!G>W9?5LPTw1Z+g+CecX?Vy;Nc2G=E zJ1C~fjtpciOM{N z^hDJlhV(==BZgE|mbRS(>;u7^>i)r?L3ug0{euPhgL3C~w0}^^hUbz^k8I(ZYjPu$OM zy@8j}#Pb!0@%TJ;iGvI9e%^yKkX&4IbI6h8ET6=0JW|fbb#N{c_XZqoV3fRk124(# z6Baygfqh`RJ@Tdok3DHJeAn5&SL1{&PQLoAclmBg$nO$izMr|#MweeCVjTf{% zikF)A`(1nOXP#%zOu+Ly@B4ZGIM0W$X6?21+H2qMYyU_ni($%wSEtM?A3~HD9eDB? z6fs>A@K(#9(yOr9jk}9}nc}U2RDD2#&xUxR6=y;dncg0G`!S%{Vtu-cIilRVY=MiBX~{+P1C$kLbOdJX`AfdZgrjC^GN@gk)DI^o+LMG_@df^90&u5U(i6hyt~T zStiXuW6Y=Ce-9oq#N><`5qaQP8)td%0xy2-RlmtkKfngT3LDvi1bArJI*zFSeDC~t z@2v*n!}q{&FO@G4;pE1;0X*As>j!Lp!gp*$SmApSNVtPr>`#0Enq)klk3mIH153=? zn?);o7K5)@_le3l+tE4qJE@9C5yi|o43&Yx;fat(!C*@Qwd;NHX-{^{s(92~C%z?& zS4p8j^wz(>iU#TCO;EuE!bibgF6TRrTLVv61QHC81q05($qXQV#72KW6boGRfKN8J`{>v=S}F&Z#({S z(Yx5N<9h{vx#+Fh3H?3~J>NXlo<}Lr3tCnW?;cH#`zJh)vO(`#QD6D&`IQ{@;BNxM zOug_%{pGX#IpqHc411NI@sTeN|3&CW(bpB735X;rdLQY4Bhp1LDtrVGQ=+2#6#fJd zeP+>>fb=&L@Y8_BfH+EBGzpOY-+?gt`wJlXp9Q2l&v}mrTnLCG07X0pj;;El)7AYT zb>E5n#MGwf9zgQn4ao3#jvYr3imCzWkLQxnPZxcJmIrf`BA#}lzdr)fAL}3adB+A@ z{Y9;c*8x)Bivf|hMP~rwXhad`K*awGiAJ2`3*rx$R4n?w!W1Cmw@%>~6)sbFg~B)> z<6j2|(c{V#Mic^wdp(E~@Mp^pds3bgvg4ea6_1Rg4>K2|uJ)r}p8MH@eB{S+MY=8b zrzyQ!{r^?zw%pHEdaKfZ0y><$Z<>Si%!Hr5+`$(*_$CKm#3yo@dHqK^JFPVP{vo@-#QBo;EbMGzgAk z)&j*UF!?~YZu2TGn>(j=N&QOWHFJnNc}>R9?X^pcRakqz$ve+vk3;z_^x9L~nOJy- zrD~eKD6XEFS!+`_2X7$Gxe`O>nTUMkG=)^Sl{m!c})j!;;#SE3PrKt^ezD zTBo7F;PcLDDUNA~%(Ku8%D2Dgw4UXp1fO?K>x@u{Yciqic~(oJdBy5$NyArLyRf2$ zl}$e@2W_Q%e22pSp}7ov`uO*W(ZU(Z~K|oXB@_Kf-v( z4B+E!H}j!$-XK#$Y7cUdv*}9w#~+wnY>{VUzlYzIsk39-=hop@2(Un4=Z%Giuk*%f z=EwHAWu$DM8)NwZV+~QjYJsUgMMthEz(BXf4ycB&wJ)x5GWx(u{I`k!MSBE&6i^iFoJogc^^BTJ}8zhE5s}yaUe!? zBLnetZ5`4eaZDv13WlB5k;^f8HDf`fBi?yWz7pR)uMVMvs?uu;;FdT#PV-7-)hguO z5e!ews50Jpi%Bs2FbNh<-vYjo#DNl1jv?E&7C_5rtvNxLL2>q(U)DI7`ZG%tXT{UU zQ`3lvA6_`m(iaou52&wnfj-gpoZjWtoMl4B2{AmNYombp!aN`*y;RMo)?%uZQy-I_ z14t8C1%aWEiAahh44lDmU{=CTw(m;X^o{H*eG$;|3^Ojzn34r`0aOooD)kQnjK}y7>Tk?vfR0p``zdmihA4HNC>uQXN^lN z2vndiAQ3h-;J;|^z4(9lxNNGafjY-Xlkiiv2lKk-5g6$v$srR#W> zxBT@9v&Pu=IdzbXMG4$DNY~X3Plfp$Tsug`a7&;GldiRx-7Uu~?2@`z3e&GSbyex9 zQ{~0lHhRMZIF0FhbY$VwLVX@}G1d{dbX1j2Of9Sebz)U|_JFY+|LvQ1V zJtnl62d*iIp^->mQ;=8&<&vjysV0TDc%QO9VG6Kh2S}BvYYM{czk)}UTKeO%Lo6Lb z+p{Clj0_65e}xh2#85vJdQjTRX8h7jdKYR9B^Ye#14v8U%tZ|t`^_#hn1hZCXf-jb z7aK)hmVMfyxWvRJk0OhH<9O);a;rTKZK!9u zq6THCX87ci9Yg0(Lxg~3$xJS7zgW`6ww&otpm9Xe`2+0J1`GYjAVj>4sc#?wpMq}M ztCcVTe**^F|3vw&e6_5g{+8u7HG-#=r9Zk8zR({H7fAip@_A0Iv_{J3aw(s6D4(MR zB`GpI52Y|M8})F&_Vd%I5eu_0u;8C)D_AU5g9^4B6|648<~vmoPaR}T(wY~P(LY@k zT`Yan7N`Bc;&Sak=CA{4TN?`{uCzh2Y2LKe21z@$P^u1mFgS@qKf-1_nXrwvGcLG+ zp6BAfXzzVigflJ>mN~-0Ii`tua9kiPW?Zn{vLLl9Q+v$7!0pf2L~0$BMsjW-sh#@g zG?GF!>afy?IwgIJx5&MgSn0co0~U|GfG*V9%hK@~(vL>dcO{Br=~?25SE^v8`kln_ zY#K6)Y#5*H89v0OS4p3VLZCl}{=EFuibRq7Pw9DM1GucCEyS4cu{c|$ztZ$Pf<~RG z#G+Qmj^t6caj@pF<0()QO|%G{u14eZWFi`ybwFbIs0nj^fZ7OUG%F)xvig?X$;J}L zG0~P-=`#tmDR^Z4`H?46urH71@x?d{Z5N`-B#!VN_$7%EICyw#iCN2r&D?2BMMlYI z6V0%VAO0s61JfW%4h`SI(Uvp5iQy%5$+B{jo*XazHP*QX8kr%XO{T;lZ8u_QEr#^X zuxShP*Nm?^=T3_;C%2ipr>fFRanMUv_^CBzf&5F)3*xCY zf*(|NE~%E57ioK>DU38F&*Bu{K6WZ0l2p>Pb2fp z28qb4OtqkOM)lMD4Ynsp?`nT~1Fs3<9Ia1d^M%?p7$|0|pxh=?|Go`nBsA7Pe|?ks zT~?ga|7{unG+i)?|J>pCWc>ehbpN@-|53(2O$3h;{>+^E|2X4+`{@45a{B*a#{ZM~ z{QKA8V;BaQCWJ$mblF%8S!YGZn*ED#$L(kXqcr@8yb7l;EknI6DD4k-tcJTZZ^@%1 ziqIu`KhKV#*$cOG5ft{``#5m3EuDqv=QBU?(z}^rVal5MS<&nJjf<<61?Cnx?D#$6 zMP;Q$z@FW@jg_gtm?z_(!TSA3bupCz6DG+!@jo~dQB+E|a{5$-)GCW(#9DwMVDgjbq7nFK zfP5nH*+6OM>a30hcVqQJ!ZoT72fILFoCEG??@N}^Cd|;2aF@h*3kKoQ8^03o#9$el ziyOTLj_JnzBWd5-@4_#P(feYZm@^|uyhaUre+h(MZUrZr;&>Qg8tC1A`scaBRvg02 z!w8th*{^LB;s1QPx2*+7F{d?|hvCB=Q#h7~IGd8#sbL}?%E9+p_|Hbjl%!bOx`9yU zda>DkiTMUG-uy^1)=T(lO!EVo))$YK)=s~lD}j5V)5zj2i=!ihf&QMI&q(5gl0Lr2 zQM#ruIX+hU*@?+SS?&KIh{9ns|Vt?ezcqiO`8_SYbQE$xCBx@;V z8if2fAh9%%70wV$ioH|da}6l+F3{*GDqi}0;z$%CjxwGwql|dCVq5aX;fJw^G`!2M zm$>7rn5=dzXM2kA;)FzSym$*DsC9G-s-9DBglZ}#pKz3@u)jjT7A&7NO;s49Hzzxlr>|Cbs0 z>$Bwx)yQufMgB(BzliPIA!y&&$c=FdYf~nq4cQ?H)r54H8<41^z-b?a zYL+DV{M&9YW8j!$Jl{$Z^Pf|K;5~HqXD|T*V@P7%5|~giEwO{=HfJOaa~XTf(ShzC$o>ogAVykKk9RE?l{-A44l@ z!EZoaD)Z1IpD_G00LFyIWcjaC`dfMY*P-O_%O}4_>6d^fmwfCO%Ex{GT<2W6bRTaU zxN_0!3XK0P0J+kqSoiI8|1m3m-AcbWkAM4)v9e|P=b;LI`RIj8pA4Ue9XdA4e;GFh z@hMvty;|wT;K`MKtx7*T54}(6`Shb*Qhxd9gZrTG*#}*W9E~EsaJ&ScH~fgwZwFhh z^y^W2zVz$c2Yo>4GmRQq>0c--^zvpqIkM>0`=EF2gFdhidLa%S@yn-QwbCC!JYeb9NxjNb|avf|gI^rd;|gG%SdIKC|ZWk(r8 zK6>{)=yI3=BJ%mKn`q>(H6SbeL8Tv;hc1WPLE~C}uJYA-wDDM!$A6E~Ps>Bs?8~yt zH5L5SsrPwK=0`@@zshIN9nNhVdnfuN@|EMS`%l6)@>9cw1sAnDesSA@caHt)0pweW zznO!EuW}T=yFsf{z8Nmx9FFx(xW5Kmt9);{e7{pN|If!qJ5gQAH(I>U0H2jN8XwQX*6oM9 zo4^;_559i|U-5qMJqo^w``}}~{0)2|<>R9Jv0H2MI z_S-r0`8z&&qw#I^={FkRYv8l_HyYm&2WHB{XneE5w^7qEA0N|uDfs%7kK>R)dOPjK zR1oh5f8Ae9Js7QC|C-?|pN>y*rsK;DU->u=k)gO9f7i-(PVY=iU3 zy9#{$$~RhlX$N1A^65AxXFPrczTL`ql^d?&OuyfOFQV@|jK=pN_-d3-$0s?%oq7<; z!+!8pg0Fu+_!8g?y>8NPv~a%zzM0CmVwCu91z)T3EggmLHR`8)I$p^c-y=9@e8cEB z8sBX2&D;;ZrQmDY557CVw^8}ljuMYwP`@{ge#ec%_Z;~4syvRL@#oXS$pLz8d8_&6TJ4lNfJ(8TSLe510Z>0(Jmi4Y(fgD8SqCPQl)Z1|I-ygZsUJ z_$F;oc)7ZlDt@fOzhXQ}{%6d%bkcna?^5?06u(m8+3J3@;vbmt@T7h~%K3@nT?!Yg z`&`9OQutSl(~*LUDaZ zU{ayFzhmY(lk`1H{|$B5cM>K|27W8tX?K$JH_ZHM(w_l|Kce`*11<;tB|!2Y zqi`+ebL6|)%%9-S%oq#t1->UH60daSvD5Y?P!Z`|00K6XbqW~%Y z@8+KWq&EPG|4#Am15)mt3a?i<4sb2p-^YBG@C}78Dcq^>w+bHy{1W*71@H#IGC+oN zG9b$tFY6G0#muiK^#Kz9H^o~OU#57O;wLN4OE}_xypi`cz^}mn^?lL04$o$)dI*F=L^cz4Fm7;q9 zX8^VW(*H6*`j06*Lfzj-+d%iX0Lk|U#UE2#+8EG(2%P$-0U58Gly9Qq2P^(A+E&W> zBOv8AD?A5~{tp2B3gDm7=TOcrK=KU$l71H;<9(yT5~WX4`lkWgLGMRjPJdqoTn?P~ zxhbzo-M>55$m4x3>JtSd|A`9UJiyTT?om7FoWn8vISPx_{Y1r&QM>@~M)2{GG{ScP z>F*6d%K3@nafQ6UMf%Sab}RfE;LUJPDQs2u%M^YHW!pf1QPd7idPeaF6~9;U?lBtLj3^8#97H~e ze}&x&TNQF$oAfe;5rrXzgCL53h208U71k*%Qy5VgQaFfA!OwAh3cD4yDy&mjrZA!q zK>Q`puFxKgy&rQUaiopCkMb+<@xELg;>+(PjCM-rauTBf%b&-;!_Nr z<51G={=j$Cf7fI~e@6Y=^}i3$u84f~zg6jW{qQBF51wrN9|zfTpAY4cUojy4uUGxb z)xTZe{AcxFr~cdFN8*Px;P;5?H>mn?N0)TF{<&HGuUG$Xzz^vxPyCM8@M|>uGS#me z{`g&|^nw!&J{N%g?f%MFH2me04gH_hzg@rQyI720kNT&*9{RWI(|AxEN8^2doznvO?nv0P1GyP=f$0~o1%D-3Xc71+~ z%5PHrW;4AZ->&a1fE=bz^=T$Nwx^`q{h6CI{9+9sB%vE_j1e^d$|f6^gH^s=UpzD8LPpHcmHtNyglME&gk!m&!b%q z^rU`$(@grY-;(?}z~JL-`cEKVp?ms-K@$c30Q=;M9{khMn|3UT7d*1YK*S|Y7 z{M{Np-+d$9?k}9J?OV+$Cj6x8$9A0`Um~aey^{_8MfGp@2Y#Ub_p1LxHGI2%f2oGQ zLBoGV{oD2b6P4bibdFc3pIx8-hSCd9HQ`^abh|$PA4;F8^ffkoGp`A4Q+l1!JC$zN z=l`Vi^-4cl^|SjcY27=|xKS_J5SVQRV-O>TmZS_GW3fS;m}WX=tqFr&mXF-m|Hts(H!hK@+ACJCzylfTZXVdESg@eBDVeBkXl`!AGf>0P>Wa%Qzr3=RZmacnyPu9wt@Mm@t}rrG ze@KmdpbRpM9ujw4FgJJN?fYfEAo$Rkqr2htBEK}*3Xf52?|9r536}hFrQZJ=kgP38=GN2z$cNm)|NCbt6!1` zXO=JE9zWgyo54Y##hIiIhv4nj62+up~iy z7E2mYG?5f|XQ$StxsgFt_m7h@VcluP>e0mIWzuZR1iDXA)GQ}cK$Mu+K++q*ORrfe zd2KK;$zd{I9a?JZ6S>k0b~aE!q=@KC3*birh1-H7sOD9=fL7> zT>?eeb|98$lGe{|da_K(wwzW>hT`=Umc{l7BtQ!mBxO<{i{$q;eN}#MxoD_ zHxOi|{`<|$U~@L(PCDh~%jAqvm7(vCz`T5}Ky)F&_@NgGI+%{caSQY%Sv1?71PQ*b zBR~jrDlR4IXoLR1vY1B5=@Np(TKkIZI!s3`tbE%%oeoT3oB8R47 z;`b6Ij19FC*pGISg74#T{$#1}r*eu__w}b4yGCWRLZM?bY~C-(8`X|ejn1nv4VSO? zbkD2&(CB-P`?BM-T;;W59?h>G^7wP&Z0~J>fXIE>aoT-`hzSic(eTC2+CMu^dlB9e z@K2kIeV~JbcATgW|7PM3$rjQi#jpMU$Qi+W=sH_t@Xt z+xkhyC$|i;@1^JRf9n?d589Q={2C zPd#c4BEVjYx!T{h_ki#nPeYL0e7*Bg{DSQYv2NUl-?+p`<1!tu{|ZPbskh}*5A$yG z>y@dYaC<$pz!ei*|9w-k#zOeRT@+laJsAuzw%S{T*qh6TCJRa9X;Tvf?G(@^YmXt~ zIx_Der=CR^;zI7{paO3wi#4m(iSQfm{3TP4iE{z(*`^o4+mKxHy>RHqr1&k%{2LrL zU5o#sy^M~?E$JKj9{F%95@t@VW{E^q=P#M|qSPw^JrXsU@EP#o2v|%i!*H?$oj6Zy z^x`J3k=KFC&B>m`WS;{b3J%}f7fpS+A7PkcD_6ly5`wXxH)xIZEZi3!Ko(C6-0YQm zG~PXR*jYj5!ny&9)jNquymQ`iV~Qb`vc`O#fuS&_;T{ACQ?xKn5IeX(-2OOFMyIVe zg5(S()|Bi*#+ql2lgFUINQ%G^ay<1g2vw=q%tdgToHz*{Nm(DI`I?6SJxQ4t;)kQvBBKlx1u#*gR9> z;bOd))`AMG^JXX?;*8qUv6$vnR{?vda}NlOaD?+cl9E$Q1UPnk{XZuhD6eD zv)fcCB$TaNxbACzN^S70X;k!k?#z=mDaqwik!cku+_aF?$~263-aXY8?{nk=`x{7B zmhN!-eA2;69+R##|3R`OKlJYC8$JV-F_wB-^fqlyxcxACymhPbgBtgWO+U%ozapZ> zM07NLF-$kHWngf>2W0K6L?tnG0#?CcD&Q{&(TXSE&%wvyD;45JWOF>VQ|Kgq1H?`2 zttcVA3QTV(Epan7MJ+)M#%+6RU^sED*qOFX3X0Pek_>1o{sN-`y&2(&3yjvuvxd(O z)cGGU%qaeg_MVQITV02zNeU&#nO2nMVG6uFf!*j#^)n4@u=bT_?4+<^FA%Bt5wSmJ z$`3UU=}@A>#UZw!Q|Js`WYpxqItKPo_fWP&zj zBT>RAz)_=tk{XIGYd)F_Z zZKFRf^rHn#)R}PBMoc&#O4A2J{NVqsKb)5lbFIr0sV&2KwJJ5lK;Q|Q!D2p@V<7K= z#z6iPo{UW@_C{#T!|gl(V}e{h(*y~xFvh>5GSjxBK1u9gQVogFwzh0c@+i+t{b9x} z7DA^pJg%f~_!A|4c%pu9EPYfgeVgi*IIRN7cw{X7t!bj{t^`alp|$zV$Wy~;M-jij zj4)SF0$`-DVxT;=w%RJ{@2rd|Ex(C#-#yVlepj&4CPAslEy0d$g4WXr_&_eP(#+nMTumKnXO%B2=8ds?=LS zE@`!Lwm)_}I$=v(-W>feKc;2)P}EHXV7 zZoeKpm8ph4j7@Xc*x8CIBSEqV`F^8IQ+HNJ9y$ZVM$=wwFn#ho7$(}4I9e(plHeg0 zil$;SH`>%JHZ2`9(qM3FkX<_=zj#k*sbOK*5CfEtx9bd19iVQ1I?<^|56)n-k9hV z3<5BY8lJ(FO+7D0oZdq{Tbr2)NIe4?Y_rhY1TO{YbkXUb_$D}r5fHnL);mCkd8giR z$DJrZL+@a%gA#`LNJ6~x3XHB6p-nJ}`rgQ*jmE_1zq7D)E<)L7K{m#(_Kqy-WhJ={ zG~)wvL7J4rgC{~tTn8@^23A$&XUKZp2e1A@2lsZ8I`wBW=!y||xq0UI^m1Vh9%YRC<= z+B-FB2ciH#e={Uu)H0;Kk|I}V^pJ7%=EUin6iq``>slq%(u+34(*MM~v*UP^x?coe zEPX#S7<}ERuj?%X6Zm!ng@Hw@JhG%1DyG;X+uAdIxRMKfgq8SNlR@^XwCZvSVX z6wQ7VqPt?9YiDwHmQJ>MWvGL#Et2#pw3z^p8t||Ie8?u2mNF>@zs^L|A>~Fpn$_{W z7z7^r2jk}}2DFJ+W`da&ngY`0n=qxe41Ebq@wSI&qU@I;&6szl@>=zh^P$sB;o3IS z&tYmiN_nyf97igL1fpV0bMY45BI=Kh{DH~vkW_R-PFEowQKZIi>4(!)7V1_X_XcoB zw^zsjUgX{*>ZQMKGO(&2Ws6c1;4_h1kL+lL6id0jA1XUFi;!ZrhQsC@2q!fv}*Imr(#Do;xL~4i%RPTxWc_D)nl({nzl1 z9?a`Wyq<%W5xowm&-WX7r0y(AOT>Q#s$fG;yz}DarX9WoomQ`D^l26iEgV{kelrT; zmH-EGQgoh2miF4bXg{9i5{({x@CCLEWiKf4&Tp`lQh%w%s2LfKj-ME@Jws2hMMUt? zwg>vb&aki|#}!z%=~6K`W_d3<@;eMK(+xd%(?HsB^nTHOZ;&K*x0CYJRmU*+Z;r8?T4U6TL5xO`^MuSec7q+qCT3(7 z$>{;1dTGKqhC5zkElT}yr~6p`?nk*sT}Es0XPE$Th1z0AUCvjf{6V6HT&UIMu$10_bR{K99jj{c?k=e?D z*#=n^@Kyu{Fesy~eBt*hFxJ?@?X#sui2dq*R8tf>!{k9&qSoJ7Jg`4G*71HblYfWu zqUxOuB8tK~bcO2*hF73VLkqYS8N_u)tFeh~wC&w7L%ens?_4-ldRNY0D$rhFzAMW| zyfb8EaWapNa~+yxbnR6erAg>xWyHfsizIl?#_=e|;(>VQRZ|OwFU9+!-8#tNUNb#< zf=|>?MJg8UF@Ki^i1l}1WRVEQbGGZcu|t7Wr6|+@Ro^ziM8V&sF+V)siFY?s6)32S z2T<&Khp{$LX(EO~$e{`dP#mH4VJe5s0;b&~%r#kg;E0B^D@HCl@`UU*qr$TtF-73h z5<5xFSBB@C`ZwIbi6=Wy4wSe{hmxitpvk?!BtAtWhGfdG+fVz}uguOuVzH5Fnn;W&G4sHu86H%1qssMM z(mDHeL>Oz+=MZfAg^f2S(|D-Gh~jQPo>W=9u>>}!+sSAW2dzvzHTL;%`%H=)*-}|L z+>8M)T9b4!2Ro<<8)09$ZQIOv`a)B#umrMzf`>i{FY;q7{c>(gJE!ZXp~^yIG;n;Q z0Xn?MDv~^2Sf4>V_5c`AAGd2ZV}nqlvv^~??eBOGXK`QiGE;LUL%erLsMRIu@q62D zC<`SgUYef$(WU9cN2ahK8p%_K5^N;fHe=o9fJ@UeKwkLKUNnDr$U3v6&W8ZvBipM= z-)#N~{J*g`)_M7I)9hfR@`8W0OI*;n;|ZJe!gr`MrkfZGB)ick z1=RlsCN8z&P=QN4<9{PD&IJBJfM3oEab%vxo9XGHe(`=89MreY)-sDvxk^d z;r8u}T?(Q*KQq&8#7Im{LQ0i*VWf-0VXAVEB*g);R?Af2oH7t0jzgFLHo}M)X4GB= zC)O|#v7s($==e^2UXrfWl+eCpp(%;BJsloTPcr{`ky)EKJ&OHwD24!;)J&be%F^B8 z+fG2bNbP5h93IP(&5GjHV*l9&jJR-`3oB_A{fQ!ZYT~bEe*zZmGmAl(fE2_>ew)Nh z((Hy+$|*B{gDs)>H=t6`Or~_vUY;$KqC1p;YEsi0@gr+LFxIK(l%B>$GX@rV7AIpD z-ba7P5IIB%@#xL}e*2dK-dWxyL4Liiot2V>%2o!L%g(N>Mu2v99y(hOe);GFhD;kd zIqft{2?veMR4zNNv|GaOf;{vlls$ehd&4g)eyvJB9qnW;`90%|$MeMVm@NN$lwOpF zPWvPLrsFSH`qe3YDd;)vR4aWFh2+qGkJ5+o#DDN$<8fsky0uf#2DV)BxA*+H=9iPM z3Hwu|LoT|#Cti)cxm@%;#~A&}0CL$mEk4%JwH#)pf0@#GuRfRj&)Xy{u|PIA%roMPx2jV%2Nry06lSI?p!VaR#yuJ#F~4IA*02<+2V;Q$E)BfLuoprt5dezthNN z{g=<`?Mtt%3}5-!4&>wGvQkX>*dFBLI|91ZDc@3;&u8D3)9#JRr|m<|crOKCxAL)_ z2!!jzo9T2n!++Mqn`yQ${;ib1%kZ-u3Gh4lMfraNf9N^G&vr#Vo31(ZnTonQp!SH_ z&g_eSA^7XmjxO7s(fFCq?ci@!`gJClw+JDEQM-v;H=_9(-r{usaC`Q))(l5dpw zjU9{nruGWiPVI|-2Ke{vG3n>^NLGH1^j-@7fwv4l+p*E)PX+OA@HD++__bZjiYNKF z1-D%Jw0+CsI}z>QWw6IJ4zLRF3AC5j0R9pXMQhTx06z~r1vm$A3E*tND*$H!eiHBs z!1&41&J~SOc;rc;&?RuEU6*pe+W^UTw&G&|KLh-^6GNdZ0iOh9cwK-O0KZk?4S*K` z|198zfFDjV;lBaM@LvYJ2Jkn4^#60fdf?v%yc+NpK*~!fTnR{d3jitaLcm(Up~*(> zE7lz$x{<(v*!3wXT3!Q)MMPXaQ$ zy8%B7cr{=g@F0cBNukhu;0poieh%QJfQ`o){6dA#9&7Y^OyL%Vy$X8(FM_|X0A2`q zB_Q>g0$2n15egFVX8@VMj{?pDTnfnWrz#u=SP6Xl(Z>BNfYhf6knV>l{* z_i+mUj)F-3p8?YSZpCRAli^&b?k^r`=zR+R4Uqn70Ga-k3dA6HX!3US>ayTtEButC_D_1eD9&bB8(|KUEv2|6W=!#zNGLE3LjDUpu%4$ z{1G72;cI|Qhg!g^0OtTQ9nJ%!-s2UgT}r0QF98{k9{^IHI~4vN101#wv>SB|;JJWf zP~T{G@-pD>k2m%G4nXElt3uj?BTl=Mg!O>bs|=8OoeW5M;{hpe3?TJ;{801}fV404 zIY8Q}B;S_+$#)(g^&JmLJzqVJz z<5db610Dga1`Go-efOfDoCnBrear{in5O%UfYf)f!oQ9+>HMm~T?z*jKCJM5K<2{_ z02%);0bUMR14#X50hR+Eu8_yZ$oF|bx*rKhKH8sTJa&J=v~zy|i~|2xK&JPX0m;wR zwQB%B56E~P2T1xMfQtZMha>rZ3&?WvFd+5Y2*_}GZi)IG2S~oL3Wq`le-LmE-2X%2 zcNN|OSONDhD7;$XxquhL{WOKgD?~Q(o5Uq06zvIA7Da5rARNyF+zEIJ-~b?aC-eiJ z1lR|7B497zWWXLk6uAi-0g*Km)&rge*a~S3=mDmgqeWH0u}?J$(=9_@C3jJAeyoX69LggO(+CJlRBXQa1vl0@(WQK zSEewcFr;wMZU8XTX@HG=h-0VHy8;B!A?7doqCHBIE8UOtZv@rgd==|=3 zUv8KVq8;Qn7YRvv0TUkILu1uH5})68rSDdHsnYE{`*TX4sq|Kc2l;lM8i9V4zZRLz z@0&`u^VHc&?^ZewLW+KH=l63IO7V}v#*cF((p#YiKdzUMUVWy)YXL~_GHB=^rLWca z)1CAIrJtenZl#~E^lGK=roNP~^u-#!T?e{O{qI%!O-i@xK%GjTruw1mO8A8;{}Gix zP5uAeh7URX;_AO&>Ghiab{(Tp(|>uf;b*!qes&#Wz0$jsPP@IN+jWe8S9-6~f3I}A zPVq;jPt^Q5SMw*L4a-rQKLZ-S8l~4MeYVo~D*YIx+jXqH8o!N7=lhY=&#nU_Klf8t?K_1>ff$2{aM4`sQ#PP|A6ZEIi*LGem?U9^6fgz2O54%SJXJ&3VB&pcnQfIVY7687rks@iK-Bw9X(y)_D0-EeI^jg}c1t5-GB`drY~A(Vj8 zmfAHiY9?Hxn`z6XDUHLZxvzX=YgaB8J=+S9=mA}8TfS&)2lBVr{erS9Tb8d_W^xTq z8NJCP2F!wC7@JDD^4Cyo{^s%(%+{P7l8?D4Onsk)Ac+#)OgaaB(0vpeKv`w( zbjDPr`fo{IQ~Sl_iY3>11&1X%=wgaZiO*HULqf9@s1i4HF@L847|+&kP)lnV53ETj z;)-#j?0ELu%A*9SeLg;e#nSN^_XQM@EE>=1k(*Z$eLGm2+K3HTdwozI*fPuS)9`#{$W@t z-~QS^8^*YmALa39KNgi_iuy6_pK<)luUH4w)lddQ-ca!;@m7RTg8%Ky{u$R9`9U4| zS}}j~e;R$yXemH%)Gso@3nL(MU-r+snArGssyx1%Kza6q-plQ8LJH^F z*II-Z1zdkP-uZ)0j9)eW_|ZTAutgwt@TLKN+>iG;V!7;}?WUyI_O_iW5kCj)Pa6KB zHI;I|J(~1=r1LOWq4n!|NZ&^>0h%Wlr_Ds(5T(ocTVrqLe@-6myWo-zuB62N`!aDO zKw^ahajWBP4@k@sCz*)ih+|3;CvkZ^eXpc~p6kSEzyz*cKA^ETmP-=FK5wKXPZ&)x zSU)LG?UBnjYLCY|pA36Z6Jdf2mqc(J9#;!+0uM%B;^|*cwOL_oN5!|diwjejRGS$Y zs?7}qhBLj<2g&JJU8_pH8E)qih|ylnQT+^z=D;AX=ln&JDBS)%I16G9H;3DQY8`OW zv_Q^(BqO|3Wp8!* zY&IchPaR52j0JtL2YaV1_^^5Ow`pTZ680;{GTe+=fYrfaLorAog{OZUdx$UX4E)@G8KQ0Otc@d|osI5c{x2#{=RhP04U;QL5N`r8FqgnthK(*57mJq?JhmZD}r zhQs{~@*`}Xc`iB#5Z@%;YB&^IqY*&NZ6>hS18stT9~?vP34>t12#_5M_ruwno(k9x zh&}ZQeSqA@?gg9y*aL_?cG(A?2DlzL&I`ys_yvG#fupX;K6n}6a^M#N)&X)~yasS4 zU^O828f71RHeeZW)Ct)K$DWMrgBJrL4B79F03HT>B48M>5Rm)f1%TWiFGKwBZye)G z$o~ijK_~1}*sZWtVV%M9&3SlhXGvqWE@$M!Idkf2j0srC+W7ZTosO z^rQSTmCy1?|F(U9SpD~_{|yL(^ezbvXH%3OQTmY52bJEW^qA7;DZNbT#Y*3+@kd^X zeC8iN?&nay0i|DT^#kOWR(g}l-vxIi34Mu!vp)Ih_2Ba3$2#;z2k&+GZ$f(d{a@(t zw>bQlIQ$%A`Te&#_<9F_)WLb)!0-Pj4({$R{tRW)&(E{Metf&5?-(b%n;d$FTBtW&$20XZl>A9gDW`v6t*@swERaU{6p-+Z**biL6haLLEsmJE2vAuz{wmx+_N zALD6mAB6H8JQjJ3DOjkD}wWOFyHUedTUv#I6tuoTYo_+gWt43g@BNZ4OOoUj;N3Igd9}m-7%aRaY2v2Sr5dF6aN;{>hBe znKL8unf((STlpW|KjC?0e%$ZiXK@bO_^0I1{_dX~kA9UO<)OF{z*jT z*!>fpzob(W#=DqjWqteFKe6L-%$?-3=j^N?jlM+@U%oAeXDMrwtJkbpy|lKrvfLx$ zM;#-FuUq~Ph59far+%?Ryfh1l+}HkzP3XNUuMUZ?NgyuJd%2PXP&nsIO$ZP3FHBaz zfHY$Ks)^&HfBu1mXQVj~``BNu{gYVw_CW}WrM^sH7Cx=L3GxTl?_qyltRAG@XuE?O2jXrFx%ijebEYreC!w+LI8Bma+4ut*(7u6o`x7*t-bh<% zU+`>sA1;!yUqM4IF#q&c;)~1}Ec?S|MZmI^zW4!?lQ5bgw!pwWau=f^OVTjgG)N0H z8N&wUslnl(jh22etIhKs{FJbf$MU3(XY<_M?}0s<$0ahdnT5!#VyY}>WR@UWYQ)k; zWV=|TsY-pASb=ntNW3rMz$hB`J3*pQmIOVpeZuFTf{KG(PheYzFNYsC+l^sXFuG?xnviR6Guf$)U@-aU0+4Wdw-I)B}!QUQT zmu39qv-~;kuRaQft`E(+ur$B)kca3_W~jhi~dvbe+9()V$ru1 z?*cp=_-%k#e=PbEAl4&`>H(?uRKSw~ITpev_l@vd?i-jAMIJ)sql>#=JAPXufNoC&xbkn6Q|fLuSV0W1cr z2E@9sth3GlECUW*Wu5g@K=6d70picB7XxDGBAbI)SJJzfVP9zV${{seDmn0*;0=RSC zaD&pfDc#o7DN65Gy1VZ9Ta{m?^m&j;`AiRfyOqwd62Ch^)1U?amV@66S3iBJgEu+& zR~-C@4$gAvm$%Eo|LWj0UgYOL#=%)%{B-x8M3qCo+QDf@!tek4PWXp9^tX`Le*R@h zPe0B(_ZsvR+`jR+TDv2^dXO?X(op|+%Sy11JI&{*bj8KzI4k<;V!bI#4_ ze)i1V{O3%^N$>1sKa(gpi*6P19BjZD2My74ut9ka5=O2R%ucC>)#lbk*0Q4r^VTdR zivB~?KC&!7BE|g6kb#B2Tnlz4N1dhPfG__#jJq(DSy22RzV{JKG_#zROMOGht-hg+ zroM9ISj;vQUA9@VngJxTR*^~m-}T1Kf&Kq4)*DUTlB-<)wKj3iv`%?QUbV}jdlf7X z#V!i!%AH?}+$(n&la-uRGTki1$^RuYN{WkTOrL&EX(Vz^aS7a}7n1W(2PqvPT0)`J%T@c81sf^1{!#A&ise|g!|L6WGKaPj_#Z;cbWK7GUvG-BmG~<#>>~_MzC8TXQGig_ ziY5bMK2^lk$^yU-;0a}_=+}UxbKHLjAhVzJ4nQms7qtSC&T@^iS#&wzc)$uk@}CGu ze$0i1KLUs#;MKqhKsevB_2W*sbAB^O27GVhkG8J{;Kq-Dbo+6hOnSGv{U6{yva~;b z{04{aj?cM{;OC#^;L9DH@%8hY@#}*5i>h&}b&a`%<=t)L^)cVJN|4uwc|C#pTgO*OU^Z%+$Z9-+Q2qZC|AF;hZzyU zA3pXwwoHkG^WPvD@D*w+ZgG@lmS<^GN#Eao=f_wa;zxOGkN2R!e}fL$`$R2?<`t{2 zB@JI~ZLpuPa!_~VyI=KG)b>3Vh5ym_b$V5=LG{rOd8jU-?udyeetxWeYy&$be71kw zh{Y|+vme?3RuS*B{n*Zk*{|7fBH9Od@b_bkEC1Lia2<#3-N*d`{aEbQ*ET``Ui^?t zBnQN1jZ2gUwn6R#c~b-ai}v!w<8B6r=g!MhgRxt;(y#A^K&<1*B%XMDJ;^5%v&cjA ziklo=B|EsTf1JK!8&A*ZN3h|JN{Ek*Y_2RFY97Wzw(BcXv}s*cSn`fFke)owzR|(Q z?catPI4LjhC#*svj*B8N?qAgkEyC>)3ZqqO@6`nJ$nAHKqOtUib!tvM*2!fg`|ziY z9HhzOvS8@?HT=&Y`Sz$fJww0gSR|G{%sk5=`wjQhP#e7dX61GC8UBtQ z@K>d;Ex;biMj^&F@JTTVrR2%@yLeq@du(KTJUy>4R=PbFp0_ueoWi3_jFddd2h`;K zx8Xza&?v40a2Q{;W% zId|;BQ?YQy(`>!Ss@u)ae*Cs>b!b?~M|>-~X{|f9odMyELOe*wT&^6m8&NOD zFBW-Z>$;8R0h*E>c+vz9x4w#-ImrH0=UVVomA=*zhVAbj7^*kX8a`NZlx{H4-E+a? zXdG!%EVSm#3r;|(d*DF+o+9hq53u1|b7b4ziU&Xmtr_38_fz42#JfX#Vk6r+FB>t} zsp3z)f?%L)-zBLTgVgzw?d5|7@F3c?pcv6){_H`RbT_4mCh4pCFG-DkA>972jIVk9 zuX4;=@sX{354vj#XhMDw;&cL})`5_C&pR__#HSTR*z3Y@X;tCiN!{G-<{MfjwsKI^yl?3+ZxH zyz}aUWnIcOizeLRoW%PnW~;U;^%2>pDf>jSV_!2bKQ!xxfN(o^dW37}Ui>np3R)u; zLvu_1amHv!JwD zA1{4AeEXMKl%$!xhgG>U{GTXsc(v#UEaKs|dqBoJ2$yu0pDXRdld*Tv6m+nTUOW?`5eOyS*ruMNrPWQO<|7gb!VY)TkWuW2%OI@yb&96~3K|1?C{8g`RHzDr(y=G53H!tH$21da$;g^hoLJ%V{< z2`2p|72|Cep;F!^tkh9i#}4p~hthsj@P0lal& z$4RL1CF!wyW9d)}4vti<$IB=0F{@LL@wFdjc?}{a3BrbUHs!D*Xq&zF6XDyw%Vfxi z;Al&qd`;mkR{y{w-2P{u*D*4zNnC?YOxk)Y0*^(c#}CBP7 zO8dSs%ArK4XUxVi$;l!SZxHjXs;o$Jf>TlQ zIyCIPtaSG7@a-E-iuEJWch3nwFcwb)o7d>qZ|)m9DD}|0&$grc-4Tutr0@iCx?*GL z=0s6N$IHoy5>B!U2Y50%|JX>Qy7F2e8H-F7}w0YY&dw4wuT%&^r7bf?a*e!(9XR`@jPwzG-h*Z^U#u^D?-bb65?cw=PbXHCulX|@E)x9O}q<+)( z;@-rer|wNX-L`FS@`KdVrEet)M*2qjJNj@J8vx37J@^{(59*QFWP$x{uhB9fSUXNS?{XIJ$vcxr^Y*P_M}jK zm2!ub($RPGfpVoip1wN5vBw$u5X^BLK;#-92&0ZqFt+fXru6B*@9_U6Z}{hH_@}8n ziR%Le;74kjh^KEXu%nw7{MtM)6I^z<<5vv{tsyflAHK?ozV z#HpQgv6gvI^TI&;{8h--x4hUx44uLvV;;GZ+0v#*;VSy!$xKWb(U>CFqT4D^LAH-$ z1`ZtrFVZD!ulOAu)<5&qAVMt+B@TiMbB7~w(_gLv1F9*yYtyRYrhT;Y<}vnJEl%zN zf!#!Ybj6)x55^;BoeK{hi7(-+c>Negm#2%Plb=rYzq>P4@uMf+=e%>t7CasVGRCFO zx+-t;9}7u+vCi>h*fY+m>i-o&3pFnq;*7dvNA#U-V-hhG-`?_$cgt}+@7VIx+ovx= zdrVI=#=z;ss*SN($^P)1-;}-=?&K6{R@INfcixL1tTAKEvs2MiA4{GW{?Dr4#X4)o zMAugy7>YjeQM5BLc8ra6`T7@-L}Rv<&w}lN)XwmoS0j;zxKv7)1iIQqz0uOA6Pp4R z+m}`HemI(jm*FKlJEL%o_CAjPhp)`0mJ9V&QZL9yQPe96 z3P1$pf)C-uu?9|4JVJ<<<%^-NS6eZL!YiZ@f->1HLBHHfKA;U1S<`$Yn6oKxwi2j~C6b0aCRdZO%cl&BF)8I^!IQb$O#ZtV_gG&&8j58IRxnnObAMYAY(uM~eDb zM!?C?aQopB=Hk{%w~uAf@=~B=7teVf--Y+@{v@e!9vSfjo_&F<^rhyPu!gY~H2_J0 zF+5(lOnerS!!97ATx z9J_QhF&GS(m>-ZV#y|LG>gGS_j_w&vz=*CInPd8EeccUmfH59ASj#-{p}%vO4)|Yy%lzl~W9eJ!a&{IbV6+Bm z{>5(SEJ1ebH#9!?zUdyg^TU}^ET4`+Neq6pKgRC{{N=PSqV&7-(5vNeKq&MEDoCz< z+p@zb9cN;(=9!D$s{1S4N5q$<-@f*BW3M7*@iG4L*?rpTwu9~%*LmQbW50@$C}&~K zzV6=)Khr}#%kQ%jk^mv1d`uVlET8Y)qVIsPR{5Ad@;Q8Gz>zJ=9_3>?$!Ga;oa6o* z7O;m33vjejbLv`Wn{+!Mvb^X9KnzWa76G0LI7{g#DSoKp zuS>ffn)C!9`F^Q*nc^oa&i7tO=V5M!^BfAsali)v8J``1jL$=WjL&+&X`o*Scp~8O z3ZMU!IXAu$a0=Z20g&{#;zfWb10SpKWgG@4z7_Cjz)gS*e<>iMP&5ya=gveEhcn=|64i!=wZtw*HD%0#g45Kq8^_D z`t^YHzY37?tOg|ibcGWX4jpRjwA=;A{Okbay@1*3{wy{|nZN4+SsrEplK$s|jr)%Q z>F@J^%;$2zQvpu{WO&aP82BAP(iZ|Uo#v_gWI*b9|3P98rKlZ{^qT|`w?*@nBBL(SMfn)8o%EtUVy~o z$0-8&ixq!g@fyY7LfAZiWBa{Xpz|$(UZsN+IG+<%dXI+JqW*2adVr`?n#F zGVRv`#E+i`f*=3BL#OR1Km8Vme~v@{r9;2N#U1{u9QuGmpX<=M)Qf-K$BC66-|Fyx z(ZSzz@Q)mPql1??@?UW1D9eHH-TN459s~5t9eK|f9#M=Wc$ipGuvoy> zu}_{gqM)k4PwmRaC9oDhzq;bG%P+5#<6f&l<)Q z!coCep^!biEZh!bfR;-V87gbf#Mvo{FTBgar&?>J#dGj1(0DHXOtk4k9ek(LXn@7z zhe)fA=SHbnjv2v1^2??}NbO61ymQtw&MrMS!cWe<;cTC=E}iSVTN&EUPy~PY*nD!$ zA>Y@J!6v^t`oU*$cJus0w=CcOo_Cv}{FI00KQs-45*Z?7op+NGquf02#_H>#p)&p1 zh4Bu*Zk1O9d2EZ_Z(nv122{@7X51JmW&`H?H2R*)zRu4r*K~`hkA4i6F)j!dqNCU3 z4v5_6IdGL%rt)^HJVkjf4kah^Q8>HKi3sljz`eydPmc^^G^_E)ZEIw<=-?3tANXXD ze~*KgIe4{$*Ex8TgSR?(pMw`W`jk0%wS(6=c+dEt{(TNU;NXJ}-sQ;acJLkt?{n}0 z2Oo6sVkf>K2jAoJJNktV3C6F`!6Ob{?BHb%UhR~ZItMRy@Ipu5GKW5JXi&cIC!0dH#vB#gLgT2w}baMc&n4XT@K#u;MGq0)j4?CxM2LN9lXxLn;g8=!MmLF zYjVQta`;;vddTtL<M(!SYt<;1LHecJL-AyfTMg z?cfoo{?|G5CI@eIaVNYkhu-brJr3UG`0sP*-41=gp$|Iv9v64YSDAzNIP&`(e9*!7 zIC#jB*W|YMPJZ_}_<)1AI{pWp{Hb=rt8?%!hrh|8_c-)!2e-ovg)QbPf#;fV@Gb{m z>fm2<@T7y^>EPEp_!Q)jZ*uT;4*q2aU+>^IJ9wjmcQ|<3!EbkPtP=(F`+|dC=ink|zvLC&SqS43d<=(?tQ z-giwjG`B>S)vs8YY;Fh{JA)eV(iJUBU^W3FRwp7WS|VR+Xl@KOEQ!cX=m?fiBG=py zSq%}MchOE%SXti;ovvLreN|+2V}EV$IKT(LBQppvT^Rwq0M@-{cLv@|S@$W{9+!ivV#5iGxC+>_0C zz0%5Cy5ib~mP90RLsQ00tTXc3mt`^;;bD!oAZq-;xS)_RXylHu_|UQv*fNL>C08$P04s7dv!0l7Gihz>h=c_nrp8!WCgLXR z)-*RF5ha|A(k&t5Y&>C^Y~lRciz_NCszP(;S5+@sSW){~t~{XzVPUP>t3TG^(rhP_ zBbOp`%ja`3?$V0S)mATvU$!t*F;{*^7euS3FZ^6}h2NpJykhSBa?fc&{E8ed6_@#W z7R_;3;1J+o7}Kj6974({O4BH)JK0XP%bMuwi&KU*%TbwYS>9k*x?C)rz<0)h7EXc= zuy7J^pg|L)Q1tT4O3XUu^tp=`T){-}yImZws4S0{JFXJ1iiH&mE_Vr+<{)L9rptn< z=LfN60*Rmu$u7cr3#ia&-o?|a#DMm^`BfDQkf*XPUbU!lVZ6HXb7&^X;oZ-bB3YaL z-ePV(hGQy#Bc^dlV!CP39D+Db2iX-U1X*p*ezPz)F9Y8Mpe!K4 z$O`D9peR9%fQSMr20$^RfU;sf20Z4B88c$Sj2`1LVa@_#j;ILtt(l%-6XN%O|Gl># z*mtU{x;poC_smo)`|?FzRFqtudGa>T`CW1^S6Dx%7KW?esS>#tUrkdJ?ppe5WkpsMAjd~;csX(a}_*Tl@OCj2m34WStf}sOglJ59Kp{a zIGSP`6*XvhXb^=irqyztK(#|58GP5EC$=IHG=j?@&k15l2trrcE9-jU#KAv3h2sC;V4fxzM zZFb+%_Iz7{wW;cipLr-vgaw(R8GoqtND9QYV_E^wI#vbl2w5Y&>LR=ttQs;u7vv)6di8A5u<=sp4aB)QtSCK>*+yF(An*=L+c)4}y zuChhJo*!#GvBtZHoGZ>gvEMWPJyGHLv-*3YRtS9*?_pU0q1?1Sqw%gHIa7M=4$nwM z`?t|}keZ5DowpHpwZOcx zcxDdF2CfEX0#^YufGdHiz!kt`Al{`iOalH5OaLweMgx<8A;6_TKj0Fe9Jm~R`q0PbO2({&d>sgy+uP4Aoj!z4S?ADGNg05rUA2oF~Ce9_UsHZ zfY=K(Oa)>O(U8tF!``A{5)gZmh6zCIT^dFMvBzo{0>s{{p&t-?wuW*b_Hqp!fY|dj zv;al|O@P=_HZ%ZYug);9j6{MxKErI_C}1WKdya+~K2FiiHKnI`?&;sZUGy!@64S>CXd3q8_PaxSJ z_5@}EdjKffr>;_B#b_GTQ-GCuLInWQ-1tXb; z3Jd{S0R4bXfO24CpaZZG&;r;HXaY0`8UPyr^K`iPRSmO&W}xZapL)OyU|nD;&=i;q ztOHB})&?d3YXPHyHGv^O6QCck22c*H4s-xk16ly90!@HbfCj+Iz&r_m&S5st7<4Ak z2$%sh#9u0~A}|?P0hk0V4@>}-14aYO0z-fXKtCY57H9t(O`Nm)ji$!g`$m;>cD_;c zoPBQ;0ixi>_cCa+-21XlhjHY*YiH>75)hp498C{>zn;6}U(FYlA!{`h~w`25u zM!PclBcsWJ3F$9i2?>Mi&FIFA4q$XgMu#%GFQYj-`v@P-Xfk|6`sOn_j?t-%p2O(d zjHa_JNd7&eS2MaS8Zo(KMz?14Zbk<(nruK&_(VpNWgnt9F!~~+k23luqpvgiA*0_j zI*ZX|(3!}+XLJKbe`jlPiAy)Mz3IWAfpd4dKjb6GCGRUPZ&Lw(RqwkFuIZnpWeS1-IUQQ8STXA&5ZVA z^lnCvWHf#EOXU&6XtF0y^lV07Ve}eC-(mDNMn7Y8Dx=>pI)l;Q82y3KI&|}ZpFVDO zdkKN%gs=+bnPhyKxwrn54Lj$<@^H$?Pe zMw>HwBcm-DeVEbqjK0Qb8Kbip-Hp-T812L8a+oBM^JjDoMu#%mg3%F-wrBKYMt5d3 zeGf(H?ak-~j27NYPGa;uOoqsjaWb_P1KW6k2M&~ek3!^_Wn!alz_mk0&7_CQ>HRSg*qboAHG$w!Ksx!JSqw6u+ zj?uKfq3|w@mNMFp(cHP#;D<8WneoRl+MUsHjP_x45~Bw)dJm(AGMatoCmF@)hm1d- z(YcJC&gcS0Co;M+Hv`4mn9=5pUdiYVjNZiP?u_2W=z)w*W%MvcpJ4Q4Mqgm`UyQ!a zX!_of+2rnnwxZ^eD&D;vn)-*L04vUWk#DZx;CS&8QqZ4 zZj7dl6*?~`fwg~3XH>oi!x~LOeS8h$(`}Jt1ZRm0Wf~u#z|isVk%6>*hHqBLbZ!Li zIV37Ph_{B!{FP)?1l2-wA8YW+{7DDi1Yx@U#{>sPj0}%pUz*t33l|Q;g(JIYZ6#bt zg$rxp!bZ5T6)su}7k0vhpt-f6xwW9#PS9*8XtonH+XIP83-|sjGnjHkq z4uWO}L9>IP*-_B!C}_qBEW92^L9?Tv*-_B!C}?&RG&>5K9R87hLn_80 z72~iL5tkhPF!&Zz#?6%U@VjQi- zI9iKwv=-xNEyjVjO<4K07V{x?U#ZxCrD6w`ial5=c44X5hoxdCmWsVtDt2S3*pH=R zN0y2`St@pAso0mLVrQ0$y;&-DXQ|kqrDBJcialB?c4?{Dr=?=2mWsVvDt2q3C>RPw zC={Sjd_v&~MJE)TP&H!3h;=Vki=eWolL$(Sx`?2*sDlWK#qJ^Y4zY8HeM9UTV$ZM^ z(ku20v0I3}LhKY`pAfr**dxRaA@&EcJBYnO>Gj||4Kv*`3sJ|?+cHJ6iAKl4+T8|Y`>5;BS~KdHm7HZ zp^7d_`uRfaYRR~N2I}@3NNIE zPB)TEG|8qIVTBAPpN!(J;~FOAl3fxb4BUf)^t#TOWNr+_(tlkPUpYy#N5)xZ`$EBj z3gmN~jp3K%u9F4Z@2a9?Anh{5U^x#aQ(dn*&(X7!2j!7yBCP!DoKsRuva3io(PREJ zN7~mkivP~hFu)Dd*JLl249+Kd@J9HV%{^X5*~--}1WKc3DN7}*A31@ja1}FHoPdlI zSP20xS4wucQn_p1oEK~k!l?e3m90>+uS#S(8cn^T4b1!CK#q6{`GM=+yW zTzIGw^}yy-GVExDj2dWG>Rvq!8yF;;NNCEj%;HJ3b+d4tvtG>qm;)A zr91$o{79*kVG5Izy?_*VnxnTL0CRs_ji|^`ZEOM$5uotXxr4A3Cr|+?uvy1f0Ey6c zJ5EoSqj!KQ(Vd(m{g<^9-U4A&h@iITCypY^xfvXfg61n}SKLLl7P0g>txxGh2+9+m zh9q7q+4_rGV-$Cq7%0Y^Q!vw2T#ejRsgabNX_Q-y+T+{GWffVm`uRG`>8dprKIB;; zWKPB3NZl2rV1hay)}S=g!MCEvf?Uomtx|lPFGQ&nND1wU8WC4aD(2hBjG95Q_R+|W zK8jSdtgmc%Up-_>ku5bc0ap<<bkFm404rx9mgPR*!QKxILVQ@wmALd+bwx)!4dhn^doqI0@l>e%D-Kea~3GM z&YDWoAVIF+t)SAdtAqkZ<@xsxUEPnEzwT>}41 z3H-Aq@W}+`?_5R+{PQL7$oWeNOMCGhFF z-0$3_67qk!1pbv0_*YBd)6p}(bN`mWzg`0WMhSd+PW3x?s|5b-68M=V@b8qsr*njV z=kArjzh46XK?(eaCGg1(*6$oWNBo`JSpt7o34CGQQ(PRoO9;QG1pfXK_+D4AC>iq**ExC8p60@jMOH!?Ev;@%9E7X%p zNr`$@lWOgtMP)IvwpM)o|B2q#_F8I7OPj*(yk-l~CTGvLCzZIh$vOU6yw+Cya8!~$ zt!1etUTb^4rlWHZd@a?XO-yrK(ITZ~gchY> z;DEo$Xd6(=m38y<3Jz-J*3Gq5kHBHWgU7R0Yi=V1leTWHk@1%0%67-s=Mhn%k%44& zV93ZZX0FaIUNSIxM!`S;j0kXy;ONNU@CY&~ztm-40Ndf;JuNK|0YsHS>jqC4)sH>uh2LC*#bi5YurhgqTul@PotFHO&}`rC(! zN~4-LC@UZ1xUBEMtYJRiPrgq|Uh!hr%!cXfIv5&#i;}Q#V=W$S4-Pz|953y=OPcgv zTS<)9t9tst@;6jsN(^jr(!KPjS>?8V?Qi(LMbC#HrVZHtCNlq&d;IOP-PV`epS^J3 zlff&mE}Y@K<5K4@2`%lrJp2^CIDDzyqjI}4Q*ZZ~w6?U_)owz(v|GgG*RY}(YlZYS zE)iGl=&*8Tm7M?PM2*hRjv9Z$c>L$~nGKhpA_3HJ$^-5GMx2#|hFll3pelxE0 z&2a3uE4NCz<+_Cr-b{!^_yWpe)cT6G=R2&erkn;Y?_vrnXTG{(5z2^O7oqeW9c|lX+0AqL_g(j|UVmuYys$-yXOzNnmrCi>QR5*m zqAS=}x?Fq(y}jGM$gF)mT~ZF-KAxG@q`afExliG~gN7B34%>Hps&$q5hq~&XxbAzh zQUhD-m|Kgyh-zVA@w zK~vZM{hPHH%G!+OMO9XXLOSzXDdppTa;ZQ5*pMmT?;qaovu4oZ%QMUCms*~G&+@Xx zojxC@^{bv&BT3%o?zqP5PX`a!@H5}Al0ovX8vEp%;=OCG=yG-5PvaY@Dk(zSP1||@ zl(>0$QlD?K$J4!=IrxdLu3_j^h3QYYq95o{Kvi3Y=T#?|KXWuD|9$ywlrtcgOTwwzt}+)P0Ht zb3c@Q;#E*LpXGdE&jVv+;Aw9MsdxxwNXo zKSRtH@9VT;@HEHL9rxGIv)C0d%%gqU+HM2Kz02xjQDAza$-2Vihc@!PC*s38E&o1c ziuB}*qeFB|9Giwk|J^oSum3FneJv)}zLWID#jW>pmyjB}j@D?>VMvRmZ^tYf__?vu z8P7vH9e3ylwr)3S#=0>lof3{M8oT=15YH0J;YZIIGh>gpS~6_vMIHIKvKz0q-G4q+ zv7*b)!y^yYUEnadtWaOVcxmOjb7V%RR)gR4UTkrFn%S!-^_SdKs|V#VN0}w~=MS!5 zy5@@&F1M?Dack?2mse6&zU*P1UDaXdcklbxLaLr->6VsHORc_EaenPe z9hT`EzyG(^*#pX9aV?}x&0F-(zu4f`qeK0NHG00HV$k3XFOn)awpmv_ud^j%jO3ryj`j{P|BjvhXgCnn*h8}o5VQBNzW(Ms)eoTp*oHJ_A!)i(q6!`Dn z-0*&kY=%7Zfkv87hlaScez-UK^nw0c`qXXKJE-*EEtSI3Wr=BSP`Uj{$G)X6Z0^*4 z=f(3~0yf_m)M(hv(CU+$j+-Vq+t+k$w0(8IIhUI!c6~dy!90^C4qJ>G1Vz}}baT6Z zAZ$d&_ocHgjFoS3PEn3`!l0|tjE@IJLddU{IK__>Q> z0`jbDPoAn2n7@wUhClxLx7_?;I>X!E|Dcdvz2&{IYSe|%Tkf^mGuhOBd|>>^MJ>u1 z{aDiOe)6>87j04pH-GcJ^r`E9z1w$e^7Clhc89j^nw*>cJg3}%o#9U27re@^>Fm8X z#N={=VUGF#Of2At*XHUp>pB>w(g~P70cV;#j z)zj>J{lf!SHEtT#?*7M5y?d{D^=oFTRaQTpM$hlPGCXHCVokozos?v->!YyHPdWq5cs+vmo_+O^%4HKCi%b^nr5mV`r>g6m|XhI&Q9n z%y4ch_xtDhYSg>*k7iawymx>8NB7od&-E1=>6E&WG_%H?v})T%bQl`4bFRtZg;%af z`Y-x>-Pt>Gud6Qu4(ECAKJV$D)3>_*OT|3L3T2L%`ZV9sU}W2oSDq(^Pm5c&%jDUc z;h*@FaLJ(*E*+37+qjo7v%9DI31la)@ku=rbN{G(DY-g&s7%(ZK!#2*q3tdE5qOI2yCo#&ujAQ?3xF^ z8Ts@bdb&ySrR5)H0fw`(vdBdLLSPFTbZ#$Jk1d z)!KObo~V3jvjJxh27A4~V5S;D-|+=!CmqPCSI0D2@;rK@kcWnlqVmQw`VyS++7bl* zl&w=*w|>Xy3oZ#AYqgy==tIH_uS<>n%}@AFs6I2aO3KOY4gK6K>~t>Pbug;4N;+r$ z_W}AZI*rVp;+mdq(mCmQpFwurZ7T(id(fbd=4>ZtXUnTm;~EbroVv)hZkf8(+XV`3 zkn%}waNN_Bh*7ylvCT%@JYbohaH-7UIPO&4-zWZ$@~%^AVo14+)IK9NZrC-e<{GPx z7nc4S>uR-n-NtG1zF!-6khUGa?n~+Kj*aFVd@%pXUp;1zN_q6U<(o#SK2x@@h5(SHhhpWedzd%D(@e;9-CJAvu@Ea z#;)GYcU%&X|JSVf)%)o+oAhqSUVWjCZIL;uV{K!I)_li^zW+_@6_xzKg^ncPy?^jL zw-Y{b|!j;n9@tL)5Y`Wfy`wqHs8{&mvH(*Y){_HW%f=xu|RyZ8DyUCAkB-&yBb zXzB8kx_8>1X1e{jUegt}0nx1%%-zuBrFGBXoL9!r?)ne!lyjz6wXG}GP4EkPEzf*x zF-$U5qu`iFfq(3t8?Vfq3{U$^9(es()`foE`p2d|uIqnAXhT$vREAE=_HXF@{nqO7 z_1l+q?{>+f)1dnF+3KIU7*XthQnosh`WsJXyj`8!zuVtYZ6|gaHuYAgmLEPn7}_Q9 z$Ff`7n`CTRyL8W(>8*y}oZz#yhv!b|#46tYIs@bZR}&uWbsJV8U~tr+0GB!syM7pF z>XA~fpr7rFrMmYU^_?-RQcO=@-JRP4#&`EVJbuY$N#O1)+lIaP)cpA7*oJS6!^YYj zI)PLIHaPu7(%a6F^vCT-a4hi4<`3n*zw48lO@tT zmtF2!dF;EKGW+ngG)K2CV}B+kcB$cU zA>rK9MZIFz)KQGlb-N!kwa0P$9$jBOY22co&|nn=ctLtHnyU@#))L zc5d!*?C_y)V|Ly@V3tyA;^tkot@W%j`qYg3s&mP`YKIT!=riLIT@@40Cm;R}dcJo- z^1TI9Wex|dGP}LF<>*j%!NYz13&zb0nq;ga^bM*%(%Ec{-?uh~HrwRGi~{wH&$O9Z z#oV~$drOH)fx!P-o$8eOY&fMs{f~G105 zH!8Nf9aZkHYyU3xPcFCdvr)#qiOr54ec|Z&IsM-S}N-f8kAYwU`-uPtlpPW%|r>2A>S5f=*!4z>@yJ$rbQO_CLdFVu|5^Kz`8y(z9! z2j{euS-l4>*fpaReRQnewz0L&9Uxf;AN9S zpQH$b(#uUk%;W2xd$3|{b<>>oJtJ?0$4<{V+$y_!7okpR4}j{ldzA~`OXlP5JK@-QK%->#WOsKmBpp?LDY&=<`2#I>+m6NK0|X&N;5Z(jDFYZT|*(we#ai) z>0d2IDQwYYDIF(ci*X*~#+^GjWJHxAubjc0m0}WR!Gig3) z_O+#wQ-e;2={S_#bMRtqi;I0{E)3fd`^zGF)wHMQpB*=@;p{wP(1@y^?!B)OaHoEo z4s||Fc$RwVgvr|_GTQqz;Y#KNA32CP910H+zv^*Opq}g-m&gc>KVwA!b zU6#@ruA|?@x9oxj4UByk)ERes%DBzrva+(K{xiCu*7wF&;>Ii9y_>VI&)1+ucZ{re zbgY(bKfwKIkB81Kiia~hXVsXY<5~7)xWksl54`(2)(BkEdq7g3Wp?3V*WDj)o^-qN z#4^XK`4qXp3gv5tR6c&dVpfOsLfa75CD*(CE$-@H7=6g>_`8$=+S82Ga}Oh|bqspz zPx6*lZqqr{VE$0wFV3Ah%xN++D!Ov-=lu7}d-v1Al*(`3?R9Kr_1St-h4r86 zor*o(VC(Gay%&y3`teuGN#&MY|J83)__r5dPWV0 z-)M#OS^lGHog4PDRIV@BrID=CA1T(?le()PjQegTi_w}XcyjsDF`pSZBy8x|5ktm) zi+(xwKLx#MZIb_7lA!ox@hb^i(E^T#~bI)bl^Lv(=a&zXFnrB|`m!&?JReEUZ zH0o>4RS%05-4zSkJ@YF6D@S+fPAfmSM zgk^&q>g~_eKi=4+vQhegc0;$Ud=mKY=dz6(6kHfp`}r56E`FoC&zgDo<0ij%v+HM_ zd6yGxS8sUJW$7ooq};n*;pIWItGg7sTSm_DUw6_cazH!R+Ey+8>U`(m^Z2YI&+85A zQ?J9kum}I79C2^8Xu{+t$;$@~2wB|^P|3-e>N6@a!#_>$J(Xw6%xB43?L=Vv{B`mlG` z<2L*=dD38ne~t9~%F_PRc6zYcJqIyxO8$n!9sHROv zXUO>R8_I83`r_uvQPE{;NIrM#`r-A-AVY)b{<#;c3B~>E_<~&{UPTne)e8DXVHZ+O zoe+x(nu(OYDdp)xmy!_nQ^=yVZDdvXW)owZWfV z^1gMMp%*4Gj(-~EHSPYzXD56n{4hTGKKW?h- zsPwC~odN0k7nBJmK=@o<8xE4A%U(U{(bS=K`-Q>E>^gUCJ z?waFe=S!H6(YbLa7H20ImAkEWijkRt&cN~tW~}^|8w53_%ptW7G|4sm-NUQy(;qa z{HQr?i`o}%dyXOJ47BSIw zeRY>)yqqREdT;3qpN-|_&vj0zGk)&IyPKlt)m=Bfd;XWvLsCyTIR@1AnI7SEOj2{A ze%!$2Pw#}?GxBdYwMF642^~@o6rAcm_14tJ558LT9o!?bT;r;eC##Pg46nF$bk8YQ zoN9YoEPr3s*gB!tgypg@vE_`F-DF-LAZ3!I}l{+xn+<-E;BtitY~@7^PT@w(N8)s(A~i zvL0!d_RsifCK)~S-TCHwo?V_aYiptHlV&S?M(N%@*Jk7{NylYhFUC!O;q*-sXpnZe z#oHs_W|p2+dib#l1%oWdnXgkko~6ID%Dalj*G4~>BQZV~+Pivu-FL$_f1TMfu+z_f zWvNz$1M|1PzK}Aolw`oel}NRYoVtuk42|2{QK*Z+%IW=f4|$98WzY!Ep4 z8P!qR_x?-G&rBR%|8C1d%Yio&j@}$SrGBfGMQJ9pTH)I2g-f))s*PY5S{B4%}z=Y!`Y(EPcJpYiD0>N7=Y z{Por2Nwr${4$d>)teM7t(|=YQYY_18!`sh7LcO)7QNK~={m#8?H#B%0y(H?hb;hFB z4|{czobNfg%*}=s+Z8&T>t=S~lE=uEH}2@~3Qbzv*|`09>(v+AMe~3=J|S&A?K9Sn zyn44mC6#+WQv$%q6ZENXPy3UXJ8XJ0V`$CtI_2x~XUDaytX3%+tBN$i`Ryl-~BH zSr32SxuEl9$@eA=+#g;U&PF9JTAjYzd}~X*t6aSCcG*oWY45o6oY+doO+B-F!8@yB z(=MqIKQDJe($b!xPey;6=rr?T*;yG|Dm{Wd$zMO+j=wyWyn6eNtrP0@J2L6S$rqW@ zE(uk2K2JO1ZwvTBOiV~9yorG*O<)oGfyOqo-O-0-@fw2Pp?+Bsda5?%3ibD zVc#y-F0Gt)$+=Hm$IWwTb8(?z8f*y&UpmVRj1_| z_iPm%+10xAFWvXKYX{9(cXP^`WtBp1EbDBaZQH?4aCr!s&|>Sm59LzgaDy3JWJPT@OL;X5^YLiE^8-V*15_d31XwI^w1&w~7C z8D$eb*UO77>N|z6?6u=|LC z{TIE>E~U^nN*Ul#=x1H8WlU+in+_N6Vx204k(AOgSoip1#btRL-xakrG8;;5DyiS~ z9ced&uF|*uzBWsrsnwxQMco(4iki1Cz}L<9I;0)wQ*SIGrqmIN4P(mr!%kq zLS5hcnIFG`TG$w#yf4a8?mbKfSlZhMnZaYLcQ17=q=wePctoI zo97aBm(uc7BQ5%CYnRCX05oyNfzg9dA+>p#2d%$9``Znp|f#9*u=&c27YOEDYbf+ zrINin&Ue37Fx0)w%f)GFrmS{#45F7eT(avgE%9fWZ>uU)i*Ld4dH=X=QIFp$p;3iR zS?3A{ugLZ@`zFag_Wb(O#`-QMiH~#6nM+ni1deR|d0SQe+pPzkFp_Mvuxc{i?`_;Q z>A>qIGlbT4=i=*GjxRf;emr2`b(x5tbQ{!&9>9@3qNmtdsg#Xddks0PcL-4=QAR3qmW`g zN}c=J|Go~4yYPO?=&`GJe=B;=TUg^BTD~l0*(v*5VKGe4QR&%A)Cnq(dL;i zsk8K0zW31yiNV|RR!_TeW5=1`AFh(FOZJD%{Ssl(d2pyA!zqgjoyZ>g`$>}q^YS^55->%17rSzo!sQzf%-xsPM*jp6O zC-m8CeyVpOj$4|S@#LXM3kynfD{|`RE@0Nk?RTZ5@vVXMb53SxJfoCz#WEhT`m@W- zDLq$j9=GMt5KLO9#vJG6S$wc_z~uSRk`{b=OkYCZBrI<)0+A@w6h<#$G}$*D3;tx_ zXdu}~B^<=ihoLjW)(pvRJZ#5U)&`CTmIhKhxkx3&^9V>Z*`Fo)Afw5iEzt`YJ&w_2 zSC{15GrBpW$-Xbif5xB_4L*IRJr0-#90Obh90i;ToCxg4Xd8y~V0;4nzd=bP@B$E9 zB$o6&KgBl{h(A+zMpJtvx)MVyf9RY7%S%9tXDvgN8AnrHVA!%W2f~^9;YJaH&phNn zY%g%U1Z6Mi^ zuLVp3Vr|8pvw#g~?wo}hz!3OX2l@f40p&o9x!gGmRe%1b)SogyQ-4YY;<*)f&O&)$5~CA8NV*$SD*UUe>vlOGrk$)hcW&|#*bk9`508m zB{2Rc#$UkrH`??3&5U0UothlYZzz2xjDMEVkL&aNdrZDFlYh?m8yfKZ?~I;g&eMXu z^l?m{?jKzK8}fX?KKd%gw_|(@436YDd+5;F5Q8YW0OF%OE--n{{yF%=F}RYO!op`@ z@Fn*blmE)(S1^7825WM=86An63%Lv?-vEOhxoeDn6*nPr*^F+%=t4%%$IXbGU{Aa& z3(wgTNBa8XWBsnV(o1^ zjDLsmH!?o#k#cS~;}GB}_z_!hrnpe1G51iR%YmuP zKcL3%r$&dV(Nt{8;j5_WJEg|Ir$)b3qhr&E^~V9`&fb3h zbPOb2LE&maII}G{l5rGoetlF_ByW^mNo)w6drCIeiy{(2S&!ft{0Wm>JP_k4 zI)+i}Ns@>Oi6QnloS&+sn7oS47%hsB{3C*K4n2AC%K0R*{E38GLMa@dQ0@p-3QZ?- z4vGpL9vRAx)8viE7iCQ4)K$UMyk;nl!|NW76Qh|OWteY89Ard;j%4(3^@q`$UZP24 ztz5xQvb84H+CdC!qm`>AjGa|CAwFBpFm_hZsF6na3aMzV$#t|AHQH%#VQ)d?+Vfnp z_rY=xE-M%Z&5*6_#E^~}Az{ZxFi~x#!Gz@+fyr{C6eq0I2uxNyevbZj)ph7h%M%uRR&jRjBRJrO(->18Onj}iV_5S++2cG19xJ9Q860HbyNzhCEZ{% zUnP~WO(UcSR=(9E1h2j;pvq;5Q1XPK z8Zn4+ci>AITo#0HJ7U?3tpQfbxrD3pRoYfjFqO8&yzPtH7EGOMYIBr|vDvV?REZ6I zZLz^yOKdQF(_82lFr%&!n{vN_b#<-$V!XA*W^Y{-n-)II;S}*zdMRHvHm!?#F$}tE zq{hZhDL1UfmCFWZZ^S+Z^Y2`EGC|`n76Ge1&QmaD53}$^l7hi}n20a(6i<|Zy?D+S z_G)k&fl(TNHy6<)KPxB3b0D5DM#8GRlIeI!IXH7^D{Cvx9z6dewZ(xMw$|2m@N8`* zg(uI3ubr)}nVHnlmWci5dRkXt_&!3B|c2taHg3GZbh{2RZxk zm?CoSPwmIoRnkXclkvlCDQMb{=g*Q6^{d)v7xZB7g>x;1gfN;#!zk>Da%WoOFnRx| z@NuExgZ=&8T|_1>ga_DW%+m?_Fx{8Xz9B0f6_q8~XZK{%a;7hU>0@NE_StD2NJ~08 zAITUIQ~o?zAW|v(Q+C<(=Y#BrJE!6-C0dc96wRF+fyLApl|Nc~@yVC-~A`@zG6jM^sFe#WR=}Z4@Hl zIsD2L=W-qcRZKf?g-6<0;->b*FBi&H`rK8Km2*g|tc;WGQY2fLvsbI&Xim@%zqxfZ zqa4O@2jG`Q2{ZZ6b6x1Cqo#BWCp`qe+H_6exFhh(=|W{j8i-YvIQgowb?oP4ayyHY zb5Z2M=(T~8(Q9!834$&aNBvFP^DVXPu~35@Q~(1ZEYd8s5{pV4Hxo#;yztw4`ki17HIn#y)Nr11ihVx|Q~2h5YHklh(~b|EFlV zbuWD1|bMT?j-*Cq;aI=vKrl7ji#|dSzdjeOxqdC{Ae{=eI5I^8sA%uo~=f! zucN8yE61m_D&+1(+>%jwElbxCk%40(MGh8e>Y@AxheiaA2^|58kl{R&UpW}k zKczLLuzckggS6(u@-%pilEjFp;Yt*=1V;LYh7So14~-lT22MItT0XPIX>d5!tttyu zwM8sQK1Tkg8yvzW(<=A$|MY%tZAW){a@_rV6wY0X{NKEv({m|u!u?#J|EKr!U#uOI zK2lB3|F|vi|L}e;=waLEl8P7vlpTvk^eX9oZbmn6xESsi_jl+cFM1xziaL=(BfBSWUR;imZFrYPWUmu`v^*`%Gnw?__?&*8Qn=_NS{yS=+9&UxVM0%x4b z;I4SbO1yc^dJYEC(_&#=X~HMh=Mugp~#9d7GhyVVeJ-l8D5ybxGP@a z7!l#Xk4WU^9j7C=raX4?RSD)ZtfT~n^qyRisg_fX^B`osWxg^WnYS0!k6eN5x?WZI zTy#@>#^ej9uh3*hs2#ovjND7+ z)OpUNj->=0t02v4iKcdu-B3Yu+QU;q$sN+ts9qcq5}DC~s%7MgTk;cc^=4J*kWj%{ z9{bd2R)sbR?#?>$!gM#sb5Zv?oz6rqV+rSf$5S9K-LkDPFT2suh0 z=Y;ol)ZXuD0j4|t)0sS_mvg_7p9FyzHvbZD(!Y_XxsWIOVvh2|IYGW#Y?;~O+eUaE zjC|8P=>ZU9m?fP9Li4EvAkEjNFzf(Cp_p0%F?X>v2f~?F237<88cgzk#Fw1uMIiap zdGn+v0*FU8mh`-UXkQ@8)Y1`H1y~nY0azADdh$8-64UEIn$Il)Qn;B6sZ21=T808C z9vb~99M=_)u9nO{00@<3oEVxh1aST|&!l;uaNqJ~G`&ATj^?8@4;1bjJ>W<4z!Z*) zxh1Y?9+=JK&oI8wp6nQ34jFPFRpybOhz2i}h2PEiYe*2T9t%(Jm5@`P7mkD<6Xp2N z)#y8F^dL35lNxQIMz2t#X^Em7UxFG<{Y06sG+i4t5_2Ho`3FA_}h?Auy(tMA7pcT>eJGpm5={s4HaK;r&F4|393c3VM84+SfGZ^$Nc%xdO@UH~sGX!!?a~QF`Bw zbLc>nK6<~!lX)paN%P%gxrXTDoQ_f zE6ChZ+(gx&-+)s%k`VI3e8tPtjW(fv@_S>E-onIBh_O8vS)JI!F_ezTDv7aiKulrE z#vV@KyjrR3;+%wES||L-QUmbIrCQv7;U+V(b|Kvq_1L-u zvbil(8s7pGU0M`=WT`fKtno2nES30}a;-Ik(8irCwT)U3AuYnv1e={)XA{pK75aP8 z`V41X#@V7PChB9^nODjvj$U<)&C@Z8?}!Wc#Hj{uiCwU%HaVF*XKfq+yWB4Wo==k93WuN4 z%bSSQSf1!)KpK<;Xdm7vZWk{ArUTboIg{r`@w92mC02-)-qMt^<5DRDjX}po8{5W{RG$zSX^N=b|N^QHG zivY;p=z1i0YFTnsdI<^+Vsqr9D=8E70As3OIAUWLmgn(m#lRDB`N z+*!qmR1`#TDkUB9dN1cT%7nk&IPjI}hkDkPw_n253zeFtF1}tGKv#|e!8HYja_Lz} z0<Re;7IS?VMbXiNgM>7-Ftd^FQZr~^s{LTuZJTHkd_It5Fd$Tx`g z^p-B)``XjZ+9<&GDO=F-c!)Y0Zv;24vyD$a5hiy|hSrO>LeLzJF~Uv(aRC&Tfm=czN#i%fJ) zV&;6%S{pL1sOVLD)}9b?@h73ujTO&m_?;*0)fmO~#Uft%HRn0j{_-R$L+N>n&s{-J zzc`gSySRweyXO=x;vhtvGaTjFo~ArT@lEi{6)I)kfe5iDo}jXI#17RzMsw*A21P%& z3n#Ch`HMnX@=yI(Sss8dE~Q^7fn3rk5?Tdoq*>_qWuTsoZWuJvBg5p0-8@lUk*M`6 zoC<-93gTN>+FB^2G3qkMM<}_%+0!U43(bWad#Pz8_B41Y zQb3{}VHXl{%h}#5>0iu8W`=~J0{K+2L$2vCP+9DxhBP1_X4f<%)9@}lw4(!w3r|q9 zPlK=Kh|E6=yoB<}sYUgsF=X={+YE(7I z%XCmR9U^@-XRFrqD!2&g^Db@r_>nkCNguT3^wg?J#%bD6j3z#1JJmE5A`EH#rZum8 z>_-qL=dxA-ehj2{>4og#`EAZtt+IT@WRS9H5I{?@pw`}wYX|&2nSZPvWvf}Pd_)ga zBKn%^B1~^^qu|?`JMG!?8>hI{w$xO_XX%-eBB6ofE{9s;CMN+u3;BswjxVlM_J@V} z63zd<(fvs{e4X1>ZZ4n0O?|n<@aHef6lYyAD@2~SNx2YPuCL0?;y6kqEgCvB#&aU{u>jxkRh1$=E{ga3Gi`pFH(yAvFu(KTpEJ;$w4N+cAM?7Xo^F_s z(B!l)OCuku@xvpXXDa=dy`O=7eBl|4Q5@|UOTQM~*PyMlfl=IhcnhBHiNlOB$ewk*jX}?< zEK(Xf8L`AQ;xB0^tc6P!AwTuqf~L$DoG?XL3Ll}2g?vcAaxaV^K_A)Ncm;I<%p$n3 z7?ZNksYJySfmj)PK@Gddq;MRrV_$) zH?GaPA}Sh~Wz!1yxm%cWyeuYu9_xlU8pc44B(j5R;=YD-)8Uqmvc$NC2_V>XFVc)W zXtRQ=7IYpX3OOGhXbM}Y29;-=C*ZBVZ;|7sUPoN{@fA86DddVP$6TwF3<_nbokgi% z>Ps9>7cVtbl)9}|ijUD9QfhDTa60($-Am9Rbcmcpt-1`jbd3|FbAlm-Vy7yJ8mwNq ze33UPD)KtYMa~r{6*&r&zM)eo(39|H1sZ@$zNqqW&*!fAS~oU|ccpo$az!W=3%#$y zhfAkfwz3r0vt-aKOFb<}Nz>_WOgBm8z8U9;l;K|Iu82zEl;Ng=n^iiW425gb94Gw~ zdG$_Yo1&e}m(A&Hh<=XwrotmRHqYpsEB6kV`<$rTP!My@bv9y?jPaE#uFa9LaC2OA zaD|7;R1uQ2Y)B|gFBPuI+yMIo-iS8^PbrhRxD~FmX-b#R`9nzI8iU0`Qf#^*7yBB- zK87AXCm}cU=eQUs$5Egj#~Ln<7knJ)h+_?lBbDMPMU|82x(0Iuw?tQTh;xvLN%Wb` z36TUT1PjloF|qub=#wgPo^u@chBT{&gfT{4iUqf+8k~$!lX2fg!9-7EJov@E^aAvG z8p{&B8~Rb4Y{ng*&Xp;3OQZNVq)d4#$ki<0q#GdFIkc*00>XeSMmdzP>r}Y{3oIH z=~0wWev?C~jpizehcy6)OP7}F>&Cc8PHjyIDMpA z@PiU=PT?v&4=*%t#Yw*93OD_{qH0JRPbG-9q_`p%mSx=SkZ<;)3iJ?nMGoHgVB-j- z;}fY#bf%SHRAr%WV5Mkc1QYdCdgxkjk*#zVKZT)J7N!3pS?G}b?gshla*1#@Lm^=~ z&F?orD|DF|#p!{m8HDb>h}=Rmh=o!70b(lGFE`iV>z6)u&Y>sgD&s3Bz~6R;Kp+=y z{3taKr7?OLLaHskl(_L+zS+A&%Hy|^et+oaN{iNds&jH~S-}^JYR$*rb5r;mL{(<; z!aF&5;Ns4`m+GhV@{mf(xp+r&O>+e0tBod?&-Ga1sxDHwure;}L~zm1a$NAJs5lKV zq+zTkm)Ahwpy&E&a`{S`MciW3wt%==(#D5f3a&5)hN%&R9;M{loqg8nf%;L<5<^klVN>UmMPscCg(N zeNBW8hLr$1SR0Oqw8l;~kzmgVq+8+?iZqg6oPaV=3WD2MBQA&s66c0(7jD1D=z#UK zm$WG(Q;cm$A-H`QzW-4Q=%sph#rqsCHs$8L5Mk0}T+GSoRwOR%EB#ad_=g?NJrW&k^Ff^|cq;dyqitu-ar4XTJNDYha z+;chQGq9bws&A(&aSsUUrRg+;7rp3}PWi6O4=;wynqk!)er z%5SM)o0AkEC~h5G6QZU-cY9i%wZ zniL$Tf>x41Q>M3-Jc6+8H4&4V2;)SrhQi&8lk-qy(*n)$jL{74(GS0Aa)@jS;4bOH z7R~5J5HyN+gff--OGkXHrB+6eoON0SoFOGky&+T~MrLfq#lMjmxjf)rSyX=Szc}?| z6(KjhI4g|OaPSNIBf4A6< zl1N{Aic!`ru}(wu>8R>_k#bv9kzvHrb5npdXCk^-f$*pT%{oe^l7{(|2EL&BQSw#C zBaX|bP%fsBUb_`v1JzWX7Jfest25yp{|_z|H7x0@vFvqs9@67`J^7)*OY_Z>yIhHg4%ao5Z>S4mh> zQAvlXy@R^Pz7}WzOENz3@G}o3p=n?;ecN+0E76#mz+!^XcX5 zDsgr8gtUh%#Jz~%KB?*KV$TBx8feM1+nEm*9ovv4N4n-GawUMg@)u91$D| zhGbOKpy8oGGq@S=pD8H z4OeV>SwiRqG;+no^?yCR|7AL`08w%3<*LH`9}vZrpHMD>%HrY`801vlwEQ0335Vt7gxUmUtJI8v?|U_g({gSuDs|moixL(4rlS_f-uKURhuTXGKX;A;y{##71d zKsjj(pJK}M=>fb`OPAtu*&y{!FUt)yy)o8(U8-}n#YUPI2{59F#+E&PF8JILj+{QNF`gCY0+ z59H{1YW5$-1N#skg??M0~_lC5)3R=+eZsK}{(FG}sJAzHfUUA`UCIKeqBdfg$H$>eCfP?6K3 zcM{~Ivv|EUeyGSRrI%jClf2^PXdF?I)6#ElK*sY8FVDsmjebM@F&}avOztF8EB3E0 zs^6(nIkeD2|9Q*nrSXPyTFQZ5D@$i`H14R#sp)M*it)W@H6Zp6Ee(KMfN#xt|GPk< z(;2-Pm<)OXa4v8J^Y7053mfp^o-n)sr0^+>o(tRzdK7RIumO`|J5V^J?=sYi7-w`|Q1E z)~pfVrbB)F9~=G%oQnTfz^{SRK=GYv;b(xCL+@eqP8PnY!pnIXY$yB|;3UfVEU0om z2ujXZLEMO&zz*meK=CaCuZKPxRC&um+=$l?@%XIaL!jh*&FEWMuRu3h=uY{!Q={!tVf8-Wx!r z`w62jHTn$0Lk-=*QTSft!|EpD{Q~?v_<+%01y@4nz-8b(a4C2JsD3d9bnOl*y* z(&!tFZZY~?qfa(^AH%`m)yR3BjfYn72~h3#5O^+f?*Jvg9bAO}N5PMSm7x0lUWTvp z!t`nAUx2EIC;bc5h|ie+Li3+){zE~Hi=7N#-wRv7&@X{1*Q21)z0c@7jQ%uuE#XVe ze}?%V2Ywy@Bf&3$!z}#G4|_SX%dC3;11S0H%>UblUormk`Lz4?y^Z^!>|Q1yH;*g!cy3@Tq+{0HBNS3u?WWl;W)ng6{; z-)eM+(X)&`2fPjb6F}wXSWx-d7tDgY8opTW$*#Qee-$V>GeF6? z7`y>&1U~`p1*#lF!BZ&5J41c^-++q07W@MEAow}(`=H|8394K-f@`pg#1HL8bSY z;djly%jiXhA2mF|@WY1h?(WCa^Puvx2Go3h2iOg^f|}RIgWm-|1b!CW2~@g&|A3!| z)`EB9e=nE=Z!^5!@Ir7g{)d2yC#B;rL%%kptn8cM??Bbl&kTFP|APJ&DE=Ek$!#&L zH+*rova);de;mw$-Jtko$6R=k;W$IxCnNt?2YdO?fTABa`oD~pf~)*x?@;-Wop{kx zj6TWe{S0MuTzvoB)$_@2{a2uW3f=+A&b{*aRSR!3oDY5m|2k0he;6pf-N8?ReY<$n znN#)4V?p)Hk)YDs9aO#sS-9>)Q25_Lh5rgv_)pCLQBeK$Zcxu zQ{nfz;Ia|q)rEf&RJf*X@vHlbmeIZWm{i$9`;P`UfTTNgJy;E{0yAJYSOqQtmw@V5 z$AdNCabOi#2@V4#ZwM%P>PM7w=tl5Zum_Yp+4(vKR6jZzTnLT=wYPi}SOp#q>i&m? z;4tt=a5Mdcc5(Ly9RaR`rffrd!I5A$_-$|{xF0AxY=?nUL0(CR)_}_YSnyDAI7mAU z9R^l_n|F5iTDkjycr_l{3(c$N&~A`d26qpT@~?HKgTQH^=&2yDe(wGs<);ez0B{&M z1snqM%H{6;X#%y5#;elMUQqe%0hQmCAg>ngo*y2KL#IKj{8Pcb!Lgu|5AvuVDiu`G zvhzsW4&6vU;E^=67i7wI_xKD0yUo81ybgK^IFx@=L8el7Zx2(_&6gsLB5w_%&%G{YLh3d1tPjYM+s4Z98745t~^7*-gT8Ezzh{2bhC*lpNmIL)xe zu)+{<@xHCfAuqwc$^VE(U|4^A*66UF*e9B@2m2*EtFnoI6P;XcPor-(dLN@dXY|2F zpEc6+A1NAnO$-`29afUOS;pUF^cn#`8a5beF|{*7(O+{1=QKZ?q0*DZi&1y~*fylfPLs<*OOx@j6T)qn@#=%(WJldXrKO63;(@^PdEAvqpvi27n8Tx z=sPX^I?>3hIL6Dn#lj!8@GlzujL}~+`d3DO$LQ}E{e98Mt2)-pd)nwOqhAzFeVu3d z`Ge7y7~OAlgVFyKjl9jrdU^Y3l7Mbwl9xMDH1g&f|M5mIF?y`gHyWK1y({ZSRX+aN zMsFG8=_`$HI>FOdGj_`PKaDixP8+Z7$dCAIjQ!`3twpAY5ZLI zTqt)HT6o&RFCbkPPM+lYEd5oMU)jl3etWI|Of>!)?$UibcYri=je{>@Lw-V{; z{?s`CBZ>U}K0)7=Nbmjxt$VlQ^3F=c*S)Us@YN7;x{sQS(?3syKb8ppe4@P1CFJj& zs899NxP0By7pL`p8mE^g zbx&Pf-m?jLvl2A#<^}xPD~iXLrG_{?Izewr@avwxIR94@^s$Nh**!t?4OI|d_rk^H zjY!D*e1d*5LFW?Xy&@t1{)Bwl!;Gi*l|=b+3HiLlDYfpxDW@u#G&%|fToL0l=9xG~bD z?-Pvqx=xW-z0F1YZ_Wzwgl%hROd+9f25yGBkSSUYuop(P8hWh;;$ zZi-u&$XKDde&r-^>Q1==qpJzqtn*st%~&XV`{6RUU|=<$ac9kxt6Jupx^(ju3l_z1 zsw*_YnvWN|eJ<)Tv1V{JOI_DZJTGsp)yLKdja64v1@iX=^LNmxrD&xww3b!Kc^5X- zm68^!gNmc2X~%fG#u`c~%xszE?&xzYlh1Exh`LukcR`-2S6#=<)Ve6=o_9|Dd>+&}Rb^8+8 zF7S4lDrlYjB@a=S=sBkD-fYuNUfW*X4n_Q^f}5sL-lY9qG5C^NH;ToNSGb-aUXu0k zMJ;B4*y6=HpXDUxv%pVe7x#BVr%{S3O5a(U|R4V125FUG|#AGLZX^X<=kx7pGCIrWy zN-@br-pNrD=Z%I!+%xLc&NJE7ooAxATkL`kFF!L<-E1dxnipP`Kk_nW)}jTi%%>sD zkz?W<;iV;Zo`+fS-G{odB*H~rA9a4Rfn=vhf3uhzQTT5ke497I+Ue4l!g2Ge2s=WqcSp=&n;`V zBThUrugGU$Oeo8kP!`=GxxFTFvcfs1gs_k+E?Bg_QXMmv9`(L>zwjhyynoHLr`2;}Ib*+rji`KsZ& zP;LqG^m7v**7~-_6^PuCUG!DMd?fAD$@P5rz1c ztWM^?EsgT)y*r(2wG*3Nb>Ei_lEAJ=B&Y(}`r%S2m-0%hGrm|ZH$dx}OeCb+u^kMBppRtJ* z$Rf#!ma&PJv57uo6Me=eTE-^2jKz$QVO(WMYh^H@)_>@ZbL`I%Uv}x^sy}B}UI&47 zWOi{ds=6Bsgc@klo}@7DpD_Wer2w zIo+{f8?ewuVaO42=`%7yn0c^1ceU(E1(|fERrT%5hLvT`3c^y(I4c2r2ENElMCMc^?hHOw77w!gt#tyn)n~8Aq(Y@}hOCgq@{ZwnHg?X6 zOe)srE~`=lriod2?pw{Y?OfW1SbxwF`y52>?BNYqdXVWJv(Tg9$6fG&I??`gDtBf@ zDmw`~bZ3qPN2YRvQ`z01MnjEm%)Z-q8{EOp#RZ(X-hO|-uz-TS zAIvx++1j&iJ)Y$GLDvy%1H#XTtu#Agj{#>7{9jRt-Ew9fZ%4db{`f&_Xt#e*v${mQO4{+;fWA@)s zBA-$QvdSBmg4Jgc6b$pFWYVmxe__Eu{61bb5Z~da6NB*ns_K_~_9K(d*u$sFhQ}@x zbB1_=4WwFUMI~--Jfy2=!^&D8l8GoMzyE&{=l*riSd%~ZpBWb>rz$gOkU7fA#)TGf zi!lGAoL|YGRL>a{EMbAcg-&##vPEL$dZjjtsh)!CLtO~=1TZ0>@^DL>8TJlVSiXu7 zmnZBi#9I>$MCb1<|9s0)XAeV6L+65FGL-cumQdm?qbx~K7zyeUz1~kVt~X3j-tjzM zF&m^S)U}HXej~oAo+~I?-%1z3jNcx}>{85qmE)HAn*Mpkp`UP}=Y(nsElN>jDayT! zc*}CGQuTOC^?WRF_w(RMviQth5?E9xW{iO+L3zhDOh3W0THlp!=90~sbB8knx?b(- zE_CV4Nxt^arS>t!8hPJSoUUHpc;cy;pDGUZ8J`>FD*IYr3$>LWkHOAHu)E8AVfU6W z&dWOi&PZhCDNz;7ew60I4N*Jb|{}!_^r#lQ~Z?4y+NBH^0nfe?#OZD6z z%T!bq-q3UFzJ2G@Xu%h2IpibMV&AFi{fXC^#dIw*>n>Jj&Td#{Rd{ot@^0&`Ex&(r z|81`Q^*nSoNQ%USE^8u)#$$%NIb?XIjeI-1QP|@dQgAO%OkV7rt5DXEn5@|I!Mz`2 zoP8j9vG=q>dBe9WZ&+MjZc;@-{*b%l=ZBJ z&Pr9#BW#?N>6A~|1Jcc;Ke?_zi&eRM0pb@ZYSY+w%j3L7cAy3rzfFx89nJo)b5q+ikJnWC$SO#8?-QehNF=^!r&Bv?gDN*nLcVl+5k7CkxkED$V(i)1M zF$Mi2QF%q}T@bF%lY;l_+@#S3?eT$Y3hB3AI8;7-*Xy%;2D!_-75*oKtI+AiLvA(y z4=s}syh2xFKA*eZ1oI{!>bRm3@~U@3;!KN}bO%3;)sp@}&$Z z_bFPSRQg>*e7HVXONOfvapU-3Du3%O+`vlfqPRaBE#Ra9;#cUy88=Y;DhnSd{=yx^ zZ?kY)e<;eI>HABkRIVtzdk67XTe$ncEfIgcg>T)LJa6THm+@)bIT!d!oKt-QhGGBkay1T}3;eP4 zUn5|p@!5DRDv#3Fx$SP_)3|gl$V;5R6@M)}!~W^h*ElWUPvlqp(#2o+rst1Vy9SW2 zdiw_aHCsHt#<6pOKUO|joSkZXHXe)0Cwc#j$-Qzg@eq8Yti0Rfdj-B>?}2Ym`stRpd_CKIP?WCP??m`E8=vL{=R*CJXz!Wu zhx*Yxu|0mZ&#myUw*1<>QIrqyJp|t>85@D>!o1V09@0WSr=1uA|PRJ;YC;>`drfUX5E0S^XG0Y7ZG8~9P^Z9LD<2BoKa zG59>l@?_;FK*^g1O5Oy+Q^0fZuK+Is%RrU$Z>(u6AFqIl_hV4;q(3WKdaoFE*TF;gv=o465Ak@Ln<%{4=O@r5AP~_$5&J{uHQu&jpp46q(N4ph5KKUn$rJ9D(sc^phZ-v>5>y1zl`-36+@-vUZ* zJ19B2PH(2G`3egDO1FBq{Nt7GW#vk!tAqsk5{wUlxf7yr% z%8Q7>+O!dFB)`I5!*0Vi!)b;!h82coh8v0O;v04wwi!+{tTC)GEHm6l{`fh#*Rb2L z&2XAwjbVi$;Nty|g6aH0*ys9@X!=0dSJKTBPM@1jAom3Q%iRQ>F;*YiX?)(Aa;X6Y5mx@2z!lzsO8hGT??-f4G!rSnd{O}!dkA?SG z_*t}*OW)65Wfhb|@fUvB%Uf#U;XVFr3-7h?`z<`Yr#t<3rN5Vt|F(sP_iU%XPxuN8 zf6l_gd;FJ8{#Xmwcvb$wd+ya%e=Ds1&O(;UKl8iXpisXSe}#pI_wWh}A7b%UZHgb< z8CE~N!@SS2fWo_sVX}p9vhZJ;{9*PUt$9)PH_hbVZQG3WvB}E6 z+VZbwvrFH~r+L)LxA6U~e!_cx&g8E)`IlP!jn=*=Tl|&QeqXTgDw99U!Z%s?2_b!p zKiI<47Owfp<JS$hG@%AJMvfFCMOWC{7=p z;GdM>znA>S`G1xO*YbHhT=Qt0o}WnXR|#6C=i~h9260;RXPjP~;BO)@9==zCPU^>B zpOE*}1pnU?;kzcn>k{FAP2}g{1bt+Jo|CBW>IALrBmPD1h(!H=Hj(~)iTL*1h~mGU zkhfQY|A|ESVF~)?1piA3`k+L9o=VV8D<)DyOen|}Ympo0fXcpTtd$7MYcW~^(`U|X zp1WYiRW5a}t0x69ucG7hAU%nC>5Q17G73C(Q=4m3=cSxdWHTy`%`>NGrk6EOLC@;k za~mA@{KW{egd(ZR!i)u`?dwx4RI~Sf7h+6i@ zxH2$PI%D>`bz$?O7O&y2AX6A_(bAq%tDSh>)JQcnugz#WrlhuL`uv&tGb>(e^IGS| zw5j2el)^fg-7@1UpNQ0q8T;V7^&>ma6ZJc|QME0Y)kN zDyp{`E!oY}uRvA{H9~&p%*VX+Vpr|~jxtz2(bSD~07)zs(>&=+sU1gImv--txdxOK zFV29X;!N=tEG%=>u*g9Z+3N>dTZ=RA<6AQ>$we_k+)>*^)#~*eqmEG=(W&Vc#8X*X z=Fe~{_rB_bv|?ZJO2Iv^+8%fdeSNlFp%=`V@8ftI;)O9KPkq3Kmmi-t9HTKGhKQIw zhgH=aM(?5$0%A2;N;}@QaQ={iaW7odGGoEKg{_&EW=4kZUA`ElLR4(!N9Pm@E3MGS zW~2fx<^ZR2X9+_VPJ{74jmJ2xc_U8Kz;V(~6mg&UToL!55yp1hv#^(z7%T%b$3v(X z>(z1JsAI=H9c!#N$HQE1@*O%JIT4ia&hY?=i+XfCKS9FiP$&3Hhfuf>CusOwyDPYEjWjCDHkdUep4GU(ye$B(J1$h#ftah^~$_C&`n zJh}!r8?trO&xw{^E>DXU)L9E<|KmlgZJ0oSeQRc!eulbr>J}&ZqFtj`Ty@ z>^sFiFUmIVQyAZhA9?ObKeWr_O;e_Dn~|rVU57h6De@{1xg-71&04^~b*s{FO*EW| zb~O2(?S9xF2_Me?*(2S$QrVDWAXuAI`B-msPVx1hbt>CebKdXkkK6z5biF`(o^F5L z>j`yUH+z#rr8^&73HaYPJic09cK3OY8qf3{WBae~C4OADF|Mzr{A?$F=YvY$=M>(uzjSBhh-Wt<~dZRx3Zhhy{+3C*3zPMh0p}b=< zWozvGriz~K{JsFq3SSA*1v%aYKkRCw^ZSCJF5#3=h7p`|SxIG=w-K7lb?`Tp?G)s4 z$}fZL%vJR>mUp{2osu?g-O@wrb95bvw0h8C<^nK-d~P?-}Xa>~FCvhSYF} z6Pn81G_sAzxN(kG_4#qko}pKcu=H_tdiegJzv;&Mh(K`WZKk?1moqsOsu` zddF!$?)>PWaqG()*Hc$NE~qQz!*>p8>7d=?@7hyF?s78o8Bt{xXC(C_yvvsD6U$C! zq4F(uWkpRf?on%l3wD^H#O3La6MIcNe^Na^<*%zps=NP#`ok4@Z}#uZpW>D)(3jA7 z(!EK~(RNP5@XgHr>CTC?-&;X{mP-q{;&l1bnOZ3T5^5vLt3E}cN9qc!gVKJMLEnb! z30;;VhF$YhPRiZn?&h!dwSMewTZbk`p?+_P@%|r5gtD1eG;Osz+??8ZefD>m3qr38 z=&#Jq997@>1J{)G?XR`b8V%V$xU8XLwP&h*DQd1>#VJHnIgblNEup}treBkCwZ0GC zG1PjAYIgdyVLlw<>!S0z3jd@1@v$Mbe6{!*i1c6M^J(e$v6(nA|0nr7uN&(UUOTag zyoZUubbYHoI2A80`Ks@{+Kb{2Pli*bI!zJqv|`|M2tH%+@$$vzRi=*i?wI^{B$lGTkWR;R~^yw%+2?@_XX%}-PBnI3fmSIB;V-y4;QCT>`Mc_ubalO-fZ?d%H}j2e9>O0f3}5EUN3V#+1x#O( z2tN=~6h-BIP=ESwh|iD8zaL<4IPpY0xS#}IQwgr*PpW4H(fdzq=$sMKi|MgvMi)zVa_{J@pc-6be44NnphOlAE1b3 z;p$$SjOw$`WPZuT$4tw<1p|8ZPv7Ciec$JWP$)YwuKe6K98^#@T8Aj_ z7*7+X+Ls~!BN}vEL`{B!cDX(L>f4`E5@gze*||S*lDrO>#=llg{nzi$-+P z>>|x=U3!y}^zTIs#HF^SCcCX`h=ty&(9X~6kxv%7(>4Yb@md$r`2}T2d0(FQCL>*a z>L99xv+x&A@Zsdr?v`KPYvow3wR1n^cPM?IZTMEHL|h$RkngvVtK9l>Q(x(9><0Fi zU4~WcQl-+f--;8@`rYy_U0A(C5@RLOddN+;)oVZ=5{0i?EFZg?nEd@7`w2o`PZd6(31m=L)RmK|MylafmbA~Bt2tn!W z+xaI*AGPEkU*UmLkY4+;nzHg+{Q;MP_Xp;uvF;s5Uk#QGJ5sQ`k-BWZu8F%3^~q7* zaXNH;u8!7Np=xHDS=W$Tt^T4*bGL;fEjm!Ow!A}IR}ER(48`>@)ds|mUS-oSz0eZS z4nhMnbA9J+uG{Mha-O($Yk8jUi{i5pr>5tQ)7Dk!t#3Pj9c{l%Q#S42OH1pJQgpFt zW+suG#D6dr^AQ?J&%e1 z`@EDH%4m0qZSI@uYWeT}Wf||~+Qswp@ewIb&@gX~;A4;~&De<`%@og4fz`czzZLvU zS709CbE^r#eO_iCIx0K*y*l>0hq>6xEbsV&Yc>kv zCVJ|&ml0Q=-QbI5Y?=AKtPQyqs{Rk0CStz-cb+RVnL1^jw#w+u99iAlKSmFk`t~Pi z92z(TSskU?-yGD>aMEX!B^3+dwK>CRvdkx%OE)}^Drm0S#P>Gs#d#0D?`W+5xO#Ul zI_1kX4Kh{4o+itmcD1hYKp)XZPFd?-E<^6k%MF@u;Ryrf+vY+7x~qJ>7l#>@=NVo& zpI_*(ub=4}BDUKZWmKz2enp|H=GP{gQ6VJ=MKl=jTIBDfPJ%nT2Vge{Ad8 zKpoh0w|9Em;|=5fxaej7iWUDbvilK7>{C;Q%VWB6Yxyvf365?(U@7H(_Q#re1JhlyY6elqE0$!Xk{3U3?Yg3I3B zxpev4_VnSlJYAH2w}rRBRx1BNf5`e#QTz()c)Gi*RQ<0W>eK(u0O8Y2@O}e?w^_q4 zKujt5n=O2x`Wqv!(I6J^qmd z9t2O-Yd#-so;zQDyT40(I%lxL_^i3|d=^jn)j~>}@wsJ8g$}H2AuV&-!P+JQhvmo(bOy&a ze>fNN5vzw<_%;}y4fi5>uKnTbH9pNJ1@aR46u)$vEA0G==9eAuKLdaFzkGkye6u6| z|G?j6=Up`a6!0g;kLpAB!>u>|f!bSqx*u+x@!7moR3GB|Bz(O);5(D~s|G#iBf$ya z2f!3~IRoufa5Bi8Q&|n34IT)d3GQzA77a25`Xz8YxZZFbcsjK1Avz7b1#ANAK*>D? zl-vfJ*l+!`nfna~-I3#)Fdo=ANGadGMpqKLF)_Gq@|L^Bqce z2B>t;0nY_%z;nQ(K&7|0;YK!IMXxoy$M71%Bf$p3|Bn8u_Xul>Z$@%Wk#8TR@dt_xK1K4O50E86Iso!tg_e9{^QPn|Z%bJ^dJ*3_b{| zUcO;C4?GL{LQv_}7(LqPVc>cAzsY+HLvBPrsCL~5HiEt8e;+8hp8+NBI#BW!g5sNH z{uh|P?9GesM5A?2kkZ*Y*r)R|@NDQVP;!-G`yers22L$hF>wf9#lPDX?U3-Wq0*;jN!qCG?Uy2Ez>dthH8O}p*~cFV<-;Y zLLldohHeI@f}6k#!Hpp2j)v-acNDlDM3%dkROO_bCex-xHs-@ZlCN`|L_Td{2DQ!fPyi9$^X(-=ot8`}|E+$G~0Ae}#8Bs;umL zR{l0C|E(6j*}^wi_$mu$u5j_2Ec|m8KGnhxvGi-mr`-OQ{t!!F=LwX4uZ5px;Z+tc zaOHEcIqPfkt4#j079PIm-?Z=z7Owls6hC}VK56wo#M)@w>^loSsKYzs=(R(&Bep{F^NP3X8A%0hGUu_{*JQ@uk-#ceaK1TKG^4A7$Zs z9w>hJ9=^cJFZ+XX4-v+{$gNAzs}uAW67<&+^p&(1UXk0zuQ>ze1d)}!T*Ou_%#Xo z%L!V~zj%62B+Ap1piiS;#rY3U(CUlvaHrNTrTgZ^b5IdQk=k8O;7s4fy`6eHX9#4d z8GU~L14|{vJUV5tcy{cVLP@R}{@6#J*F4-Qkiqe~6wC6SPM)30i=$|z<|oDoXOik}opgq5nU z?Iq~#I*<~U4B^3Sh zbvS$a)h*3Mq11bPcJvdgI|vX2+LW80TL%vHBXr>K_#oX5S2&7NG6(8p?(&C$1w=F7 z_F4SoH!x4}lvj#3KWz;hI&i)C*gL8h;~Jn|d}w0u4V;a?T`ig=VFy|fpS#95?vTH6EXnjuTKd;Nq zz1MR!7qNIECwYq7%evr3hBQ0;7D~82xi*ttg^=~|g?LI#_;yx4^k1J^yYqiv{=Z+B z)bmQC#e+T+8a2aE@JKx@d97m_vp+?9iUSCkJw%7)7n|fQ#hdKw7%i0H(CVi#M~ij} zk+1@txf*q26vNZ)?+hxx{n3s`TT}ep>6-B8CpBbG8|idxUv#N^4Vk}6i^>!|bB*g!s4LWfMJgs5yBnM;nUeI%xJ2%$ zep)K9X+)ztWZqJHl5Uhs2kXamt6W;L>v`$A@(vkuk#fpHh3BTA$J$EVKcuri54trH zuqRyY*I^USjICPwQG$z}M~g=B-S(FI|Tk zX-hAPHmlK#>dDOY!m3~5=*r9K+@2dq&$Y-F%XMZ(eQuYR+n11+eSKaC#uBB^3MEI? zF_rG3oU=`Few#hz|u)I@tLplSrNg4*R$uk^}~RjB{89^5z0+1_2+ z)4x{~$VmuipLVGi(sw#6$^N&b0W<7bPQ$!_9<*#~kNaC@oOG-YM86mN)q7(aH&b4q zGnF~pky~l{C3!WhKB^6EQ8x{E3&ZR2ShJ8nsh(H)>k2}a3SvE8-Rt$@HbvTALF-HE zeCX+AA9oSeZ;n}8_Y8tKPLmnAaQtEnzW;97kuXtAW6ExDVf}j>C*68|pG@9}Yy84J zm+gglSt`Zr1AE?GMAvs-KO{B&n!T3|gVR@66uNX(ednYKxO(6iz3c-~{W{fZ*W3S) zZvRUg{=L>(O1He@BP8tfxd_Q?AdkYAZo=4-0bOa&lK&U;D#k+!!lmnrwq`6`7FFsy zZ*^xxPy<|naC&p3MAxy7@DyhAJ11{T&v?EuH@H4`+WPbwRUED@on4=P{x9j}Ycv09 ze`>3yjoRmyKV80JA7)#q^dp`R#`3zi(=#6J-!Gk8KAX+Y^tN>fi-l*McYSV8^53~o z9JxBOi^6qwDapK(J{0}LFE1e=m1`Kekk(3PA9EEH(day@e7=RLv*J!rhaPdH!`MYH zDDU_ROBNJby2oDc*!ix&H(#wbzE`87xUEYI9E#Xdz(TER3P3M5#xkLRrHjl_qQ;&A z9&O2xKJlfX91YNp!3A-h_;|bhnMX%FgKF1YbkvD-l8+* z!)ZeFA>SxW=NB;+J%8xPs0F%j@1%7j~VR2arba&4Zj*-Rkxwx?bRWybnmHHPwFoD99f{ zmS_jc5w%HI_>HRQ+Pak*TFz?vWkfYiPyZxT_pF!rXkuVoyQV4Zdq>218ds;Y&q=Q` z*VtXqjkeL@^%QZF-BW5pUt=Wl3PDjKjdaqI0+hEr7rp2?gcRoF4xa`Rm{65Qejv0J z#LlNtI2tdCbG2%ybr;NYr}_k_LM4#b>n`u8h{tS%!OF0rpc3AuvZ(}%ulz@q@H>L? z#iPMWR>A{CTxi0&B(w;t7Q4NG!)1hi>@>xrIVIB?rQ{B7(6buj8O3tC<`RFZ!_Q|t z>T04$p^Z?ej}?!TY`HqC`&iYuLrH^rV^c=|WDX(ngm7i&bd-C8@_nv&WzHQRbZf1?IY==J?)i0U85^V2If)0W1X8JSu; zsfl_lE6iWk=Z)vL!h)b&-7|fUV}bMvr&pZR6ZW(;T;12#3?fEO`%b0w|H6LMkA{>E zud(k3z31bUnF80egYdnLJE{LS8vld%zvT_DPZaVI>8q8{S89MiZTdXQuX90PD#1UJ zz)$jj1MhlrmVc(nV*SEzz}LG2z6&TP`_YwWg6vyYjscNbc{s?vb>;qsJAstBvX4N8 z|B63sF;)II$Uc4L7eGF#DnAX1?^?sTApa^q#vk!j7%pWKUi4{(FH>&OOvDcN0ww1S z-j?`8uKcs%ONKuO`LwOP9%LWB@=C)qL8Uhyl)Q6!TT*=40Tll@P~pdc3ja9|bzu{z z{GSYp{}{u=K*f`OhSC{ico9!X#gn~2<#Qv*r)A|jkoK?qmf;G+3k_v!SMp_NOenn! z$$y7_%$9NG??F1_h+l)M--kiITPv>t*;1{XZK!=g(PKcqQ!9VvdvK-h4Z&3&3M&2w zK-M5C|AD9QDUhbDybnb8qOuc2PoeS@kazpaX&_Ms*BDk90?uDLjzeJx{rVKq{158| z9}!L6gzs}50u)_EVdXlAtNqF_zTOZ`_zDX@$HK$-RJjyB&B7sFd?$=Qy%w&@lsgGp zJi#^cBTm1NpecJn___qGkI#7g*AwCUC&EW3=v0DE?w1~#kauH(z9m6-C+Le3^y~z! zha6dm+#eEja(}lb5q?!7|M^AmuzzSK%A)Nnt;U@*<@~1R(yQdGL|-#Gb*85B#3oj> zZ&7HMEwLIK+uum+%0zb2N^kTeHu~6|QI<>Wvc-2A!yZnwU5JM=_Va_&CM z>Dq)%k!5AFB@SP- z{(CaN^jTzHjH&-!6~^f~s_OvrfXUt=l9ipsP!c9d@>EN_U>WA>G-y?hyrX zV%f3ilj9z-<{H;IwwGbsSiQ{!=9aP~*}Boo(gJGT`pj|Z84|-P8X`kTW<1|Q>wmP8 zQm`87e7zZn!YkQ+MM7(MV`25~IsQ7nek^Ll7Wf>?XC2Eg0}G!N>veK6oUU~z607WH zrP|mzO=pFnLKTp^tb)RCKmzNBOMgLLH-yi9zJ#vDm-tfhYBs1I&(5b z=Q3q`g*ACq2bw$DYD6;2kb2a$jE)9xrPHR9LOvX8oBm>feN+WzlBt-EmWcGn)g z)U(iv4J4mh{#>W}UpjYn#RDp+eMpr$2k)(9_&)ldsCm}b^%AYjbv`;4h9No|dy4w# zdSp|-Jv6~HFs+Yz=riZc{CwNGxEeNh#iP1=>FSadDYmZ|TR5kyGv2m9!)nvFTw}=ZE_RWUtl?qj-BshTkmv)^lD*P|lVlzPFGpsfC z)@DbJL9@m|2gTD6v}^j{ZCrJ&9oqp#9)LzVV3_M$u$ zbElA<>d~rLKYIhV#};pq>WenwjQ3?t4SOPWnTr!;bx z_T-j6(?9P)J(JqE4r;wVWTLgzzva}e*PxFlzab=_ImaiRIV+ZI=JZ&S+ya|VGIO}r z8*@uvaolTE0BzZ_@8m1krR<)>nEP-~##nz(|L^q2-%>=I5Key2{n6P8GdonHQrTxx zy4UaxXSD1kXB(`%LvqGQs<{Idtr_UvEQX6HQ-`Yo?Z;U{sZCU3wa`&hUY(O;XGVT0H|=sMH8Im3`6YCAtU zWVh6#+jeeW+Ot#Z>>!1)vU-q)%2YDAI`~GhI%|jQ_UM+KYsYP=EuXZde;gOdGI_}Y z(pSh_M7i?!NMHjJbJF^jA_?S6zL27Rt-5qc`?&*>u|5CpGqTdF=)S(FAqtRdH+Dkio=I zYbLWuYCbS-mQ_2Mb0+B9mbqU&1#`?b%1I5R^*>PNL`JvSr$< zV31}GG!BJhZlyL?_k>G?$#OdHxsdAaGHU0Zj#Rl*5&3s2`d)w~b2|RKcdd&CrW*w= zq~9}{E0Pl-MVp6nS+W_j+$AEUp+YmJu3 zQ$1(#*A;?p)<3Hu`^V6R&??Az+TjnWVlpRNSGH`w9zA~QvoAMhM{_0nZr(0a|Iwjc zi_`LttII-Kj7|Tjh>WEqpVxjiABGXZ_HBb(&v%*fWiIddA!0&~qH;dvHWfA9x`$B+ zcOAkTU!#hy4&HrVfU$ksu+~(4?#v-{?@jeH_T}wqQ+OD=>TO+IP?DF4V-wx&{B(Kh zpF9xD_ac^KL&NkJKFFQC6l|%UZw6-GH{Iks%sl|>CYDWE*fO769xCc4R!pBeYr znc4HoSoQL&HZ#hayk+sqv$;c|$ypM2KkFveo|~#{n!ZSUn5-{5V)3aJqmGzafzmzq zoXJ%Asb$<=aB2nT)#=Cj|9_i%hXR$l|1>Q2?naqQ*#!xDhFT{oW!Ixk?-Dp$UMZ@% zZVNvOEG2)v7O`+Lq*rQRZlOjjZXo$x7CzLo6{m0E=M!GC{91^^X-LHSMe=Jbe4zX_S-8&al}f*h{WQ6O%D>sd z2a>PNF*%*PEY*JD9Ns_SDH(2pcPD?P%D=ahPQgEMPT8O(!v+o8bGIQ~@Q%d)ApZB7 zoe%YI=fb|`B!BPfXgv80C|hZEG1SkU3w&p{558&F&+c-wEe1+%hW|^<&P7-sjrL1p z_9*Uzuh;mje=>g+?yD;OC-~oEd>RMN1-?Z3;#Xbu*!`~>7tRI#68pO&;TdK2E(Xen z%GCg0h4ERn7vw zFH4^7`){xQcA;;sGrob+RlgYx-)iI2cyunLo9H*`{;hxS>P)?e-!=#sPM-?h2I5E0M7!|KTZRA6jlxgCxLr_%GWkLh0lWZ zpzd!~zxXzo2ES(Ey0=w)((6#W>)uwC<0Me!I0{rbJ`BzW|1y}l2HXg$U4IFx{+5k?~D?!bPvq9Z!r+RJ#nHwul2Nh5E@d>5)D0%-R@?y!jskQWcf2G0CYuUk0ax zkAdQQ!05Y-z6HFT@aw?EAiS0dx2fxhrt!# zhrl*)7`OyvY8|=|Wa@KvN0_39PJ?C&adt-r^x#yVjaHv8 z8GWJAe>8fg(fvlZ8vTaR?MA<2bk^vd)mf1r^b~eCy3)cwESflBU;iMZ!@atimlZyZ zK_z#l(cyljsYdr$xbEo||3;&4G2=dX7k5kI{P0IQd4u zW%Ljx0l5#+t_rU*TBkxpPc>R+M?_0+LGC=GR~bFi==Dao8okBnn~bht@{#+x(P^XI zJzRKuR=)dJm7(vhDyU4Ji{x zr4>)_wgi1~BK=Vb`STLteTned33(E@BPps1-(uWvbL z%!0z$b~WfcF7sV5gPVLOoYg#k&df0jF2AxcPbfh~c}kr-xmuic6VEfT&gb0o&Z(a~ z$$U!P0IUMUZeq-mf(K;s;Y9K@Zidv--4J z=C>@Gp0Qf+il&hoYCie=jhM0YoyM!xoisr6_v^-(A|+N6mcI@&s&~bWF3Buwo-<~q z8X#7HSQ%BxipYXF27f-`P2v=lt2uuSao%%0H_?;E(4#0;=%*qSf^mqM z6m!;`nYyjj$53UQ(tK|Hq{(&XG}li)b4pyC8zX)!_?j|B-B3fJ5uzJLV=d)u9E`b~ z;W43p3ifVhwm3sR{AL4Ueuk@{T^~l9*wKpFbasBzBKTU0iE5y;G0dff-1beHYQPR5?ymD?QRVX=ONYE;6Yz)p2_9AGo9TXv1G1Y*fPdX zDc;HgcA0!+@zOtIypC;*V#Ik|Q|F^tEzQ();^r6gFb?{6A_s(DolHnx7EgB?vzO$1 zJwJj)CS~4bC@D_8Hzu!n-W;aC`LjH;-)NFR4fi6yc?%O>`BVzCQn&Tg#HLd@cJ3n7W7i@Xb3uPD)?Y^n`I+^89y zN4(Wyd5wF=sv^;y|kEw8O8utV@FZ};nKYkVKgmTk( ze~}9`pC9himroMs-m8B6e^~^{;}yAV2#X^pNJ6oG{C4%(SDT#mE_K#mhIoDPZq^6v zlixx-pwGTI!#qCAe4CrktDAaWo~4cNJvpa&0&YZJ+*$D>uN~>fhjoIQ@X|;<@=98^ zIiJ4*kvr0l->3@5Y28e&hC)hSaI7u4J``vPAI|?8)>o>8ELQ2A7(T6+Ikz8w^lo>^@h*iwIZEM4WY{wCz*Y<)?Kq# zm)%mIebIFxju>3(lp9^82Kmx&m5CR%Qf}ffjiQs&xwD7suG~tgW^r))+6tH9`kX>Y zyS}2Xnu^;NT5oypwdww*f@XS=60Nz3KdGMo;cuv~W7D}MURbD}q#huZpB)@3B%D)- z-9zf``MqJQ*1{VYd`@TW`ep4~_bC7LS4gPm8$(#1`ugVb8};FgT50+6PxB-6t@bT7 zvQqPw%g^cE)O+T%i2OQpS*9`~yG0%xkzW;w!5fSFHOSU08nf37=|Ap!I0S z`Fi5)2x@5~ZDR1pJ{q&9^zZ6)U7adZC|Ne=bFPQ&^0v5WBMCddT@Wq6e(x0hP)8cyhUn;)Vz2v6xzf`#P@8q=JTS|Y(y<`!l z(d=R`aNY^q_w?mo9frOpr2s(?Tp5=mj9!SPxb6v;7ifO1(ACr400bRzY`gbnymC%oPMhyS<`Bi&37x+zYM*00G|EC&XuVdm*;47i0 zA^o0B#y>5|Um_pp!9V&J5VrCiFHh}Qz-Q%>5vEb> zZ+3vNkI;S-YmAjs!Akx$fX9L3!Q;Uykaxuq+jjB%+P_x(UmN`pcnGxi-3|qF;L)J& zvJuWRyv%Tl;RHjO6RLpk8E_={2q^jA1eL#)Ao>@T*MmoZ4IuC4m7_q(e~xi+Ab1}r z`VR0QQ2Wx7(+WzC?!l11_8;WG6;JuU#h=5WUj=FN%3p)Wf=_}+g1SfRFt80&yemNd zjkt(E;+p^-1$yz3hoA`!NK5IkS1~a!c?K#52h;IelSII_fWtxw1PzVH&}m!8}StO8g?7D8BQ~- zF|05ITs+y2*FI)&>TA0H;d5k4?j8%*8^7Edqt|<~>?cNtdGa?#hk5a@Mu&M&>+(u3 z%zJyNaL{3%JJ9GbuN`f4n8(J8CVy>~zX_tLxbXedVDuI$SME}yE2wn2`9?PxeWTG! zjK1CIRYrf?==DZFXtWwrPW@ErR~apPAfl%l{STwtj9x)m%kc}}w~S4-L*(>3PH#)l z&nD;}Bxt<=#^du&Q9#pY3uw)4asF`$dP#!+t_1y|1pl8C;io3(GZXZj1l^mUTNCm% zZsPe}o}lL>_%BV+=O<_uug|%#>AWeJyY~AZMGN76N!G6emfF(@OSf8kjxU&p#qRgA zDHE-XCsw@Ny02f?4b_gwoOl~-0a{GzH}>$ITh zSFznsyyoaa1HX`3UFI3^^*cC$M|&OfTiJ#P9^r*C?}K1oAoH}}CJX$bjsiWCI+OYO zK>G~FDa?>83hT9XY4%-M+-Kh=uqfAVAuxC-!-XC`&jo%V+XbFJ=LKHMe1V70e}R`T zLV=e`QRJb5$n$;M?KtI>aVNWFNoTj?Di*`%$IW(>{q*g>ZeyUl-Oruw#%4wrw{_NLY}tLu6Gy zx)M*Ff93F;U$AjMx3aF{_!H-v4=?yg{{nH>sC%S(CiB-t&?;3pC7)O)i`J=bculNX zzTsJt-0F`lrgJ>T$zP5v)?q#Nk3k^8EZ3|_L6>*@Of1>uY2MC*sRJFg{T|i7rj0Nb zE~3NPYbx+4?~tlWoOc|w9UbGyZ*&TgnAnnZML^JOFg2tevtoVJ^Dj- zs>n|GJu3FQCiZ(QzrB5HpRb$mCvN{KYbF9Z+v&DJ3jQXL)PM-d=I`%fk^9+9veOtPiBkIf7f>@pmFNWbYdWrz;(GQ{fV) z+4l%V_Qntzv#*wSR0cl;ly{r}MGO_l$Cl@5-cyCT;T>u2q_QuQ3#?w0FIO$5bGIo8 z>{B=7T(h{SePlZ$w_1fCbxjOCr?#>JxmC7X&g?3)TsqS}nPL2Cbs(j*aY-|;> zL;`BZ_1Bh9?1xDS6*3jci3%DeRYFcw=!mIMPN)M-bJ@-^Ql(v4@Md$vMniV_7J6Iz zG#^%)1qqgSe2hnIn9nqY^DuRjXwEUGvoFL`JO<{ptrSNk zz$5~rT*>q=i8{L-xepz-NWc!g(Ao~|IRFX}dHj#zzmS9u2O|X3mHve2rw?C|oT2|ii z8T@4bfIWsu>@1$%MjNLd(%;(h$r~GI{HLMwz9v|IRDst6^5+rGZ3C_*-Al}ywMH>1 zd{#CU?5UaWFe>14q3S=YH|K`Vhd+wYRA=qTT^eR=PPIR=D@L(3O46M*^oHf?`L4~~ zSja7RFy3*LxA&0?*qtA(@<4Wlcj>o&FT?YXZrVBBxl0@WYtrMMY905~aur~AUxMph z38)$W;-zuZ>B4E>+Uy^qTt4R0P%Y8yN~-++J%^>o-KLzSJI}$Kkn^?H!FrngYACPm zRnC#?1`OjQ`{M?)dO{W5e4G>MC+`a7Cg%oX-_0C?vtARt?vR%sRKDG`P{kyw&S*J} z_cM!De)A0C^_{^V*ZmSgkHSB;ZyebPX>zZy*g<&L+IFp>vx9H}?>q6gSZ~G1arh}L za}4{!4cS*MUzr1)Q4|bQIPbZ0Fi#Lah>^Ru_ zw~RQ%Gkv`4pi!2vZ=(lX_P6;g$%2!MLErD+DfU(!+4(8h*Eit>H8Yjhhu}0r&Ry{s*y#Gg=zoqNu)_mQ}&({rOFRu*X?N%$l+Sk-Of4nZL zU0rxDGI5w?!o84tLraN|5NgA3^*S3iD8RYT;TdI|YB zd2^=EJyix7=CvT z;IzJ0YTvBO7_i?^a^I>Ke>r`Hl-k#7(+4K*V*ZzsztO_)9U#2RzULLc)V`O#SLKrD z)<@&VenHv7zcaVsR6ggz{!C)OO8gD{UvK;>uXBOFseQMb26sj$*v0=z{;#+F8ut~Z z2!TJbUnKr}_&@DGK0hjtbAi7^eqM&5%lK74&JDmnlE6Kg3WxF9D_11n_M?8er$3MS zW3Yz(j30m#z^{U5fY*VigVRCWh^gRV&`sb+z&cRzjt3P_=WG>kKk!iSZQ7H(RQ>}z z5?l)^-a}vtTm>rLZJ^>cgG#RsRC=d@O7BEa@s0)+Zy!+cWba(@-lct%-bPUAZ2*J?>Ax?$db^A!5~W}BYw_$z4(6w)`FFw;|E!y8L>Y&6x7c1E-rJsYGdMqFrg3M9)T#)2d{VjmDuBi?28Lh=6u;x*z0qaOwN zH{yFne;#CgXoSww?h5V~dQA9)ve5;%oSoe1s?9t&=xv4s7GItL7G~CB&U!v;_T~guGi4;mLd5WkUs)$R+ntk4VJdn4m9Aq_-|1 zPqtFx^8b^dS10H%CFmy-@-I(>Z%c&FPSDzmEIvNddq-FLxM$41s(DuHbX{7VI24pWi4!|Fqx8ZVplByk+ner!T|2F# zElZt+TWp7h+{pqC3Pne)3JwDmY!1h>b;a~KbKOp^&xv+8xh#1Bf=Ics?!5GrS{-tt zN_exkom?b`jpcm)ecp5(Kulad)057mcH@QNtX=p5DGUe)$l}cGs`@X21gkqYMWAl0 zUOb1pXRlbW$fxg*)5XqJ#jjG2i>_j0yv5(ooiB{Mn&)a)cAy=2mF#kT-B_I@&Sy2V zS3FNU?liscAlG1#j!s3=+B0{p<$7GS-R!G0?93Cl+L(zHe0?e7_OMx`4t^9BhPN5w$w8R?HW9Om%ch1p_v0El8+gI@Ne|JXB@niyZ!1g7r)p2>X1NE9{z11O!$7! z6P2!qlTQAB^+12%u+{&o2kN0UGiR<<#Q$H$#Yrc}?+strykJJbwc-EA`YhAzyGHsa za)A!>1F!1Nz1R7n!M+nDPjU5~a=s+IPkojkhcyW2WRETGEW44{j`UfkTE3=PjM>QJ zQ>1J-iz`B0fyf={v-Fs}RX%RnI+JIl)=>278950b&i^XX8woDli*GbMB}U)Ya^lhd z!TcY>|AYAdeqE%`Vs^vR+}oVez0DjfLT_WKw+POD@dJ|Fy6+|d+mNgjFUJJ>Ps%$! zMRn9?f6Lt{TzfF@9$m)WkX^c(Rc6N<(A}%yy-<@pc`$KF0Lvjfrh1!}f2`x^1TkulE3iw z*CbV+8%!#g(B^m+vi`u%zX{4;Y3mdvC`S7u>r{1_^BOoshD0tJW`jWYe}_YK+F{>S z8PjGD1$>*myeP-7sbskpQej`=Rjhi4z`jlwQeL0CLB*#QB|6=CyPooy360r*ir-b* zi`&*KlpDt@ycnMbS+-=bRNXqd?*<}L0~|H$)7PKNFWLFGF1AQ*yG5U4Cg!4&Iby3J z#l;!iJ-T$AyA{37Wvuh|)d(hkT;bB2!G7~^xzJQOD({f;E=^8_SmFBjR|eqg(^>$0 z`A}bD`HE52DRCFguC~tpCG-qe6D_MVN2WMSsc!Plvh&-Q-czRQ>~nj3<^yfNA5`^d z>Jg%sW#;yuctL;sZ$>gAMoXq2c# z8$h@F@_OC?duD$7bwkRQ%}ZorEEm$>2z&oU#c64#N%d$A!=*)~P&)23@L7|2_egih zZ<(cIsz9*z|6GZ21AM2O4*iuwt`xOS@(+V#@!qWlbDib9(o28g>sjdZ0T=< zjh143`Tf-PEn8*G{O^4;S(YzK2=n)?A6zrfrS@I^_IFtYsx$Pr`+E{1{k8Vj(v8`* z(qH=*Ezot?^WL+4|C z`sW+d+j^DkqYdM>T-{huZkNnVm(1Vu$@Jeo5YzASOnnQe#BA#inDCh8>Q=e?6V%E@ zGw)B!J0`-*wA;g!yDn^l1`QPUA;V7wLV3sU-4IjFF;8*90}a-g-Qvor;K%$3T%X<0 zzVV&*Ejwj5wCemiyRV^( z0zkvjZ>GmRcXgqKc2_&T`$@H>?;}3xmAUhOFz&I|VGW(v4ob;tl%~6${sZ;5zVnkK z2i04*Z|uCD)ZcA9`d?>vo;X^a(UpQ!8wb7KIBsj})b>BV+y2fj<;%Z}5W>4%crusi z8Qj9)a+yB*x60)i#m(b$dAM?^el-xo0WkD`g8YrE`$6ljjG+E~&h9+zM4zqftBr%+ zsz3U7jXXc}#2Mt(9XY2u22xnAHlQ9%o?A$ zYSQ)zxyu~pHeiuFOd8l!MSE`I3tt-F(xVr3XsT*F=YJaNz zKZCEixJNHzwdG&mxVR~uZC%gk z%U@J{`f~RCd;Cdc2G}rHO?vL=4F1|o2Z9+|x^m?j5*JT>uTgk*R zDA#%q4^_|3bMQpQ2oE|(Gt5?e-Q_zr7srbI=~%I8z8)_mw{$g~p}gY_6lI)GU!PQF z+TR(}I##!yv0opXy!wz|*iB;zWJsXz>rUaObPi^V;YJvE+IFel=%3xK^Hc4A;!^IV zJVCc{H#aYL*a|qmt2Wz5(RFuwD4m;+c#GnN1__+o4>xpqMV9jAMr#4ZTTWZgNn3lG(^F6BMH}%J z1R;Envg-uf-Ukz6pzAABFK^>uo@RmZm==H{^@tQ&wm4d*{{tt&9+ZF2r2m-}ez0w%wK%!Xn3 z%9wfe9Q#5m!C>~WGCrg6uK`1!tP5cL4#qzl0~XBr1q(TF!K2LU6y1w~+CIJYWrUbJ_S4l_V)ns7yJf(@_}Cjo(7BqVTzUkDgR0!<(~(H z$ly7Gp8{ei8ypWr)Pj#g2+kM@ZUj;eK7C5g62V!5oX>`r;L|`@1s?;F|G$ASMc)+n z_2M1_Vn`eO9Po7DIY9Ci2y%X#;XVc=ALqBp*8n6R=dtNNe7N3c`a2-g@tok3K&FG| ztTG)*Amh^lr2nNtUnVrqgQdI=P%g;#vMwJ*_XAG^&G|z5y9nq9eJYUekMo-3=X@yL z9|JNUegEG;fWq$~9-MDA`i1`?jl3}9dCrG1E~dVw;LiCH6Z^FFeM5EIiPUF<0WjO^baih zT8mz3g}=w5|7P(gEO&dKyemxG$ge{-V zb?1C;YHw&sj`p>gz&J_Jv4e}L-RAre`#KQhpKm;jE@72(L3|rj>~EBA@$Bij)?P>NV`r^G-zHt zW;DHXi3nOEz9NvvPv>rYjP)nfD{?fw^G1=^EAo0po{;14!9XUjd1j^ zgB<*}Q*DRQjK7ncc%rGXxJLKS9QI)-g82486Pr;BPZySG`p!w4kOH!j4aauv9o|p~ zS4!oox@h{RlQx2bfjUDaf9D5c1&y-XdPrHngkXE&0RtnW|E0KR;mAma`L%`0V_^@H zfwAka)*XeRPWkP{;f`1GOvID_P*LGmk$zvG-?iJQ77Z6~4|g2M(^BFX(^3yjY3g0z z#HZ51r@+mnh)Ate+&6S1gbu~|)5@Rg z__Iv$h)Onw;x7?XXP0SxZ2LG!c125C^aUJ$3a5%=o?l1_iiQTdnnQnjH!UNyPyDs_M)$QB8Kb( zvFdQ*=6qi)8ckKuJEv<<6v6lo)N}K0UtSFA zgo?fc5TfIl$!xdo6M2wZ_o;HPTxId!@H<$hV!U=BweSZYP4}s%=Q6s_&l=q)=L|4a zf+XtZ&W@;7e=?#u)t|12a>Oyn;+b6zbV{fU9J)cNKYwsA^(R!HCN@UhjAqqbk-p6`-PqReI1oa5|H;nOA&p<>w$` z2_e17g+Cop`Pq$%hz|%gt0OBvSt&&)ipm*Vz?!d>pg(mhK`%g+8Hl78HQ)thw0Aj_ zp{^`wa%BOOq5Ud5s1;SO_0LeYDVxFH;_1+pp{@WHA%MZJ(YL#Gb1_tsVI>%-3}quC z3en#9*-9arLm7(J%u$ARy@6aFya-L5C^UZx-D!_Yp^2REcb=@8LOmC!T66yzn=Qh_o0M?Df%-I{r2F~K@&@&LDtbcjIv~Tp3dr#1 z0Ljn$naI!mJ#?QS?(ag+N&O)2kD|W#J|OwNBG?3^-Y^Oz-&7#^ULC9XwgTy138Y@} zOd!*9iXiuKkmmjlrspqsUrf&ckn#E-{r-x+BXm;eD}hWe^`hi6deL`Ko~W1o29W7k z4`e!T1Cp-^$oO9)G|y-t&HL=AFXugW)YIkx`Tl>4>Qo5)A0YML6+jH>f|G@&9*p)q z5JJ84S|HPNz2Gvz&j?-tWIAU6na8mXF3oSZo(J_mz zv*=qa`Ywy+**5O*zi!c;7X7$IM=kmqi!Qe46ObRUa?DSx`0zYKxBIgeeU`<~8B;eu z_3m!^OO}68TTNZ@f2;W99s;H3tZmaePh|m>rc%r~uI(*NE9;@ttX*2;VH9mCw1V{R zsNY7^OsWkFRCtcA19dG`5zCGZT+P(Q#(DolMLqIWvwGn#&r`%!5+)Gzuhkf-tr z@e|P=k)!E1yM?w}j7++#!UoeCY67;N#%oZ={a1 zs_VrO)6bb&3IB_S7QXVK!@u1M|K;rT_kiVK`F|taCHx=b@etCleCY7+fsY*NM>CIx z=j=MTidm;oYNfHw)Ps@S%|~`5_YRRblDn$&2+lq~ViN4ofAcMZc7;a#qZAet-gemR zqftGSAzwNEHyr|B6ZrBmW*bf3o#5kYnuGDZtLtR&RUqnM@EM)Xq9=gtul5LiBar=4 zDh$YXh1l~+!GrD++f|i~E4M)0^@y?w5#rkGL;@J$Z~d3xu2g6CB($i?W;M42GM2(sDo3qFo)F zk-zSG7Sub1IWjjydgq?4&ecJEnu+6)nGhLIhsEh;*fX-WL#FfLa&h{WPKU%6V>@KT zxLh1D2aUJcb}5tN2j!i*LUo%Q!A_jL)=nHo?nmj45<5#UPCp7=s9gQ1P^e_aRK>aE zsJ8ann)=!s%$7Bj9AD0TN@Xm&0lMn`)NXeH)Yi^#HybyYB~soEZTeH_ZYXo8{i%Op z2M&hvP)&V%Pxkq?(ju!rwX`-?O9yRgYRbb4!iGZhMNX?&bwIhIs{AL_xIe=vPv}n_ z^c>#}BJVWe-v@baBguEHM(dyTiM)X1?L_1w;}^-q&m(fQ{@Lz-(Lrw#c_l@M)<4^T z@XFwI!xYRvBg5VOGk(+f&xk-b!}Cu*v{C&tea_nAt*-ll!mriErn><{M>U$4Zohcftc{3vPAx`!X;SJdCR4R+8}V?t*ubf-|=|4wr_ zYnGj3&oF_W2|Y7spby-X0}?ks2yu>xihkZlw2Bj?ZIQ&2l*}3x?t8@R7xP{HG7;@bJWtX6 zUbGIIAH1sshW=IUXGkA@Gv3!_b>n*@d0U2mPbuJ3Gv5QLs^^rbp=fUFskyCB#06Kp z0x6d$olY(sU)Zy*T7|?UCZE-D=A8UYyi%5#fO(CW8*r{y%Vck-%7m9pCJgfALWmmV zp^D+R$|uDRi=E1?6RV@C1(O0i0SeQaRkE<0;XDOKy5SDG@=1l!ROO^V6@FG@&qc4E zvG2jAufE~xVsd{A+^|*A%#<5F?^&LFXUdjH-RqGt@lA$D*>&x#NFMO7uV<9ftA?j+ zj|^km!`e+s3Y-S#zyntUGn62r;&dBdBMk*hu~M@pqW zcA}9OJO%Gp)x~vzXliAqCJuqmC5RRA9MB`xLnT(1+AmY=0KB6jI2js#1TO$}@d0JO z0t+=*7cqrq*F|Ul0M1c#!p~%>w<_L+pd1Mm1FVHDEYY7wRUGie>dH%BPA>kbKm9X= z>ZxQZx=pYR_w_=CRRvv%xgD-5FLeU+o(uQd2guKstgB#;*DoiOFgG-ylI~45+mO2> zb#crMdUu8nt>?sEIXCY)J14MPPe&$p58jx&9yoJksvf9R=z6fp#AI+4-a`1TOHlkz z!E_`_|CLVR?^o$mO9^-yDV$LDFG10ti;_QgHEJU#(vS#M=2;K?ojjy9wfMQjdxytM zxqtvG0V0V#{zzi~`1mpK!StGy9YYn2E-jOPQ9-fdaJtgsgRt1YB;Fen$9-{sPBBmZ zp4<|aBW8z+VS`OzaPrzuyR++=ukIlM(bJvWD-UCb?mV-bT zUZ%1#$atK9%Hx(+k+tzR3Qj{);$Lf_{ zl(}x#WU{}r5s_1$3{$)C$?$%2Rho2F`JzeF;8b|aoqAm~x(ugDz52+6@wtfgcEoPt ziKbQ9rn7bvmMUPmRc|0ZJ(^fEsl=z3eet;r&s6O2IfCbeJXiZ-H_>j9FNS&Sd%1!L zTN5LxS(vGQi0={U>{dH%28XLBqaJnLgUDbee$(I@6wydJ{+y~Hx}K@h@K)@y#MW!Am7@S=kH|G$**5=B$;kN$b)}{g{Lm5%qxd& zxNoD$lEF8j6EQ_VH7PGLg6xFpbAZ*B_q7`z;fMEO_N(vbEDpBTs{*3qb-)|7N1$^M zUTQFqA-XW(^`nCOJ2~y6azFgDyutM<8@NgBA;wy9@=IPEN#*0c^ra&CxS=!^8IOgP zsYoGqiKeQaO#D7CRW>29XaA7{iGgv+iYN8UJS-Nlx(X)4RLb@vT2?0kwb%8caAGp! zz@>${x9|{rRCIF3)TYYRclkbf879_E#y5gjzwOK}?(bu9PGardhsSa2C7S!xVzv)X z>eU)bl|0l0|Gbys-pf)8dCE5P>D0ZEGJiZoAoat{_@Hn`eN)E9hHP+xFyg5FuEO6I>K!>lgCIXR=Hn?9ab z=Zcovv>r}f!q#kpYRx)yn}+sm@NFbSH#2YJd(o@BA{#c5-ut7GWS4HV zsx%|pnH~tp85iA>6j^cE&HAjxpcJBX>ng31*$!T(S$Pblqr+-ebnIAZUPJw2RIs{H zr!=|4YF0#$az(QeTg)8z5zaS9Tdvz)G~}m86YENRv3Y! zaqK>^DRUMe^-62~pGf>5b%bEjWnl1a)nKZ|9hPW%t5WNV<1?aI!i453oSMh>3cv;n zkZG~PsjDU={;>bZ#}ki_OD=q}GQAdE+U(w)^NRePUqI;Yo}ClLchS2;6fvTaq{eFS z<=)uI+rOENR2*%_yKEv<_TY72EcUv?z+v0)8GKIRXpr?hYq^ z%VmSf7P~Q1bzFB98%&`bjDjm?>D3jSC(Y{erJ64E*az8cVk~zi3LnoV_#FP@`1hYu z=JSr{Zh3V#;;Qs3=uh4o024l9JaXT(*9K7^*#CBs6TM_UNETm|rr6QZ)HNklsphi5 zUgmQ8t|f3ZEelEmc1-6-l4;uV+o-u@~Wm8ipFpY#lQY(am8F3;rFCot+MLkK)+j?g&RmDit1|toUXsT!`-&d)RyOQqc*C-|s(iOJe7^WYygwERtTh!4X)M z+#{99-`S3kG2E)gz$~5@4@FXkL3VFy7G!Tq&4TQoqUVQ2r>TkuDf=>)><1wfJ@&g8 zN2$|gRjKvN4fH@*9?Gn+kog6A+6M&Eq%@sZZsVi%@=5Ypn|q`X1Dyp=Z7e?keIa zUhxamP*;DA!l??prVaq!Qzrl~sykJ22a*s@Rk_~O9g(#9^tf~0ojuJ6VZ`WNuA^6G zM-Tcixad5v(_5tdOpbItQXK9u7~fK7aP}yJoGKzs?Oz^Uyaq@k$19Dj3#wp{>~qO zsWQD{054Wpbf;7mpzX>E8GU1T#}QyeDf{N69w1}50=MeKBiYeB(-j|AG(YXKu1ftt zi9zpNqB+@$CL_pzhK@kU@af|fKBu!~)8kFu%TwuRjZyJLcX{YUpjkb-*Wu#`=jP#J}P7Qa-1I$14H#* z&Ch%tjsI>i^bBc!=JRO$R5Whdr}>%hqw#YLy+PLL%X;rjI<0$7CP5hYZ2B;Ar;+!P z;n$(5GZ;SyzP-3}jE3(=8Iv!w5-R1)Kd$916nT749zHAo#zHT2HrAEwo2ce9i~a~C zy-VnOfER&YFZQbhmx%iXz)!(*$2VUau#g4-CM41`v4`JRUd&_y`uW)Bd}_PXSXxHv`ExPV8Sr!6e^PK>C{p zqG=&?e- zh6bVp?oR+O1pXL!KJedw=K-sL^fv=|8t6$tWJT}=6pT}VhXa|PTwFxHKNslz0nY$w z|1%)%zXxPIlfYtNi`Xv)BI|5{xXpMo(Ez+JJ=6A707!Zg7~`=7y@ntGMKMth7!-U?Ouj$_c&xHF9AoK5T;51-2@LXU$ zFo?g!K;~x@$ovcgnV)9^DSrZx^2Y*af_@m^1?D5~t)cxlfRjOg5y*J26l?}EAEQ9# z<1s+WdmG4`h081v0&>1Y3Yi zZxxW~d0={<0y4h$0`XV$ zef&_)oj|5{C2%T`_u=q8@%)?_K;EM<9Y{~ikNtT%KlTEdAA5kzkH>+O&-E!_Em|)$ zr+r9YDR>5u`N6aPXwR_*Kcjm{C;LAYf#}**-kLwrg5$q6LB3LFE5CkayMHG&N1dwSoA<_`caA~5X@!u=%my5gUZ#4>S`d7CK zZTd5J3T^sV_ZWAy+cXagZTe473T^sJzafo(vmWYY(kRazhUveZMk#Z z23Q<}Zi0uNZTSya?tifS|Jb6xX7T^ok~hzCzs90(v*>*m{Ub}>-In{K7R@6D@#mOd zTkcm{@xRI9Kgn{xz@qCc{y7%??-u`gmba_mhEZ(A=C8))IAr5A!p^(Y1#J8EzJ;|Th_dAMYX*-s%qZc1uDs0XWP_*Bdc_*%_&mu zjaTYuEVt;o241t79i+BjR5~r>jf%E+CCqYXva@|znE^k@;aQc@x#iKhm&%+yVogh~Pt(?~h$d&i*q&fM#v~i^h9w|_0&NFi|U6%{S z0NEdJt+}=d*CC+*I7wL$xuPOm9xdl_T5a{sR%&7mZS~j{*a+!TlrsD)^g(3YBv`+? z726EynIXBWfm$X_Ek)~fb?qUpW5#tpu?EdZsx^)%)z#ED*R|cy8gp)wQG#6VOY60J z#$Mmt<9MuLAnGb1CxwiQ5+STvG9>Dm$mrK;{PDE3cIU>N%;8^|IC$c&l4|@)vLr~a zlQ-r$-E#Sp*n0RGVULB5v$C=?gq9dQP-jGL)+*J=%$+8 zoo>=2nEm+1)0lmIhGsvH|L7(tbExakJ6-bVHy<6ovnU~J9s0r7jT<>fsnC7CJEh|( zB>Su$GupcG4HB<_`09Z?ba8wQ=)_9)ctno2ZhVu-i-^2_ktZbAgEyFGB89Ur+=}p^ za!~gNvX273tbKjtW!_2G5>JP2yz`ieS64^nvWx?qY>1@F8n{B>Sj^{P^$Jf0+l4!p z2TPC|%yX`W;%G0!!qiu{nz;J|;(=ulm_64T<_vZ} zye&hgU~WF(i+@}P)CDE`B>{iu4d8-9vDcy4-?>CPO!hiV_IF;Y9ZI|oCH~H{wL_WL zq0HZToOXzK9U}hD_fZnm!U0dLs{NhprK_a`9*0H#&d1?^``(#h>B@EfVul}6lUpP6TXLrLhF&`vDCPTk8n+bY*38ZickDPo;9skO*RtOk5kk(^gs zpxm#7WXy$P)?myML<#g71uIiOF5)1RA^$BSG!n^c}OH_C^T zzwvi*W_gfNhpKv(J=}t{ZC;HZeObler@){R zyqR_1o#xkJftrH!%q_zy>o|W(QpNd7IFzl%3_WjH82T6rZb>wGCD@*ZV<3`zA(F%{ zhQ~dxL(kt`jLBkEBh{REznT*t zP;=r>syT5pqwAg%$BZrx)=8?GjHF?u@m#Dhe2S^itL2=OsEYhcWEI|~Oc-K@e2khQ zpRH!dXR8_V*{&J#Ij(tE%#bhcMGz6pOf!$LfPmMvn9>_t2e)eDhEO})j)_oOe$PJ4dSp2@tAVbaJ$(;qeNGKe`T~o--lCbG?)3FpwC?)L^{MqW z*VW&khIxlJNC%f0#@Ds9>Jh&q3U`98s5in^);7iKab_{E!kt@V4uD=>rw479R?M9} ztER5DsYyAjF(cT_SdRUEHLB!*9`x8ExO|84^D;e)*+aF#OwDKHB)DSmbp`MD{=);}<}qi1wVuBXZR7 z3tu3O_~Ja5JG~=~Upf$82;MfJapm0_?(qx#^Pgpk-!6`GKCI#RB{Zy0$#B+XUO7LC z&W~O#{zxxGZcgE6FJcXn_i43UB1cazW5O{oAwj3SWe;PSh!Zc9_%dbf! zHM@{sVLa`aoiDgZuv#!8SSF~d5cv7|pufq20pgC?tt>T>9f=;2FnDBIY4FHz1`Qs& z^%EaEoX6R#`FQ^@mJFO8i6rO5D%0&t)EXzXOwSxf9Xpp%#}KmwNsoomPvY%)yawo| ziJ1jiw!fhQue<49g+@mlonVv+sfB z3CrTKc1*>$jPX5O#n;5;=)DX9899+ynQX_P3d?gHKDCO>iJcWcy)F%XMRY80YL(aj zFuL%=o7u{Q``9T_0d)1R!%%Ho{%05Ceyx$>a=4C5dcKqA+9GumRuVcV(WY*~B10Ed z?4b~Kmm3o7q9Puu+CwdJQxCArcr1Es3l=382UY;8)D6Pg=j4ARvBSv~7EH+%PFbpy zVXK+{Kl=Um;m9EM{;D|O!pQpR2u=`99#ADHn(UXObXYtx<7>7bkiSG6_4~Kzu=_qg z6obkXXPYp#8HWMQu1IP=^6nY+hW(v$5vj`bO~u$Y)e}k2!ID+%%}LKG17aK198`y@ zJ|I>i;;y#z9E>xti)mJVBn8&g{IW6O{4t7(;0c!18WsW47d+O3P|YTo87B4EK7%E8 z{>~rKF}Zj{Rl5FIjAVKdw~ah8e3B=<^U{;v=l+1oR7o_kePSfhpHIeU>XbR@@)=md zegq5FoMib7)XXu6LH?X%=dAY&^+!_$ zk@Kr|#j!!veKput_3C}-E(Ka^+hT#1Wr2CE_03Sk2SR5TpB-upoEr$om*coITwl%+ z7JE8%5U!1U1CfbdQz#_2`<&`KEXzG0-#?5wXtLak#T{#pa=KTGyL{)f{4Wvr%i%j$ z`2FI3B7Elg^0NHzQC|Wzx1TfoLh1CJs-l-2|1xpMXFI3=>QUU6h&#{s`7qcHh#&R2CVqUM9zI!r$8>N#-+oEQIl`7JT(0Lc>;6tX z2p`w;<;!|LdCxi1`vdUplW<4kI}71F2fp3H$M>#`Nw1}Mcn`g-voSvY4G?~VkE&jm zujofWr0qhkZ$ulR?)@qT9vG|FTfG5iWFK>rwcCa@Ps_w_)SqFeDpxeVh1q+BL|h`yv_Nu_sLbrrrF#_|F&j zH$=W^*Z)J@8$|w~_&4q1X(GQv{KMI!|G7;34@mmh&ZzK#G+Z~q_?i3Jw!x0>0oc1!wZ%_8pPTuvI8JWvrO~++ zP(^XcgQb5GH_pE=tzT9fZ;Ek}-0?$uH!U;kW=#R3QNOxI9SvsexNsq-rH&dGlbDdW zpnxf0irg`q|9v>>UW^oJSfu$C0^~*AG zLh_hOEWU6pBVlB{4)n^X*}37dGwHOMM4Zk>GOegz(b9Hx{6Nrmo?-n&t7@ zHv5%3YjfbMj@nGOhh?>mO*%1H-O}FJf}7nK0FtDZ8pyNcsAHA=k{qY(_vCTXug0;; zye-FyIqncTw;j^XSI5DXjgFlw*Bm=n#?el+rA~pZkjrdb(wyz#U$=)s^o>5m;(&I?IiOa8hl`Fp+Cf?dE$*|?e*Zi`Qc&Y&aw@FYYf z@!lkV=WTfK=nUhq*qp!*?k&gf;GGaaKhO&FV6Z=c5ca|zikE)OZVp6}I5K7;coM58 z`23w`;b})jAN%Ez9TokGG0n?!ppZyonFmxJJj{bfY+##VdhI|+Ujl}8Ax007+?t;K zX1H|wI`6T9DqgJ+81Ca|cJO`tlqc1y1}G}RNLwF6i%n18lxNf&OooZ9zw>`UAp+2( ztR3L7A?dh2#Go>{SLUU|O0kf7NNsQD(Gd$f%${*5&yK;YH&-Mi^AsDR%uu0~jNQaz z-0pI(Q89{)p(WXw%anxsK9Aqbok*-*533}`lq-7<))`gGHLP6u(p0*T^6VL5uYSs{ ze=4bj!l;UK;!h+O;(Eb&9}bVhQVHG*R*1XWl+0v5ZbOS-gnM<`;#YGLdV$Usym+hw z!3)QHx<0E0uMjIY)<2J8jytT9Z{hb_*s92nXEBPkHrew?H`wjPP!>{DVUk9fma8G=_M+zazJUVFo$G{fq z$2l;G;TnGz`;mB;AIGUmeCoJptiS6!>Si|iOf#g8f!LoL~{)bFexEKV%HjTU4xJ?Z?{hvp$RUHwXmlU6uCqKbyf!UlTi zWFV z2YG9CIRj$%8x~4ch?Oo-6Q7_WjRVWT>hJmyJTnBU67@2r^5ox2_v>5gdSkN^!(-!z zC-&#ZKAspJ?XEvRxaL>)-J^bWOJFQsv5X;)cqgJeUi1TFt`NKkQS)()LP%TI3YykJw!nJU${_A`gW9yjwH;cizrF1Xu6sn&@p$;HaIB06Erj_oTEdUfQI$}l zC$<$X9^O-qMkQG}3AJVHB()r^D*3d|Xu5BuhE?^2>U@OSSiG%1&`{eRXl-k`wyAza z`&ogu`rwM%>*@om8eNQ_N{LzI``{j@u!FJFe2i60zrXyGdL_F2~P~(9ofQBg=2Rsq<^ZZ_e{+Zyv3El=o z*CrST764ZO(P{-h1H`;*a1IceRdf;X1Pteo1|9?Ze;{4x^8|MQ8QwiQokjl&M87Gx zLhR>@{Y5~=<6p#{`{NiN-Xlf(r-797GqIlo#5)OoTI`Pz`@bXq(FY6uNxz4phXi?# z6#1_Q9tY%EQIy1Xbo3GRsYrs> z5iG55Yr|HMWvkj6V~Dv)UOSRnab>mE$TTjmZ;xGjLv!s4aL~4@9PK+3YP1a|6GYR( z=((e+J_ZiVXoXd`Hx@j2RG>M$XwgJ8^P>xYaS)=Qe0iHIiEcvl`3j5a=Rm3Wnj zrw+(tQuEQCiIae47;SvMNw`;wync}<KsU@}Eg%Gi%b0 z$3r&u_#F4PKc$9ORhxEHY@=kH>w{s|fFA7jJA>VA<~Tzc>~34yP=;WuuNgQ?e z4>RO1FWu|!+5!*d$@r5PcOdpN=wGd(N1xx7LVZ51NfeH&!jJ;T+5TR!gkHojeK`j$ z==5Suj~cd!=N&wkcuopOyp|pjpBPQ8%IETIxlFgK{{a*aU+i>G@0!I;ZW>SGQGzh9 zt~~i#R(6H6{jY-0a9<3+)_7h?*O_@!M!Gs7*?j_$>Kn5issoc4es6O1V*^YC49j{h zcl3dj8L1yzEcY5wzA~ntY0bl)1;Cy6+eFJ+KoeI{R+5=qih5eBJ!lTlD8F+V1~M zx7@c_GP}D&YxV(jC&B8=Si7TDSLVZY zjxybgT=7u?_1;cr&nWvuIpS!#Ov*{8$JK*juO-`;)oIDikiA0tqx4@&r zwY9msFaPvCLcRQ$!Yq+;X=wIc_>b;~GKboKVL79rJbo?n(Lkw6mDPVa_&q{p6auq^ zk$~wDc_ok+(^j6}(fUI@BIiHR2q=R_!)+w_j@4-Wp@`&LKz#IKFvbcUbiG7LAErkAHlJJoLX?^qm$BJ*0=f z!=i7o=vyti+oHc<(d`zEzJ({exJ7@>qA`B<@Ncx}f3xVXTl6<9`pXuL@3%+3s-&); z+NR|#P}?=E2&`yqUr`&YYw%rLyEITAP&*dY^RmX(^-BW{I0mM^EnvFCWWr%VfopGw z)d%WuE^SQlI&(F?Yq=OIz_Wz{jqQQvmRO)Tl*@9ej~%(davU=ggZx-SZF2w{9s^DF z&Dtf_(h_K@ZChS%k%46`Z2@d(45$%;65_BbH%N&$#oII9kUs3NbT}1hNl|Lb0OefU zxLmnmu+30>OINgpR5I#XnwPi5aZnD}0!v|keQtZ?Aye&P5BZigwqc?Qw}sZn0@%}8 z+XN+QV^dT8^4g{V(i3lPkGHnAw8fC)auySFquwXHfu%Zz$era_eq?O*%W+7=_u9r- zyF;(2Z*Q+%Ue7#r`&zMlStzgq;p=#q0BzbEf!21+!PT}wkBirp34+$`wM{X;HY1O; z9cHWz3(4x+9G=xU!ATP3YrK9%tI9J7fb4qi!MNUMUa@*B`V}_SX62#0Y{jHY3(kxR zENg6S5AY4jO26iofL3`2a9|O3dJ~MqL*CltE#A) zcg58;mGfrL@y)9&H;h--lvm82S6<<(o>OtPvYfr(ib^jIGT$*oN-4Ux>x7 zv$NT?wVT_$!(54VTVOG(vWqULsH%~qFiNgPmdf3=7@5v<7gkm(dp^`u%`2~|SX7;{ z$dwqyX&l_~(+=6maofB3r6{UX^3>sTjF8(>uZ&j5u;q5Do2qnM_r_7S3`D!D3!1YkAzN>! zoMhIL?E3Mbd~#TxDK6qezYC|NWIAlq^`l$Ws%$0*i>=3>1beLW@U4DLuNM*jS?fiL z!Gp0-a550Wi%u0<%^iYy2d7j)7;9g)2a5wN8AkRZt4CK00=)Mbjfu99# z1bznC4ZIq-8n_790K5vg2zVth0$d0z0WJVe2F?dg1YQBm2VM@`kKT7Ra4&Eka5r!+ zZ~#~Z>;qN;dx3L+8-bSryMa;QYG4G|0K62q2zUuF0;~X*0Ly`sfwO@VfwO@5z%X$C z7@w~UxEF{u5(T?~mmzykdB0gndu0#UaLHUd8e>;@hMTn#)D*Z|B2E&`%T6-0n2+UneE6ft$) zHD0wk=NehB&bLMuAP7~D$Ds_Xd8jg4z@SbkdJmXsZp1(L!|}X(ngsqyKP&VdLhlj! zD?t)@O~JdCxt#rXx=YCbF9#B2z`>!`6@?I=7gRo^w~mB7MdH)DSxKW zWkQz;&2?3Dzg*}mg#NtHpA|YG^irX}A@mBNeG!YWud!;{y^w234Ia@ zBhA-^E*1JaLSHE~_v}*s3Zc1gl=Q7ab6p(ie-oPPgNEnoQ{Hnz*9rYMp;rj~uF$K5J^_sb%`HNoC3H$?GvD;DLjMGnpXTdA zKO!`jjWhh+Li7B8(nCUX|0U^ngx)N)YA7J@QK3&qBSZ7J&=(5L{h9P%DfF*}ZV>uq zp%X&CD)he!&GXpk|9^x&AoNb5kANH9e=l^Q(C-NS384$o7}9XREBPl0&Gnw7BSLc@ zHR)@FHv4^72z`mTuN7MD|ApP1Li0OE|91;rEA&r={=CpTh32(=fjpUg|@=POnrjb0;NS&!OO51GBe~Q_E;W)%jpR}zxztE5HIhTcMsx@Ya#^%m zY=no3jr35l5g#fx@iVO7Y(xY2hrt-^;OEDqJ*MG$XPW&&v%AB8ArE=|^xbItX(*3= zsmH*0k3JT6OkVmUN#81-b5jom=A%16R z1~mA}FsPIulnp+w4dSGL!YAUN{Y(xe`p`e)+Dd+gtMN}m9{#iI#&k;%csg|Bte;*m zAJ-5^xhD9%^d)bWm+oKtNzY2!Cdk~}jGu5{6u)~JM5ur0yk$7M5W9VEIxMmMgYqc{ zD(hZ(cok!_HlGs9$9G(V?R|U-Wm~4tI(;taKoLvM2pY$n{DH$M8e< zW1r*AIarn}mJYIfHJsRfAUtJzxb!V+C$$o`LUDcpzk`iX7IGIcvtJ+oK3L1mX6|i{ z%Fi<8htU|E0S0~Ep|iiZTED_@@(sMjaJqa_j`zq=!E#t}{W;t5I`A0NiHBo8HkKLhF&l)U zo+Rh_bK>J!@a0;c-XpCVCFk-F-J3GD-uo=rQt!P<&Lv~~lrihkFHMZQJj9b4dibUdY0fR zf^Q%Y`unvC&R5h1BtLZHYMpzjxI>3ZQ?vv>@H(zcFdzs}_S|pC_3!38sPtlEp$o>p z@OZ{ay|Co^cIvfhuE9U|Blhd~`CcUrw;pl7NZd{N+9~cFztME#U+s599B8jvah*v#)Tsa2xYNYGNxuRWF<$j=zg=eFZof{vxjCD zd(X>hZ~9;DPwtWOV)~PYMz`l9^(Rkp$z##mhac3d58azfzn$B1h{_whA|U1vDKZPgAOmYB0}4va>(A1mRItwh!0?%+;S{ zQqev2^iM$^l5zTz3&RWMd;24aZEvDqVRb9nqs-B*%ydVx`yn;#hfGC3g#C+y^gm`= z{f|iB7%`FLnC-Lkedz5Rd1&2{oc)o+fg`OBARF<`E%*ud@o{La>BFAQKFgGf^d;!S zR$zl%1cy_1f`h%LEgfqxDZ=wc!tC#^`Rh=?(_v9Ub%$jYg-%WmfGvhoH;%aZoNP|r zH@Ov@s%vL;ZPK4R>YYfs@~Fc$zm1PB&eQHVe@y(S;YZOiOT2qv-Rp^Whht~Dx~&&y z2cY{aUuIP9%64sseYh`$-@!Eqp`0f;>nn8zSAk|%25X)?T^aEDe9z!NSAS#=9bqoU z$K#{)M_Q#HK>5m;en5_XLnRo@emaKd;g^2H@u*1o_)fpB-HV+8G&f40u@5xWGBLnm7wIpt2RLAZ}?%wGIMcd~dZ54m?n{7NUH zZ$EI2ubuBH^)pXGKa>1NG&!8yT|Q;c+R2{gm*1Vux^e!D3FHAZxx+)JMC$gLEz^;@ z_o8*rMW(z^nTKQQv^IwKE{H0I?X#)^b&R9S)aqwe9CkNt2v=plx2%4&2!%D7_s)N?)K3a<11-)whRvk`zX z?XICeYP)-lYGgC*ZZ`_dOa|~F_0&d=ls8|q8DLNrjHi(VJ(`}nRpPaTo?$v54^5@7 z>}aR|?h!d!ySq!|^(txTH;6nT*`79-XCj4jT(Jn@u`jW=06GX1Sf;NU|1{*`KkA|S zRviQUu*PWzIj+EgXAvCo0c|H#oj5enIcW~v>55%ceEyOOY;Pld1A>%BI*3P{&z4-+ zi^C14+#L0^ql#}eIKq9?@VgiPzR*rr5a(CyiXVffJI8ev;q7QwqUpuQ;RKD1(K=jX zQqdyj z={1vv%$XihFu0C-^mkT+12-#G)!~*{k#fIC(Px(QxMJKroASDb*WCzJ@n53I?Yz)4 zk^A@IQv(NIh19TzG6$I3H9&p6{Af8p3;!~Vj`9KAhM;rP6b0&CREJ z#ItX)nFTl8cQ1YiIqE?1?x;+vOG3lxMZ@9rnu$&USOfRUq}<1eE#m&p@4}`$dCvm8 z#LDDDivY=Amrwaa@+&-u6&c%|jt(W$OG(u2j3m`5thfcZDt(q8C!lscQ|^zv9I1P> z(jP@v182hMo&}C%<#DaiyqBu-4xrzmYe0v3dsXSBr%cFtkC-=#B!888i{S_1e>gT@ zl0WpR>~!mFy%`Bm(zFj=?!$_T<9PQ(ZrR4{bRD9o7*i^3TmEuNG+lWLZb*I)ch!{s zBAk3-)sZYP(bAuc^Ey~&!O^-bx z`OcK5b$Psf!Ndv0g^2v{&iFrg6lvY!LX(0GJU<=A5MHQVcjv|jtl(0cs?q1dFkMq*Qwap8;eHj2Izp3GgUc^mkjrpCkLl& zIX}(Px$dg$5}^$$1ANbx)((Dc7Mrx%%Pi`*X{y46G89 zM9I4%h!iRWUs@#jl@fruZ0w<8T9_kHQ5$j7R9YoS2{)|=>R$ItkcCU5ahqIa^4@BA z^RIuJ;_LQ@UaU;t%gP9C7q6Ahyid$?MYimn*j;glek$y)NO!MY-@W*Yywe%qnR^*8 z6%?!Y&s212%?RSUUq;t){T5s|qtl8My^Rx_?r4?E2~xD1aR_NX4HJ?!yu{bf$Q6gxC9 zUqNRpmwN|0J1{Td>yXQxHG#$+7jeA9aZw@lb1)2F88hA);T))bxvz-v@$grB=f^0Y zt-m>Eit$s%$hY_}%~$=qU;v0NUhpk+ps_w9_$&}(mkXZ+7J|MDNcU!-AGlC(CJ4XA4vZ#K=dDjR|645@Nyvfj=`Bgm?G{oA!}C zln9#n!3m)0e=Lyx@73?8=&L}+pI4Dn9>*P&*NOZk&2{9Y7Xm5I=m)2RMp+1c3dnHZ zhj4~VeI?WP0FeH^4P-hJK!(dNKGU-V2vbxd7y#0}3<#0qND~1HzYK!oSu+k%>(P-H zrr-Z%@NqnA$}i)u#0_hp=mW%sdB%bC6_*eQygh5j$?i0oTf5471jOoOKn||D) zi!B;^hCKY-FW~n7w&l+K25xtb+uii9EdIY(^yL=4+M<_R^u-p9JujZ{S}oc;(9TTu zshy6V8$sj>5o@9|`_2#^_SxQ0%Q;azm8<>h7)I7ydt-fDi)%*IHK%DE@1-X{t1i6+ zGQ>&Wy^^gHaP46I7WU z*j(G>aN#UdiseNy&2a?fj+ZwJN6;W=qOBM*2`2f!qTiTWGGl5$8GQ~IE`d4Q(Osbo z{Ihyx?vJA}`VB*)xuxEVYEWek^&Bv{pUu%LuZEE6l<*<-8%7S)2Fi?OWL!p?1;=JI z{f1A{84w?ZkjEyN?TOT5kI2#V8v&6Q5qZTTPe`_@4d$6h;b@nA0fdL|m#+*7+XVz) zmVSf0%y)e6KD4p*8ddPbEtCs3+0Cl+5r#M zPwLZ((>elGh0O0%xR2p07WC;j&`WHa?CL%;&e7D(C84)M&xCd=zHoAz(z8SFlNUP+ z6UqLrD)h3lQ`Vv6JBoDP^6(&Jm3d_;F(D;pTuw2!C^1V-G&y;1CWkhnk<{uQB#F5%hPSs+|UMIE{l-2m_eE;e=b)IWc5RVdrwJHX8=ZpbL;5=0V z)w^(Bv(g5Y>Hv6&dM1hGsrm=~ohQR7`)zPqJKXnUS3n$P{T+(|>1%M%JnS(KFW`Zr zE`As5;LR9*KR(KMsbB7MFy9|%9?2Rn{T%W+{@4VBDY^@Y&T+5{$o}+FalcgDFA(=n z0`aK`9uDOA<}G}LIPUoakn(ur4&`kIQr>rf_PkGl{HKcjL?DtJWIs9|$ngpBHNoEtJ}0;ZNdMmh!W6B<52|i(1rXoG;8MZQ z2`&(<6a?_QKJFpXNQ-%&+ejlK=KBpE&p712NyDAz1JGQ6fASc^Z@8PTwdgNc^fZfR zbL;jWwdikH^cOAqYKz9Z^vGLf(Tx^8$)a_qS5M6G$e9}4l!)_O6tZuuo~^M0Sad%g z59D!(#`YR@z>(@;!*NBtNeNQ@c+e|ro8t8~SQ(*g+vC?NTwaI!2;jQ3aiu~WyyW=g zvz#hr#WZIR`y=dgnO^KUXP3uHxjWdo`qyQwBLV!wd;R(GS!@w$5zdDxjS5vc~Vi60qWrl=af;ga<`u0Kq>Uoa-HP1^EW5k-lTj^3rDxo1GupnHC6Wgd#ACmt+sI*-xy@+(_0=M8k9eY9g(4d=@$-lrt-sE5 zC}_-ldml2-9YwU+4Vpv$lAU$E2jLwH*Zb6p6jts!Pb5@M=XiB|uQX?A$a=M9+I~cLQ?Ewy-!qE; zUEFK|nN*esFA}_05R!Tm8<>k)ftSui@0=nFlV$U=l%8%}dC>FVg$(%)| zHGZ-U#LZxiLCXZ5btjY)tZ~Wqqt%}dquj-vrDk*mqEAng=&6)AzP(pSS#I8w+HyNe z{Jf5gqSr>pl6Jn2w7%=ykVpTCVz|dWPHbjhbC1Z=qSSW|B`9Mkoc*(E zgm)sX(ctYvW58rplZIh@_|K@)9xNZ)us>Fj!~(2=(9USGUte_Knm_mITW@)FH$tdL zK81UlIo%#rOKoK~K9W>(>1v%>5hKFeQ1x{F67cS&RaMs?tNi7!KwqLrE{Va!eh4{= zTVaQjTVfXg55$kSA6l~Ep>sfdP@a6}X780#UxA>_-S`Rj@zbm%4gM855v7V|Yc#bs zpzOlQ9pS_dsK)+$L`IpamKON$o4J`Sb$RzY&;Ft7@3CT!VpGZQQu0~gl&nZfB?%E8 zq^bhTy0H8P_c_H6$J(;tfpqMc!%Fvs9|pT`ZI0M-SRd}=$4JMP&3(ERYlL3vxZsor z{attBeMj_qB4i_H;;}{|00`su=VaGpK27;~IK6f_`A|7s_01G27jQ+gjv^J8%@kC3 zui{BzITKkYgdi-Rk9ALA1x6vCl6Os1umho%;HfIPM+uQPatFjDR7iM>ilH*qrF^9B zQbJQIPX6@?Bq`BnA5J`WAk=Tx8{Izs z2yS@p+!@cuA{wj-S@YLQz4W1C%8rhAu$U&zZ1;C@;<;<*>Z8k(`=<<)?)G=_OO4#Y zatfAaBr2uWpr~A9&R-38c`d@TnelPldDD_Oz^hsfllltZg~P#HdBdf@i%p77`CYW` zg~*t@_-2fs3p-+$MAB` zIGlWGusbIs$6w(-zIGLzq3g3{g%wN6VVRrF@&(26HT+svjk)UfH;n-1x-Nt&NU4gF ze6bp1RJKNknAUE@_Ac>igKF%ys)p`)+>eI^o(C`q z6!n+?##{-fH}ds{%kf^9~C;l95z*pDOF%H-M}v^TBr8%@5@ z^eK{?m>J%)KIf9E48wP;?YcP&J zIWd9t=76df?B}CcuI+VK8qBzC^mqQ245^Bq%DO#dFehfv@1tuT~YCwR(jxl7$(ZN}k8@ zdrWQUWl>%5`I5iuQZV*0k1-?AGi3lP6jd0zr|d&0vpZrle0g1O`PUC3Sy&l1Bdru+nkLQ&Zlqta}O)JLaY*oQhXjmHyl(@GDT`ZWG zY7X5oZKG!nE6=qq>se523JkyIE6jrIz-HCj?*Mwiq`~$+=(tmuK5z~ zd#0fd3?|Eep>&Y{9hEzm{|VY(*7~$bu%{lP=Pl$2jKmMQ>eWMV{9lg$jl#!xDr5Mp zb!L00osB^P;vW125M#|C z&mH1C%QG1KbN=E!!LJD>fyl(78-eJL23G(P$6zIp>$1)TLMIbE6G-{5>-;Uc2MAq5 zum^~~Z16_0zZi%-4h|z<@EH6P5dGrdqd>;zJ|MlpQ_&xR{{r`&K&JN|Ak*6^c&*^&K&E#Vkm=<;k<2fiH_CKw)+MS) z-IEP^k|bDbh@%;Qaa|+z8)p3U3Tb4t8LvzP&2?&~o_v)w+&9U1X4?Pb?p@%c zs;>RdbEMT3tz0}0GX0#QJ*6%!1BM1e#yqp=l@O;Q=hPlSeh8+Df<2$@i2#pmd-f{YAafmnxn5CCU#0GIS`tQ|apvhbSlf zmk&?*@J1j0j1T{+5C1nG&KI0JziJusZ~!~LwHN6 zj$x4zN7s}eu^&4e1MXShW?@+GEg4VhA@_h4(JH&=d2uzkrGa|1yNkHQEcq}fyJ7jK~vCgJ%+_V8_GwB z;1M~NzNbUEIX*CKPjH}j{)-9>U+q;A77n(J!`peHU8ky z=cwP2cl%2 zx~J=fi|VRUJKe*xvyxA@3!{5)%AT1eu8vlLnKROY${T`w6zqtR% zO>P+OBEv^eG-p2`@84Y`Uqm;!^Elae*)^yZ8|06V%V_lkn=7(Zm~US zr(?&71;9BEvh8>uanS9$5lEhSRD;qtK_&xlH`CkubQ^J`&nW#g;FMv*bX>S`&cobz z?psuj#NpXU;xNo-GBf%UA%D*D(BHQX zGZQaTF+&d-J9Hi^Hr9JI!nO_JhrsvffTsZ^+WEHuorR%6?}x?hdlbXIgz>&d@7BC1 z54Sn6ADs{1SNYaqeCsA&JDE)?XQ{qS4ggZ#7QA@MD9;zhvXj}*#0WPT5QwpYuAtR- zV#ZpB;kh;p4O&k6m1R)}@Uh2tBZ5cdSnuV2^W7QPtMX_cuT>Xekl8F3`j5i-UM|NA zWENni2n-m>R_x_ssLkJErr$FOZ$vLUj#$nH@ZfSO1?LizGOeE8iTV|gnr(|;ZtRb z(KC{KkD*bKH!-+56MQ%`0ejUk^H{c%+<8Mm-q_s8P;OM-n6kXFxsm0$QF&u3^Ty^z zMslO_#>Dc*=0@6QAeZ8eS?Wa{OdrFXwM#sfp0L$}buO>xp%8$7o0 zC|o)BR!(g7mj48U+GcQwA-x)n9vOq)Fb2JI40_)f^voFa!7=D|QpfibLT>#vW;A+4 z>GLFU?!14rd3`DPIj=9%{npyPIrDGwRpA#J2j6P&6_10DbLXOQ@bUY)U>tlefiEx) zKHA|OJZQc*4p(39Wj-(tzU#oZU-|U@I zTk$o372sb5h;NjVTEO#x&r>`MNcm?eemo%MPfhX z4t;rHA0Xyva<1RI0r~xfcV{8(>2S{q>lBXxVyr9-0b)K^NPSfy{{T@2Ilu1$z(KUb zB)|+Han3PN1Ua{l>8M-7R8`LH!)0NE@+}3#lwHp2W4dzSc;^)sDZKy??}oztsHfxu zh&mT$6z>PbR94RCBYhKaOqC1Ul->-;a>W#n0J2;mK+FQgUXxXdARqiq4k;u;d=Pwu z8HIfcI~6u4j3^8#1dw#i6b=Cq{2182{QkAy8=oMK0$r%{`;CgvP@H}ONWVaF?(-r3 zA;te$@rdHzQhc`Jobr($3yl(XC>~ebo+q|I@t-K&e!s|hVu;J25gC3@I)3Gl$#4`P z@hwWHzXReKrQ7qr{-X5rNyqOP&F>P$Pf>i1;%6v6U-4Hp{UYL^+3%NSiZ>LP^05EN zI*PXURVWMBX)2Ze5ZHo!;1}!i3BIJ(%GVr+|e~1q*!k6(Qy^{#S@08xA^j{#3^bCmzJU@@=GfD?Z=t9K5 zdo=xC{l43+^gdy)#~3K`LrVXWra!3iZv&1$CzRpJjZgK_ z|G`I}@59&naITZN08WAul3?E_8CzXvfk}X!hg3b}L#Szq-wT;rfV62Z+tY+bYd6L6yoQuAsRxX#$ET2^$ zt(mv*DnUgqj$^N$S8XD4Z-nT*a$DL_hq;;#x#o*z3rc)WBf4d0Tg}63+rh)?iDYBg z2)34R=CqK+QmNdCjc;CRd(+MJiG(Wa?4eNhP$zq)lRYEKbt;&q$esyi&xmqP1oP*# zJP8*Wp7Ltm-bl;l?v|cH+Eb})hR&H(wn(l;yLwY;)_+vL$}>WtndKEwG0qS@BaTEWO@- zWsND^s`9J^%*C4RH6exbTbb{3>KZbD9f06-^m;4@f8=G^bm+&`_=9J?4gNUcui`m) z9NZR9y`5VBn3US(f&!bt=@sI7x|z6E_LtQLzw*2GAeP5i|7iVSl+)-lhcCd};| z!dKND!1JvSov3`Ht?yXB#7r;2es}onkRAjP?Hs-z5N#e#E99CY`dOIY2Y8Lk_W=4| znClt^fB?K#lh*)po+Y(4ah`d?Qp5#$GkIeXs`1lH!THVV#!G$p0w0cVArC*kF+8}8 zMfIzi);6t!tDbt>7yj*%3teV1)2P;5ankZa9g}{@X$Zga)QTu(%zEa8D(Scm3l6{lKO? zjzb5rNrDU1KspI*7;C-4%F*)(0{8I-x`GzhiQ#&McOQy(J!Km{DjE8;Es8KPX8HC` zHG61<==wL-`bV8USkl%=w+)Lt?7j`BJMuh59BZ81B#T6NW+(*V00u$56nwOC@&NL? z4IG{4;C+Le<{l>_i06-0j^bB|-;o9xC$FZ*;-XmU0F10@-=5qLKcFvFz+r6MaRi)L z5Nkx7P%B2{F^4OT#K})^bjB!Vy|_He()fH^axfA9jnV$=aVd#q(Z5Jew{xG@<|+>@ zzIRufoM4j8VwsfimD{uLj*FgT&JqI~;r-j$lZ_8!dS3py5PCBF{s|=C1^Zl+81~0q zPn&F=eZ*1JpKj~nwRlb_mhK3}({lmaLMkIM33j+8N`#9TA(kmIcpn!sq#n+`>GUn3 zif7D1imN{VbM5t}?Se z)AA>wt`;o_Us{<2mJ74hELQo$*eB#^QVRPSn$Z`XubAJ;Wn=0sh>oX|MKLqs(sm8{ z1mf7Eb-t+FJQ53iEJ$@JWEYPq`@Oz|=qYFlbR6StEWPY$j8QHZV;tiWXUfxs4v;t% z{Q>(WcwSN0)5Td^ts%$=c%ydu$J1Ea`+RV`lkt9!9baYB%E%$8e4d?WDUD&8gcFP;dyabk#es)c7wIqW_ zX3KRF2}OQ+HRt{BPq7eeY1p~u3?C} z^}l5KcVW=2NwpUQyV*CMBKgu8)b|DY zA1hRixxY+yW?^KDrI!{+#xgJ`&+NLSC^;1$2@nJUscHzqbt7JL$*dS`Cw+qs@x|WS z9xm>GU%Q_#%ujL1#?Rt%&IWhbv*06%V#Ðf6^8&c5vg6>ySmOX#%E(ZP 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�r8A}kN;5d1B(Az@en_> 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%0DV;G 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

{ks)$4JNPb< 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ஹLMwL4MUFO`JrLR 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

H49|j{0cN2Jzi8-?@ND5R9W; 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

(auw~^KYilrCzbJHTy<+n&&Od!E%Z7 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

Jsy^^@)?!UmHRsQ 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,ANFx+iFd1t@P8{ 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

lST@FN0}E#nHNWy7e|>F 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

{ks)$4JNPb< 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ஹLMwL4MUFO`JrLR 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

H49|j{0cN2Jzi8-?@ND5R9W; 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

(auw~^KYilrCzbJHTy<+n&&Od!E%Z7 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

Jsy^^@)?!UmHRsQ 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,ANFx+iFd1t@P8{ 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

lST@FN0}E#nHNWy7e|>F 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 Y)hT@txvB!XVUIZ{&PGJPbzb5B1y|afvH$=8 From 41b3230a9ffa0b3125712b5f148e4cad24905117 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 15:38:31 +0200 Subject: [PATCH 438/465] Update version and README --- .gitignore | 1 + README.md | 29 +++++++++++++++++++++++++---- purple-plugin/telegram-purple.h | 4 ++-- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 1fbc4b6..d9775cd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ telegram *.o *.so *.a +telegram-adium/libcrypto.a config.h config.log config.status diff --git a/README.md b/README.md index 86180e5..e6ea9bd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Telegram-purple is a Libpurple plugin that adds support for the Telegram messeng This plugin is based on [Telegram-cli](http://github.com/vysheng/tg), a full-featured terminal-based client for Telegram created by [Vysheng](http://github.com/vysheng). -# Version 0.2.0 +# Version 0.3.0 Warning, this version is mainly for development and testing and NOT for productive use.Even though it already provides basic features, you should still expect bugs and crashes when running it. @@ -20,6 +20,7 @@ When encountering a crash or some other bugs, please report it to us, preferably * Discover buddy state and info - Profile Pictures * Download and use profile pictures + - Adium Plugin ## TODO: @@ -31,12 +32,11 @@ The following features are currently planned and will probably be added in the f - Geo-locations - Multiple accounts on one client - Respect libpurple proxy settings (implemented but untested) - - Adium Plugin ## Platform Support -We only provide an installation guide for Linux right now, even though it should be possible to compile this plugin on other platforms. If someone manages to create a working Windows, BSD or OSX build, please let us know. +We only provide an installation guide for Linux right now, even though it should be possible to compile this plugin on other platforms. If someone manages to create a working Windows or BSD-build please let us know. # Installation Instructions @@ -80,7 +80,6 @@ NOTE: Ubuntu is currently not working, since libpurple doesn't seem to find libs sudo zypper install gcc glib glib-devel libpurple libpurple-devel zlib-devel openssl libopenssl-devel - ## 3. Compile and install make @@ -105,3 +104,25 @@ Now you should be able to see all your contacts and chats in your buddy list and The Telegram phone applications for iOS and Android make use of standardized Unicode smileys (called [Emojis](https://en.wikipedia.org/wiki/Emoji)). Pidgin does not display those smileys natively, but you can install a custom smiley theme like (https://github.com/stv0g/unicode-emoji) or (https://github.com/VxJasonxV/emoji-for-pidgin) and activate it under Settings > Themes > Smiley Theme. + +# Adium Plugin + +We will provide a readily build bundle soon, until then you can try to build the XCode-Project yourself if you want. + +1. Compile your Adium-Version and point the Telegrm-Adium build settings to its build-output. +2. Get zlib and libcrypto.a and provide it somewhere in your build path. +3. Build the XCode-Project, click on + + +# Authors + +Telegram-Purple and Telegram-Adium was written by: + + + - Matthias Jentsch + - Christopher Althaus + - Markus Endres + + +The plugin is based on Telegram-CLI, which was written by Vitaly Valtman and others, see (http://github.com/vysheng/tg) + diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 25344e9..4704116 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -22,8 +22,8 @@ #define TELEGRAM_AUTH_MODE_SMS "sms" #define TG_AUTHOR "Christopher Althaus , Markus Endres , Matthias Jentsch " #define TG_DESCRIPTION "A protocol plugin that adds support for the Telegram messenger." -#define TG_VERSION "0.2.0" -#define TG_BUILD "2" +#define TG_VERSION "0.3.0" +#define TG_BUILD "3" #include #include "notify.h" From 17e925e4ef3005c95ad2a6dc6089ae75e500242a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 20:53:14 +0200 Subject: [PATCH 439/465] Add Makefile target "purge" to delete all user data --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 24b09db..58490b5 100644 --- a/Makefile +++ b/Makefile @@ -104,6 +104,10 @@ uninstall: $(PRPL_LIBNAME) run: install pidgin -d | grep 'telegram\|plugin\|proxy' +.PHONY: purge +purge: uninstall + rm -rf $(HOME)/.telegram-purple + .PHONY: debug debug: install ddd pidgin From 3773562201365f968b098875b3135d478ae8f84a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 20:54:24 +0200 Subject: [PATCH 440/465] Do not compile on uninstallation --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 58490b5..83289e9 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ install: $(PRPL_LIBNAME) install -D purple-plugin/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png .PHONY: uninstall -uninstall: $(PRPL_LIBNAME) +uninstall: rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) rm -f /etc/telegram/server.pub rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png From 290a3251e6aa9b664a665ea92871f5ac546abb40 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 6 Oct 2014 22:56:02 +0200 Subject: [PATCH 441/465] Remove unused code --- msglog.c | 23 ----------------------- msglog.h | 1 - purple-plugin/telegram-purple.c | 17 +---------------- structures.c | 1 - telegram.c | 14 -------------- telegram.h | 3 --- 6 files changed, 1 insertion(+), 58 deletions(-) diff --git a/msglog.c b/msglog.c index a2c59f2..029a426 100644 --- a/msglog.c +++ b/msglog.c @@ -10,29 +10,6 @@ #define COLOR_GREEN "\033[32;1m" #define COLOR_NORMAL "\033[0m" -/** - * Log a message to the telegram-cli message log, by - * just writing it to STDOUT and appending '***' - */ -void log_printf(const char *format, va_list ap) -{ - vprintf (format, ap); -} - -/** - * The callback that will log the given msg to the used target - */ -void (*log_cb)(const char* format, va_list ap) = log_printf; - -/** - * Set a custom logging callback to use instead of the regular - * printf to stdout - */ -void set_log_cb(void (*cb)(const char*, va_list ap)) -{ - log_cb = cb; -} - void hexdump (int *in_ptr, int *in_end) { int *ptr = in_ptr; while (ptr < in_end) { printf (" %08x", *(ptr ++)); } diff --git a/msglog.h b/msglog.h index 952b61c..17e324d 100644 --- a/msglog.h +++ b/msglog.h @@ -4,7 +4,6 @@ * Set a custom logging callback to use instead of regular printing * to stdout */ -void set_log_cb(void (*cb)(const char*, va_list ap)); void hexdump (int *in_ptr, int *in_end); void debug(const char* format, ...); diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 24e9116..0014d95 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -61,17 +61,6 @@ PurpleGroup *tggroup; void tgprpl_login_on_connected(); -/** - * Formats the given format string with the given arguments and writes - * it to the libpurple log - */ -void tg_cli_log_cb(const char* format, va_list ap) -{ - char buffer[256]; - vsnprintf(buffer, sizeof(buffer), format, ap); - purple_debug_info(PLUGIN_ID, "%s", buffer); -} - void message_allocated_handler (struct telegram *instance, struct message *M); void peer_allocated_handler (struct telegram *instance, void *user); void user_info_received_handler (struct telegram *instance, struct tgl_user *user, int showInfo); @@ -934,7 +923,6 @@ static GList *tgprpl_status_types(PurpleAccount * acct) static void tgprpl_set_status(PurpleAccount * acct, PurpleStatus * status) { purple_debug_info(PLUGIN_ID, "tgprpl_set_status()\n"); - } /** @@ -1229,10 +1217,7 @@ static void tgprpl_init(PurplePlugin *plugin) PurpleAccountOption *option; PurpleAccountUserSplit *split; GList *verification_values = NULL; - - // Redirect the msglog of the telegram-cli application to the libpurple logger - set_log_cb(&tg_cli_log_cb); - + // Extra Options #define ADD_VALUE(list, desc, v) { \ PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ diff --git a/structures.c b/structures.c index ed30181..79df0bd 100644 --- a/structures.c +++ b/structures.c @@ -39,7 +39,6 @@ DEFINE_TREE(peer,peer_t *,peer_cmp,0) DEFINE_TREE(peer_by_name,peer_t *,peer_cmp_name,0) DEFINE_TREE(message,struct message *,id_cmp,0) - struct message message_list = { .next_use = &message_list, .prev_use = &message_list diff --git a/telegram.c b/telegram.c index 8c27259..941e9dd 100755 --- a/telegram.c +++ b/telegram.c @@ -454,20 +454,6 @@ void telegram_dl_next (struct telegram *instance) } } -/** - * Login, and perform a registration when needed - */ -int telegram_login(struct telegram *instance) -{ - if (instance->session_state != STATE_AUTHORIZED) { - debug("Cannot log in, invalid state: %d \n", instance->session_state); - return -1; - } - do_help_get_config(instance); - telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); - return 0; -} - void on_authorized(struct mtproto_connection *c UU, void *data) { debug ("on_authorized()...\n"); diff --git a/telegram.h b/telegram.h index 5901518..95fdde7 100644 --- a/telegram.h +++ b/telegram.h @@ -331,8 +331,6 @@ void telegram_change_state(struct telegram *instance, int state, void *data); */ void telegram_connect(struct telegram *instance); -int telegram_login (struct telegram *instance); - /** * Read and process all available input from the network */ @@ -425,7 +423,6 @@ struct mtproto_connection *telegram_add_proxy(struct telegram *tg, struct proxy_ int telegram_authenticated (struct telegram *instance); void telegram_flush (struct telegram *instance); - void telegram_dl_add (struct telegram *instance, struct download *dl); void telegram_dl_next (struct telegram *instance); From 2f7f2068deaddef67116915e9509abe244b2fc68 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 6 Oct 2014 22:57:20 +0200 Subject: [PATCH 442/465] Improve event handling-system --- mtproto-client.c | 17 ++- purple-plugin/telegram-purple.c | 71 ++++++++++-- queries.c | 2 +- telegram.c | 68 +++--------- telegram.h | 187 +++++++++++++++++++++----------- 5 files changed, 216 insertions(+), 129 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 1c7a635..a0a9018 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -938,9 +938,9 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { peer_id_t chat_id = MK_CHAT (fetch_int (self)); peer_id_t id = MK_USER (fetch_int (self)); - peer_t *C UU = user_chat_get (bl, chat_id); - peer_t *U UU = user_chat_get (bl, id); - event_update_user_typing(tg, U); + peer_t *C = user_chat_get (bl, chat_id); + peer_t *U = user_chat_get (bl, id); + event_update_chat_user_typing(tg, C, U, 0); if (log_level >= 2) { //print_start (); //push_color (COLOR_YELLOW); @@ -1004,6 +1004,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { fetch_skip_str (self); fetch_skip_str (self); } + event_update_user_name (tg, UC); } break; case CODE_update_user_photo: @@ -1050,6 +1051,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { fetch_file_location (self, &t); } } + event_update_user_photo(tg, UC); fetch_bool (self); } break; @@ -1125,12 +1127,15 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { } //pop_color (); //print_end (); + if (C) { + event_update_chat_participants(tg, C); + } } break; case CODE_update_contact_registered: { peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (bl, user_id); + peer_t *U = user_chat_get (bl, user_id); fetch_int (self); // date //print_start (); //push_color (COLOR_YELLOW); @@ -1140,6 +1145,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { printf (" registered\n"); //pop_color (); //print_end (); + event_update_user_registered(tg, U); } break; case CODE_update_contact_link: @@ -1193,6 +1199,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { s, location); //pop_color (); //print_end (); + event_update_auth_new(tg, location); tfree_str (s); tfree_str (location); } @@ -1333,6 +1340,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { printf ("\n"); //pop_color (); //print_end (); + event_update_chat_add_participant(tg, C, user_id, inviter_id); } break; case CODE_update_chat_participant_delete: @@ -1356,6 +1364,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { printf (" deleted\n"); //pop_color (); //print_end (); + event_update_chat_del_participant(tg, C, user_id, 0); } break; case CODE_update_dc_options: diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 0014d95..dd58418 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -401,10 +401,53 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa conn->mtp = telegram_add_proxy(tg, req, fd, conn); } -void telegram_on_disconnected (struct telegram *tg) +void telegram_on_error (struct telegram *tg, const char *err) { - debug ("telegram_on_disconnected()\n"); - assert (0); + debug ("telegram_on_error()\n"); + telegram_conn *conn = tg->extra; + + purple_connection_error_reason(conn->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, + err); +} + +void on_update_user_name (struct telegram *tg, peer_t *user) +{ + +} + +void on_update_user_photo (struct telegram *tg, peer_t *user) +{ + +} + +void on_update_user_registered (struct telegram *tg, peer_t *user) +{ + +} + +void on_update_chat_participants (struct telegram *tg, peer_t *chat) +{ + +} + +void on_update_chat_add_participant (struct telegram *tg, peer_t *chat, peer_id_t user, peer_id_t inviter) +{ + +} + +void on_update_chat_del_participant (struct telegram *tg, peer_t *chat, peer_id_t user, void *_ UU) +{ + +} + +void on_update_chat_user_typing (struct telegram *tg, peer_t *chat, peer_t *user, void *_ UU) +{ + +} + +void on_update_auth_new (struct telegram *tg, char *location) +{ + } struct telegram_config tgconf = { @@ -415,15 +458,29 @@ struct telegram_config tgconf = { telegram_on_phone_registration, telegram_on_client_registration, telegram_on_ready, - telegram_on_disconnected, + telegram_on_error, - message_allocated_handler, + // user peer_allocated_handler, - user_info_received_handler, - download_finished_handler, on_new_user_status, on_user_typing, + on_update_user_name, + on_update_user_photo, + on_update_user_registered, + + // chat + on_update_chat_participants, + on_update_chat_add_participant, + on_update_chat_del_participant, + on_update_chat_user_typing, + + // misc + on_update_auth_new, + message_allocated_handler, + download_finished_handler, + user_info_received_handler, on_chat_joined + }; diff --git a/queries.c b/queries.c index a714543..238016a 100644 --- a/queries.c +++ b/queries.c @@ -1865,7 +1865,7 @@ void end_load (struct telegram *instance, struct download *D) { //update_prompt (); close (D->fd); debug ("Done: %s\n", D->name); - event_download_finished_handler(instance, D); + event_download_finished (instance, D); instance->dl_curr = 0; if (D->dc != telegram_get_working_dc(instance)->id) { debug ("%d Not the working dc %d, closing...\n", D->dc, diff --git a/telegram.c b/telegram.c index 941e9dd..6ddadec 100755 --- a/telegram.c +++ b/telegram.c @@ -15,29 +15,8 @@ #include "loop.h" - /* - * New message received - */ -void event_update_new_message(struct telegram *instance, struct message *M) -{ - if (instance->config->on_msg_handler) { - instance->config->on_msg_handler (instance, M); - } -} - -/* - * Peer allocated - */ -void event_peer_allocated(struct telegram *instance, void *peer) -{ - if (instance->config->on_peer_allocated_handler) { - instance->config->on_peer_allocated_handler (instance, peer); - } -} - -/* - * Peer user fetched full + * Events */ void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int show_info) { @@ -46,42 +25,28 @@ void event_user_info_received_handler(struct telegram *instance, struct tgl_user } } -/* - * Download finished - */ -void event_download_finished_handler(struct telegram *instance, struct download *D) -{ - if (instance->config->on_download_finished_handler) { - instance->config->on_download_finished_handler (instance, D); - } -} +DEFINE_EVENT_HANDLER (peer_allocated, void); +DEFINE_EVENT_HANDLER (update_user_status, void); +DEFINE_EVENT_HANDLER (update_user_typing, void); -/* - * User status changed - */ -void event_update_user_status (struct telegram *instance, void *peer) -{ - if (instance->config->on_update_user_status_handler) { - instance->config->on_update_user_status_handler (instance, peer); - } -} +DEFINE_EVENT_HANDLER (update_user_name, peer_t); +DEFINE_EVENT_HANDLER (update_user_photo, peer_t); +DEFINE_EVENT_HANDLER (update_user_registered, peer_t); -/* - * User typing changed - */ -void event_update_user_typing (struct telegram *instance, void *peer) -{ - if (instance->config->on_update_uesr_typing_handler) { - instance->config->on_update_uesr_typing_handler (instance, peer); - } -} +DEFINE_EVENT_HANDLER (update_chat_participants, peer_t); +DEFINE_EVENT_HANDLER_3(update_chat_add_participant, peer_t *, peer_id_t, peer_id_t); +DEFINE_EVENT_HANDLER_3(update_chat_del_participant, peer_t *, peer_id_t, void *); +DEFINE_EVENT_HANDLER_3(update_chat_user_typing, peer_t *, peer_t *, void *); +DEFINE_EVENT_HANDLER (update_auth_new, char); +DEFINE_EVENT_HANDLER (update_new_message, struct message); +DEFINE_EVENT_HANDLER (download_finished, struct download); /** * Calculate the configuration path for the given config file and the given instance * - * @returns The full path to the configuration. + * @returns The full path to the configuration. * * NOTE: the returned string must be freed manually using gfree */ @@ -93,7 +58,8 @@ char *telegram_get_config(struct telegram *instance, char *config) /** * Return whether the current client is registered. */ -int telegram_is_registered(struct telegram *tg) { +int telegram_is_registered(struct telegram *tg) +{ return telegram_get_working_dc(tg)->has_auth; } diff --git a/telegram.h b/telegram.h index 95fdde7..eebf435 100644 --- a/telegram.h +++ b/telegram.h @@ -109,6 +109,46 @@ struct proxy_request { struct telegram; struct download; + +/* + * Events 1 arg + */ + +#define DEFINE_EVENT_LISTENER(E_NAME, D_TYPE) void (*on_ ## E_NAME) (struct telegram *tg, D_TYPE *data); + +#define DECLARE_EVENT_HANDLER(E_NAME, D_TYPE) \ +void event_ ## E_NAME (struct telegram *tg, D_TYPE *data) + +#define DEFINE_EVENT_HANDLER(E_NAME, D_TYPE) \ +void event_ ## E_NAME (struct telegram *tg, D_TYPE *data) \ +{ \ + if (tg->config->on_ ## E_NAME) { \ + tg->config->on_ ## E_NAME (tg, data); \ + } else { \ + warning ("Trying to execute non-existing event listener %s\n", "E_NAME"); \ + } \ +} + +/* + * Events 3 args + */ + +#define DEFINE_EVENT_LISTENER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) void (*on_ ## E_NAME) (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3); + +#define DECLARE_EVENT_HANDLER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) \ +void event_ ## E_NAME (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3) + +#define DEFINE_EVENT_HANDLER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) \ +void event_ ## E_NAME (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3) \ +{ \ + if (tg->config->on_ ## E_NAME) { \ + tg->config->on_ ## E_NAME (tg, data, data2, data3); \ + } else { \ + warning ("Trying to execute non-existing event listener %s\n", "E_NAME"); \ + } \ +} + + /** * Contains all options and pointer to callback functions required by telegram */ @@ -161,48 +201,105 @@ struct telegram_config { /** * A callback function that is called when telegram is disconnected */ - void (*on_disconnected) (struct telegram *instance); - - /** - * A callback function that is called when a new message was allocated. This is useful - * for adding new messages to the GUI. - */ - void (*on_msg_handler) (struct telegram *instance, struct message *M); + void (*on_error) (struct telegram *instance, const char *err); /** * A callback function that is called when a new peer was allocated. This is useful * for populating the GUI with new peers. */ - void (*on_peer_allocated_handler) (struct telegram *instance, void *peer); + DEFINE_EVENT_LISTENER(peer_allocated, void); + + /** + * A callback function that is called when a user's status has changed + */ + DEFINE_EVENT_LISTENER(update_user_status, void); + /** + * A callback function that is called when a user starts or stops typing + */ + DEFINE_EVENT_LISTENER(update_user_typing, void); + DEFINE_EVENT_LISTENER(update_user_name, peer_t); + DEFINE_EVENT_LISTENER(update_user_photo, peer_t); + DEFINE_EVENT_LISTENER(update_user_registered, peer_t); + + DEFINE_EVENT_LISTENER(update_chat_participants, peer_t); + + /** + * A new user is added to a chat + * + * @param data1 The chat + * @param data2 The added user + * @param data3 The inviter + */ + DEFINE_EVENT_LISTENER_3(update_chat_add_participant, peer_t *, peer_id_t, peer_id_t); + + /** + * A user is deleted from a chat + * + * @param data1 The chat + * @param data2 The added user + * @param data3 NULL + */ + DEFINE_EVENT_LISTENER_3(update_chat_del_participant, peer_t *, peer_id_t, void *); + + /** + * A user in a chat is typing + * + * @param data1 The chat + * @param data2 The user + * @param data3 NULL + */ + DEFINE_EVENT_LISTENER_3(update_chat_user_typing, peer_t *, peer_t *, void *); + + /** + * A new device was registered for @location + * + * @param tg + * @param location + */ + DEFINE_EVENT_LISTENER(update_auth_new, char); + + /** + * A callback function that is called when a new message was allocated. This is useful + * for adding new messages to the GUI. + */ + DEFINE_EVENT_LISTENER(update_new_message, struct message); + + /** + * A callback function that is called when a download is completed. This is useful + * for populating the GUI with new user photos. + */ + DEFINE_EVENT_LISTENER(download_finished, struct download); + /** * A callback function that is called when a peer user info was received. This is useful * for populating the GUI with new user photos. */ void (*on_user_info_received_handler) (struct telegram *instance, struct tgl_user *peer, int showInfo); - /** - * A callback function that is called when a download is completed. This is useful - * for populating the GUI with new user photos. - */ - void (*on_download_finished_handler) (struct telegram *instance, struct download *D); - - /** - * A callback function that is called when a user's status has changed - */ - void (*on_update_user_status_handler) (struct telegram *instance, void *peer); - - /** - * A callback function that is called when a user starts or stops typing - */ - void (*on_update_uesr_typing_handler) (struct telegram *instance, void *peer); - /** * A callback function that is called when chat info is received */ void (*on_chat_info_received) (struct telegram *instance, peer_id_t chatid); }; +DECLARE_EVENT_HANDLER (peer_allocated, void); +DECLARE_EVENT_HANDLER (update_user_status, void); +DECLARE_EVENT_HANDLER (update_user_typing, void); + +DECLARE_EVENT_HANDLER (update_user_name, peer_t); +DECLARE_EVENT_HANDLER (update_user_photo, peer_t); +DECLARE_EVENT_HANDLER (update_user_registered, peer_t); + +DECLARE_EVENT_HANDLER (update_chat_participants, peer_t); +DECLARE_EVENT_HANDLER_3 (update_chat_add_participant, peer_t *, peer_id_t, peer_id_t); +DECLARE_EVENT_HANDLER_3 (update_chat_del_participant, peer_t *, peer_id_t, void *); +DECLARE_EVENT_HANDLER_3 (update_chat_user_typing, peer_t *, peer_t *, void *); +DECLARE_EVENT_HANDLER (update_auth_new, char); + +DECLARE_EVENT_HANDLER (update_new_message, struct message); +DECLARE_EVENT_HANDLER (download_finished, struct download); + #define MSG_STORE_SIZE 10000 /** @@ -362,53 +459,11 @@ int network_verify_registration(const char *code, const char *sms_hash); int network_verify_phone_registration(const char *code, const char *sms_hash, const char *first, const char *last); -/** - * Retur if the current phone is registered in the given network. - */ -int network_phone_is_registered(); - -/** - * Return if the current client is registered. - */ -int network_client_is_registered(); - -/** - * Export the current registration to all available data centers - */ -void network_export_registration(); - -/** - * Fetch all unknown messages of the current session - */ -void session_get_difference(); - -/** - * Fetch all known contacts - */ -void session_update_contact_list(); - -/* - * Events - */ -void event_update_new_message(struct telegram *instance, struct message *M); -void event_update_user_status(struct telegram *instance, void *peer); -void event_update_user_typing(struct telegram *instance, void *peer); - -/* - * Load known users and chats on connect - */ -void event_peer_allocated(struct telegram *instance, void *peer); - /* * Load known users and chats on connect */ void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int showInfo); -/* - * Load known users and chats on connect - */ -void event_download_finished_handler(struct telegram *instance, struct download *D); - /** * Set the connection after a proxy_request_cb * From 7d63485e0af22a54aa2fe6568bea5f7d9ac95ea2 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 6 Oct 2014 22:58:16 +0200 Subject: [PATCH 443/465] Fail gracefully on error responses by server --- purple-plugin/telegram-purple.c | 5 ++++- queries.c | 15 ++++++++------- telegram.c | 3 ++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index dd58418..d28d44a 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -314,7 +314,10 @@ void client_registration_entered (gpointer data, const gchar *code) void client_registration_canceled (gpointer data) { struct telegram *tg = data; - // TODO: disconnect and exit + telegram_conn *conn = tg->extra; + + purple_connection_error_reason(conn->gc, + PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled"); } gboolean queries_timerfunc (gpointer data) { diff --git a/queries.c b/queries.c index 238016a..633ca26 100644 --- a/queries.c +++ b/queries.c @@ -423,14 +423,14 @@ int send_code_on_error (struct query *q UU, int error_code, int l, char *error) if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { int want_dc_num = error[s] - '0'; tg->auth.dc_working_num = want_dc_num; - telegram_change_state(tg, STATE_ERROR, error); + telegram_change_state(tg, STATE_DISCONNECTED_SWITCH_DC, error); } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { int want_dc_num = error[s2] - '0'; tg->auth.dc_working_num = want_dc_num; - telegram_change_state(tg, STATE_ERROR, error); + telegram_change_state(tg, STATE_DISCONNECTED_SWITCH_DC, error); } else { fatal ( "error_code = %d, error = %.*s\n", error_code, l, error); - assert (0); + telegram_change_state(tg, STATE_ERROR, error); } return 0; } @@ -462,7 +462,7 @@ void do_send_code (struct telegram *instance, const char *user) { } else if (instance->session_state == STATE_CLIENT_NOT_REGISTERED) { telegram_change_state(instance, STATE_CLIENT_CODE_REQUESTED, NULL); } else { - debug("do_send_code() Invalid State %d, erroring\n", instance->session_state); + fatal ("do_send_code() Invalid State %d, erroring\n", instance->session_state); telegram_change_state(instance, STATE_ERROR, NULL); } } @@ -476,8 +476,8 @@ int phone_call_on_answer (struct query *q UU) { } int phone_call_on_error (struct query *q UU, int error_code, int l, char *error) { - debug ( "error_code = %d, error = %.*s\n", error_code, l, error); - assert (0); + fatal ( "error_code = %d, error = %.*s\n", error_code, l, error); + telegram_change_state(q->data, STATE_ERROR, error); return 0; } @@ -545,6 +545,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error } else { failure ( "error_code = %d, error = %.*s\n", error_code, l, error); telegram_change_state(instance, STATE_ERROR, error); + return -1; } telegram_change_state(instance, STATE_DISCONNECTED_SWITCH_DC, &instance->auth.dc_working_num); @@ -587,7 +588,7 @@ int nearest_dc_on_answer (struct query *q UU) { int fail_on_error (struct query *q UU, int error_code UU, int l UU, char *error UU) { fatal ("error #%d: %.*s\n", error_code, l, error); - assert (0); + telegram_change_state(q->data, STATE_ERROR, error); return 0; } diff --git a/telegram.c b/telegram.c index 6ddadec..771840a 100755 --- a/telegram.c +++ b/telegram.c @@ -79,10 +79,11 @@ void telegram_change_state (struct telegram *instance, int state, void *data) case STATE_ERROR: { const char* err = data; if (err == NULL) { - err = ""; + err = ""; } debug("telegram errored: %s\n", err); mtproto_close (instance->connection); + instance->config->on_error (instance, err); } break; From dd27d4f66c99c2d959cba889a9cae8cf7b132daf Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 6 Oct 2014 22:59:18 +0200 Subject: [PATCH 444/465] Remove unused includes from XCode project --- telegram-adium/telegram-adium.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj index 069b0c7..afda2f9 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -426,7 +426,6 @@ "/Users/matj/Library/Developer/Xcode/DerivedData/Adium-gdwrwbgfopymlzesvaaamabjdyym", "/Users/matj/Development/adium-1.5.10/Frameworks", "/Users/matj/Development/adium-1.5.10/build/Debug", - /Volumes/Workspace/adium/Frameworks, "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -463,7 +462,6 @@ "/Users/matj/Library/Developer/Xcode/DerivedData/Adium-gdwrwbgfopymlzesvaaamabjdyym", "/Users/matj/Development/adium-1.5.10/Frameworks", "/Users/matj/Development/adium-1.5.10/build/Debug", - /Volumes/Workspace/adium/Frameworks, "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; From 056d7c7c199f9ca0a19d0009ce6e4c7a89bd310d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Mon, 6 Oct 2014 23:18:45 +0200 Subject: [PATCH 445/465] Improve README and update to version 0.3.1 --- README.md | 41 ++++++++++++++++++++++++++------- purple-plugin/telegram-purple.h | 4 ++-- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e6ea9bd..c5bf76b 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,25 @@ Telegram-purple is a Libpurple plugin that adds support for the Telegram messeng This plugin is based on [Telegram-cli](http://github.com/vysheng/tg), a full-featured terminal-based client for Telegram created by [Vysheng](http://github.com/vysheng). +# Changelog -# Version 0.3.0 - -Warning, this version is mainly for development and testing and NOT for productive use.Even though it already provides basic features, you should still expect bugs and crashes when running it. +Warning, this version is mainly for development and testing and NOT for productive use. Even though it already provides basic features, you should still expect bugs and crashes when running it. When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace of the crashed application [https://developer.pidgin.im/wiki/GetABacktrace] +## Version 0.3.1 + + - Improve error handling + - Fix some installation problems + + +## Version 0.3.0 + + - Provide Adium Plugin + + +# Features + ## Already Implemented: - Chats/Group-Chats @@ -82,6 +94,7 @@ NOTE: Ubuntu is currently not working, since libpurple doesn't seem to find libs ## 3. Compile and install + make sudo make install @@ -99,10 +112,17 @@ The username is your current phone number, including your full country prefix in Now you should be able to see all your contacts and chats in your buddy list and send/receive messages. -# Unicode Emojis for Pidgin +# Troubleshooting + +If you encounter problems running this plugin and you have updated from an older version, +deleting your old user-data might be helpful. WARNING: This will require you to enter a new authentication +code and delete all your secret chat keys. + +To clean all your user files run: + + + sudo make purge -The Telegram phone applications for iOS and Android make use of standardized Unicode smileys (called [Emojis](https://en.wikipedia.org/wiki/Emoji)). Pidgin -does not display those smileys natively, but you can install a custom smiley theme like (https://github.com/stv0g/unicode-emoji) or (https://github.com/VxJasonxV/emoji-for-pidgin) and activate it under Settings > Themes > Smiley Theme. # Adium Plugin @@ -114,10 +134,15 @@ We will provide a readily build bundle soon, until then you can try to build the 3. Build the XCode-Project, click on +# Unicode Emojis for Pidgin + +The Telegram phone applications for iOS and Android make use of standardized Unicode smileys (called [Emojis](https://en.wikipedia.org/wiki/Emoji)). Pidgin +does not display those smileys natively, but you can install a custom smiley theme like (https://github.com/stv0g/unicode-emoji) or (https://github.com/VxJasonxV/emoji-for-pidgin) and activate it under Settings > Themes > Smiley Theme. + + # Authors -Telegram-Purple and Telegram-Adium was written by: - +Telegram-Purple and Telegram-Adium were written by: - Matthias Jentsch - Christopher Althaus diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 4704116..72c09d4 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -22,8 +22,8 @@ #define TELEGRAM_AUTH_MODE_SMS "sms" #define TG_AUTHOR "Christopher Althaus , Markus Endres , Matthias Jentsch " #define TG_DESCRIPTION "A protocol plugin that adds support for the Telegram messenger." -#define TG_VERSION "0.3.0" -#define TG_BUILD "3" +#define TG_VERSION "0.3.1" +#define TG_BUILD "4" #include #include "notify.h" From 531d27ef6133d996f5deb9339d065d3f03f2b443 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 9 Oct 2014 20:12:22 +0200 Subject: [PATCH 446/465] Set Build-Target for Adium Plugin to OSX 10.8 and include AppKit --- .../telegram-adium.xcodeproj/project.pbxproj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj index afda2f9..44109a7 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410948919BB2D7D0083BF3F /* CoreFoundation.framework */; }; C410949019BB2D7D0083BF3F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C410948E19BB2D7D0083BF3F /* InfoPlist.strings */; }; C410949B19BB337A0083BF3F /* TelegramPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = C410949A19BB337A0083BF3F /* TelegramPlugin.m */; }; + C466937819E703370036A108 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C466937719E703370036A108 /* AppKit.framework */; }; C4877C1819BB37EA006FA91F /* TelegramService.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1719BB37EA006FA91F /* TelegramService.m */; }; C4877C1A19BB3D91006FA91F /* telegram-purple.c in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1919BB3D91006FA91F /* telegram-purple.c */; }; C4877C1E19BB676B006FA91F /* AdiumTelegramAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */; }; @@ -51,6 +52,7 @@ C410949119BB2D7D0083BF3F /* telegram-adium-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "telegram-adium-Prefix.pch"; sourceTree = ""; }; C410949919BB337A0083BF3F /* TelegramPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramPlugin.h; sourceTree = ""; }; C410949A19BB337A0083BF3F /* TelegramPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramPlugin.m; sourceTree = ""; }; + C466937719E703370036A108 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; C4877C1619BB37EA006FA91F /* TelegramService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramService.h; sourceTree = ""; }; C4877C1719BB37EA006FA91F /* TelegramService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramService.m; sourceTree = ""; }; C4877C1919BB3D91006FA91F /* telegram-purple.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "telegram-purple.c"; path = "../purple-plugin/telegram-purple.c"; sourceTree = ""; }; @@ -106,6 +108,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C466937819E703370036A108 /* AppKit.framework in Frameworks */, C49A915819BBC5C5001B3DC0 /* libz.dylib in Frameworks */, C49A915619BBC278001B3DC0 /* libcrypto.a in Frameworks */, C4B81AE519E084C300E9177C /* libgmodule.framework in Frameworks */, @@ -154,6 +157,7 @@ C410948819BB2D7D0083BF3F /* Frameworks */ = { isa = PBXGroup; children = ( + C466937719E703370036A108 /* AppKit.framework */, C4B81AE419E084C300E9177C /* libgmodule.framework */, C4B81AE219E084B800E9177C /* libglib.framework */, C4B81AF419E087C500E9177C /* Adium.framework */, @@ -374,7 +378,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.8; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; @@ -408,7 +412,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.8; SDKROOT = macosx; }; name = Release; @@ -445,6 +449,7 @@ ); OTHER_CFLAGS = "-DPURPLE_STATIC_PRPL"; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx10.8; WRAPPER_EXTENSION = AdiumLibpurplePlugin; }; name = Debug; @@ -481,6 +486,7 @@ ); OTHER_CFLAGS = "-DPURPLE_STATIC_PRPL"; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx10.8; WRAPPER_EXTENSION = AdiumLibpurplePlugin; }; name = Release; From b2d3a39fb4004ab58b5d62017b8d4b3e9c0f8b67 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 9 Oct 2014 20:13:08 +0200 Subject: [PATCH 447/465] Do not use colors when compiling for production mode Pidgin and Adium debug logs do not display terminal color codes correctly, avoid that. --- msglog.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/msglog.c b/msglog.c index 029a426..4ded692 100644 --- a/msglog.c +++ b/msglog.c @@ -3,12 +3,21 @@ #include "debug.h" #include "purple-plugin/telegram-purple.h" +#ifdef DEBUG #define COLOR_GREY "\033[37;1m" #define COLOR_YELLOW "\033[33;1m" #define COLOR_RED "\033[0;31m" #define COLOR_REDB "\033[1;31m" #define COLOR_GREEN "\033[32;1m" #define COLOR_NORMAL "\033[0m" +#else +#define COLOR_GREY "" +#define COLOR_YELLOW "" +#define COLOR_RED "" +#define COLOR_REDB "" +#define COLOR_GREEN "" +#define COLOR_NORMAL "" +#endif void hexdump (int *in_ptr, int *in_end) { int *ptr = in_ptr; From d66775cc70b638f84aca2a557f2354f5ad9f3268 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 9 Oct 2014 20:20:21 +0200 Subject: [PATCH 448/465] Avoid compiler warnings --- purple-plugin/telegram-purple.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index d28d44a..9ae32c0 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -1109,7 +1109,7 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) for (i = 0; i < cnt; i++) { peer_id_t part_id = MK_USER((curr + i)->user_id); char *name = g_strdup_printf ("%d", part_id.id); - int flags = PURPLE_CBFLAGS_NONE | peer->chat.admin_id == part_id.id ? PURPLE_CBFLAGS_FOUNDER : 0; + int flags = PURPLE_CBFLAGS_NONE | ((peer->chat.admin_id == part_id.id) ? PURPLE_CBFLAGS_FOUNDER : 0); debug ("purple_conv_chat_add_user (..., name=%s, ..., flags=%d)", name, flags); purple_conv_chat_add_user( purple_conversation_get_chat_data(conv), @@ -1119,10 +1119,10 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) 0 ); } - struct message *M = 0; + debug ("g_queue_pop_head()\n"); - - while (M = g_queue_pop_head (conn->new_messages)) { + struct message *M = 0; + while ((M = g_queue_pop_head (conn->new_messages))) { debug ("adding msg-id\n"); int id = get_peer_id(M->from_id); if (!chat_add_message(instance, M)) { From 8a63df1529541c2ff98f3c5e48cf1b0bfbd6c3bf Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 9 Oct 2014 20:21:12 +0200 Subject: [PATCH 449/465] Fix TelegramService settings --- telegram-adium/TelegramService.m | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/telegram-adium/TelegramService.m b/telegram-adium/TelegramService.m index c4ed743..2ba4d15 100644 --- a/telegram-adium/TelegramService.m +++ b/telegram-adium/TelegramService.m @@ -49,7 +49,7 @@ - (NSString *)userNameLabel { - return @"Phone Number"; + return @"Phone number\n(with country prefix)"; } - (BOOL)supportsProxySettings{ @@ -78,7 +78,7 @@ - (BOOL)isSocialNetworkingService { - return YES; + return NO; } - (AIServiceImportance)serviceImportance{ @@ -88,7 +88,6 @@ - (NSCharacterSet *)allowedCharacters{ return [[NSCharacterSet illegalCharacterSet] invertedSet]; } - - (NSCharacterSet *)allowedCharactersForAccountName { return ([NSCharacterSet characterSetWithCharactersInString: @"+1234567890"]); @@ -99,10 +98,6 @@ return 16; } -- (NSCharacterSet *)ignoredCharacters{ - return [NSCharacterSet characterSetWithCharactersInString:@"/-"]; -} - - (BOOL)caseSensitive{ return NO; } From 531a36fa63e5da5d194bb2e2f7274c2f9f56d7ec Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 9 Oct 2014 20:26:47 +0200 Subject: [PATCH 450/465] Add comments and logging messages to event listener stubs --- purple-plugin/telegram-purple.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 9ae32c0..6aa2768 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -415,42 +415,50 @@ void telegram_on_error (struct telegram *tg, const char *err) void on_update_user_name (struct telegram *tg, peer_t *user) { - + debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); + // Update user name } void on_update_user_photo (struct telegram *tg, peer_t *user) { - + debug("on_update_user_photo(id=%d, type=%d)\n", user->id.id, user->id.type); + // Update user photo } void on_update_user_registered (struct telegram *tg, peer_t *user) { - + debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); + // Notify about a new user } void on_update_chat_participants (struct telegram *tg, peer_t *chat) { - + debug("on_update_chat_participants(chat.id=%d)\n", chat->id.id); + // Refresh chat participants } void on_update_chat_add_participant (struct telegram *tg, peer_t *chat, peer_id_t user, peer_id_t inviter) { - + debug("on_update_chat_add_participant(chat.id=%d)\n", chat->id.id); + // Add chat participant } void on_update_chat_del_participant (struct telegram *tg, peer_t *chat, peer_id_t user, void *_ UU) { - + debug("on_update_chat_del_participant(chat.id=%d)\n", chat->id.id); + // Remove chat participant } void on_update_chat_user_typing (struct telegram *tg, peer_t *chat, peer_t *user, void *_ UU) { - + debug("on_update_chat_user_typing(chat.id=%d, user.id=%d)\n", chat->id.id, user->id.id); + // Set or unset user in chat typing } void on_update_auth_new (struct telegram *tg, char *location) { - + debug("un_update_auth_new(location=%s)\n", location); + // Info: new device authenticated for this phone number } struct telegram_config tgconf = { @@ -483,7 +491,6 @@ struct telegram_config tgconf = { download_finished_handler, user_info_received_handler, on_chat_joined - }; From a8f228cef58cb1e1790f315a8b90539adab9d49d Mon Sep 17 00:00:00 2001 From: mjentsch Date: Thu, 9 Oct 2014 20:55:55 +0200 Subject: [PATCH 451/465] Upgrade to version 0.3.2 --- README.md | 18 +++++++++++++++--- telegram-adium/AdiumTelegramAccount.m | 1 + .../telegram-adium/telegram-adium-Info.plist | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c5bf76b..b8bd9ac 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,11 @@ Warning, this version is mainly for development and testing and NOT for producti When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace of the crashed application [https://developer.pidgin.im/wiki/GetABacktrace] +## Version 0.3.2 + + - Add compatibility for OSX 10.8 + + ## Version 0.3.1 - Improve error handling @@ -127,11 +132,18 @@ To clean all your user files run: # Adium Plugin -We will provide a readily build bundle soon, until then you can try to build the XCode-Project yourself if you want. +## Prebuilt Bundle -1. Compile your Adium-Version and point the Telegrm-Adium build settings to its build-output. +This bundle was tested to work under OSX 10.9 and 10.8. If it doesn't work on your installation +please send your Adium crash log (which you can find in ~/Library/Logs/Adium 2/). + +[Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.2.zip) + +## Build with XCode + +1. Compile the source of your current Adium version and add the created frameworks to the Adium-Telegram build path. 2. Get zlib and libcrypto.a and provide it somewhere in your build path. -3. Build the XCode-Project, click on +3. Build the XCode-Project and execute the created bundle # Unicode Emojis for Pidgin diff --git a/telegram-adium/AdiumTelegramAccount.m b/telegram-adium/AdiumTelegramAccount.m index 154664e..0843d26 100644 --- a/telegram-adium/AdiumTelegramAccount.m +++ b/telegram-adium/AdiumTelegramAccount.m @@ -15,6 +15,7 @@ */ #import "AdiumTelegramAccount.h" +#import @implementation AdiumTelegramAccount diff --git a/telegram-adium/telegram-adium/telegram-adium-Info.plist b/telegram-adium/telegram-adium/telegram-adium-Info.plist index 775c6b7..1fadca5 100644 --- a/telegram-adium/telegram-adium/telegram-adium-Info.plist +++ b/telegram-adium/telegram-adium/telegram-adium-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.0 + 0.3.2 CFBundleSignature AdIM CFBundleVersion From 2bebb7ab62ed95acc5e2cbab681ea59d87190e66 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 10 Oct 2014 17:16:16 +0200 Subject: [PATCH 452/465] Display time correctly and don't display empty messages --- purple-plugin/telegram-purple.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 6aa2768..f51be8a 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -542,13 +542,13 @@ static int chat_add_message(struct telegram *tg, struct message *M) // chat initialies, add message now if (M->from_id.id == tg->our_id) { serv_got_chat_in(conn->gc, get_peer_id(M->to_id), "You", - PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); + PURPLE_MESSAGE_RECV, M->message, M->date); } else { peer_t *fromPeer = user_chat_get (tg->bl, M->from_id); char *alias = malloc(BUDDYNAME_MAX_LENGTH); user_get_alias(fromPeer, alias, BUDDYNAME_MAX_LENGTH); serv_got_chat_in(conn->gc, get_peer_id(M->to_id), alias, - PURPLE_MESSAGE_RECV, M->message, time((time_t *) &M->date)); + PURPLE_MESSAGE_RECV, M->message, M->date); g_free(alias); } return 1; @@ -565,8 +565,8 @@ void message_allocated_handler(struct telegram *tg, struct message *M) telegram_conn *conn = tg->extra; PurpleConnection *gc = conn->gc; - if (M->service) { - // TODO: handle service messages properly, currently adding them + if (M->service || (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED))) { + // TODO: handle those messages properly, currently adding them // causes a segfault for an unknown reason debug ("service message, skipping...\n"); return; @@ -585,9 +585,9 @@ void message_allocated_handler(struct telegram *tg, struct message *M) case PEER_USER: debug ("PEER_USER\n"); if (M->from_id.id == tg->our_id) { - serv_got_im(gc, to, M->message, PURPLE_MESSAGE_SEND, time((time_t *) &M->date)); + serv_got_im(gc, to, M->message, PURPLE_MESSAGE_SEND, M->date); } else { - serv_got_im(gc, from, M->message, PURPLE_MESSAGE_RECV, time((time_t *) &M->date)); + serv_got_im(gc, from, M->message, PURPLE_MESSAGE_RECV, M->date); } break; @@ -1282,7 +1282,6 @@ static void tgprpl_init(PurplePlugin *plugin) } PurpleAccountOption *option; - PurpleAccountUserSplit *split; GList *verification_values = NULL; // Extra Options From 61c8735578bb49f379f2e69dd30ddd9081af3b7c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 10 Oct 2014 17:26:31 +0200 Subject: [PATCH 453/465] Force-free all open connections on close --- mtproto-client.c | 4 ++-- mtproto-client.h | 2 +- purple-plugin/telegram-purple.c | 16 +--------------- telegram.c | 2 +- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index a0a9018..784fc40 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1915,7 +1915,7 @@ void mtproto_close_foreign (struct telegram *instance) /** * Free all destroyed connections */ -void mtproto_free_closed (struct telegram *tg) { +void mtproto_free_closed (struct telegram *tg, int force) { int i; for (i = 0; i < 100; i++) { if (tg->Cs[i] == NULL) continue; @@ -1923,7 +1923,7 @@ void mtproto_free_closed (struct telegram *tg) { debug ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", i, c->c_state, c->destroy, c->queries_num); if (c->destroy == 0) continue; - if (c->connection->out_bytes > 0) { + if (!force && c->connection->out_bytes > 0) { debug ("still %d bytes ouput left, skipping connection...\n", c->connection->out_bytes); continue; } diff --git a/mtproto-client.h b/mtproto-client.h index fe6dcc1..073e353 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -508,7 +508,7 @@ static inline void hexdump_out (struct mtproto_connection *self) { void my_clock_gettime (int clock_id, struct timespec *T); void mtproto_close_foreign (struct telegram *instance); -void mtproto_free_closed (struct telegram *tg); +void mtproto_free_closed (struct telegram *tg, int force); #endif diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index f51be8a..30a5ddf 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -213,21 +213,7 @@ static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition con telegram_flush (conn->mtp->instance); // free all mtproto_connections that may have errored - mtproto_free_closed(conn->mtp->instance); - } -} - -/** - * Telegram announced that it awaits new input from the read-handle - * TODO: this is currently unused, evaluate wether its needed at all - */ -static void tgprpl_has_input(void *handle) -{ - debug("tgprpl_has_input()\n"); - mtproto_handle *conn = handle; - if (! conn->rh) { - conn->rh = purple_input_add(conn->fd, PURPLE_INPUT_READ, tgprpl_input_cb, handle); - debug("Attached read handle: %u ", conn->rh); + mtproto_free_closed(conn->mtp->instance, 0); } } diff --git a/telegram.c b/telegram.c index 771840a..6999e9a 100755 --- a/telegram.c +++ b/telegram.c @@ -193,7 +193,7 @@ void telegram_destroy(struct telegram *this) } free_queries (this); free_timers (this); - mtproto_free_closed (this); + mtproto_free_closed (this, 1); free_bl (this->bl); free_auth (this->auth.DC_list, 11); From 4843c4052df832446703d3d057a1c00cc98b5e55 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 10 Oct 2014 17:28:10 +0200 Subject: [PATCH 454/465] Remove linebreaks from user names --- structures.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/structures.c b/structures.c index 79df0bd..4073ae0 100644 --- a/structures.c +++ b/structures.c @@ -183,10 +183,21 @@ long long fetch_user_photo (struct mtproto_connection *mtp, struct tgl_user *U) return 0; } +void sanitize_alias(char *buffer) +{ + size_t len = strlen(buffer); + gchar *curr; + while ((curr = g_utf8_strchr(buffer, len, '\n'))) { + *curr = 0x20; + } +} + int user_get_alias(peer_t *user, char *buffer, int maxlen) { char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; + sanitize_alias (last_name); + sanitize_alias(first_name); if (strlen(first_name) && strlen(last_name)) { return snprintf(buffer, maxlen, "%s %s", first_name, last_name); } else if (strlen(first_name)) { From d5fb1601b7cf20ca81f52459ea139df0acfe55ea Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 14 Oct 2014 18:53:59 +0200 Subject: [PATCH 455/465] cleanup useless comments --- mtproto-client.c | 1 - net.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/mtproto-client.c b/mtproto-client.c index 784fc40..2aad896 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1884,7 +1884,6 @@ void mtproto_close(struct mtproto_connection *mtp) { } stop_ping_timer (mtp->connection); } - // remove all ping timer that point to this connection } /** diff --git a/net.c b/net.c index 89dfc50..bc0c7aa 100644 --- a/net.c +++ b/net.c @@ -67,7 +67,6 @@ int ping_alarm (struct connection *c) { warning ( "fail connection: reason: ping timeout\n"); c->state = conn_failed; fail_connection (c); - } else if (get_double_time () - c->last_receive_time > 5 * PING_TIMEOUT && c->state == conn_ready) { debug ("sending PING...\n"); int x[3]; @@ -327,11 +326,8 @@ int try_write (struct connection *c) { x += r; c->out_head->rptr += r; if (c->out_head->rptr != c->out_head->wptr) { - // Inhalt des Buffers nicht komplett abgeschickt, - // es geht nichts mehr in den Socket break; } - // buffer ausgelesen, alten buffer löschen struct connection_buffer *b = c->out_head; c->out_head = b->next; if (!c->out_head) { From 2b366fe1a842fef7f3c23f54138afe9156a6688b Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 14 Oct 2014 18:59:04 +0200 Subject: [PATCH 456/465] Fix segfaults on disconnect --- net.c | 6 +++++- telegram.c | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/net.c b/net.c index bc0c7aa..f4a17d5 100644 --- a/net.c +++ b/net.c @@ -81,7 +81,11 @@ int ping_alarm (struct connection *c) { } void stop_ping_timer (struct connection *c) { - remove_event_timer (c->instance, &c->ev); + if (c->ev.self) { + remove_event_timer (c->instance, &c->ev); + } else { + warning ("trying to stop non-existing ping timer fd: #%d\n", c->fd); + } } void start_ping_timer (struct connection *c) { diff --git a/telegram.c b/telegram.c index 6999e9a..0bd80d3 100755 --- a/telegram.c +++ b/telegram.c @@ -206,9 +206,9 @@ void telegram_destroy(struct telegram *this) g_free(this->secret_path); // TODO: BN_CTX *ctx - free (this->phone_code_hash); - free (this->suser); - free (this->export_auth_str); + if (this->phone_code_hash) free (this->phone_code_hash); + if (this->suser) free (this->suser); + if (this->export_auth_str) free (this->export_auth_str); //tfree (this->ML, sizeof(struct message) * MSG_STORE_SIZE); tfree(this, sizeof(struct telegram)); } From 91ac1b06ee096cc6ca359797b3880fc36f7eae15 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 14 Oct 2014 21:42:03 +0200 Subject: [PATCH 457/465] Remove old printfs of telegram-cli to fix issues on Finch --- msglog.c | 8 +- mtproto-client.c | 203 +---------------------------------------------- net.c | 9 ++- 3 files changed, 12 insertions(+), 208 deletions(-) diff --git a/msglog.c b/msglog.c index 4ded692..2c131b9 100644 --- a/msglog.c +++ b/msglog.c @@ -20,9 +20,13 @@ #endif void hexdump (int *in_ptr, int *in_end) { + // TODO: figure out how to log hexdumps to purple log int *ptr = in_ptr; - while (ptr < in_end) { printf (" %08x", *(ptr ++)); } - printf ("\n"); + while (ptr < in_end) { + ++ ptr; + //printf (" %08x", *(ptr ++)); + } + //printf ("\n"); } void log_level_printf (const char* format, va_list ap, int level, char *color) diff --git a/mtproto-client.c b/mtproto-client.c index 2aad896..3f71d6c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -906,14 +906,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { } } fetch_pts (self); - if (log_level >= 1) { - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" %d messages marked as read\n", n); - //pop_color (); - //print_end (); - } } break; case CODE_update_user_typing: @@ -922,16 +914,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_id_t id = MK_USER (fetch_int (self)); peer_t *U UU = user_chat_get (bl, id); event_update_user_typing (tg, U); - if (log_level >= 2) { - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" User "); - //print_user_name (id, U); - printf (" is typing....\n"); - //pop_color (); - //print_end (); - } } break; case CODE_update_chat_user_typing: @@ -941,18 +923,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_t *C = user_chat_get (bl, chat_id); peer_t *U = user_chat_get (bl, id); event_update_chat_user_typing(tg, C, U, 0); - if (log_level >= 2) { - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" User "); - //print_user_name (id, U); - printf (" is typing in chat "); - //print_chat_name (chat_id, C); - printf ("....\n"); - //pop_color (); - //print_end (); - } } break; case CODE_update_user_status: @@ -962,17 +932,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { if (U) { fetch_user_status (self, &U->user.status); event_update_user_status(tg, U); - if (log_level >= 3) { - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" User "); - //print_user_name (user_id, U); - printf (" is now "); - printf ("%s\n", (U->user.status.online > 0) ? "online" : "offline"); - //pop_color (); - //print_end (); - } } else { struct user_status t; fetch_user_status (self, &t); @@ -990,16 +949,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { char *l = fetch_str (self, l2); struct tgl_user *U = &UC->user; bl_do_set_user_real_name (self->bl, self, U, f, l1, l, l2); - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" User "); - //print_user_name (user_id, UC); - printf (" changed name to "); - //print_user_name (user_id, UC); - printf ("\n"); - //pop_color (); - //print_end (); } else { fetch_skip_str (self); fetch_skip_str (self); @@ -1031,15 +980,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { fetch_file_location (self, &big); } bl_do_set_user_profile_photo (self->bl, self, U, photo_id, &big, &small); - - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" User "); - //print_user_name (user_id, UC); - printf (" updated profile photo\n"); - //pop_color (); - //print_end (); } else { struct file_location t; unsigned y = fetch_int (self); @@ -1059,12 +999,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { assert (fetch_int (self) == CODE_vector); int n = fetch_int (self); - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" Restored %d messages\n", n); - //pop_color (); - //print_end (); fetch_skip (self, n); fetch_pts (self); } @@ -1073,12 +1007,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { assert (fetch_int (self) == CODE_vector); int n = fetch_int (self); - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" Deleted %d messages\n", n); - //pop_color (); - //print_end (); fetch_skip (self, n); fetch_pts (self); } @@ -1115,18 +1043,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { fetch_int (self); // version } } - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" Chat "); - //print_chat_name (chat_id, C); - if (x == CODE_chat_participants) { - printf (" changed list: now %d members\n", n); - } else { - printf (" changed list, but we are forbidden to know about it (Why this update even was sent to us?\n"); - } - //pop_color (); - //print_end (); if (C) { event_update_chat_participants(tg, C); } @@ -1137,14 +1053,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *U = user_chat_get (bl, user_id); fetch_int (self); // date - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" User "); - //print_user_name (user_id, U); - printf (" registered\n"); - //pop_color (); - //print_end (); event_update_user_registered(tg, U); } break; @@ -1152,14 +1060,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *U UU = user_chat_get (bl, user_id); - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" Updated link with user "); - //print_user_name (user_id, U); - printf ("\n"); - //pop_color (); - //print_end (); unsigned t = fetch_int (self); assert (t == CODE_contacts_my_link_empty || t == CODE_contacts_my_link_requested || t == CODE_contacts_my_link_contact); if (t == CODE_contacts_my_link_requested) { @@ -1176,14 +1076,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { peer_id_t user_id = MK_USER (fetch_int (self)); peer_t *U UU = user_chat_get (bl, user_id); - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" User "); - //print_user_name (user_id, U); - printf (" activated\n"); - //pop_color (); - //print_end (); } break; case CODE_update_new_authorization: @@ -1192,13 +1084,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { fetch_int (self); // date char *s = fetch_str_dup (self); char *location = fetch_str_dup (self); - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" New autorization: device='%s' location='%s'\n", - s, location); - //pop_color (); - //print_end (); event_update_auth_new(tg, location); tfree_str (s); tfree_str (location); @@ -1209,8 +1094,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { struct message *M = fetch_alloc_geo_message (self, tg); self->unread_messages ++; event_update_new_message (self->instance, M); - //print_message (M); - //update_prompt (); } break; case CODE_update_new_encrypted_message: @@ -1218,46 +1101,13 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { struct message *M UU = fetch_alloc_encrypted_message (self, tg); self->unread_messages ++; event_update_new_message (self->instance, M); - //print_message (M); - //update_prompt (); fetch_qts (self); } break; case CODE_update_encryption: { struct secret_chat *E = fetch_alloc_encrypted_chat (self); - if (verbosity >= 2) { - debug ("Secret chat state = %d\n", E->state); - } - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - switch (E->state) { - case sc_none: - break; - case sc_waiting: - printf (" Encrypted chat "); - //print_encr_chat_name (E->id, (void *)E); - printf (" is now in wait state\n"); - break; - case sc_request: - printf (" Encrypted chat "); - //print_encr_chat_name (E->id, (void *)E); - printf (" is now in request state. Sending request ok\n"); - break; - case sc_ok: - printf (" Encrypted chat "); - //print_encr_chat_name (E->id, (void *)E); - printf (" is now in ok state\n"); - break; - case sc_deleted: - printf (" Encrypted chat "); - //print_encr_chat_name (E->id, (void *)E); - printf (" is now in deleted state\n"); - break; - } - //pop_color (); - //print_end (); + debug ("Secret chat state = %d\n", E->state); if (E->state == sc_request && !disable_auto_accept) { do_accept_encr_chat_request (tg, E); } @@ -1268,22 +1118,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { { peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); peer_t *P = user_chat_get (bl, id); - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); event_update_user_typing(tg, P); - if (P) { - printf (" User "); - peer_id_t user_id UU = MK_USER (P->encr_chat.user_id); - //print_user_name (user_id, user_chat_get (bl, user_id)); - printf (" typing in secret chat "); - //print_encr_chat_name (id, P); - printf ("\n"); - } else { - printf (" Some user is typing in unknown secret chat\n"); - } - //pop_color (); - //print_end (); } break; case CODE_update_encrypted_messages_read: @@ -1305,14 +1140,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { } } if (log_level >= 1) { - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" Encrypted chat "); - //print_encr_chat_name_full (id, user_chat_get (bl, id)); - printf (": %d messages marked read \n", x); - //pop_color (); - //print_end (); } } break; @@ -1327,19 +1154,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { if (C && (C->flags & FLAG_CREATED)) { bl_do_chat_add_user (self->bl, self, &C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); } - - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" Chat "); - //print_chat_name (chat_id, user_chat_get (bl, chat_id)); - printf (": user "); - //print_user_name (user_id, user_chat_get (bl, user_id)); - printf (" added by user "); - //print_user_name (inviter_id, user_chat_get (bl, inviter_id)); - printf ("\n"); - //pop_color (); - //print_end (); event_update_chat_add_participant(tg, C, user_id, inviter_id); } break; @@ -1353,17 +1167,6 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { if (C && (C->flags & FLAG_CREATED)) { bl_do_chat_del_user (self->bl, self, &C->chat, version, get_peer_id (user_id)); } - - //print_start (); - //push_color (COLOR_YELLOW); - //print_date (time (0)); - printf (" Chat "); - //print_chat_name (chat_id, user_chat_get (bl, chat_id)); - printf (": user "); - //print_user_name (user_id, user_chat_get (bl, user_id)); - printf (" deleted\n"); - //pop_color (); - //print_end (); event_update_chat_del_participant(tg, C, user_id, 0); } break; @@ -1426,8 +1229,6 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) { struct message *M = fetch_alloc_message_short (self, c->instance); c->mtconnection->unread_messages ++; event_update_new_message (self->instance, M); - //print_message (M); - //update_prompt (); if (M->date > c->mtconnection->last_date) { c->mtconnection->last_date = M->date; } @@ -1440,9 +1241,7 @@ void work_update_short_chat_message (struct connection *c, long long msg_id UU) assert (fetch_int (self) == CODE_update_short_chat_message); struct message *M = fetch_alloc_message_short_chat (self, c->instance); c->mtconnection->unread_messages ++; - //print_message (M); event_update_new_message (self->instance, M); - ////update_prompt (); if (M->date > c->mtconnection->last_date) { c->mtconnection->last_date = M->date; } diff --git a/net.c b/net.c index f4a17d5..e0cafb8 100644 --- a/net.c +++ b/net.c @@ -354,16 +354,17 @@ int try_write (struct connection *c) { } void hexdump_buf (struct connection_buffer *b) { + // TODO: figure out how to log hexdumps to purple log int pos = 0; int rem = 8; while (b) { unsigned char *c = b->rptr; while (c != b->wptr) { if (rem == 8) { - if (pos) { printf ("\n"); } - printf ("%04d", pos); + //if (pos) { printf ("\n"); } + //printf ("%04d", pos); } - printf (" %02x", (int)*c); + //printf (" %02x", (int)*c); rem --; pos ++; if (!rem) { @@ -373,7 +374,7 @@ void hexdump_buf (struct connection_buffer *b) { } b = b->next; } - printf ("\n"); + //printf ("\n"); } From b3642e2e7e9dfd976f35b6df5bf7df930abbfcd4 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 14 Oct 2014 22:08:15 +0200 Subject: [PATCH 458/465] Remove correct server.pub when uninstalling --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 83289e9..666566f 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ install: $(PRPL_LIBNAME) .PHONY: uninstall uninstall: rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) - rm -f /etc/telegram/server.pub + rm -f /etc/telegram-purple/server.pub rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png From c54ebf5c175fe123b20240a490d784d6aa11466c Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 14 Oct 2014 22:15:02 +0200 Subject: [PATCH 459/465] Error the telegram-plugin on failed connections, so hopefully libpurple will inform the user and restart it once the connectivity is back --- net.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/net.c b/net.c index e0cafb8..97763cc 100644 --- a/net.c +++ b/net.c @@ -283,29 +283,8 @@ void restart_connection (struct connection *c) { } void fail_connection (struct connection *c) { - if (c->state == conn_ready || c->state == conn_connecting) { - stop_ping_timer (c); - } - rotate_port (c); - struct connection_buffer *b = c->out_head; - while (b) { - struct connection_buffer *d = b; - b = b->next; - delete_connection_buffer (d); - } - b = c->in_head; - while (b) { - struct connection_buffer *d = b; - b = b->next; - delete_connection_buffer (d); - } - c->out_head = c->out_tail = c->in_head = c->in_tail = 0; - c->state = conn_failed; - c->out_bytes = c->in_bytes = 0; - close (c->fd); - Connections[c->fd] = 0; - debug ("Lost connection to server... %s:%d\n", c->ip, c->port); - restart_connection (c); + warning ("Lost connection to server... %s:%d\n", c->ip, c->port); + telegram_change_state(c->mtconnection->instance, STATE_ERROR, "Lost connection to server\n"); } extern FILE *log_net_f; From a9a48fff909cc431d6fadc790e877640c514c8fa Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 14 Oct 2014 22:29:22 +0200 Subject: [PATCH 460/465] Update version to 0.3.3 --- README.md | 6 ++++++ purple-plugin/telegram-purple.h | 8 ++++---- telegram-adium/telegram-adium/telegram-adium-Info.plist | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b8bd9ac..9c0a2df 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,11 @@ Warning, this version is mainly for development and testing and NOT for producti When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace of the crashed application [https://developer.pidgin.im/wiki/GetABacktrace] +## Version 0.3.3 + + - multiple bugfixes + + ## Version 0.3.2 - Add compatibility for OSX 10.8 @@ -138,6 +143,7 @@ This bundle was tested to work under OSX 10.9 and 10.8. If it doesn't work on yo please send your Adium crash log (which you can find in ~/Library/Logs/Adium 2/). [Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.2.zip) +[Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.3.zip) ## Build with XCode diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 72c09d4..bc4cd7b 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -20,10 +20,10 @@ #define PLUGIN_ID "prpl-telegram" #define TELEGRAM_AUTH_MODE_PHONE "phone" #define TELEGRAM_AUTH_MODE_SMS "sms" -#define TG_AUTHOR "Christopher Althaus , Markus Endres , Matthias Jentsch " -#define TG_DESCRIPTION "A protocol plugin that adds support for the Telegram messenger." -#define TG_VERSION "0.3.1" -#define TG_BUILD "4" +#define TG_AUTHOR "Christopher Althaus , Markus Endres , Matthias Jentsch . Based on telegram-cli by Vitaly Valtman." +#define TG_DESCRIPTION "Adds support for Telegram." +#define TG_VERSION "0.3.3" +#define TG_BUILD "8" #include #include "notify.h" diff --git a/telegram-adium/telegram-adium/telegram-adium-Info.plist b/telegram-adium/telegram-adium/telegram-adium-Info.plist index 1fadca5..4e10af7 100644 --- a/telegram-adium/telegram-adium/telegram-adium-Info.plist +++ b/telegram-adium/telegram-adium/telegram-adium-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.3.2 + 0.3.3 CFBundleSignature AdIM CFBundleVersion From bd4bc51651b386fc39e88673ae6e0d826d6a5b71 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Tue, 28 Oct 2014 01:20:30 +0100 Subject: [PATCH 461/465] Fix library includes in linker step --- Makefile | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 666566f..c85fe48 100644 --- a/Makefile +++ b/Makefile @@ -3,16 +3,12 @@ # srcdir=. -CFLAGS=-g -LDFLAGS=-L/usr/local/lib -CPPFLAGS=-I/usr/local/include -DEFS= -COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +CFLAGS=-g -I/usr/local/include +LDFLAGS=-L/usr/local/lib +COMPILE_FLAGS=${CFLAGS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=-lcrypto -lz -lm -LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} -LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h +HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h INCLUDE=-I. -I${srcdir} CC=cc @@ -50,8 +46,8 @@ STRIP = strip PRPL_CFLAGS = \ $(ARCHFLAGS) \ -fPIC \ - -DPURPLE_PLUGINS \ -DPIC \ + -DPURPLE_PLUGINS \ -DDEBUG \ -g \ $(CFLAGS_PURPLE) @@ -65,9 +61,6 @@ PRPL_CFLAGS = \ ${OBJECTS}: ${HEADERS} -telegram: ${OBJECTS} - ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ - # # Plugin Objects # @@ -76,15 +69,14 @@ $(PRPL_C_OBJS): $(PRPL_C_SRCS) $(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) - $(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $(PRPL_C_OBJS) $(OBJECTS) + $(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) -o $@ $(PRPL_C_OBJS) $(OBJECTS) $(LIBS_PURPLE) $(EXTRA_LIBS) -plugin: $(PRPL_LIBNAME) +all: $(PRPL_LIBNAME) .PHONY: strip strip: $(PRPL_LIBNAME) $(STRIP) --strip-unneeded $(PRPL_LIBNAME) -# TODO: Find a better place for server.pub install: $(PRPL_LIBNAME) install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) install -D tg-server.pub /etc/telegram-purple/server.pub From 560b55b29922b99bdc7e44ee084b50a9a21abd86 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Fri, 31 Oct 2014 20:37:30 +0100 Subject: [PATCH 462/465] Don't print debug messages in unused functions --- purple-plugin/telegram-purple.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 30a5ddf..166a15e 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -401,49 +401,49 @@ void telegram_on_error (struct telegram *tg, const char *err) void on_update_user_name (struct telegram *tg, peer_t *user) { - debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); + // debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); // Update user name } void on_update_user_photo (struct telegram *tg, peer_t *user) { - debug("on_update_user_photo(id=%d, type=%d)\n", user->id.id, user->id.type); + // debug("on_update_user_photo(id=%d, type=%d)\n", user->id.id, user->id.type); // Update user photo } void on_update_user_registered (struct telegram *tg, peer_t *user) { - debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); + // debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); // Notify about a new user } void on_update_chat_participants (struct telegram *tg, peer_t *chat) { - debug("on_update_chat_participants(chat.id=%d)\n", chat->id.id); + // debug("on_update_chat_participants(chat.id=%d)\n", chat->id.id); // Refresh chat participants } void on_update_chat_add_participant (struct telegram *tg, peer_t *chat, peer_id_t user, peer_id_t inviter) { - debug("on_update_chat_add_participant(chat.id=%d)\n", chat->id.id); + // debug("on_update_chat_add_participant(chat.id=%d)\n", chat->id.id); // Add chat participant } void on_update_chat_del_participant (struct telegram *tg, peer_t *chat, peer_id_t user, void *_ UU) { - debug("on_update_chat_del_participant(chat.id=%d)\n", chat->id.id); + // debug("on_update_chat_del_participant(chat.id=%d)\n", chat->id.id); // Remove chat participant } void on_update_chat_user_typing (struct telegram *tg, peer_t *chat, peer_t *user, void *_ UU) { - debug("on_update_chat_user_typing(chat.id=%d, user.id=%d)\n", chat->id.id, user->id.id); + // debug("on_update_chat_user_typing(chat.id=%d, user.id=%d)\n", chat->id.id, user->id.id); // Set or unset user in chat typing } void on_update_auth_new (struct telegram *tg, char *location) { - debug("un_update_auth_new(location=%s)\n", location); + // debug("un_update_auth_new(location=%s)\n", location); // Info: new device authenticated for this phone number } From 1b6fdf44e8e5bb36fef478f24ac4652ba04aad17 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Wed, 5 Nov 2014 21:52:18 +0100 Subject: [PATCH 463/465] Fix link to Adium bundle for 0.3.3 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c0a2df..3e4d86c 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,8 @@ This bundle was tested to work under OSX 10.9 and 10.8. If it doesn't work on yo please send your Adium crash log (which you can find in ~/Library/Logs/Adium 2/). [Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.2.zip) -[Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.3.zip) + +[Version 0.3.3](http://lauschgift.org/telegram-purple/telegram-adium-0.3.3.zip) ## Build with XCode From f46c685bbd15a538d2c6bd41882fb04a5e27550a Mon Sep 17 00:00:00 2001 From: Vysheng Date: Tue, 11 Nov 2014 20:29:09 +0300 Subject: [PATCH 464/465] Rewritten to use libtgl --- .gitignore | 21 - .travis.yml | 12 - LICENSE | 339 -- LICENSE.h | 339 -- Makefile | 43 +- README.md | 15 +- binlog.c | 1686 --------- binlog.h | 150 - binlog.tl | 10 - constants.h | 383 -- gen_constants_h.awk | 37 - {purple-plugin => imgs}/telegram.png | Bin {purple-plugin => imgs}/telegram16.png | Bin {purple-plugin => imgs}/telegram22.png | Bin {purple-plugin => imgs}/telegram48.png | Bin include.h | 24 - loop.c | 350 -- loop.h | 79 - msglog.c | 4 +- mtproto-client.c | 1735 --------- mtproto-client.h | 514 --- mtproto-common.c | 357 -- net.c | 549 --- net.h | 163 - no-preview.h | 105 - purple-plugin/telegram.svg | 177 - queries.c | 3095 ----------------- queries.h | 161 - structures.c | 2090 ----------- structures.h | 423 --- telegram-base.c | 372 ++ telegram-base.h | 9 + .../telegram-purple.c => telegram-purple.c | 801 ++--- .../telegram-purple.h => telegram-purple.h | 79 +- telegram.c | 480 --- telegram.h | 484 --- tg-server.pub | 1 - tgp-net.c | 584 ++++ tgp-net.h | 88 + tgp-timers.c | 75 + tgp-timers.h | 27 + tools.c | 259 -- tools.h | 43 - tree.h | 157 - 44 files changed, 1506 insertions(+), 14814 deletions(-) delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 LICENSE delete mode 100644 LICENSE.h delete mode 100644 binlog.c delete mode 100644 binlog.h delete mode 100644 binlog.tl delete mode 100644 constants.h delete mode 100644 gen_constants_h.awk rename {purple-plugin => imgs}/telegram.png (100%) rename {purple-plugin => imgs}/telegram16.png (100%) rename {purple-plugin => imgs}/telegram22.png (100%) rename {purple-plugin => imgs}/telegram48.png (100%) delete mode 100644 include.h delete mode 100644 loop.c delete mode 100644 loop.h delete mode 100644 mtproto-client.c delete mode 100644 mtproto-client.h delete mode 100644 mtproto-common.c delete mode 100644 net.c delete mode 100644 net.h delete mode 100644 no-preview.h delete mode 100644 purple-plugin/telegram.svg delete mode 100644 queries.c delete mode 100644 queries.h delete mode 100644 structures.c delete mode 100644 structures.h create mode 100644 telegram-base.c create mode 100644 telegram-base.h rename purple-plugin/telegram-purple.c => telegram-purple.c (57%) rename purple-plugin/telegram-purple.h => telegram-purple.h (58%) delete mode 100755 telegram.c delete mode 100644 telegram.h create mode 100644 tgp-net.c create mode 100644 tgp-net.h create mode 100644 tgp-timers.c create mode 100644 tgp-timers.h delete mode 100644 tools.c delete mode 100644 tools.h delete mode 100644 tree.h diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d9775cd..0000000 --- a/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -telegram -*.o -*.so -*.a -telegram-adium/libcrypto.a -config.h -config.log -config.status -.idea/ -nbproject/ -tags -.DS_Store -.ycm_extra_conf.py -*.pyc -app-hash.png -.gdbinit -core -core* -telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate -telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad -telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 915d880..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: c - -compiler: - - gcc - - clang - -install: - - sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev - -script: - - ./configure - - make diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d159169..0000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/LICENSE.h b/LICENSE.h deleted file mode 100644 index 0dcf708..0000000 --- a/LICENSE.h +++ /dev/null @@ -1,339 +0,0 @@ -" GNU GENERAL PUBLIC LICENSE\n" -" Version 2, June 1991\n" -"\n" -" Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n" -" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" -" Everyone is permitted to copy and distribute verbatim copies\n" -" of this license document, but changing it is not allowed.\n" -"\n" -" Preamble\n" -"\n" -" The licenses for most software are designed to take away your\n" -"freedom to share and change it. By contrast, the GNU General Public\n" -"License is intended to guarantee your freedom to share and change free\n" -"software--to make sure the software is free for all its users. This\n" -"General Public License applies to most of the Free Software\n" -"Foundation's software and to any other program whose authors commit to\n" -"using it. (Some other Free Software Foundation software is covered by\n" -"the GNU Lesser General Public License instead.) You can apply it to\n" -"your programs, too.\n" -"\n" -" When we speak of free software, we are referring to freedom, not\n" -"price. Our General Public Licenses are designed to make sure that you\n" -"have the freedom to distribute copies of free software (and charge for\n" -"this service if you wish), that you receive source code or can get it\n" -"if you want it, that you can change the software or use pieces of it\n" -"in new free programs; and that you know you can do these things.\n" -"\n" -" To protect your rights, we need to make restrictions that forbid\n" -"anyone to deny you these rights or to ask you to surrender the rights.\n" -"These restrictions translate to certain responsibilities for you if you\n" -"distribute copies of the software, or if you modify it.\n" -"\n" -" For example, if you distribute copies of such a program, whether\n" -"gratis or for a fee, you must give the recipients all the rights that\n" -"you have. You must make sure that they, too, receive or can get the\n" -"source code. And you must show them these terms so they know their\n" -"rights.\n" -"\n" -" We protect your rights with two steps: (1) copyright the software, and\n" -"(2) offer you this license which gives you legal permission to copy,\n" -"distribute and/or modify the software.\n" -"\n" -" Also, for each author's protection and ours, we want to make certain\n" -"that everyone understands that there is no warranty for this free\n" -"software. If the software is modified by someone else and passed on, we\n" -"want its recipients to know that what they have is not the original, so\n" -"that any problems introduced by others will not reflect on the original\n" -"authors' reputations.\n" -"\n" -" Finally, any free program is threatened constantly by software\n" -"patents. We wish to avoid the danger that redistributors of a free\n" -"program will individually obtain patent licenses, in effect making the\n" -"program proprietary. To prevent this, we have made it clear that any\n" -"patent must be licensed for everyone's free use or not licensed at all.\n" -"\n" -" The precise terms and conditions for copying, distribution and\n" -"modification follow.\n" -"\n" -" GNU GENERAL PUBLIC LICENSE\n" -" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n" -"\n" -" 0. This License applies to any program or other work which contains\n" -"a notice placed by the copyright holder saying it may be distributed\n" -"under the terms of this General Public License. The \"Program\", below,\n" -"refers to any such program or work, and a \"work based on the Program\"\n" -"means either the Program or any derivative work under copyright law:\n" -"that is to say, a work containing the Program or a portion of it,\n" -"either verbatim or with modifications and/or translated into another\n" -"language. (Hereinafter, translation is included without limitation in\n" -"the term \"modification\".) Each licensee is addressed as \"you\".\n" -"\n" -"Activities other than copying, distribution and modification are not\n" -"covered by this License; they are outside its scope. The act of\n" -"running the Program is not restricted, and the output from the Program\n" -"is covered only if its contents constitute a work based on the\n" -"Program (independent of having been made by running the Program).\n" -"Whether that is true depends on what the Program does.\n" -"\n" -" 1. You may copy and distribute verbatim copies of the Program's\n" -"source code as you receive it, in any medium, provided that you\n" -"conspicuously and appropriately publish on each copy an appropriate\n" -"copyright notice and disclaimer of warranty; keep intact all the\n" -"notices that refer to this License and to the absence of any warranty;\n" -"and give any other recipients of the Program a copy of this License\n" -"along with the Program.\n" -"\n" -"You may charge a fee for the physical act of transferring a copy, and\n" -"you may at your option offer warranty protection in exchange for a fee.\n" -"\n" -" 2. You may modify your copy or copies of the Program or any portion\n" -"of it, thus forming a work based on the Program, and copy and\n" -"distribute such modifications or work under the terms of Section 1\n" -"above, provided that you also meet all of these conditions:\n" -"\n" -" a) You must cause the modified files to carry prominent notices\n" -" stating that you changed the files and the date of any change.\n" -"\n" -" b) You must cause any work that you distribute or publish, that in\n" -" whole or in part contains or is derived from the Program or any\n" -" part thereof, to be licensed as a whole at no charge to all third\n" -" parties under the terms of this License.\n" -"\n" -" c) If the modified program normally reads commands interactively\n" -" when run, you must cause it, when started running for such\n" -" interactive use in the most ordinary way, to print or display an\n" -" announcement including an appropriate copyright notice and a\n" -" notice that there is no warranty (or else, saying that you provide\n" -" a warranty) and that users may redistribute the program under\n" -" these conditions, and telling the user how to view a copy of this\n" -" License. (Exception: if the Program itself is interactive but\n" -" does not normally print such an announcement, your work based on\n" -" the Program is not required to print an announcement.)\n" -"\n" -"These requirements apply to the modified work as a whole. If\n" -"identifiable sections of that work are not derived from the Program,\n" -"and can be reasonably considered independent and separate works in\n" -"themselves, then this License, and its terms, do not apply to those\n" -"sections when you distribute them as separate works. But when you\n" -"distribute the same sections as part of a whole which is a work based\n" -"on the Program, the distribution of the whole must be on the terms of\n" -"this License, whose permissions for other licensees extend to the\n" -"entire whole, and thus to each and every part regardless of who wrote it.\n" -"\n" -"Thus, it is not the intent of this section to claim rights or contest\n" -"your rights to work written entirely by you; rather, the intent is to\n" -"exercise the right to control the distribution of derivative or\n" -"collective works based on the Program.\n" -"\n" -"In addition, mere aggregation of another work not based on the Program\n" -"with the Program (or with a work based on the Program) on a volume of\n" -"a storage or distribution medium does not bring the other work under\n" -"the scope of this License.\n" -"\n" -" 3. You may copy and distribute the Program (or a work based on it,\n" -"under Section 2) in object code or executable form under the terms of\n" -"Sections 1 and 2 above provided that you also do one of the following:\n" -"\n" -" a) Accompany it with the complete corresponding machine-readable\n" -" source code, which must be distributed under the terms of Sections\n" -" 1 and 2 above on a medium customarily used for software interchange; or,\n" -"\n" -" b) Accompany it with a written offer, valid for at least three\n" -" years, to give any third party, for a charge no more than your\n" -" cost of physically performing source distribution, a complete\n" -" machine-readable copy of the corresponding source code, to be\n" -" distributed under the terms of Sections 1 and 2 above on a medium\n" -" customarily used for software interchange; or,\n" -"\n" -" c) Accompany it with the information you received as to the offer\n" -" to distribute corresponding source code. (This alternative is\n" -" allowed only for noncommercial distribution and only if you\n" -" received the program in object code or executable form with such\n" -" an offer, in accord with Subsection b above.)\n" -"\n" -"The source code for a work means the preferred form of the work for\n" -"making modifications to it. For an executable work, complete source\n" -"code means all the source code for all modules it contains, plus any\n" -"associated interface definition files, plus the scripts used to\n" -"control compilation and installation of the executable. However, as a\n" -"special exception, the source code distributed need not include\n" -"anything that is normally distributed (in either source or binary\n" -"form) with the major components (compiler, kernel, and so on) of the\n" -"operating system on which the executable runs, unless that component\n" -"itself accompanies the executable.\n" -"\n" -"If distribution of executable or object code is made by offering\n" -"access to copy from a designated place, then offering equivalent\n" -"access to copy the source code from the same place counts as\n" -"distribution of the source code, even though third parties are not\n" -"compelled to copy the source along with the object code.\n" -"\n" -" 4. You may not copy, modify, sublicense, or distribute the Program\n" -"except as expressly provided under this License. Any attempt\n" -"otherwise to copy, modify, sublicense or distribute the Program is\n" -"void, and will automatically terminate your rights under this License.\n" -"However, parties who have received copies, or rights, from you under\n" -"this License will not have their licenses terminated so long as such\n" -"parties remain in full compliance.\n" -"\n" -" 5. You are not required to accept this License, since you have not\n" -"signed it. However, nothing else grants you permission to modify or\n" -"distribute the Program or its derivative works. These actions are\n" -"prohibited by law if you do not accept this License. Therefore, by\n" -"modifying or distributing the Program (or any work based on the\n" -"Program), you indicate your acceptance of this License to do so, and\n" -"all its terms and conditions for copying, distributing or modifying\n" -"the Program or works based on it.\n" -"\n" -" 6. Each time you redistribute the Program (or any work based on the\n" -"Program), the recipient automatically receives a license from the\n" -"original licensor to copy, distribute or modify the Program subject to\n" -"these terms and conditions. You may not impose any further\n" -"restrictions on the recipients' exercise of the rights granted herein.\n" -"You are not responsible for enforcing compliance by third parties to\n" -"this License.\n" -"\n" -" 7. If, as a consequence of a court judgment or allegation of patent\n" -"infringement or for any other reason (not limited to patent issues),\n" -"conditions are imposed on you (whether by court order, agreement or\n" -"otherwise) that contradict the conditions of this License, they do not\n" -"excuse you from the conditions of this License. If you cannot\n" -"distribute so as to satisfy simultaneously your obligations under this\n" -"License and any other pertinent obligations, then as a consequence you\n" -"may not distribute the Program at all. For example, if a patent\n" -"license would not permit royalty-free redistribution of the Program by\n" -"all those who receive copies directly or indirectly through you, then\n" -"the only way you could satisfy both it and this License would be to\n" -"refrain entirely from distribution of the Program.\n" -"\n" -"If any portion of this section is held invalid or unenforceable under\n" -"any particular circumstance, the balance of the section is intended to\n" -"apply and the section as a whole is intended to apply in other\n" -"circumstances.\n" -"\n" -"It is not the purpose of this section to induce you to infringe any\n" -"patents or other property right claims or to contest validity of any\n" -"such claims; this section has the sole purpose of protecting the\n" -"integrity of the free software distribution system, which is\n" -"implemented by public license practices. Many people have made\n" -"generous contributions to the wide range of software distributed\n" -"through that system in reliance on consistent application of that\n" -"system; it is up to the author/donor to decide if he or she is willing\n" -"to distribute software through any other system and a licensee cannot\n" -"impose that choice.\n" -"\n" -"This section is intended to make thoroughly clear what is believed to\n" -"be a consequence of the rest of this License.\n" -"\n" -" 8. If the distribution and/or use of the Program is restricted in\n" -"certain countries either by patents or by copyrighted interfaces, the\n" -"original copyright holder who places the Program under this License\n" -"may add an explicit geographical distribution limitation excluding\n" -"those countries, so that distribution is permitted only in or among\n" -"countries not thus excluded. In such case, this License incorporates\n" -"the limitation as if written in the body of this License.\n" -"\n" -" 9. The Free Software Foundation may publish revised and/or new versions\n" -"of the General Public License from time to time. Such new versions will\n" -"be similar in spirit to the present version, but may differ in detail to\n" -"address new problems or concerns.\n" -"\n" -"Each version is given a distinguishing version number. If the Program\n" -"specifies a version number of this License which applies to it and \"any\n" -"later version\", you have the option of following the terms and conditions\n" -"either of that version or of any later version published by the Free\n" -"Software Foundation. If the Program does not specify a version number of\n" -"this License, you may choose any version ever published by the Free Software\n" -"Foundation.\n" -"\n" -" 10. If you wish to incorporate parts of the Program into other free\n" -"programs whose distribution conditions are different, write to the author\n" -"to ask for permission. For software which is copyrighted by the Free\n" -"Software Foundation, write to the Free Software Foundation; we sometimes\n" -"make exceptions for this. Our decision will be guided by the two goals\n" -"of preserving the free status of all derivatives of our free software and\n" -"of promoting the sharing and reuse of software generally.\n" -"\n" -" NO WARRANTY\n" -"\n" -" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n" -"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n" -"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n" -"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n" -"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n" -"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n" -"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n" -"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n" -"REPAIR OR CORRECTION.\n" -"\n" -" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n" -"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n" -"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n" -"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n" -"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n" -"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n" -"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n" -"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n" -"POSSIBILITY OF SUCH DAMAGES.\n" -"\n" -" END OF TERMS AND CONDITIONS\n" -"\n" -" How to Apply These Terms to Your New Programs\n" -"\n" -" If you develop a new program, and you want it to be of the greatest\n" -"possible use to the public, the best way to achieve this is to make it\n" -"free software which everyone can redistribute and change under these terms.\n" -"\n" -" To do so, attach the following notices to the program. It is safest\n" -"to attach them to the start of each source file to most effectively\n" -"convey the exclusion of warranty; and each file should have at least\n" -"the \"copyright\" line and a pointer to where the full notice is found.\n" -"\n" -" \n" -" Copyright (C) \n" -"\n" -" This program is free software; you can redistribute it and/or modify\n" -" it under the terms of the GNU General Public License as published by\n" -" the Free Software Foundation; either version 2 of the License, or\n" -" (at your option) any later version.\n" -"\n" -" This program is distributed in the hope that it will be useful,\n" -" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" -" GNU General Public License for more details.\n" -"\n" -" You should have received a copy of the GNU General Public License along\n" -" with this program; if not, write to the Free Software Foundation, Inc.,\n" -" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" -"\n" -"Also add information on how to contact you by electronic and paper mail.\n" -"\n" -"If the program is interactive, make it output a short notice like this\n" -"when it starts in an interactive mode:\n" -"\n" -" Gnomovision version 69, Copyright (C) year name of author\n" -" Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n" -" This is free software, and you are welcome to redistribute it\n" -" under certain conditions; type `show c' for details.\n" -"\n" -"The hypothetical commands `show w' and `show c' should show the appropriate\n" -"parts of the General Public License. Of course, the commands you use may\n" -"be called something other than `show w' and `show c'; they could even be\n" -"mouse-clicks or menu items--whatever suits your program.\n" -"\n" -"You should also get your employer (if you work as a programmer) or your\n" -"school, if any, to sign a \"copyright disclaimer\" for the program, if\n" -"necessary. Here is a sample; alter the names:\n" -"\n" -" Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n" -" `Gnomovision' (which makes passes at compilers) written by James Hacker.\n" -"\n" -" , 1 April 1989\n" -" Ty Coon, President of Vice\n" -"\n" -"This General Public License does not permit incorporating your program into\n" -"proprietary programs. If your program is a subroutine library, you may\n" -"consider it more useful to permit linking proprietary applications with the\n" -"library. If this is what you want to do, use the GNU Lesser General\n" -"Public License instead of this License.\n" diff --git a/Makefile b/Makefile index c85fe48..c66802c 100644 --- a/Makefile +++ b/Makefile @@ -3,16 +3,19 @@ # srcdir=. -CFLAGS=-g -I/usr/local/include -LDFLAGS=-L/usr/local/lib -COMPILE_FLAGS=${CFLAGS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb +CFLAGS=-g -Wall -Wextra -Werror -Wno-unused-parameter +LDFLAGS=-L/usr/local/lib +CPPFLAGS=-I/usr/local/include -Itg +DEFS= +COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=-lcrypto -lz -lm - -HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h +LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} +LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} INCLUDE=-I. -I${srcdir} CC=cc -OBJECTS=loop.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o msglog.o telegram.o +OBJECTS=tgp-net.o tgp-timers.o msglog.o telegram-base.o + .SUFFIXES: .SUFFIXES: .c .h .o @@ -37,7 +40,7 @@ else endif LD = $(CC) -PRPL_C_SRCS = purple-plugin/telegram-purple.c +PRPL_C_SRCS = telegram-purple.c PRPL_C_OBJS = $(PRPL_C_SRCS:.c=.o) PRPL_LIBNAME = telegram-purple.so PRPL_INCLUDE = -I. -I./purple-plugin @@ -46,8 +49,8 @@ STRIP = strip PRPL_CFLAGS = \ $(ARCHFLAGS) \ -fPIC \ - -DPIC \ -DPURPLE_PLUGINS \ + -DPIC \ -DDEBUG \ -g \ $(CFLAGS_PURPLE) @@ -59,30 +62,38 @@ PRPL_CFLAGS = \ .c.o : ${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@ -${OBJECTS}: ${HEADERS} +# ${OBJECTS}: ${HEADERS} + +#telegram: ${OBJECTS} +# ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@ # # Plugin Objects # $(PRPL_C_OBJS): $(PRPL_C_SRCS) - $(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $< + $(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -ggdb -o $@ $< -$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) - $(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) -o $@ $(PRPL_C_OBJS) $(OBJECTS) $(LIBS_PURPLE) $(EXTRA_LIBS) +$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) tg/libs/libtgl.a + $(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $^ + +.PHONY: all +all: ${PRPL_LIBNAME} + +plugin: $(PRPL_LIBNAME) -all: $(PRPL_LIBNAME) .PHONY: strip strip: $(PRPL_LIBNAME) $(STRIP) --strip-unneeded $(PRPL_LIBNAME) +# TODO: Find a better place for server.pub install: $(PRPL_LIBNAME) install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) install -D tg-server.pub /etc/telegram-purple/server.pub - install -D purple-plugin/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png - install -D purple-plugin/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png - install -D purple-plugin/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png + install -D imgs/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png + install -D imgs/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png + install -D imgs/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png .PHONY: uninstall uninstall: diff --git a/README.md b/README.md index 3e4d86c..6ed0288 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,10 @@ Warning, this version is mainly for development and testing and NOT for producti When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace of the crashed application [https://developer.pidgin.im/wiki/GetABacktrace] +## Version 0.4 + + - Use latest version of libtgl + ## Version 0.3.3 - multiple bugfixes @@ -70,8 +74,14 @@ Unfortunately there are no packages right now, so you need to compile it yoursel git clone https://github.com/majn/telegram-purple +## 2. Get libtgl to tg subfolder + + cd telegram-purple + git clone https://github.com/vysheng/tg -## 2. Fetch all needed dependencies + + +## 3. Fetch all needed dependencies This plugin depends on a working libpurple client (like Pidgin or Finch) and the following packages: @@ -143,8 +153,7 @@ This bundle was tested to work under OSX 10.9 and 10.8. If it doesn't work on yo please send your Adium crash log (which you can find in ~/Library/Logs/Adium 2/). [Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.2.zip) - -[Version 0.3.3](http://lauschgift.org/telegram-purple/telegram-adium-0.3.3.zip) +[Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.3.zip) ## Build with XCode diff --git a/binlog.c b/binlog.c deleted file mode 100644 index e49e655..0000000 --- a/binlog.c +++ /dev/null @@ -1,1686 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "binlog.h" -#include "net.h" -#include "include.h" -#include "mtproto-client.h" -#include "telegram.h" - -#include - -#define MAX_LOG_EVENT_SIZE (1 << 17) - -int binlog_enabled = 0; - -void *alloc_log_event (struct binlog *bl, int l UU) { - return bl->binlog_buffer; -} - -void replay_log_event (struct telegram *instance) { - struct mtproto_connection *self = instance->connection; - struct binlog *bl = instance->bl; - - int *start = bl->rptr; - bl->in_replay_log = 1; - assert (bl->rptr < bl->wptr); - int op = *bl->rptr; - - if (verbosity >= 2) { - debug ("log_pos %lld, op 0x%08x\n", bl->binlog_pos, op); - } - - self->in_ptr = bl->rptr; - self->in_end = bl->wptr; - switch (op) { - case LOG_START: - bl->rptr ++; - break; - case CODE_binlog_dc_option: - self->in_ptr ++; - { - int id = fetch_int (self); - int l1 = prefetch_strlen (self); - char *name = fetch_str (self, l1); - int l2 = prefetch_strlen (self); - char *ip = fetch_str (self, l2); - int port = fetch_int (self); - debug ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - alloc_dc (instance->auth.DC_list, id, tstrndup (ip, l2), port); - } - bl->rptr = self->in_ptr; - break; - case LOG_AUTH_KEY: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->auth_key_id = *(long long *)bl->rptr; - bl->rptr += 2; - memcpy (instance->auth.DC_list[num]->auth_key, bl->rptr, 256); - bl->rptr += 64; - instance->auth.DC_list[num]->flags |= 1; - }; - break; - case LOG_DEFAULT_DC: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - instance->auth.dc_working_num = num; - } - break; - case LOG_OUR_ID: - bl->rptr ++; - { - instance->our_id = *(bl->rptr ++); - } - break; - case LOG_DC_SIGNED: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->has_auth = 1; - } - break; - case LOG_DC_SALT: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->server_salt = *(long long *)bl->rptr; - bl->rptr += 2; - }; - break; -// case CODE_user_empty: -// case CODE_user_self: -// case CODE_user_contact: -// case CODE_user_request: -// case CODE_user_foreign: - case CODE_user_deleted: - fetch_alloc_user (self); - bl->rptr = self->in_ptr; - break; - case LOG_DH_CONFIG: - get_dh_config_on_answer (0); - bl->rptr = self->in_ptr; - break; - case LOG_ENCR_CHAT_KEY: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - }; - break; - case LOG_ENCR_CHAT_SEND_ACCEPT: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - if (!U->g_key) { - U->g_key = talloc (256); - } - memcpy (U->g_key, bl->rptr, 256); - bl->rptr += 64; - }; - break; - case LOG_ENCR_CHAT_SEND_CREATE: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (!U || !(U->flags & FLAG_CREATED)); - if (!U) { - U = talloc0 (sizeof (peer_t)); - U->id = id; - insert_encrypted_chat (bl, (void *)U); - } - U->flags |= FLAG_CREATED; - U->user_id = *(bl->rptr ++); - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - if (!U->print_name) { - peer_t *P = user_chat_get (bl, MK_USER (U->user_id)); - if (P) { - U->print_name = create_print_name (bl, U->id, "!", P->user.first_name, P->user.last_name, 0); - } else { - static char buf[100]; - tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (bl, U->id, "!", buf, 0, 0); - } - peer_insert_name (bl, (void *)U); - } - }; - break; - case LOG_ENCR_CHAT_DELETED: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - if (!U) { - U = talloc0 (sizeof (peer_t)); - U->id = id; - insert_encrypted_chat (bl, (void *)U); - } - U->flags |= FLAG_CREATED; - U->state = sc_deleted; - }; - break; - case LOG_ENCR_CHAT_WAITING: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->state = sc_waiting; - U->date = *(bl->rptr ++); - U->admin_id = *(bl->rptr ++); - U->user_id = *(bl->rptr ++); - U->access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - }; - break; - case LOG_ENCR_CHAT_REQUESTED: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - if (!U) { - U = talloc0 (sizeof (peer_t)); - U->id = id; - insert_encrypted_chat (bl, (void *)U); - } - U->flags |= FLAG_CREATED; - U->state = sc_request; - U->date = *(bl->rptr ++); - U->admin_id = *(bl->rptr ++); - U->user_id = *(bl->rptr ++); - U->access_hash = *(long long *)bl->rptr; - if (!U->print_name) { - peer_t *P = user_chat_get (bl, MK_USER (U->user_id)); - if (P) { - U->print_name = create_print_name (bl, U->id, "!", P->user.first_name, P->user.last_name, 0); - } else { - static char buf[100]; - tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (bl, U->id, "!", buf, 0, 0); - } - peer_insert_name (bl, (void *)U); - } - bl->rptr += 2; - }; - break; - case LOG_ENCR_CHAT_OK: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->state = sc_ok; - } - break; - case CODE_binlog_new_user: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *_U = user_chat_get (bl, id); - if (!_U) { - _U = talloc0 (sizeof (*_U)); - _U->id = id; - insert_user (bl, _U); - } else { - assert (!(_U->flags & FLAG_CREATED)); - } - struct tgl_user *U = (void *)_U; - U->flags |= FLAG_CREATED; - if (get_peer_id (id) == instance->our_id) { - U->flags |= FLAG_USER_SELF; - } - U->first_name = fetch_str_dup (self); - U->last_name = fetch_str_dup (self); - assert (!U->print_name); - U->print_name = create_print_name (bl, U->id, U->first_name, U->last_name, 0, 0); - peer_insert_name (bl, (void *)U); - U->access_hash = fetch_long (self); - U->phone = fetch_str_dup (self); - if (fetch_int (self)) { - U->flags |= FLAG_USER_CONTACT; - } - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_user_delete: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->flags |= FLAG_DELETED; - } - break; - case CODE_binlog_set_user_access_token: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->user.access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - } - break; - case CODE_binlog_set_user_phone: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U); - if (U->user.phone) { tfree_str (U->user.phone); } - U->user.phone = fetch_str_dup (self); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_user_friend: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - int friend = *(bl->rptr ++); - if (friend) { U->flags |= FLAG_USER_CONTACT; } - else { U->flags &= ~FLAG_USER_CONTACT; } - } - break; - case CODE_binlog_user_full_photo: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U); - if (U->flags & FLAG_HAS_PHOTO) { - free_photo (&U->user.photo); - } - fetch_photo (self, &U->user.photo); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_user_blocked: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->user.blocked = *(bl->rptr ++); - } - break; - case CODE_binlog_set_user_full_name: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U); - if (U->user.real_first_name) { tfree_str (U->user.real_first_name); } - if (U->user.real_last_name) { tfree_str (U->user.real_last_name); } - U->user.real_first_name = fetch_str_dup (self); - U->user.real_last_name = fetch_str_dup (self); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_encr_chat_delete: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - assert (_U); - struct secret_chat *U = &_U->encr_chat; - memset (U->key, 0, sizeof (U->key)); - U->flags |= FLAG_DELETED; - U->state = sc_deleted; - if (U->nonce) { - tfree_secure (U->nonce, 256); - U->nonce = 0; - } - if (U->g_key) { - tfree_secure (U->g_key, 256); - U->g_key = 0; - } - } - break; - case CODE_binlog_encr_chat_requested: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - if (!_U) { - _U = talloc0 (sizeof (*_U)); - _U->id = id; - insert_encrypted_chat (bl, _U); - } else { - assert (!(_U->flags & FLAG_CREATED)); - } - struct secret_chat *U = (void *)_U; - U->access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - U->date = *(bl->rptr ++); - U->admin_id = *(bl->rptr ++); - U->user_id = *(bl->rptr ++); - - peer_t *Us = user_chat_get (bl, MK_USER (U->user_id)); - assert (!U->print_name); - if (Us) { - U->print_name = create_print_name (bl, id, "!", Us->user.first_name, Us->user.last_name, 0); - } else { - static char buf[100]; - tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (bl, id, "!", buf, 0, 0); - } - peer_insert_name (bl, (void *)U); - U->g_key = talloc (256); - U->nonce = talloc (256); - memcpy (U->g_key, bl->rptr, 256); - bl->rptr += 64; - memcpy (U->nonce, bl->rptr, 256); - bl->rptr += 64; - - U->flags |= FLAG_CREATED; - U->state = sc_request; - } - break; - case CODE_binlog_set_encr_chat_access_hash: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->encr_chat.access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - } - break; - case CODE_binlog_set_encr_chat_date: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->encr_chat.date = *(bl->rptr ++); - } - break; - case CODE_binlog_set_encr_chat_state: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->encr_chat.state = *(bl->rptr ++); - } - break; - case CODE_binlog_encr_chat_accepted: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - assert (_U); - struct secret_chat *U = &_U->encr_chat; - if (!U->g_key) { - U->g_key = talloc (256); - } - if (!U->nonce) { - U->nonce = talloc (256); - } - memcpy (U->g_key, bl->rptr, 256); - bl->rptr += 64; - memcpy (U->nonce, bl->rptr, 256); - bl->rptr += 64; - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - if (U->state == sc_waiting) { - do_create_keys_end (instance, U); - } - U->state = sc_ok; - } - break; - case CODE_binlog_set_encr_chat_key: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - assert (_U); - struct secret_chat *U = &_U->encr_chat; - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - } - break; - case CODE_binlog_set_dh_params: - bl->rptr ++; - { - if (instance->encr_prime) { tfree (instance->encr_prime, 256); } - instance->encr_root = *(bl->rptr ++); - instance->encr_prime = talloc (256); - memcpy (instance->encr_prime, bl->rptr, 256); - bl->rptr += 64; - instance->encr_param_version = *(bl->rptr ++); - } - break; - case CODE_binlog_encr_chat_init: - bl->rptr ++; - { - peer_t *P = talloc0 (sizeof (*P)); - P->id = MK_ENCR_CHAT (*(bl->rptr ++)); - assert (!user_chat_get (bl, P->id)); - P->encr_chat.user_id = *(bl->rptr ++); - P->encr_chat.admin_id = instance->our_id; - insert_encrypted_chat (bl, P); - peer_t *Us = user_chat_get (bl, MK_USER (P->encr_chat.user_id)); - assert (Us); - P->print_name = create_print_name (bl, P->id, "!", Us->user.first_name, Us->user.last_name, 0); - peer_insert_name (bl, P); - memcpy (P->encr_chat.key, bl->rptr, 256); - bl->rptr += 64; - P->encr_chat.g_key = talloc (256); - memcpy (P->encr_chat.g_key, bl->rptr, 256); - bl->rptr += 64; - P->flags |= FLAG_CREATED; - } - break; - case CODE_binlog_set_pts: - bl->rptr ++; - instance->proto.pts = *(bl->rptr ++); - break; - case CODE_binlog_set_qts: - bl->rptr ++; - instance->proto.qts = *(bl->rptr ++); - break; - case CODE_binlog_set_date: - bl->rptr ++; - instance->proto.last_date = *(bl->rptr ++); - break; - case CODE_binlog_set_seq: - bl->rptr ++; - instance->proto.seq = *(bl->rptr ++); - break; - case CODE_binlog_chat_create: - self->in_ptr ++; - { - peer_id_t id = MK_CHAT (fetch_int (self)); - peer_t *_C = user_chat_get (bl, id); - if (!_C) { - _C = talloc0 (sizeof (*_C)); - _C->id = id; - insert_chat (bl, _C); - } else { - assert (!(_C->flags & FLAG_CREATED)); - } - struct chat *C = &_C->chat; - C->flags = FLAG_CREATED | fetch_int (self); - C->title = fetch_str_dup (self); - assert (!C->print_title); - C->print_title = create_print_name (bl, id, C->title, 0, 0, 0); - peer_insert_name (bl, (void *)C); - C->users_num = fetch_int (self); - C->date = fetch_int (self); - C->version = fetch_int (self); - fetch_data (self, &C->photo_big, sizeof (struct file_location)); - fetch_data (self, &C->photo_small, sizeof (struct file_location)); - }; - bl->rptr = self->in_ptr; - break; - case CODE_binlog_chat_change_flags: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->flags |= *(bl->rptr ++); - C->flags &= ~*(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_title: - self->in_ptr ++; - { - peer_t *_C = user_chat_get (bl, MK_CHAT (fetch_int (self))); - assert (_C && (_C->flags & FLAG_CREATED)); - struct chat *C = &_C->chat; - if (C->title) { tfree_str (C->title); } - C->title = fetch_str_dup (self); - if (C->print_title) { - peer_delete_name (bl, (void *)C); - tfree_str (C->print_title); - } - C->print_title = create_print_name (bl, C->id, C->title, 0, 0, 0); - peer_insert_name (bl, (void *)C); - }; - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_chat_photo: - self->in_ptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (fetch_int (self))); - assert (C && (C->flags & FLAG_CREATED)); - fetch_data (self, &C->photo_big, sizeof (struct file_location)); - fetch_data (self, &C->photo_small, sizeof (struct file_location)); - }; - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_chat_date: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.date = *(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_version: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.version = *(bl->rptr ++); - C->chat.users_num = *(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_admin: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.admin_id = *(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_participants: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.user_list_version = *(bl->rptr ++); - if (C->chat.user_list) { tfree (C->chat.user_list, 12 * C->chat.user_list_size); } - C->chat.user_list_size = *(bl->rptr ++); - C->chat.user_list = talloc (12 * C->chat.user_list_size); - memcpy (C->chat.user_list, bl->rptr, 12 * C->chat.user_list_size); - bl->rptr += 3 * C->chat.user_list_size; - }; - break; - case CODE_binlog_chat_full_photo: - self->in_ptr ++; - { - peer_id_t id = MK_CHAT (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U && (U->flags & FLAG_CREATED)); - if (U->flags & FLAG_HAS_PHOTO) { - free_photo (&U->chat.photo); - } - fetch_photo (self, &U->chat.photo); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_add_chat_participant: - bl->rptr ++; - { - peer_id_t id = MK_CHAT (*(bl->rptr ++)); - peer_t *_C = user_chat_get (bl, id); - assert (_C && (_C->flags & FLAG_CREATED)); - struct chat *C = &_C->chat; - - int version = *(bl->rptr ++); - int user = *(bl->rptr ++); - int inviter = *(bl->rptr ++); - int date = *(bl->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 = trealloc (C->user_list, 12 * C->user_list_size - 12, 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: - bl->rptr ++; - { - peer_id_t id = MK_CHAT (*(bl->rptr ++)); - peer_t *_C = user_chat_get (bl, id); - assert (_C && (_C->flags & FLAG_CREATED)); - struct chat *C = &_C->chat; - - int version = *(bl->rptr ++); - int user = *(bl->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 = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); - C->user_list_version = version; - } - break; - case CODE_binlog_create_message_text: - case CODE_binlog_send_message_text: - self->in_ptr ++; - { - long long id; - if (op == CODE_binlog_create_message_text) { - id = fetch_int (self); - } else { - id = fetch_long (self); - } - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - M->instance = instance; - message_insert_tree (M); - bl->messages_allocated ++; - event_update_new_message (instance, M); - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - if (t == PEER_ENCR_CHAT) { - M->flags |= FLAG_ENCRYPTED; - } - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - if (t == PEER_ENCR_CHAT) { - M->media.type = CODE_decrypted_message_media_empty; - } else { - M->media.type = CODE_message_media_empty; - } - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - if (op == CODE_binlog_send_message_text) { - message_insert_unsent (M); - M->flags |= FLAG_PENDING; - } - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_text_fwd: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - M->fwd_from_id = MK_USER (fetch_int (self)); - M->fwd_date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - M->media.type = CODE_message_media_empty; - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_media: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - fetch_message_media (self, &M->media); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_media_encr: - self->in_ptr ++; - { - long long id = fetch_long (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - fetch_message_media_encrypted (self, &M->media); - fetch_encrypted_message_file (self, &M->media); - - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_media_fwd: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - M->fwd_from_id = MK_USER (fetch_int (self)); - M->fwd_date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - fetch_message_media (self, &M->media); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_service: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - fetch_message_action (self, &M->action); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - M->service = 1; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_service_encr: - self->in_ptr ++; - { - long long id = fetch_long (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - fetch_message_action_encrypted (self, &M->action); - - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - M->service = 1; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_service_fwd: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - M->fwd_from_id = MK_USER (fetch_int (self)); - M->fwd_date = fetch_int (self); - fetch_message_action (self, &M->action); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - M->service = 1; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_unread: - bl->rptr ++; - { - struct message *M = message_get(bl, *(bl->rptr ++)); - assert (M); - M->unread = 0; - } - break; - case CODE_binlog_set_message_sent: - bl->rptr ++; - { - struct message *M = message_get(bl, *(long long *)bl->rptr); - bl->rptr += 2; - assert (M); - message_remove_unsent (M); - M->flags &= ~FLAG_PENDING; - } - break; - case CODE_binlog_set_msg_id: - bl->rptr ++; - { - struct message *M = message_get(bl, *(long long *)bl->rptr); - bl->rptr += 2; - assert (M); - if (M->flags & FLAG_PENDING) { - message_remove_unsent (M); - M->flags &= ~FLAG_PENDING; - } - message_remove_tree (M); - message_del_peer (M); - M->id = *(bl->rptr ++); - if (message_get(bl, M->id)) { - free_message (M); - tfree (M, sizeof (*M)); - } else { - message_insert_tree (M); - message_add_peer (M); - } - } - break; - case CODE_binlog_delete_msg: - bl->rptr ++; - { - struct message *M = message_get(bl, *(long long *)bl->rptr); - bl->rptr += 2; - assert (M); - if (M->flags & FLAG_PENDING) { - message_remove_unsent (M); - M->flags &= ~FLAG_PENDING; - } - message_remove_tree (M); - message_del_peer (M); - message_del_use (M); - free_message (M); - tfree (M, sizeof (*M)); - } - break; - case CODE_update_user_photo: - case CODE_update_user_name: - work_update_binlog (self); - bl->rptr = self->in_ptr; - break; - default: - debug ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(bl->rptr - 1), op, *(bl->rptr + 1), bl->binlog_pos); - - assert (0); - } - if (verbosity >= 2) { - debug ("Event end\n"); - } - bl->in_replay_log = 0; - bl->binlog_pos += (bl->rptr - start) * 4; -} - -void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int len) { - debug ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); - assert (!(len & 3)); - if (bl->in_replay_log) { return; } - bl->rptr = (void *)data; - bl->wptr = bl->rptr + (len / 4); - int *in = self->in_ptr; - int *end = self->in_end; - replay_log_event (self->connection->instance); - if (bl->rptr != bl->wptr) { - debug ("Unread %lld ints. Len = %d\n", (long long)(bl->wptr - bl->rptr), len); - assert (bl->rptr == bl->wptr); - } - if (bl->binlog_enabled) { - assert (bl->binlog_fd > 0); - assert (write (bl->binlog_fd, data, len) == len); - } - self->in_ptr = in; - self->in_end = end; -} - -void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf) { - struct mtproto_connection *self = instance->connection; - struct binlog *bl = instance->bl; - - static unsigned char sha1_buffer[20]; - SHA1 (buf, 256, sha1_buffer); - long long fingerprint = *(long long *)(sha1_buffer + 12); - int *ev = alloc_log_event (bl, 8 + 8 + 256); - ev[0] = LOG_AUTH_KEY; - ev[1] = num; - *(long long *)(ev + 2) = fingerprint; - memcpy (ev + 4, buf, 256); - add_log_event (bl, self, ev, 8 + 8 + 256); -} - -void bl_do_set_our_id (struct binlog *bl, struct mtproto_connection *self, int id) { - int *ev = alloc_log_event (bl, 8); - ev[0] = LOG_OUR_ID; - ev[1] = id; - add_log_event (bl, self, ev, 8); -} - -void bl_do_new_user (struct binlog *bl, struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, - long long access_token, const char *p, int pl, int contact) { - - clear_packet (self); - out_int (self, CODE_binlog_new_user); - out_int (self, id); - out_cstring (self, f ? f : "", fl); - out_cstring (self, l ? l : "", ll); - out_long (self, access_token); - out_cstring (self, p ? p : "", pl); - out_int (self, contact); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U) { - if (U->flags & FLAG_DELETED) { return; } - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_user_delete; - ev[1] = get_peer_id (U->id); - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, - long long photo_id, struct file_location *big, struct file_location *small) { - if (photo_id == U->photo_id) { return; } - if (!photo_id) { - int *ev = alloc_log_event (bl, 20); - ev[0] = CODE_update_user_photo; - ev[1] = get_peer_id (U->id); - ev[2] = self->connection->instance->proto.last_date; - ev[3] = CODE_user_profile_photo_empty; - ev[4] = CODE_bool_false; - add_log_event (bl, self, ev, 20); - } else { - clear_packet (self); - out_int (self, CODE_update_user_photo); - out_int (self, get_peer_id (U->id)); - out_int (self, self->connection->instance->proto.last_date); - out_int (self, CODE_user_profile_photo); - out_long (self, photo_id); - if (small->dc >= 0) { - out_int (self, CODE_file_location); - out_int (self, small->dc); - out_long (self, small->volume); - out_int (self, small->local_id); - out_long (self, small->secret); - } else { - out_int (self, CODE_file_location_unavailable); - out_long (self, small->volume); - out_int (self, small->local_id); - out_long (self, small->secret); - } - if (big->dc >= 0) { - out_int (self, CODE_file_location); - out_int (self, big->dc); - out_long (self, big->volume); - out_int (self, big->local_id); - out_long (self, big->secret); - } else { - out_int (self, CODE_file_location_unavailable); - out_long (self, big->volume); - out_int (self, big->local_id); - out_long (self, big->secret); - } - out_int (self, CODE_bool_false); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); - } -} - -void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, - int fl, const char *l, int ll) { - if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) && - (U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) { - return; - } - clear_packet (self); - out_int (self, CODE_update_user_name); - out_int (self, get_peer_id (U->id)); - out_cstring (self, f, fl); - out_cstring (self, l, ll); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long access_token) { - if (U->access_hash == access_token) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_set_user_access_token; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = access_token; - add_log_event (bl, self, ev, 16); -} - -void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, -const char *p, int pl) { - if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) { - return; - } - clear_packet (self); - out_int (self, CODE_binlog_set_user_phone); - out_int (self, get_peer_id (U->id)); - out_cstring (self, p, pl); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int friend) { - if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_user_friend; - ev[1] = get_peer_id (U->id); - ev[2] = friend; - add_log_event (bl, self, ev, 12); -} - -void bl_do_dc_option (struct binlog *bl, struct mtproto_connection *self, int id, int l1, const char *name, - int l2, const char *ip, int port, struct telegram *instance) { - struct dc *DC = instance->auth.DC_list[id]; - if (DC) { return; } - - clear_packet (self); - out_int (self, CODE_binlog_dc_option); - out_int (self, id); - out_cstring (self, name, l1); - out_cstring (self, ip, l2); - out_int (self, port); - - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_dc_signed (struct binlog *bl, struct mtproto_connection *self, int id) { - int *ev = alloc_log_event (bl, 8); - ev[0] = LOG_DC_SIGNED; - ev[1] = id; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_working_dc (struct binlog *bl, struct mtproto_connection *self, int num) { - int *ev = alloc_log_event (bl, 8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = num; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const int *start, int len) { - if (U->photo.id == *(long long *)(start + 1)) { return; } - int *ev = alloc_log_event (bl, len + 8); - ev[0] = CODE_binlog_user_full_photo; - ev[1] = get_peer_id (U->id); - memcpy (ev + 2, start, len); - add_log_event (bl, self, ev, len + 8); -} - -void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int blocked) { - if (U->blocked == blocked) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_user_blocked; - ev[1] = get_peer_id (U->id); - ev[2] = blocked; - add_log_event (bl, self, ev, 12); -} - -void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll) { - if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) && - (U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) { - return; - } - clear_packet (self); - out_int (self, CODE_binlog_set_user_full_name); - out_int (self, get_peer_id (U->id)); - out_cstring (self, f, fl); - out_cstring (self, l, ll); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_encr_chat_delete (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U) { - if (!(U->flags & FLAG_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; } - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_encr_chat_delete; - ev[1] = get_peer_id (U->id); - add_log_event (bl, self, ev, 8); -} - -void bl_do_encr_chat_requested (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, - long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], - unsigned char nonce[]) { - if (U->state != sc_none) { return; } - int *ev = alloc_log_event (bl, 540); - ev[0] = CODE_binlog_encr_chat_requested; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = access_hash; - ev[4] = date; - ev[5] = admin_id; - ev[6] = user_id; - memcpy (ev + 7, g_key, 256); - memcpy (ev + 7 + 64, nonce, 256); - add_log_event (bl, self, ev, 540); -} - -void bl_do_set_encr_chat_access_hash (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, - long long access_hash) { - if (U->access_hash == access_hash) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_set_encr_chat_access_hash; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = access_hash; - add_log_event (bl, self, ev, 16); -} - -void bl_do_set_encr_chat_date (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, int date) { - if (U->date == date) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_encr_chat_date; - ev[1] = get_peer_id (U->id); - ev[2] = date; - add_log_event (bl, self, ev, 12); -} - -void bl_do_set_encr_chat_state (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state) { - if (U->state == state) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_encr_chat_state; - ev[1] = get_peer_id (U->id); - ev[2] = state; - add_log_event (bl, self, ev, 12); -} - -void bl_do_encr_chat_accepted (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint) { - if (U->state != sc_waiting && U->state != sc_request) { return; } - int *ev = alloc_log_event (bl, 528); - ev[0] = CODE_binlog_encr_chat_accepted; - ev[1] = get_peer_id (U->id); - memcpy (ev + 2, g_key, 256); - memcpy (ev + 66, nonce, 256); - *(long long *)(ev + 130) = key_fingerprint; - add_log_event (bl, self, ev, 528); -} - -void bl_do_set_encr_chat_key (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint) { - int *ev = alloc_log_event (bl, 272); - ev[0] = CODE_binlog_set_encr_chat_key; - ev[1] = get_peer_id (E->id); - memcpy (ev + 2, key, 256); - *(long long *)(ev + 66) = key_fingerprint; - add_log_event (bl, self, ev, 272); -} - -void bl_do_set_dh_params (struct binlog *bl, struct mtproto_connection *self, int root, unsigned char prime[], int version) { - int *ev = alloc_log_event (bl, 268); - ev[0] = CODE_binlog_set_dh_params; - ev[1] = root; - memcpy (ev + 2, prime, 256); - ev[66] = version; - add_log_event (bl, self, ev, 268); -} - -void bl_do_encr_chat_init (struct binlog *bl, struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]) { - int *ev = alloc_log_event (bl, 524); - ev[0] = CODE_binlog_encr_chat_init; - ev[1] = id; - ev[2] = user_id; - memcpy (ev + 3, random, 256); - memcpy (ev + 67, g_a, 256); - add_log_event (bl, self, ev, 524); -} - -void bl_do_set_pts (struct binlog *bl, struct mtproto_connection *self, int pts) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_pts; - ev[1] = pts; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_qts (struct binlog *bl, struct mtproto_connection *self, int qts) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_qts; - ev[1] = qts; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_date (struct binlog *bl, struct mtproto_connection *self, int date) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_date; - ev[1] = date; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_seq (struct binlog *bl, struct mtproto_connection *self, int seq) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_seq; - ev[1] = seq; - add_log_event (bl, self, ev, 8); -} - -void bl_do_create_chat (struct binlog *bl, struct mtproto_connection *self, 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 (self); - out_int (self, CODE_binlog_chat_create); - out_int (self, get_peer_id (C->id)); - out_int (self, y); - out_cstring (self, s, l); - out_int (self, users_num); - out_int (self, date); - out_int (self, version); - out_data (self, big, sizeof (struct file_location)); - out_data (self, small, sizeof (struct file_location)); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_chat_forbid (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on) { - if (on) { - if (C->flags & FLAG_FORBIDDEN) { return; } - int *ev = alloc_log_event (bl, 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 (bl, self, ev, 16); - } else { - if (!(C->flags & FLAG_FORBIDDEN)) { return; } - int *ev = alloc_log_event (bl, 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 (bl, self, ev, 16); - } -} - -void bl_do_set_chat_title (struct binlog *bl, struct mtproto_connection *self, struct chat *C, const char *s, int l) { - if (C->title && (int)strlen (C->title) == l && !strncmp (C->title, s, l)) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_chat_title); - out_int (self, get_peer_id (C->id)); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_chat_photo (struct binlog *bl, struct mtproto_connection *self, 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 (self); - out_int (self, CODE_binlog_set_chat_photo); - out_int (self, get_peer_id (C->id)); - out_data (self, big, sizeof (struct file_location)); - out_data (self, small, sizeof (struct file_location)); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_chat_date (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int date) { - if (C->date == date) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_chat_date; - ev[1] = get_peer_id (C->id); - ev[2] = date; - add_log_event (bl, self, ev, 12); -} - -void bl_do_set_chat_set_in_chat (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on) { - if (on) { - if (C->flags & FLAG_CHAT_IN_CHAT) { return; } - int *ev = alloc_log_event (bl, 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 (bl, self, ev, 16); - } else { - if (!(C->flags & FLAG_CHAT_IN_CHAT)) { return; } - int *ev = alloc_log_event (bl, 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 (bl, self, ev, 16); - } -} - -void bl_do_set_chat_version (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num) { - if (C->version >= version) { return; } - int *ev = alloc_log_event (bl, 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 (bl, self, ev, 16); -} - -void bl_do_set_chat_admin (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int admin) { - if (C->admin_id == admin) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_chat_admin; - ev[1] = get_peer_id (C->id); - ev[2] = admin; - add_log_event (bl, self, ev, 12); -} - -void bl_do_set_chat_participants (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num, struct chat_user *users) { - if (C->user_list_version >= version) { return; } - int *ev = alloc_log_event (bl, 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 (bl, self, ev, 12 * user_num + 16); -} - -void bl_do_set_chat_full_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *U, const int *start, int len) { - if (U->photo.id == *(long long *)(start + 1)) { return; } - int *ev = alloc_log_event (bl, len + 8); - ev[0] = CODE_binlog_chat_full_photo; - ev[1] = get_peer_id (U->id); - memcpy (ev + 2, start, len); - add_log_event (bl, self, ev, len + 8); -} - -void bl_do_chat_add_user (struct binlog *bl, struct mtproto_connection *self, 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 (bl, 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 (bl, self, ev, 24); -} - -void bl_do_chat_del_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user) { - if (C->user_list_version >= version || !C->user_list_version) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_add_chat_participant; - ev[1] = get_peer_id (C->id); - ev[2] = version; - ev[3] = user; - add_log_event (bl, self, ev, 16); -} - -void bl_do_create_message_text (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_text); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_send_message_text (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s) { - clear_packet (self); - out_int (self, CODE_binlog_send_message_text); - out_long (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_create_message_text_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_text_fwd); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_int (self, fwd); - out_int (self, fwd_date); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_create_message_media (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_media); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_create_message_media_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_media_encr); - out_long (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - out_ints (self, data, len); - out_ints (self, data2, len2); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_create_message_media_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_media_fwd); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_int (self, fwd); - out_int (self, fwd_date); - out_cstring (self, s, l); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_create_message_service (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_service); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} -void bl_do_create_message_service_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_service_encr); - out_long (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_create_message_service_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_service_fwd); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_int (self, fwd); - out_int (self, fwd_date); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_unread (struct binlog *bl, struct mtproto_connection *self, struct message *M, int unread) { - if (unread || !M->unread) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_unread); - out_int (self, M->id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_message_sent (struct binlog *bl, struct mtproto_connection *self, struct message *M) { - if (!(M->flags & FLAG_PENDING)) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_message_sent); - out_long (self, M->id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_msg_id (struct binlog *bl, struct mtproto_connection *self, struct message *M, int id) { - if (M->id == id) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_msg_id); - out_long (self, M->id); - out_int (self, id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_delete_msg (struct binlog *bl, struct mtproto_connection *self, struct message *M) { - clear_packet (self); - out_int (self, CODE_binlog_delete_msg); - out_long (self, M->id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} diff --git a/binlog.h b/binlog.h deleted file mode 100644 index ac4b7b1..0000000 --- a/binlog.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __BINLOG_H__ -#define __BINLOG_H__ - -#include "structures.h" -#include "telegram.h" - -#define LOG_START 0x8948329a -#define LOG_AUTH_KEY 0x984932aa -#define LOG_DEFAULT_DC 0x95382908 -#define LOG_OUR_ID 0x8943211a -#define LOG_DC_SIGNED 0x234f9893 -#define LOG_DC_SALT 0x92192ffa -#define LOG_DH_CONFIG 0x8983402b -#define LOG_ENCR_CHAT_KEY 0x894320aa -#define LOG_ENCR_CHAT_SEND_ACCEPT 0x12ab01c4 -#define LOG_ENCR_CHAT_SEND_CREATE 0xab091e24 -#define LOG_ENCR_CHAT_DELETED 0x99481230 -#define LOG_ENCR_CHAT_WAITING 0x7102100a -#define LOG_ENCR_CHAT_REQUESTED 0x9011011a -#define LOG_ENCR_CHAT_OK 0x7612ce13 - -#define CODE_binlog_new_user 0xe04f30de -#define CODE_binlog_user_delete 0xf7a27c79 -#define CODE_binlog_set_user_access_token 0x1349f615 -#define CODE_binlog_set_user_phone 0x5d3afde2 -#define CODE_binlog_set_user_friend 0x75a7ec5a -#define CODE_binlog_dc_option 0x08c0ef19 -#define CODE_binlog_user_full_photo 0xfaa35824 -#define CODE_binlog_user_blocked 0xb2dea7cd -#define CODE_binlog_set_user_full_name 0x4ceb4cf0 -#define CODE_binlog_encr_chat_delete 0xb9d33f87 -#define CODE_binlog_encr_chat_requested 0xf57d1ea2 -#define CODE_binlog_set_encr_chat_access_hash 0xe5612bb3 -#define CODE_binlog_set_encr_chat_date 0x54f16911 -#define CODE_binlog_set_encr_chat_state 0x76a6e45b -#define CODE_binlog_encr_chat_accepted 0x4627e926 -#define CODE_binlog_set_encr_chat_key 0x179df2d4 -#define CODE_binlog_set_dh_params 0x20ba46bc -#define CODE_binlog_encr_chat_init 0x939cd1c7 -#define CODE_binlog_set_pts 0x844e4c1c -#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 -#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 -#define CODE_binlog_create_message_text 0x269acd5b -#define CODE_binlog_create_message_text_fwd 0xa3d864cd -#define CODE_binlog_create_message_service 0xbbe5e94b -#define CODE_binlog_create_message_service_fwd 0xea9c57ae -#define CODE_binlog_create_message_media 0x62a92d19 -#define CODE_binlog_create_message_media_fwd 0xbefdc462 -#define CODE_binlog_send_message_text 0x31cfd652 -#define CODE_binlog_set_unread 0x21d4c909 -#define CODE_binlog_set_message_sent 0xc335282b -#define CODE_binlog_set_msg_id 0xf3285b6a -#define CODE_binlog_create_message_media_encr 0x19cd7c9d -#define CODE_binlog_create_message_service_encr 0x8b4b9395 -#define CODE_binlog_delete_msg 0xa1d6ab6d - -void *alloc_log_event (struct binlog *bl, int l); -void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int l); -void write_binlog (struct binlog *bl); -void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf); - -void bl_do_dc_option (struct binlog *bl, struct mtproto_connection *self, int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance); - -void bl_do_set_our_id (struct binlog *bl, struct mtproto_connection *self, int id); -void bl_do_new_user (struct binlog *bl, struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact); -void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U); -void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long photo_id, struct file_location *big, struct file_location *small); -void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll); -void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long access_token); -void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *p, int pl); -void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int friend); -void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const int *start, int len); -void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int blocked); -void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll); - -void bl_do_encr_chat_delete (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U); -void bl_do_encr_chat_requested (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]); -void bl_do_set_encr_chat_access_hash (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash); -void bl_do_set_encr_chat_date (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, int date); -void bl_do_set_encr_chat_state (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state); -void bl_do_encr_chat_accepted (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint); -void bl_do_set_encr_chat_key (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint); -void bl_do_encr_chat_init (struct binlog *bl, struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]); - -void bl_do_dc_signed (struct binlog *bl, struct mtproto_connection *self, int id); -void bl_do_set_working_dc (struct binlog *bl, struct mtproto_connection *self, int num); -void bl_do_set_dh_params (struct binlog *bl, struct mtproto_connection *self, int root, unsigned char prime[], int version); - -void bl_do_set_pts (struct binlog *bl, struct mtproto_connection *self, int pts); -void bl_do_set_qts (struct binlog *bl, struct mtproto_connection *self, int qts); -void bl_do_set_seq (struct binlog *bl, struct mtproto_connection *self, int seq); -void bl_do_set_date (struct binlog *bl, struct mtproto_connection *self, int date); - -void bl_do_create_chat (struct binlog *bl, struct mtproto_connection *self, 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 binlog *bl, struct mtproto_connection *self, struct chat *C, int on); -void bl_do_set_chat_title (struct binlog *bl, struct mtproto_connection *self, struct chat *C, const char *s, int l); -void bl_do_set_chat_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *C, struct file_location *big, struct file_location *small); -void bl_do_set_chat_date (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int date); -void bl_do_set_chat_set_in_chat (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on); -void bl_do_set_chat_version (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num); -void bl_do_set_chat_admin (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int admin); -void bl_do_set_chat_participants (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num, struct chat_user *users); -void bl_do_set_chat_full_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *U, const int *start, int len); -void bl_do_chat_add_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user, int inviter, int date); -void bl_do_chat_del_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user); - -void bl_do_create_message_text (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); -void bl_do_create_message_text_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s); -void bl_do_create_message_service (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); -void bl_do_create_message_service_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len); -void bl_do_create_message_media (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len); -void bl_do_create_message_media_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len); -void bl_do_create_message_media_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2); -void bl_do_create_message_service_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len); -void bl_do_send_message_text (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s); -void bl_do_set_unread (struct binlog *bl, struct mtproto_connection *self, struct message *M, int unread); -void bl_do_set_message_sent (struct binlog *bl, struct mtproto_connection *self, struct message *M); -void bl_do_set_msg_id (struct binlog *bl, struct mtproto_connection *self, struct message *M, int id); -void bl_do_delete_msg (struct binlog *bl, struct mtproto_connection *self, struct message *M); -#endif diff --git a/binlog.tl b/binlog.tl deleted file mode 100644 index c7c80b7..0000000 --- a/binlog.tl +++ /dev/null @@ -1,10 +0,0 @@ -log.peer peer_type:int peer_id:int = log.Peer; - -log.dc num:int hostname:string ip:string port:int = log.Event; -log.dcRenum old_num:int new_num:int = log.Event; -log.authKey dc:int key:bytes key_id:long = log.Event; -log.signIn dc:int id:int = log.Event; - - -log.user id:int flags:int access_hash:long first_name:string last_name:string real_first_name:string real_last_name:string phone:string photo:log.Photo photo_id:long photo_big:log.FileLocation photo_small:long.FileLocation = log.Event; - diff --git a/constants.h b/constants.h deleted file mode 100644 index cd19aa8..0000000 --- a/constants.h +++ /dev/null @@ -1,383 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef CONSTANTS_H -#define CONSTANTS_H -#define CODE_bool_false 0xbc799737 -#define CODE_bool_true 0x997275b5 -#define CODE_vector 0x1cb5c415 -#define CODE_error 0xc4b9f9bb -#define CODE_null 0x56730bcc -#define CODE_input_peer_empty 0x7f3b18ea -#define CODE_input_peer_self 0x7da07ec9 -#define CODE_input_peer_contact 0x1023dbe8 -#define CODE_input_peer_foreign 0x9b447325 -#define CODE_input_peer_chat 0x179be863 -#define CODE_input_user_empty 0xb98886cf -#define CODE_input_user_self 0xf7c1b13f -#define CODE_input_user_contact 0x86e94f65 -#define CODE_input_user_foreign 0x655e74ff -#define CODE_input_phone_contact 0xf392b7f4 -#define CODE_input_file 0xf52ff27f -#define CODE_input_media_empty 0x9664f57f -#define CODE_input_media_uploaded_photo 0x2dc53a7d -#define CODE_input_media_photo 0x8f2ab2ec -#define CODE_input_media_geo_point 0xf9c44144 -#define CODE_input_media_contact 0xa6e45987 -#define CODE_input_media_uploaded_video 0x4847d92a -#define CODE_input_media_uploaded_thumb_video 0xe628a145 -#define CODE_input_media_video 0x7f023ae6 -#define CODE_input_chat_photo_empty 0x1ca48f57 -#define CODE_input_chat_uploaded_photo 0x94254732 -#define CODE_input_chat_photo 0xb2e1bf08 -#define CODE_input_geo_point_empty 0xe4c123d6 -#define CODE_input_geo_point 0xf3b7acc9 -#define CODE_input_photo_empty 0x1cd7bf0d -#define CODE_input_photo 0xfb95c6c4 -#define CODE_input_video_empty 0x5508ec75 -#define CODE_input_video 0xee579652 -#define CODE_input_file_location 0x14637196 -#define CODE_input_video_file_location 0x3d0364ec -#define CODE_input_photo_crop_auto 0xade6b004 -#define CODE_input_photo_crop 0xd9915325 -#define CODE_input_app_event 0x770656a8 -#define CODE_peer_user 0x9db1bc6d -#define CODE_peer_chat 0xbad0e5bb -#define CODE_storage_file_unknown 0xaa963b05 -#define CODE_storage_file_jpeg 0x7efe0e -#define CODE_storage_file_gif 0xcae1aadf -#define CODE_storage_file_png 0xa4f63c0 -#define CODE_storage_file_mp3 0x528a0677 -#define CODE_storage_file_mov 0x4b09ebbc -#define CODE_storage_file_partial 0x40bc6f52 -#define CODE_storage_file_mp4 0xb3cea0e4 -#define CODE_storage_file_webp 0x1081464c -#define CODE_file_location_unavailable 0x7c596b46 -#define CODE_file_location 0x53d69076 -#define CODE_user_empty 0x200250ba -#define CODE_user_self 0x720535ec -#define CODE_user_contact 0xf2fb8319 -#define CODE_user_request 0x22e8ceb0 -#define CODE_user_foreign 0x5214c89d -#define CODE_user_deleted 0xb29ad7cc -#define CODE_user_profile_photo_empty 0x4f11bae1 -#define CODE_user_profile_photo 0xd559d8c8 -#define CODE_user_status_empty 0x9d05049 -#define CODE_user_status_online 0xedb93949 -#define CODE_user_status_offline 0x8c703f -#define CODE_chat_empty 0x9ba2d800 -#define CODE_chat 0x6e9c9bc7 -#define CODE_chat_forbidden 0xfb0ccc41 -#define CODE_chat_full 0x630e61be -#define CODE_chat_participant 0xc8d7493e -#define CODE_chat_participants_forbidden 0xfd2bb8a -#define CODE_chat_participants 0x7841b415 -#define CODE_chat_photo_empty 0x37c1011c -#define CODE_chat_photo 0x6153276a -#define CODE_message_empty 0x83e5de54 -#define CODE_message 0x22eb6aba -#define CODE_message_forwarded 0x5f46804 -#define CODE_message_service 0x9f8d60bb -#define CODE_message_media_empty 0x3ded6320 -#define CODE_message_media_photo 0xc8c45a2a -#define CODE_message_media_video 0xa2d24290 -#define CODE_message_media_geo 0x56e0d474 -#define CODE_message_media_contact 0x5e7d2f39 -#define CODE_message_media_unsupported 0x29632a36 -#define CODE_message_action_empty 0xb6aef7b0 -#define CODE_message_action_chat_create 0xa6638b9a -#define CODE_message_action_chat_edit_title 0xb5a1ce5a -#define CODE_message_action_chat_edit_photo 0x7fcb13a8 -#define CODE_message_action_chat_delete_photo 0x95e3fbef -#define CODE_message_action_chat_add_user 0x5e3cfc4b -#define CODE_message_action_chat_delete_user 0xb2ae9b0c -#define CODE_dialog 0x214a8cdf -#define CODE_photo_empty 0x2331b22d -#define CODE_photo 0x22b56751 -#define CODE_photo_size_empty 0xe17e23c -#define CODE_photo_size 0x77bfb61b -#define CODE_photo_cached_size 0xe9a734fa -#define CODE_video_empty 0xc10658a8 -#define CODE_video 0x5a04a49f -#define CODE_geo_point_empty 0x1117dd5f -#define CODE_geo_point 0x2049d70c -#define CODE_auth_checked_phone 0xe300cc3b -#define CODE_auth_sent_code 0xefed51d9 -#define CODE_auth_authorization 0xf6b673a4 -#define CODE_auth_exported_authorization 0xdf969c2d -#define CODE_input_notify_peer 0xb8bc5b0c -#define CODE_input_notify_users 0x193b4417 -#define CODE_input_notify_chats 0x4a95e84e -#define CODE_input_notify_all 0xa429b886 -#define CODE_input_peer_notify_events_empty 0xf03064d8 -#define CODE_input_peer_notify_events_all 0xe86a2c74 -#define CODE_input_peer_notify_settings 0x46a2ce98 -#define CODE_peer_notify_events_empty 0xadd53cb3 -#define CODE_peer_notify_events_all 0x6d1ded88 -#define CODE_peer_notify_settings_empty 0x70a68512 -#define CODE_peer_notify_settings 0x8d5e11ee -#define CODE_wall_paper 0xccb03657 -#define CODE_user_full 0x771095da -#define CODE_contact 0xf911c994 -#define CODE_imported_contact 0xd0028438 -#define CODE_contact_blocked 0x561bc879 -#define CODE_contact_found 0xea879f95 -#define CODE_contact_suggested 0x3de191a1 -#define CODE_contact_status 0xaa77b873 -#define CODE_chat_located 0x3631cf4c -#define CODE_contacts_foreign_link_unknown 0x133421f8 -#define CODE_contacts_foreign_link_requested 0xa7801f47 -#define CODE_contacts_foreign_link_mutual 0x1bea8ce1 -#define CODE_contacts_my_link_empty 0xd22a1c60 -#define CODE_contacts_my_link_requested 0x6c69efee -#define CODE_contacts_my_link_contact 0xc240ebd9 -#define CODE_contacts_link 0xeccea3f5 -#define CODE_contacts_contacts 0x6f8b8cb2 -#define CODE_contacts_contacts_not_modified 0xb74ba9d2 -#define CODE_contacts_imported_contacts 0xd1cd0a4c -#define CODE_contacts_blocked 0x1c138d15 -#define CODE_contacts_blocked_slice 0x900802a1 -#define CODE_contacts_found 0x566000e -#define CODE_contacts_suggested 0x5649dcc5 -#define CODE_messages_dialogs 0x15ba6c40 -#define CODE_messages_dialogs_slice 0x71e094f3 -#define CODE_messages_messages 0x8c718e87 -#define CODE_messages_messages_slice 0xb446ae3 -#define CODE_messages_message_empty 0x3f4e0648 -#define CODE_messages_message 0xff90c417 -#define CODE_messages_stated_messages 0x969478bb -#define CODE_messages_stated_message 0xd07ae726 -#define CODE_messages_sent_message 0xd1f4d35c -#define CODE_messages_chat 0x40e9002a -#define CODE_messages_chats 0x8150cbd8 -#define CODE_messages_chat_full 0xe5d7d19c -#define CODE_messages_affected_history 0xb7de36f2 -#define CODE_input_messages_filter_empty 0x57e2f66c -#define CODE_input_messages_filter_photos 0x9609a51c -#define CODE_input_messages_filter_video 0x9fc00e65 -#define CODE_input_messages_filter_photo_video 0x56e9f0e4 -#define CODE_update_new_message 0x13abdb3 -#define CODE_update_message_i_d 0x4e90bfd6 -#define CODE_update_read_messages 0xc6649e31 -#define CODE_update_delete_messages 0xa92bfe26 -#define CODE_update_restore_messages 0xd15de04d -#define CODE_update_user_typing 0x6baa8508 -#define CODE_update_chat_user_typing 0x3c46cfe6 -#define CODE_update_chat_participants 0x7761198 -#define CODE_update_user_status 0x1bfbd823 -#define CODE_update_user_name 0xda22d9ad -#define CODE_update_user_photo 0x95313b0c -#define CODE_update_contact_registered 0x2575bbb9 -#define CODE_update_contact_link 0x51a48a9a -#define CODE_update_activation 0x6f690963 -#define CODE_update_new_authorization 0x8f06529a -#define CODE_updates_state 0xa56c2a3e -#define CODE_updates_difference_empty 0x5d75a138 -#define CODE_updates_difference 0xf49ca0 -#define CODE_updates_difference_slice 0xa8fb1981 -#define CODE_updates_too_long 0xe317af7e -#define CODE_update_short_message 0xd3f45784 -#define CODE_update_short_chat_message 0x2b2fbd4e -#define CODE_update_short 0x78d4dec1 -#define CODE_updates_combined 0x725b04c3 -#define CODE_updates 0x74ae4240 -#define CODE_photos_photos 0x8dca6aa5 -#define CODE_photos_photos_slice 0x15051f54 -#define CODE_photos_photo 0x20212ca8 -#define CODE_upload_file 0x96a18d5 -#define CODE_dc_option 0x2ec2a43c -#define CODE_config 0x2e54dd74 -#define CODE_nearest_dc 0x8e1a1775 -#define CODE_help_app_update 0x8987f311 -#define CODE_help_no_app_update 0xc45a6536 -#define CODE_help_invite_text 0x18cb9f78 -#define CODE_messages_stated_messages_links 0x3e74f5c6 -#define CODE_messages_stated_message_link 0xa9af2881 -#define CODE_messages_sent_message_link 0xe9db4a3f -#define CODE_input_geo_chat 0x74d456fa -#define CODE_input_notify_geo_chat_peer 0x4d8ddec8 -#define CODE_geo_chat 0x75eaea5a -#define CODE_geo_chat_message_empty 0x60311a9b -#define CODE_geo_chat_message 0x4505f8e1 -#define CODE_geo_chat_message_service 0xd34fa24e -#define CODE_geochats_stated_message 0x17b1578b -#define CODE_geochats_located 0x48feb267 -#define CODE_geochats_messages 0xd1526db1 -#define CODE_geochats_messages_slice 0xbc5863e8 -#define CODE_message_action_geo_chat_create 0x6f038ebc -#define CODE_message_action_geo_chat_checkin 0xc7d53de -#define CODE_update_new_geo_chat_message 0x5a68e3f7 -#define CODE_wall_paper_solid 0x63117f24 -#define CODE_update_new_encrypted_message 0x12bcbd9a -#define CODE_update_encrypted_chat_typing 0x1710f156 -#define CODE_update_encryption 0xb4a2e88d -#define CODE_update_encrypted_messages_read 0x38fe25b7 -#define CODE_encrypted_chat_empty 0xab7ec0a0 -#define CODE_encrypted_chat_waiting 0x3bf703dc -#define CODE_encrypted_chat_requested 0xc878527e -#define CODE_encrypted_chat 0xfa56ce36 -#define CODE_encrypted_chat_discarded 0x13d6dd27 -#define CODE_input_encrypted_chat 0xf141b5e1 -#define CODE_encrypted_file_empty 0xc21f497e -#define CODE_encrypted_file 0x4a70994c -#define CODE_input_encrypted_file_empty 0x1837c364 -#define CODE_input_encrypted_file_uploaded 0x64bd0306 -#define CODE_input_encrypted_file 0x5a17b5e5 -#define CODE_input_encrypted_file_location 0xf5235d55 -#define CODE_encrypted_message 0xed18c118 -#define CODE_encrypted_message_service 0x23734b06 -#define CODE_decrypted_message_layer 0x99a438cf -#define CODE_decrypted_message 0x1f814f1f -#define CODE_decrypted_message_service 0xaa48327d -#define CODE_decrypted_message_media_empty 0x89f5c4a -#define CODE_decrypted_message_media_photo 0x32798a8c -#define CODE_decrypted_message_media_video 0x4cee6ef3 -#define CODE_decrypted_message_media_geo_point 0x35480a59 -#define CODE_decrypted_message_media_contact 0x588a0a97 -#define CODE_decrypted_message_action_set_message_t_t_l 0xa1733aec -#define CODE_messages_dh_config_not_modified 0xc0e24635 -#define CODE_messages_dh_config 0x2c221edd -#define CODE_messages_sent_encrypted_message 0x560f8935 -#define CODE_messages_sent_encrypted_file 0x9493ff32 -#define CODE_input_file_big 0xfa4f0bb5 -#define CODE_input_encrypted_file_big_uploaded 0x2dc173c8 -#define CODE_update_chat_participant_add 0x3a0eeb22 -#define CODE_update_chat_participant_delete 0x6e5f8c22 -#define CODE_update_dc_options 0x8e5e9873 -#define CODE_input_media_uploaded_audio 0x61a6d436 -#define CODE_input_media_audio 0x89938781 -#define CODE_input_media_uploaded_document 0x34e794bd -#define CODE_input_media_uploaded_thumb_document 0x3e46de5d -#define CODE_input_media_document 0xd184e841 -#define CODE_message_media_document 0x2fda2204 -#define CODE_message_media_audio 0xc6b68300 -#define CODE_input_audio_empty 0xd95adc84 -#define CODE_input_audio 0x77d440ff -#define CODE_input_document_empty 0x72f0eaae -#define CODE_input_document 0x18798952 -#define CODE_input_audio_file_location 0x74dc404d -#define CODE_input_document_file_location 0x4e45abe9 -#define CODE_decrypted_message_media_document 0xb095434b -#define CODE_decrypted_message_media_audio 0x6080758f -#define CODE_audio_empty 0x586988d8 -#define CODE_audio 0x427425e7 -#define CODE_document_empty 0x36f8c871 -#define CODE_document 0x9efc6326 -#define CODE_invoke_after_msg 0xcb9f372d -#define CODE_invoke_after_msgs 0x3dc4b4f0 -#define CODE_invoke_with_layer1 0x53835315 -#define CODE_auth_check_phone 0x6fe51dfb -#define CODE_auth_send_code 0x768d5f4d -#define CODE_auth_send_call 0x3c51564 -#define CODE_auth_sign_up 0x1b067634 -#define CODE_auth_sign_in 0xbcd51581 -#define CODE_auth_log_out 0x5717da40 -#define CODE_auth_reset_authorizations 0x9fab0d1a -#define CODE_auth_send_invites 0x771c1d97 -#define CODE_auth_export_authorization 0xe5bfffcd -#define CODE_auth_import_authorization 0xe3ef9613 -#define CODE_account_register_device 0x446c712c -#define CODE_account_unregister_device 0x65c55b40 -#define CODE_account_update_notify_settings 0x84be5b93 -#define CODE_account_get_notify_settings 0x12b3ad31 -#define CODE_account_reset_notify_settings 0xdb7e1747 -#define CODE_account_update_profile 0xf0888d68 -#define CODE_account_update_status 0x6628562c -#define CODE_account_get_wall_papers 0xc04cfac2 -#define CODE_users_get_users 0xd91a548 -#define CODE_users_get_full_user 0xca30a5b1 -#define CODE_contacts_get_statuses 0xc4a353ee -#define CODE_contacts_get_contacts 0x22c6aa08 -#define CODE_contacts_import_contacts 0xda30b32d -#define CODE_contacts_search 0x11f812d8 -#define CODE_contacts_get_suggested 0xcd773428 -#define CODE_contacts_delete_contact 0x8e953744 -#define CODE_contacts_delete_contacts 0x59ab389e -#define CODE_contacts_block 0x332b49fc -#define CODE_contacts_unblock 0xe54100bd -#define CODE_contacts_get_blocked 0xf57c350f -#define CODE_messages_get_messages 0x4222fa74 -#define CODE_messages_get_dialogs 0xeccf1df6 -#define CODE_messages_get_history 0x92a1df2f -#define CODE_messages_search 0x7e9f2ab -#define CODE_messages_read_history 0xb04f2510 -#define CODE_messages_delete_history 0xf4f8fb61 -#define CODE_messages_delete_messages 0x14f2dd0a -#define CODE_messages_restore_messages 0x395f9d7e -#define CODE_messages_received_messages 0x28abcb68 -#define CODE_messages_set_typing 0x719839e9 -#define CODE_messages_send_message 0x4cde0aab -#define CODE_messages_send_media 0xa3c85d76 -#define CODE_messages_forward_messages 0x514cd10f -#define CODE_messages_get_chats 0x3c6aa187 -#define CODE_messages_get_full_chat 0x3b831c66 -#define CODE_messages_edit_chat_title 0xb4bc68b5 -#define CODE_messages_edit_chat_photo 0xd881821d -#define CODE_messages_add_chat_user 0x2ee9ee9e -#define CODE_messages_delete_chat_user 0xc3c5cd23 -#define CODE_messages_create_chat 0x419d9aee -#define CODE_updates_get_state 0xedd4882a -#define CODE_updates_get_difference 0xa041495 -#define CODE_photos_update_profile_photo 0xeef579a0 -#define CODE_photos_upload_profile_photo 0xd50f9c88 -#define CODE_upload_save_file_part 0xb304a621 -#define CODE_upload_get_file 0xe3a6cfb5 -#define CODE_help_get_config 0xc4f9186b -#define CODE_help_get_nearest_dc 0x1fb33026 -#define CODE_help_get_app_update 0xc812ac7e -#define CODE_help_save_app_log 0x6f02f748 -#define CODE_help_get_invite_text 0xa4a95186 -#define CODE_photos_get_user_photos 0xb7ee553c -#define CODE_invoke_with_layer2 0x289dd1f6 -#define CODE_messages_forward_message 0x3f3f4f2 -#define CODE_messages_send_broadcast 0x41bb0972 -#define CODE_invoke_with_layer3 0xb7475268 -#define CODE_geochats_get_located 0x7f192d8f -#define CODE_geochats_get_recents 0xe1427e6f -#define CODE_geochats_checkin 0x55b3e8fb -#define CODE_geochats_get_full_chat 0x6722dd6f -#define CODE_geochats_edit_chat_title 0x4c8e2273 -#define CODE_geochats_edit_chat_photo 0x35d81a95 -#define CODE_geochats_search 0xcfcdc44d -#define CODE_geochats_get_history 0xb53f7a68 -#define CODE_geochats_set_typing 0x8b8a729 -#define CODE_geochats_send_message 0x61b0044 -#define CODE_geochats_send_media 0xb8f0deff -#define CODE_geochats_create_geo_chat 0xe092e16 -#define CODE_invoke_with_layer4 0xdea0d430 -#define CODE_invoke_with_layer5 0x417a57ae -#define CODE_invoke_with_layer6 0x3a64d54d -#define CODE_invoke_with_layer7 0xa5be56d3 -#define CODE_messages_get_dh_config 0x26cf8950 -#define CODE_messages_request_encryption 0xf64daf43 -#define CODE_messages_accept_encryption 0x3dbc0415 -#define CODE_messages_discard_encryption 0xedd923c5 -#define CODE_messages_set_encrypted_typing 0x791451ed -#define CODE_messages_read_encrypted_history 0x7f4b690a -#define CODE_messages_send_encrypted 0xa9776773 -#define CODE_messages_send_encrypted_file 0x9a901b66 -#define CODE_messages_send_encrypted_service 0x32d439a4 -#define CODE_messages_received_queue 0x55a5bb66 -#define CODE_invoke_with_layer8 0xe9abd9fd -#define CODE_upload_save_big_file_part 0xde7b673d -#define CODE_init_connection 0x69796de9 -#define CODE_invoke_with_layer9 0x76715a63 -#define CODE_invoke_with_layer10 0x39620c41 -#define CODE_invoke_with_layer11 0xa6b88fdf -#define CODE_invoke_with_layer12 0xdda60d3c -#endif diff --git a/gen_constants_h.awk b/gen_constants_h.awk deleted file mode 100644 index 06e6835..0000000 --- a/gen_constants_h.awk +++ /dev/null @@ -1,37 +0,0 @@ -BEGIN { - print "/*"; - print " This file is part of telegram-client."; - print ""; - print " Telegram-client is free software: you can redistribute it and/or modify"; - print " it under the terms of the GNU General Public License as published by"; - print " the Free Software Foundation, either version 2 of the License, or"; - print " (at your option) any later version."; - print ""; - print " Telegram-client is distributed in the hope that it will be useful,"; - print " but WITHOUT ANY WARRANTY; without even the implied warranty of"; - print " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"; - print " GNU General Public License for more details."; - print ""; - print " You should have received a copy of the GNU General Public License"; - print " along with this telegram-client. If not, see ."; - print ""; - print " Copyright Vitaly Valtman 2013"; - print "*/"; - 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/purple-plugin/telegram.png b/imgs/telegram.png similarity index 100% rename from purple-plugin/telegram.png rename to imgs/telegram.png diff --git a/purple-plugin/telegram16.png b/imgs/telegram16.png similarity index 100% rename from purple-plugin/telegram16.png rename to imgs/telegram16.png diff --git a/purple-plugin/telegram22.png b/imgs/telegram22.png similarity index 100% rename from purple-plugin/telegram22.png rename to imgs/telegram22.png diff --git a/purple-plugin/telegram48.png b/imgs/telegram48.png similarity index 100% rename from purple-plugin/telegram48.png rename to imgs/telegram48.png diff --git a/include.h b/include.h deleted file mode 100644 index bf290a1..0000000 --- a/include.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __INCLUDE_H__ -#define __INCLUDE_H__ - -#define UU __attribute__ ((unused)) - -#endif diff --git a/loop.c b/loop.c deleted file mode 100644 index b20ad5b..0000000 --- a/loop.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#define _GNU_SOURCE -#define READLINE_CALLBACKS - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "net.h" -#include "mtproto-client.h" -#include "queries.h" -#include "telegram.h" -#include "loop.h" -#include "binlog.h" - -// - -#include "purple-plugin/telegram-purple.h" -// - -char *get_auth_key_filename (void); -char *get_state_filename (void); -int zero[512]; - - -void write_dc (int auth_file_fd, struct dc *DC) { - debug("writing to auth_file: auth_file_fd: %d, port: %d, ip: %s\n", auth_file_fd, DC->port, DC->ip); - assert (write (auth_file_fd, &DC->port, 4) == 4); - int l = strlen (DC->ip); - assert (write (auth_file_fd, &l, 4) == 4); - assert (write (auth_file_fd, DC->ip, l) == l); - if (DC->flags & 1) { - assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); - assert (write (auth_file_fd, DC->auth_key, 256) == 256); - } else { - assert (write (auth_file_fd, zero, 256 + 8) == 256 + 8); - } - - assert (write (auth_file_fd, &DC->server_salt, 8) == 8); - assert (write (auth_file_fd, &DC->has_auth, 4) == 4); -} - -void write_auth_file (struct authorization_state *state, const char *filename) { - debug("Writing to auth_file: %s\n", filename); - int auth_file_fd = open (filename, O_CREAT | O_RDWR, 0600); - assert (auth_file_fd >= 0); - 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); - assert (write (auth_file_fd, &state->dc_working_num, 4) == 4); - assert (write (auth_file_fd, &state->auth_state, 4) == 4); - int i; - for (i = 0; i <= MAX_DC_ID; i++) { - if (state->DC_list[i]) { - x = 1; - assert (write (auth_file_fd, &x, 4) == 4); - write_dc (auth_file_fd, state->DC_list[i]); - } else { - x = 0; - assert (write (auth_file_fd, &x, 4) == 4); - } - } - assert (write (auth_file_fd, &state->our_id, 4) == 4); - close (auth_file_fd); -} - -void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) { - int port = 0; - assert (read (auth_file_fd, &port, 4) == 4); - int l = 0; - assert (read (auth_file_fd, &l, 4) == 4); - assert (l >= 0); - char *ip = talloc (l + 1); - assert (read (auth_file_fd, ip, l) == l); - ip[l] = 0; - struct dc *DC = alloc_dc (DC_list, id, ip, port); - assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8); - assert (read (auth_file_fd, &DC->auth_key, 256) == 256); - assert (read (auth_file_fd, &DC->server_salt, 8) == 8); - 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 (const char *filename) { - struct authorization_state state; - memset(state.DC_list, 0, 11 * sizeof(void *)); - - debug("empty_auth_file()\n"); - alloc_dc (state.DC_list, TG_DC_NUM, tstrdup (TG_SERVER), TG_PORT); - state.dc_working_num = TG_DC_NUM; - state.auth_state = 0; - write_auth_file (&state, filename); -} - -/** - * Read the auth-file and return the read authorization state - * - * When the given file doesn't exist, create a new empty - * file containing the default authorization state at this - * path - */ -struct authorization_state read_auth_file (const char *filename) { - debug("read_auth_file()\n"); - - struct authorization_state state; - memset(state.DC_list, 0, 11 * sizeof(void *)); - - int auth_file_fd = open (filename, O_RDWR, 0600); - debug("fd: %d\n", auth_file_fd); - if (auth_file_fd < 0) { - debug("auth_file does not exist, creating empty...\n"); - empty_auth_file (filename); - } - auth_file_fd = open (filename, O_RDWR, 0600); - assert (auth_file_fd >= 0); - - // amount of data centers - unsigned x; - // magic number of file - unsigned m; - if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) { - debug("Invalid File content, wrong Magic numebr\n"); - close (auth_file_fd); - empty_auth_file (filename); - return state; - } - assert (read (auth_file_fd, &x, 4) == 4); - assert (x <= MAX_DC_ID); - assert (read (auth_file_fd, &state.dc_working_num, 4) == 4); - assert (read (auth_file_fd, &state.auth_state, 4) == 4); - debug ("dc_working_num=%d, auth_state=%d \n", state.dc_working_num, state.auth_state); - if (m == DC_SERIALIZED_MAGIC) { - state.auth_state = 700; - } - int 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, m, state.DC_list); - debug("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n", - i, state.DC_list[i]->port, state.DC_list[i]->ip, state.DC_list[i]->auth_key_id, - state.DC_list[i]->server_salt, state.DC_list[i]->has_auth); - } else { - debug("loaded dc[%d] - NULL\n", i); - } - } - int l = read (auth_file_fd, &state.our_id, 4); - if (l < 4) { - assert (!l); - } - close (auth_file_fd); - struct dc *DC_working = state.DC_list[state.dc_working_num]; - if (m == DC_SERIALIZED_MAGIC) { - DC_working->has_auth = 1; - } - debug("loaded authorization state - our_id: %d, auth_state: %d, dc_working_num: %d \n", state.our_id, state.auth_state, state.dc_working_num); - return state; -} - -struct protocol_state read_state_file (const char *filename) { - debug("read_state_file()\n"); - struct protocol_state state = {0, 0, 0, 0}; - - int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600); - if (state_file_fd < 0) { - return state; - } - int version, magic; - if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return state; } - if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return state; } - if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return state; } - assert (version >= 0); - int x[4]; - if (read (state_file_fd, x, 16) < 16) { - close (state_file_fd); - return state; - } - state.pts = x[0]; - state.qts = x[1]; - state.seq = x[2]; - state.last_date = x[3]; - close (state_file_fd); - debug("loaded session state - pts: %d, qts: %d, seq: %d, last_date: %d.\n", state.pts, - state.qts, state.seq, state.last_date); - return state; -} - -void write_state_file (struct protocol_state *state, const char* filename) { - int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600); - if (state_file_fd < 0) { - return; - } - int x[6]; - x[0] = STATE_FILE_MAGIC; - x[1] = 0; - x[2] = state->pts; - x[3] = state->qts; - x[4] = state->seq; - x[5] = state->last_date; - assert (write (state_file_fd, x, 24) == 24); - close (state_file_fd); -} - -void read_secret_chat_file (struct telegram *instance, const char *file) { - struct binlog *bl = instance->bl; - - int fd = open (file, O_CREAT | O_RDWR, 0600); - if (fd < 0) { - return; - } - int x[2]; - if (read (fd, x, 8) < 8) { - close (fd); return; - } - if (x[0] != (int)SECRET_CHAT_FILE_MAGIC) { close (fd); return; } - int version = x[1]; - assert (version >= 0); - int cc; - assert (read (fd, &cc, 4) == 4); - int i; - for (i = 0; i < cc; i++) { - peer_t *P = talloc0 (sizeof (*P)); - struct secret_chat *E = &P->encr_chat; - int t; - assert (read (fd, &t, 4) == 4); - P->id = MK_ENCR_CHAT (t); - assert (read (fd, &P->flags, 4) == 4); - assert (read (fd, &t, 4) == 4); - assert (t > 0); - P->print_name = talloc (t + 1); - assert (read (fd, P->print_name, t) == t); - P->print_name[t] = 0; - peer_insert_name (bl, P); - - assert (read (fd, &E->state, 4) == 4); - assert (read (fd, &E->user_id, 4) == 4); - assert (read (fd, &E->admin_id, 4) == 4); - assert (read (fd, &E->ttl, 4) == 4); - assert (read (fd, &E->access_hash, 8) == 8); - - if (E->state != sc_waiting) { - E->g_key = talloc (256); - assert (read (fd, E->g_key, 256) == 256); - E->nonce = talloc (256); - assert (read (fd, E->nonce, 256) == 256); - } - assert (read (fd, E->key, 256) == 256); - assert (read (fd, &E->key_fingerprint, 8) == 8); - insert_encrypted_chat (bl, P); - } - if (version >= 1) { - assert (read (fd, &instance->encr_root, 4) == 4); - if (instance->encr_root) { - assert (read (fd, &instance->encr_param_version, 4) == 4); - instance->encr_prime = talloc (256); - assert (read (fd, instance->encr_prime, 256) == 256); - } - } - close (fd); -} - -// TODO: Refactor -void write_secret_chat_file (struct telegram *instance, const char *filename) { - struct binlog *bl = instance->bl; - - int fd = open (filename, O_CREAT | O_RDWR, 0600); - if (fd < 0) { - return; - } - int x[2]; - x[0] = SECRET_CHAT_FILE_MAGIC; - x[1] = 1; - assert (write (fd, x, 8) == 8); - int i; - int cc = 0; - for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) { - if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) { - cc ++; - } - } - assert (write (fd, &cc, 4) == 4); - for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) { - if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) { - int t = get_peer_id (bl->Peers[i]->id); - assert (write (fd, &t, 4) == 4); - t = bl->Peers[i]->flags; - assert (write (fd, &t, 4) == 4); - t = strlen (bl->Peers[i]->print_name); - assert (write (fd, &t, 4) == 4); - assert (write (fd, bl->Peers[i]->print_name, t) == t); - - assert (write (fd, &bl->Peers[i]->encr_chat.state, 4) == 4); - - assert (write (fd, &bl->Peers[i]->encr_chat.user_id, 4) == 4); - assert (write (fd, &bl->Peers[i]->encr_chat.admin_id, 4) == 4); - assert (write (fd, &bl->Peers[i]->encr_chat.ttl, 4) == 4); - assert (write (fd, &bl->Peers[i]->encr_chat.access_hash, 8) == 8); - if (bl->Peers[i]->encr_chat.state != sc_waiting) { - assert (write (fd, bl->Peers[i]->encr_chat.g_key, 256) == 256); - } - if (bl->Peers[i]->encr_chat.state != sc_waiting) { - assert (write (fd, bl->Peers[i]->encr_chat.nonce, 256) == 256); - } - assert (write (fd, bl->Peers[i]->encr_chat.key, 256) == 256); - assert (write (fd, &bl->Peers[i]->encr_chat.key_fingerprint, 8) == 8); - } - } - assert (write (fd, &instance->encr_root, 4) == 4); - if (instance->encr_root) { - assert (write (fd, &instance->encr_param_version, 4) == 4); - assert (write (fd, instance->encr_prime, 256) == 256); - } - close (fd); -} - diff --git a/loop.h b/loop.h deleted file mode 100644 index a48e34c..0000000 --- a/loop.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#include "telegram.h" - -#ifndef __LOOP_H__ -#define __LOOP_H__ -// forward declarations - -struct dc; -struct telegram; - - -/** - * The authorization state, storing all known data centers of the telegram - * network and associated shared keys for transport encryption - */ -struct authorization_state { - int dc_working_num; - int auth_state; - struct dc* DC_list[11]; - int our_id; -}; - -/** - * Stores the current update state of a client - */ -struct protocol_state { - - /** - * Number of events occured in a text box - */ - int pts; - - /** - * Position within a siccession of unconfirmed updates, used for encrypted - * messages - */ - int qts; - - /** - * Number of sent updates - */ - int seq; - - /** - * Last update - */ - int last_date; -}; - -void write_secret_chat_file (struct telegram *instance, const char *filename); - -void write_auth_file (struct authorization_state *state, const char *filename); -struct authorization_state read_auth_file (const char *filename); - -void write_state_file (struct protocol_state *state, const char *filename); -struct protocol_state read_state_file (const char *filename); - -void write_secret_chat_file (struct telegram *instance, const char *filename); -void read_secret_chat_file (struct telegram *instance, const char *filename); - -#endif diff --git a/msglog.c b/msglog.c index 2c131b9..0518025 100644 --- a/msglog.c +++ b/msglog.c @@ -1,7 +1,7 @@ #include #include -#include "debug.h" -#include "purple-plugin/telegram-purple.h" +#include +#include "telegram-purple.h" #ifdef DEBUG #define COLOR_GREY "\033[37;1m" diff --git a/mtproto-client.c b/mtproto-client.c deleted file mode 100644 index 3f71d6c..0000000 --- a/mtproto-client.c +++ /dev/null @@ -1,1735 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Nikolay Durov, Andrey Lopatin 2012-2013 - Copyright Vitaly Valtman 2013 -*/ - -#define _FILE_OFFSET_BITS 64 - -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "telegram.h" -#include "net.h" -#include "include.h" -#include "queries.h" -#include "loop.h" -#include "structures.h" -#include "binlog.h" - -#if defined(__FreeBSD__) -#define __builtin_bswap32(x) bswap32(x) -#endif - -#if defined(__OpenBSD__) -#define __builtin_bswap32(x) __swap32gen(x) -#endif - -#define sha1 SHA1 - -#include "mtproto-client.h" - -#define MAX_NET_RES (1L << 16) -int log_level = 2; - - -int verbosity = 0; -int allow_weak_random = 0; -int disable_auto_accept = 0; - -int rpc_execute (struct connection *c, int op, int len); -int rpc_becomes_ready (struct connection *c); -int rpc_close (struct connection *c); - -struct connection_methods auth_methods = { - .execute = rpc_execute, - .ready = rpc_becomes_ready, - .close = rpc_close -}; - -long long precise_time; - -double get_utime (int clock_id) { - struct timespec T; - my_clock_gettime (clock_id, &T); - double res = T.tv_sec + (double) T.tv_nsec * 1e-9; - if (clock_id == CLOCK_REALTIME) { - precise_time = (long long) (res * (1LL << 32)); - } - return res; -} - -void secure_random (void *s, int l) { - if (RAND_bytes (s, l) < 0) { - if (allow_weak_random) { - RAND_pseudo_bytes (s, l); - } else { - assert (0 && "End of random. If you want, you can start with -w"); - } - } -} - - -#define STATS_BUFF_SIZE (64 << 10) -int stats_buff_len; -char stats_buff[STATS_BUFF_SIZE]; - -#define MAX_RESPONSE_SIZE (1L << 24) - -char Response[MAX_RESPONSE_SIZE]; -int Response_len; - -/* - * - * STATE MACHINE - * - */ - -#define TG_SERVER_PUBKEY_FILENAME "/etc/telegram-purple/server.pub" -char *rsa_public_key_name = 0; -RSA *pubKey; -long long pk_fingerprint; - -static int rsa_load_public_key (const char *public_key_name) { - pubKey = NULL; - FILE *f = fopen (public_key_name, "r"); - if (f == NULL) { - debug ( "Couldn't open public key file: %s\n", public_key_name); - return -1; - } - pubKey = PEM_read_RSAPublicKey (f, NULL, NULL, NULL); - fclose (f); - if (pubKey == NULL) { - debug ( "PEM_read_RSAPublicKey returns NULL.\n"); - return -1; - } - - debug ( "public key '%s' loaded successfully\n", rsa_public_key_name); - - return 0; -} - - - - - -int auth_work_start (struct connection *c); - -/* - * - * UNAUTHORIZED (DH KEY EXCHANGE) PROTOCOL PART - * - */ - - -int encrypt_packet_buffer (struct mtproto_connection *self) { - return pad_rsa_encrypt (self, (char *) self->packet_buffer, (self->packet_ptr - self->packet_buffer) * 4, (char *) self->encrypt_buffer, - ENCRYPT_BUFFER_INTS * 4, pubKey->n, pubKey->e); -} - -int encrypt_packet_buffer_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32]) { - init_aes_unauth (self, server_nonce, hidden_client_nonce, AES_ENCRYPT); - return pad_aes_encrypt (self, (char *) self->packet_buffer, (self->packet_ptr - self->packet_buffer) * 4, - (char *) self->encrypt_buffer, ENCRYPT_BUFFER_INTS * 4); -} - - -int rpc_send_packet (struct connection *c) { - debug("rpc_send_packet()\n"); - struct mtproto_connection *self = c->mtconnection; - - int len = (self->packet_ptr - self->packet_buffer) * 4; - c->out_packet_num ++; - long long next_msg_id = (long long) ((1LL << 32) * get_utime (CLOCK_REALTIME)) & -4; - if (next_msg_id <= self->unenc_msg_header.out_msg_id) { - self->unenc_msg_header.out_msg_id += 4; - } else { - self->unenc_msg_header.out_msg_id = next_msg_id; - } - self->unenc_msg_header.msg_len = len; - - int total_len = len + 20; - assert (total_len > 0 && !(total_len & 0xfc000003)); - total_len >>= 2; - if (total_len < 0x7f) { - assert (write_out (c, &total_len, 1) == 1); - } else { - total_len = (total_len << 8) | 0x7f; - assert (write_out (c, &total_len, 4) == 4); - } - write_out (c, &self->unenc_msg_header, 20); - write_out (c, self->packet_buffer, len); - flush_out (c); - - self->total_packets_sent ++; - self->total_data_sent += total_len; - return 1; -} - -int rpc_send_message (struct connection *c, void *data, int len) { - struct mtproto_connection *self = c->mtconnection; - - //debug("rpc_send_message(...)\n"); - assert (len > 0 && !(len & 0xfc000003)); - int total_len = len >> 2; - if (total_len < 0x7f) { - assert (write_out (c, &total_len, 1) == 1); - } else { - total_len = (total_len << 8) | 0x7f; - assert (write_out (c, &total_len, 4) == 4); - } - c->out_packet_num ++; - assert (write_out (c, data, len) == len); - flush_out (c); - - self->total_packets_sent ++; - self->total_data_sent += total_len; - return 1; -} - -int send_req_pq_packet (struct connection *c) { - struct mtproto_connection *self = c->mtconnection; - - assert (self->c_state == st_init); - secure_random (self->nonce, 16); - self->unenc_msg_header.out_msg_id = 0; - clear_packet (self); - out_int (self, CODE_req_pq); - out_ints (self, (int *)self->nonce, 4); - rpc_send_packet (c); - self->c_state = st_reqpq_sent; - return 1; -} - - -unsigned long long gcd (unsigned long long a, unsigned long long b) { - return b ? gcd (b, a % b) : a; -} - -//typedef unsigned int uint128_t __attribute__ ((mode(TI))); - -int process_respq_answer (struct connection *c, char *packet, int len) { - debug ( "process_respq_answer(), len=%d\n", len); - - struct mtproto_connection *self = c->mtconnection; - int i; - assert (len >= 76); - assert (!*(long long *) packet); - assert (*(int *) (packet + 16) == len - 20); - assert (!(len & 3)); - assert (*(int *) (packet + 20) == CODE_resPQ); - assert (!memcmp (packet + 24, self->nonce, 16)); - memcpy (self->server_nonce, packet + 40, 16); - char *from = packet + 56; - int clen = *from++; - assert (clen <= 8); - self->what = 0; - for (i = 0; i < clen; i++) { - self->what = (self->what << 8) + (unsigned char)*from++; - } - - while (((unsigned long)from) & 3) ++from; - - self->p1 = 0, self->p2 = 0; - - debug ( "%lld received\n", self->what); - - int it = 0; - unsigned long long g = 0; - for (i = 0; i < 3 || it < 1000; i++) { - int q = ((lrand48() & 15) + 17) % self->what; - unsigned long long x = (long long)lrand48 () % (self->what - 1) + 1, y = x; - int lim = 1 << (i + 18); - int j; - for (j = 1; j < lim; j++) { - ++it; - unsigned long long a = x, b = x, c = q; - while (b) { - if (b & 1) { - c += a; - if (c >= self->what) { - c -= self->what; - } - } - a += a; - if (a >= self->what) { - a -= self->what; - } - b >>= 1; - } - x = c; - unsigned long long z = x < y ? self->what + x - y : x - y; - g = gcd (z, self->what); - if (g != 1) { - break; - } - if (!(j & (j - 1))) { - y = x; - } - } - if (g > 1 && g < self->what) break; - } - - assert (g > 1 && g < self->what); - self->p1 = g; - self->p2 = self->what / g; - if (self->p1 > self->p2) { - unsigned t = self->p1; self->p1 = self->p2; self->p2 = t; - } - - debug ( "Calculated primes: self->p1 = %d, self->p2 = %d, %d iterations\n", self->p1, self->p2, it); - - /// ++p1; /// - - assert (*(int *) (from) == CODE_vector); - int fingerprints_num = *(int *)(from + 4); - assert (fingerprints_num >= 1 && fingerprints_num <= 64 && len == fingerprints_num * 8 + 8 + (from - packet)); - long long *fingerprints = (long long *) (from + 8); - debug("Got %d fingerprints\n", fingerprints_num); - for (i = 0; i < fingerprints_num; i++) { - if (fingerprints[i] == pk_fingerprint) { - debug ( "found our public key at position %d\n", i); - break; - } - } - if (i == fingerprints_num) { - debug ( "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); - exit (2); - } - // create inner part (P_Q_inner_data) - clear_packet (self); - self->packet_ptr += 5; - out_int (self, CODE_p_q_inner_data); - out_cstring (self, packet + 57, clen); - //out_int (0x0f01); // pq=15 - - if (self->p1 < 256) { - clen = 1; - } else if (self->p1 < 65536) { - clen = 2; - } else if (self->p1 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p1 = __builtin_bswap32 (self->p1); - out_cstring (self, (char *)&self->p1 + 4 - clen, clen); - self->p1 = __builtin_bswap32 (self->p1); - - if (self->p2 < 256) { - clen = 1; - } else if (self->p2 < 65536) { - clen = 2; - } else if (self->p2 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p2 = __builtin_bswap32 (self->p2); - out_cstring (self, (char *)&self->p2 + 4 - clen, clen); - self->p2 = __builtin_bswap32 (self->p2); - - //out_int (0x0301); // p=3 - //out_int (0x0501); // q=5 - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - secure_random (self->new_nonce, 32); - out_ints (self, (int *) self->new_nonce, 8); - sha1 ((unsigned char *) (self->packet_buffer + 5), (self->packet_ptr - self->packet_buffer - 5) * 4, (unsigned char *) self->packet_buffer); - - int l = encrypt_packet_buffer (self); - - clear_packet (self); - out_int (self, CODE_req_DH_params); - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - //out_int (0x0301); // p=3 - //out_int (0x0501); // q=5 - if (self->p1 < 256) { - clen = 1; - } else if (self->p1 < 65536) { - clen = 2; - } else if (self->p1 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p1 = __builtin_bswap32 (self->p1); - out_cstring (self, (char *)&self->p1 + 4 - clen, clen); - self->p1 = __builtin_bswap32 (self->p1); - if (self->p2 < 256) { - clen = 1; - } else if (self->p2 < 65536) { - clen = 2; - } else if (self->p2 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p2 = __builtin_bswap32 (self->p2); - out_cstring (self, (char *)&self->p2 + 4 - clen, clen); - self->p2 = __builtin_bswap32 (self->p2); - - out_long (self, pk_fingerprint); - out_cstring (self, (char *) self->encrypt_buffer, l); - - self->c_state = st_reqdh_sent; - - return rpc_send_packet (c); -} - -int check_prime (struct mtproto_connection *self, BIGNUM *p) { - int r = BN_is_prime (p, BN_prime_checks, 0, self->BN_ctx, 0); - ensure (r >= 0); - return r; -} - -int check_DH_params (struct mtproto_connection *self, BIGNUM *p, int g) { - if (g < 2 || g > 7) { return -1; } - BIGNUM t; - BN_init (&t); - - BN_init (&self->dh_g); - ensure (BN_set_word (&self->dh_g, 4 * g)); - - ensure (BN_mod (&t, p, &self->dh_g, self->BN_ctx)); - int x = BN_get_word (&t); - assert (x >= 0 && x < 4 * g); - - BN_free (&self->dh_g); - - switch (g) { - case 2: - if (x != 7) { return -1; } - break; - case 3: - if (x % 3 != 2 ) { return -1; } - break; - case 4: - break; - case 5: - if (x % 5 != 1 && x % 5 != 4) { return -1; } - break; - case 6: - if (x != 19 && x != 23) { return -1; } - break; - case 7: - if (x % 7 != 3 && x % 7 != 5 && x % 7 != 6) { return -1; } - break; - } - - if (!check_prime (self, p)) { return -1; } - - BIGNUM b; - BN_init (&b); - ensure (BN_set_word (&b, 2)); - ensure (BN_div (&t, 0, p, &b, self->BN_ctx)); - if (!check_prime (self, &t)) { return -1; } - BN_free (&b); - BN_free (&t); - return 0; -} - -int check_g (unsigned char p[256], BIGNUM *g) { - static unsigned char s[256]; - memset (s, 0, 256); - assert (BN_num_bytes (g) <= 256); - BN_bn2bin (g, s); - int ok = 0; - int i; - for (i = 0; i < 64; i++) { - if (s[i]) { - ok = 1; - break; - } - } - if (!ok) { return -1; } - ok = 0; - for (i = 0; i < 64; i++) { - if (s[255 - i]) { - ok = 1; - break; - } - } - if (!ok) { return -1; } - ok = 0; - for (i = 0; i < 64; i++) { - if (s[i] < p[i]) { - ok = 1; - break; - } else if (s[i] > p[i]) { - debug ("i = %d (%d %d)\n", i, (int)s[i], (int)p[i]); - return -1; - } - } - if (!ok) { return -1; } - return 0; -} - -int check_g_bn (BIGNUM *p, BIGNUM *g) { - static unsigned char s[256]; - memset (s, 0, 256); - assert (BN_num_bytes (p) <= 256); - BN_bn2bin (p, s); - return check_g (s, g); -} - -int process_dh_answer (struct connection *c, char *packet, int len) { - debug ( "process_dh_answer(), len=%d\n", len); - struct mtproto_connection *self = c->mtconnection; - if (len < 116) { - debug ( "%u * %u = %llu", self->p1, self->p2, self->what); - } - assert (len >= 116); - assert (!*(long long *) packet); - assert (*(int *) (packet + 16) == len - 20); - assert (!(len & 3)); - assert (*(int *) (packet + 20) == (int)CODE_server_DH_params_ok); - assert (!memcmp (packet + 24, self->nonce, 16)); - assert (!memcmp (packet + 40, self->server_nonce, 16)); - init_aes_unauth (self, self->server_nonce, self->new_nonce, AES_DECRYPT); - self->in_ptr = (int *)(packet + 56); - self->in_end = (int *)(packet + len); - int l = prefetch_strlen (self); - assert (l > 0); - l = pad_aes_decrypt (self, fetch_str (self, l), l, (char *) self->decrypt_buffer, DECRYPT_BUFFER_INTS * 4 - 16); - assert (self->in_ptr == self->in_end); - assert (l >= 60); - assert (self->decrypt_buffer[5] == (int)CODE_server_DH_inner_data); - assert (!memcmp (self->decrypt_buffer + 6, self->nonce, 16)); - assert (!memcmp (self->decrypt_buffer + 10, self->server_nonce, 16)); - int g = self->decrypt_buffer[14]; - self->in_ptr = self->decrypt_buffer + 15; - self->in_end = self->decrypt_buffer + (l >> 2); - BN_init (&self->dh_prime); - BN_init (&self->g_a); - assert (fetch_bignum (self, &self->dh_prime) > 0); - assert (fetch_bignum (self, &self->g_a) > 0); - assert (check_g_bn (&self->dh_prime, &self->g_a) >= 0); - int server_time = *self->in_ptr++; - assert (self->in_ptr <= self->in_end); - - assert (check_DH_params (self, &self->dh_prime, g) >= 0); - - static char sha1_buffer[20]; - sha1 ((unsigned char *) self->decrypt_buffer + 20, (self->in_ptr - self->decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); - assert (!memcmp (self->decrypt_buffer, sha1_buffer, 20)); - assert ((char *) self->in_end - (char *) self->in_ptr < 16); - - GET_DC(c)->server_time_delta = server_time - time (0); - GET_DC(c)->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); - //debug ( "server time is %d, delta = %d\n", server_time, server_time_delta); - - // Build set_client_DH_params answer - clear_packet (self); - self->packet_ptr += 5; - out_int (self, CODE_client_DH_inner_data); - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - out_long (self, 0LL); - - BN_init (&self->dh_g); - ensure (BN_set_word (&self->dh_g, g)); - - secure_random (self->s_power, 256); - BIGNUM *dh_power = BN_bin2bn ((unsigned char *)self->s_power, 256, 0); - ensure_ptr (dh_power); - - BIGNUM *y = BN_new (); - ensure_ptr (y); - ensure (BN_mod_exp (y, &self->dh_g, dh_power, &self->dh_prime, self->BN_ctx)); - out_bignum (self, y); - BN_free (y); - - BN_init (&self->auth_key_num); - ensure (BN_mod_exp (&self->auth_key_num, &self->g_a, dh_power, &self->dh_prime, self->BN_ctx)); - l = BN_num_bytes (&self->auth_key_num); - assert (l >= 250 && l <= 256); - assert (BN_bn2bin (&self->auth_key_num, (unsigned char *)GET_DC(c)->auth_key)); - memset (GET_DC(c)->auth_key + l, 0, 256 - l); - BN_free (dh_power); - BN_free (&self->auth_key_num); - BN_free (&self->dh_g); - BN_free (&self->g_a); - BN_free (&self->dh_prime); - - //hexdump (auth_key, auth_key + 256); - - sha1 ((unsigned char *) (self->packet_buffer + 5), (self->packet_ptr - self->packet_buffer - 5) * 4, (unsigned char *) self->packet_buffer); - - //hexdump ((char *)packet_buffer, (char *)packet_ptr); - - l = encrypt_packet_buffer_aes_unauth (self, self->server_nonce, self->new_nonce); - - clear_packet (self); - out_int (self, CODE_set_client_DH_params); - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - out_cstring (self, (char *) self->encrypt_buffer, l); - - self->c_state = st_client_dh_sent; - - return rpc_send_packet (c); -} - - -int process_auth_complete (struct connection *c, char *packet, int len) { - debug ( "process_auth_complete(), len=%d\n", len); - struct mtproto_connection *self = c->mtconnection; - assert (len == 72); - assert (!*(long long *) packet); - assert (*(int *) (packet + 16) == len - 20); - assert (!(len & 3)); - assert (*(int *) (packet + 20) == CODE_dh_gen_ok); - assert (!memcmp (packet + 24, self->nonce, 16)); - assert (!memcmp (packet + 40, self->server_nonce, 16)); - static unsigned char tmp[44], sha1_buffer[20]; - memcpy (tmp, self->new_nonce, 32); - tmp[32] = 1; - //GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); - - bl_do_set_auth_key_id (c->instance, GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); - sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); - - memcpy (tmp + 33, sha1_buffer, 8); - sha1 (tmp, 41, sha1_buffer); - assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); - GET_DC(c)->server_salt = *(long long *)self->server_nonce ^ *(long long *)self->new_nonce; - - debug ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); - //kprintf ("OK\n"); - - //c->status = conn_error; - //sleep (1); - - self->c_state = st_authorized; - //return 1; - debug ( "Auth success\n"); - self->auth_success ++; - GET_DC(c)->flags |= 1; - - return 1; -} - -/* - * - * AUTHORIZED (MAIN) PROTOCOL PART - * - */ - -double get_server_time (struct dc *DC) { - if (!DC->server_time_udelta) { - DC->server_time_udelta = get_utime (CLOCK_REALTIME) - get_utime (CLOCK_MONOTONIC); - } - return get_utime (CLOCK_MONOTONIC) + DC->server_time_udelta; -} - -long long generate_next_msg_id (struct mtproto_connection *self, struct dc *DC) { - long long next_id = (long long) (get_server_time (DC) * (1LL << 32)) & -4; - if (next_id <= self->client_last_msg_id) { - next_id = self->client_last_msg_id += 4; - } else { - self->client_last_msg_id = next_id; - } - return next_id; -} - -void init_enc_msg (struct mtproto_connection *self, struct session *S, int useful) { - struct dc *DC = S->dc; - assert (DC->auth_key_id); - self->enc_msg.auth_key_id = DC->auth_key_id; -// assert (DC->server_salt); - self->enc_msg.server_salt = DC->server_salt; - if (!S->session_id) { - secure_random (&S->session_id, 8); - } - self->enc_msg.session_id = S->session_id; - //enc_msg.auth_key_id2 = auth_key_id; - self->enc_msg.msg_id = generate_next_msg_id (self, DC); - //enc_msg.msg_id -= 0x10000000LL * (lrand48 () & 15); - //kprintf ("message id %016llx\n", enc_msg.msg_id); - self->enc_msg.seq_no = S->seq_no; - if (useful) { - self->enc_msg.seq_no |= 1; - } - S->seq_no += 2; -}; - -int aes_encrypt_message (struct mtproto_connection *self, struct dc *DC, struct encrypted_message *enc) { - unsigned char sha1_buffer[20]; - const int MINSZ = offsetof (struct encrypted_message, message); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - int enc_len = (MINSZ - UNENCSZ) + enc->msg_len; - assert (enc->msg_len >= 0 && enc->msg_len <= MAX_MESSAGE_INTS * 4 - 16 && !(enc->msg_len & 3)); - sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); - //printf ("enc_len is %d\n", enc_len); - if (verbosity >= 2) { - debug ( "sending message with sha1 %08x\n", *(int *)sha1_buffer); - } - memcpy (enc->msg_key, sha1_buffer + 4, 16); - init_aes_auth (self, DC->auth_key, enc->msg_key, AES_ENCRYPT); - //hexdump ((char *)enc, (char *)enc + enc_len + 24); - return pad_aes_encrypt (self, (char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); -} - -long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful) { - struct connection *c = self->connection; - - //debug("encrypt_send_message(...)\n"); - struct dc *DC = GET_DC(c); - struct session *S = c->session; - assert (S); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) { - return -1; - } - if (msg) { - memcpy (self->enc_msg.message, msg, msg_ints * 4); - self->enc_msg.msg_len = msg_ints * 4; - } else { - if ((self->enc_msg.msg_len & 0x80000003) || self->enc_msg.msg_len > MAX_MESSAGE_INTS * 4 - 16) { - return -1; - } - } - init_enc_msg (self, S, useful); - - //hexdump ((char *)msg, (char *)msg + (msg_ints * 4)); - int l = aes_encrypt_message (self, DC, &self->enc_msg); - //hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24); - assert (l > 0); - rpc_send_message (c, &self->enc_msg, l + UNENCSZ); - - return self->client_last_msg_id; -} - - -int auth_work_start (struct connection *c UU) { - return 1; -} - -void rpc_execute_answer (struct connection *c, long long msg_id UU); - -void fetch_pts (struct mtproto_connection *self) { - int p = fetch_int (self); - if (p <= self->pts) { return; } - if (p != self->pts + 1) { - if (self->pts) { - //debug ("Hole in pts p = %d, pts = %d\n", p, pts); - - // get difference should be here - self->pts = p; - } else { - self->pts = p; - } - } else { - self->pts ++; - } - bl_do_set_pts (self->bl, self, self->pts); -} - -void fetch_qts (struct mtproto_connection *self) { - int p = fetch_int (self); - if (p <= self->qts) { return; } - if (p != self->qts + 1) { - if (self->qts) { - //debug ("Hole in qts\n"); - // get difference should be here - self->qts = p; - } else { - self->qts = p; - } - } else { - self->qts ++; - } - bl_do_set_qts (self->bl, self, self->qts); -} - -void fetch_date (struct mtproto_connection *self) { - int p = fetch_int (self); - if (p > self->last_date) { - self->last_date = p; - bl_do_set_date (self->bl, self, self->last_date); - } -} - -void fetch_seq (struct mtproto_connection *self) { - int x = fetch_int (self); - if (x > self->seq + 1) { - debug ("Hole in seq: seq = %d, x = %d\n", self->seq, x); - //do_get_difference (); - //seq = x; - } else if (x == self->seq + 1) { - self->seq = x; - bl_do_set_seq (self->bl, self, self->seq); - } -} - -void work_update_binlog (struct mtproto_connection *self) { - struct binlog *bl = self->bl; - - unsigned op = fetch_int (self); - switch (op) { - case CODE_update_user_name: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - if (UC) { - struct tgl_user *U = &UC->user; - if (U->first_name) { tfree_str (U->first_name); } - if (U->last_name) { tfree_str (U->last_name); } - if (U->print_name) { - peer_delete_name (bl, UC); - tfree_str (U->print_name); - } - U->first_name = fetch_str_dup (self); - U->last_name = fetch_str_dup (self); - U->print_name = create_print_name (bl, U->id, U->first_name, U->last_name, 0, 0); - peer_insert_name (bl, (void *)U); - } else { - fetch_skip_str (self); - fetch_skip_str (self); - } - } - break; - case CODE_update_user_photo: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - fetch_date (self); - if (UC) { - struct tgl_user *U = &UC->user; - - unsigned y = fetch_int (self); - 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 (self); - fetch_file_location (self, &U->photo_small); - fetch_file_location (self, &U->photo_big); - } - } else { - struct file_location t; - unsigned y = fetch_int (self); - if (y == CODE_user_profile_photo_empty) { - } else { - assert (y == CODE_user_profile_photo); - fetch_long (self); // photo_id - fetch_file_location (self, &t); - fetch_file_location (self, &t); - } - } - fetch_bool (self); - } - break; - default: - assert (0); - } -} - -void work_update (struct mtproto_connection *self, long long msg_id UU) { - struct connection *c = self->connection; - struct telegram *tg = c->instance; - struct binlog *bl = self->bl; - - unsigned op = fetch_int (self); - debug("work_update(): OP:%d\n", op); - switch (op) { - case CODE_update_new_message: - { - debug ("CODE_update_new_message\n"); - struct message *M UU = fetch_alloc_message (self, tg); - assert (M); - fetch_pts (self); - self->unread_messages ++; - event_update_new_message (tg, M); - //print_message (M); - //update_prompt (); - break; - }; - case CODE_update_message_i_d: - { - debug ("CODE_update_message\n"); - int id = fetch_int (self); // id - int new = fetch_long (self); // random_id - struct message *M = message_get (bl, new); - if (M) { - bl_do_set_msg_id (self->bl, self, M, id); - } - } - break; - case CODE_update_read_messages: - { - debug ("CODE_update_read_message\n"); - assert (fetch_int (self) == (int)CODE_vector); - int n = fetch_int (self); - int i; - for (i = 0; i < n; i++) { - int id = fetch_int (self); - struct message *M = message_get (bl, id); - if (M) { - bl_do_set_unread (self->bl, self, M, 0); - } - } - fetch_pts (self); - } - break; - case CODE_update_user_typing: - { - debug ("CODE_update_user_typing\n"); - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (bl, id); - event_update_user_typing (tg, U); - } - break; - case CODE_update_chat_user_typing: - { - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *C = user_chat_get (bl, chat_id); - peer_t *U = user_chat_get (bl, id); - event_update_chat_user_typing(tg, C, U, 0); - } - break; - case CODE_update_user_status: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, user_id); - if (U) { - fetch_user_status (self, &U->user.status); - event_update_user_status(tg, U); - } else { - struct user_status t; - fetch_user_status (self, &t); - } - } - break; - case CODE_update_user_name: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - if (UC && (UC->flags & FLAG_CREATED)) { - int l1 = prefetch_strlen (self); - char *f = fetch_str (self, l1); - int l2 = prefetch_strlen (self); - char *l = fetch_str (self, l2); - struct tgl_user *U = &UC->user; - bl_do_set_user_real_name (self->bl, self, U, f, l1, l, l2); - } else { - fetch_skip_str (self); - fetch_skip_str (self); - } - event_update_user_name (tg, UC); - } - break; - case CODE_update_user_photo: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - fetch_date (self); - if (UC && (UC->flags & FLAG_CREATED)) { - struct tgl_user *U = &UC->user; - unsigned y = fetch_int (self); - 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 (self); - fetch_file_location (self, &small); - fetch_file_location (self, &big); - } - bl_do_set_user_profile_photo (self->bl, self, U, photo_id, &big, &small); - } else { - struct file_location t; - unsigned y = fetch_int (self); - if (y == CODE_user_profile_photo_empty) { - } else { - assert (y == CODE_user_profile_photo); - fetch_long (self); // photo_id - fetch_file_location (self, &t); - fetch_file_location (self, &t); - } - } - event_update_user_photo(tg, UC); - fetch_bool (self); - } - break; - case CODE_update_restore_messages: - { - assert (fetch_int (self) == CODE_vector); - int n = fetch_int (self); - fetch_skip (self, n); - fetch_pts (self); - } - break; - case CODE_update_delete_messages: - { - assert (fetch_int (self) == CODE_vector); - int n = fetch_int (self); - fetch_skip (self, n); - fetch_pts (self); - } - break; - case CODE_update_chat_participants: - { - unsigned x = fetch_int (self); - assert (x == CODE_chat_participants || x == CODE_chat_participants_forbidden); - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - int n = 0; - peer_t *C = user_chat_get (bl, chat_id); - if (C && (C->flags & FLAG_CREATED)) { - if (x == CODE_chat_participants) { - bl_do_set_chat_admin (self->bl, self, &C->chat, fetch_int (self)); - assert (fetch_int (self) == CODE_vector); - n = fetch_int (self); - struct chat_user *users = talloc (12 * n); - int i; - for (i = 0; i < n; i++) { - assert (fetch_int (self) == (int)CODE_chat_participant); - users[i].user_id = fetch_int (self); - users[i].inviter_id = fetch_int (self); - users[i].date = fetch_int (self); - } - int version = fetch_int (self); - bl_do_set_chat_participants (self->bl, self, &C->chat, version, n, users); - } - } else { - if (x == CODE_chat_participants) { - fetch_int (self); // admin_id - assert (fetch_int (self) == CODE_vector); - n = fetch_int (self); - fetch_skip (self, n * 4); - fetch_int (self); // version - } - } - if (C) { - event_update_chat_participants(tg, C); - } - } - break; - case CODE_update_contact_registered: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, user_id); - fetch_int (self); // date - event_update_user_registered(tg, U); - } - break; - case CODE_update_contact_link: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (bl, user_id); - unsigned t = fetch_int (self); - assert (t == CODE_contacts_my_link_empty || t == CODE_contacts_my_link_requested || t == CODE_contacts_my_link_contact); - if (t == CODE_contacts_my_link_requested) { - fetch_bool (self); // has_phone - } - t = fetch_int (self); - assert (t == CODE_contacts_foreign_link_unknown || t == CODE_contacts_foreign_link_requested || t == CODE_contacts_foreign_link_mutual); - if (t == CODE_contacts_foreign_link_requested) { - fetch_bool (self); // has_phone - } - } - break; - case CODE_update_activation: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (bl, user_id); - } - break; - case CODE_update_new_authorization: - { - fetch_long (self); // auth_key_id - fetch_int (self); // date - char *s = fetch_str_dup (self); - char *location = fetch_str_dup (self); - event_update_auth_new(tg, location); - tfree_str (s); - tfree_str (location); - } - break; - case CODE_update_new_geo_chat_message: - { - struct message *M = fetch_alloc_geo_message (self, tg); - self->unread_messages ++; - event_update_new_message (self->instance, M); - } - break; - case CODE_update_new_encrypted_message: - { - struct message *M UU = fetch_alloc_encrypted_message (self, tg); - self->unread_messages ++; - event_update_new_message (self->instance, M); - fetch_qts (self); - } - break; - case CODE_update_encryption: - { - struct secret_chat *E = fetch_alloc_encrypted_chat (self); - debug ("Secret chat state = %d\n", E->state); - if (E->state == sc_request && !disable_auto_accept) { - do_accept_encr_chat_request (tg, E); - } - fetch_int (self); // date - } - break; - case CODE_update_encrypted_chat_typing: - { - peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); - peer_t *P = user_chat_get (bl, id); - event_update_user_typing(tg, P); - } - break; - case CODE_update_encrypted_messages_read: - { - peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); // chat_id - fetch_int (self); // max_date - fetch_int (self); // date - peer_t *P = user_chat_get (bl, id); - int x = -1; - if (P && P->last) { - x = 0; - struct message *M = P->last; - while (M && (!M->out || M->unread)) { - if (M->out) { - M->unread = 0; - x ++; - } - M = M->next; - } - } - if (log_level >= 1) { - } - } - break; - case CODE_update_chat_participant_add: - { - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_id_t inviter_id = MK_USER (fetch_int (self)); - int version = fetch_int (self); - - peer_t *C = user_chat_get (bl, chat_id); - if (C && (C->flags & FLAG_CREATED)) { - bl_do_chat_add_user (self->bl, self, &C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); - } - event_update_chat_add_participant(tg, C, user_id, inviter_id); - } - break; - case CODE_update_chat_participant_delete: - { - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - peer_id_t user_id = MK_USER (fetch_int (self)); - int version = fetch_int (self); - - peer_t *C = user_chat_get (bl, chat_id); - if (C && (C->flags & FLAG_CREATED)) { - bl_do_chat_del_user (self->bl, self, &C->chat, version, get_peer_id (user_id)); - } - event_update_chat_del_participant(tg, C, user_id, 0); - } - break; - case CODE_update_dc_options: - { - assert (fetch_int (self) == CODE_vector); - int n = fetch_int (self); - assert (n >= 0); - int i; - for (i = 0; i < n; i++) { - fetch_dc_option (tg); - } - } - break; - default: - debug ("Unknown update type %08x\n", op); - ; - } -} - -void work_update_short (struct connection *c, long long msg_id) { - debug ("work_update_short\n"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (self) == CODE_update_short); - work_update (self, msg_id); - fetch_date (self); -} - -void work_updates (struct connection *c, long long msg_id) { - debug ("work_updates(\n)"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (c->mtconnection) == CODE_updates); - assert (fetch_int (c->mtconnection) == CODE_vector); - int n = fetch_int (c->mtconnection); - int i; - for (i = 0; i < n; i++) { - work_update (c->mtconnection, msg_id); - } - assert (fetch_int (c->mtconnection) == CODE_vector); - n = fetch_int (c->mtconnection); - for (i = 0; i < n; i++) { - fetch_alloc_user (self); - } - assert (fetch_int (c->mtconnection) == CODE_vector); - n = fetch_int (c->mtconnection); - for (i = 0; i < n; i++) { - fetch_alloc_chat (self); - } - bl_do_set_date (self->bl, self, fetch_int (c->mtconnection)); - bl_do_set_seq (self->bl, self, fetch_int (c->mtconnection)); -} - -void work_update_short_message (struct connection *c UU, long long msg_id UU) { - debug ("work_update_short_message(\n)"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (c->mtconnection) == (int)CODE_update_short_message); - struct message *M = fetch_alloc_message_short (self, c->instance); - c->mtconnection->unread_messages ++; - event_update_new_message (self->instance, M); - if (M->date > c->mtconnection->last_date) { - c->mtconnection->last_date = M->date; - } -} - -void work_update_short_chat_message (struct connection *c, long long msg_id UU) { - debug ("work_update_chat_message(\n)"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (self) == CODE_update_short_chat_message); - struct message *M = fetch_alloc_message_short_chat (self, c->instance); - c->mtconnection->unread_messages ++; - event_update_new_message (self->instance, M); - if (M->date > c->mtconnection->last_date) { - c->mtconnection->last_date = M->date; - } -} - -void work_container (struct connection *c, long long msg_id UU) { - debug ( "work_container: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == CODE_msg_container); - int n = fetch_int (c->mtconnection); - int i; - for (i = 0; i < n; i++) { - long long id = fetch_long (c->mtconnection); - //int seqno = fetch_int (); - fetch_int (c->mtconnection); // seq_no - if (id & 1) { - insert_msg_id (c->session, id); - } - int bytes = fetch_int (c->mtconnection); - int *t = c->mtconnection->in_end; - c->mtconnection->in_end = c->mtconnection->in_ptr + (bytes / 4); - rpc_execute_answer (c, id); - assert (c->mtconnection->in_ptr == c->mtconnection->in_end); - c->mtconnection->in_end = t; - } -} - -void work_new_session_created (struct connection *c, long long msg_id UU) { - debug ( "work_new_session_created: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == (int)CODE_new_session_created); - fetch_long (c->mtconnection); // first message id - //DC->session_id = fetch_long (); - fetch_long (c->mtconnection); // unique_id - GET_DC(c)->server_salt = fetch_long (c->mtconnection); - debug ("new server_salt = %lld\n", GET_DC(c)->server_salt); -} - -void work_msgs_ack (struct connection *c UU, long long msg_id UU) { - debug ( "work_msgs_ack: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == CODE_msgs_ack); - assert (fetch_int (c->mtconnection) == CODE_vector); - int n = fetch_int (c->mtconnection); - int i; - for (i = 0; i < n; i++) { - long long id = fetch_long (c->mtconnection); - debug ("ack for %lld\n", id); - query_ack (c->instance, id); - } -} - -void work_rpc_result (struct connection *c UU, long long msg_id UU) { - debug ( "work_rpc_result: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == (int)CODE_rpc_result); - long long id = fetch_long (c->mtconnection); - int op = prefetch_int (c->mtconnection); - if (op == CODE_rpc_error) { - query_error (c->instance, id); - } else { - query_result (c->instance, id); - } -} - -#define MAX_PACKED_SIZE (1 << 24) -void work_packed (struct connection *c, long long msg_id) { - debug ("work_packet()\n"); - assert (fetch_int (c->mtconnection) == CODE_gzip_packed); - static int in_gzip; - static int buf[MAX_PACKED_SIZE >> 2]; - assert (!in_gzip); - in_gzip = 1; - - int l = prefetch_strlen (c->mtconnection); - char *s = fetch_str (c->mtconnection, l); - - int total_out = tinflate (s, l, buf, MAX_PACKED_SIZE); - int *end = c->mtconnection->in_ptr; - int *eend = c->mtconnection->in_end; - //assert (total_out % 4 == 0); - c->mtconnection->in_ptr = buf; - c->mtconnection->in_end = c->mtconnection->in_ptr + total_out / 4; - if (verbosity >= 4) { - debug ( "Unzipped data: "); - hexdump_in (c->mtconnection); - } - rpc_execute_answer (c, msg_id); - c->mtconnection->in_ptr = end; - c->mtconnection->in_end = eend; - in_gzip = 0; -} - -void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { - debug ("work_bad_server_salt()\n"); - assert (fetch_int (c->mtconnection) == (int)CODE_bad_server_salt); - long long id = fetch_long (c->mtconnection); - query_restart (c->instance, id); - fetch_int (c->mtconnection); // seq_no - fetch_int (c->mtconnection); // error_code - long long new_server_salt = fetch_long (c->mtconnection); - GET_DC(c)->server_salt = new_server_salt; -} - -void work_pong (struct connection *c UU, long long msg_id UU) { - debug ("work_pong()\n"); - assert (fetch_int (c->mtconnection) == CODE_pong); - fetch_long (c->mtconnection); // msg_id - fetch_long (c->mtconnection); // ping_id -} - -void work_detailed_info (struct connection *c UU, long long msg_id UU) { - debug ("work_detailed_info()\n"); - assert (fetch_int (c->mtconnection) == CODE_msg_detailed_info); - fetch_long (c->mtconnection); // msg_id - fetch_long (c->mtconnection); // answer_msg_id - fetch_int (c->mtconnection); // bytes - fetch_int (c->mtconnection); // status -} - -void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { - debug ("work_new_detailed_info()\n"); - assert (fetch_int (c->mtconnection) == (int)CODE_msg_new_detailed_info); - fetch_long (c->mtconnection); // answer_msg_id - fetch_int (c->mtconnection); // bytes - fetch_int (c->mtconnection); // status -} - -void work_updates_to_long (struct connection *c UU, long long msg_id UU) { - assert (fetch_int (c->mtconnection) == (int)CODE_updates_too_long); - debug ("updates to long... Getting difference\n"); - do_get_difference (c->instance, 0); -} - -void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { - assert (fetch_int (c->mtconnection) == (int)CODE_bad_msg_notification); - long long m1 = fetch_long (c->mtconnection); - int s = fetch_int (c->mtconnection); - int e = fetch_int (c->mtconnection); - debug ("bad_msg_notification: msg_id = %lld, seq = %d, error = %d\n", m1, s, e); -} - -void rpc_execute_answer (struct connection *c, long long msg_id UU) { - if (verbosity >= 5) { - debug ("rpc_execute_answer: fd=%d\n", c->fd); - hexdump_in (c->mtconnection); - } - int op = prefetch_int (c->mtconnection); - switch (op) { - case CODE_msg_container: - work_container (c, msg_id); - return; - case CODE_new_session_created: - work_new_session_created (c, msg_id); - return; - case CODE_msgs_ack: - work_msgs_ack (c, msg_id); - return; - case CODE_rpc_result: - work_rpc_result (c, msg_id); - return; - case CODE_update_short: - work_update_short (c, msg_id); - return; - case CODE_updates: - work_updates (c, msg_id); - return; - case CODE_update_short_message: - work_update_short_message (c, msg_id); - return; - case CODE_update_short_chat_message: - work_update_short_chat_message (c, msg_id); - return; - case CODE_gzip_packed: - work_packed (c, msg_id); - return; - case CODE_bad_server_salt: - work_bad_server_salt (c, msg_id); - return; - case CODE_pong: - work_pong (c, msg_id); - return; - case CODE_msg_detailed_info: - work_detailed_info (c, msg_id); - return; - case CODE_msg_new_detailed_info: - work_new_detailed_info (c, msg_id); - return; - case CODE_updates_too_long: - work_updates_to_long (c, msg_id); - return; - case CODE_bad_msg_notification: - work_bad_msg_notification (c, msg_id); - return; - } - debug ( "Unknown message: \n"); - hexdump_in (c->mtconnection); - c->mtconnection->in_ptr = c->mtconnection->in_end; // Will not fail due to assertion in_ptr == in_end -} - -int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { - const int MINSZ = offsetof (struct encrypted_message, message); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - debug ( "process_rpc_message(), len=%d\n", len); - assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); - struct dc *DC = GET_DC(c); - assert (enc->auth_key_id == DC->auth_key_id); - assert (DC->auth_key_id); - init_aes_auth (c->mtconnection, DC->auth_key + 8, enc->msg_key, AES_DECRYPT); - int l = pad_aes_decrypt (c->mtconnection, (char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); - assert (l == len - UNENCSZ); - //assert (enc->auth_key_id2 == enc->auth_key_id); - assert (!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12); - static unsigned char sha1_buffer[20]; - sha1 ((void *)&enc->server_salt, enc->msg_len + (MINSZ - UNENCSZ), sha1_buffer); - assert (!memcmp (&enc->msg_key, sha1_buffer + 4, 16)); - //assert (enc->server_salt == server_salt); //in fact server salt can change - if (DC->server_salt != enc->server_salt) { - DC->server_salt = enc->server_salt; - //write_auth_file (); - } - - int this_server_time = enc->msg_id >> 32LL; - if (!DC->server_time_delta) { - DC->server_time_delta = this_server_time - get_utime (CLOCK_REALTIME); - DC->server_time_udelta = this_server_time - get_utime (CLOCK_MONOTONIC); - } - double st = get_server_time (DC); - if (this_server_time < st - 300 || this_server_time > st + 30) { - debug ("salt = %lld, session_id = %lld, msg_id = %lld, seq_no = %d, st = %lf, now = %lf\n", - enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); - c->mtconnection->in_ptr = enc->message; - c->mtconnection->in_end = c->mtconnection->in_ptr + (enc->msg_len / 4); - hexdump_in (c->mtconnection); - } - - assert (this_server_time >= st - 300 && this_server_time <= st + 30); - //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); - debug ( "received mesage id %016llx\n", enc->msg_id); - hexdump_in (c->mtconnection); - c->mtconnection->server_last_msg_id = enc->msg_id; - - //*(long long *)(longpoll_query + 3) = *(long long *)((char *)(&enc->msg_id) + 0x3c); - //*(long long *)(longpoll_query + 5) = *(long long *)((char *)(&enc->msg_id) + 0x3c); - - assert (l >= (MINSZ - UNENCSZ) + 8); - //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); - ++c->mtconnection->good_messages; - - c->mtconnection->in_ptr = enc->message; - c->mtconnection->in_end = c->mtconnection->in_ptr + (enc->msg_len / 4); - - if (enc->msg_id & 1) { - insert_msg_id (c->session, enc->msg_id); - } - assert (c->session->session_id == enc->session_id); - rpc_execute_answer (c, enc->msg_id); - assert (c->mtconnection->in_ptr == c->mtconnection->in_end); - return 0; -} - - -int rpc_execute (struct connection *c, int op, int len) { - debug ("outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); - struct mtproto_connection *self = c->mtconnection; - struct telegram *instance = c->instance; - - /* - if (op < 0) { - assert (read_in (c, Response, Response_len) == Response_len); - return 0; - } - */ - - if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - debug ( "answer too long (%d bytes), skipping\n", len); - return 0; - } - - int Response_len = len; - - if (verbosity >= 2) { - debug ("Response_len = %d\n", Response_len); - } - assert (read_in (c, Response, Response_len) == Response_len); - Response[Response_len] = 0; - if (verbosity >= 2) { - debug ( "have %d Response bytes\n", Response_len); - } - - int o = c->mtconnection->c_state; - if (GET_DC(c)->flags & 1) { o = st_authorized;} - switch (o) { - case st_reqpq_sent: - process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); - return 0; - case st_reqdh_sent: - process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); - return 0; - case st_client_dh_sent: - process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); - self->queries_num --; - debug ("queries_num=%d\n", c->mtconnection->queries_num); - if (self->on_ready) { - self->on_ready(self, self->on_ready_data); - } - return 0; - case st_authorized: - if (op < 0 && op >= -999) { - debug ("Server error %d\n", op); - char code[12] = {0}; - snprintf (code, 12, "%d", op); - c->mtconnection->c_state = st_error; - telegram_change_state (instance, STATE_ERROR, code); - } else { - process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); - } - return 0; - default: - debug ( "fatal: cannot receive answer in state %d\n", c->mtconnection->c_state); - exit (2); - } - - return 0; -} - - -int tc_close (struct connection *c, int who) { - debug ( "outbound http connection #%d : closing by %d\n", c->fd, who); - return 0; -} - -int tc_becomes_ready (struct connection *c) { - debug ( "outbound connection #%d becomes ready\n", c->fd); - char byte = 0xef; - assert (write_out (c, &byte, 1) == 1); - flush_out (c); - - int o = c->mtconnection->c_state; - if (GET_DC(c)->flags & 1) { - o = st_authorized; - } - switch (o) { - case st_init: - c->mtconnection->queries_num ++; - debug ("queries_num=%d\n", c->mtconnection->queries_num); - send_req_pq_packet (c); - break; - case st_authorized: - c->mtconnection->on_ready(c->mtconnection, c->mtconnection->on_ready_data); - //telegram_change_state (c->instance, STATE_AUTHORIZED, NULL); - break; - default: - debug ( "c_state = %d\n", c->mtconnection->c_state); - assert (0); - } - return 0; -} - -int rpc_becomes_ready (struct connection *c) { - return tc_becomes_ready (c); -} - -int rpc_close (struct connection *c) { - return tc_close (c, 0); -} - -int auth_is_success (struct mtproto_connection *m) { - return m->auth_success; -} - - -#define RANDSEED_PASSWORD_FILENAME NULL -#define RANDSEED_PASSWORD_LENGTH 0 -void on_start (struct mtproto_connection *self) { - prng_seed (self, RANDSEED_PASSWORD_FILENAME, RANDSEED_PASSWORD_LENGTH); - - if (rsa_public_key_name) { - if (rsa_load_public_key (rsa_public_key_name) < 0) { - perror ("rsa_load_public_key"); - exit (1); - } - } else { - if (rsa_load_public_key (TG_SERVER_PUBKEY_FILENAME) < 0 - && rsa_load_public_key ("/etc/" PROG_NAME "/server.pub") < 0) { - perror ("rsa_load_public_key"); - exit (1); - } - } - pk_fingerprint = compute_rsa_key_fingerprint (pubKey); -} - - -struct connection_methods mtproto_methods = { - .execute = rpc_execute, - .ready = rpc_becomes_ready, - .close = rpc_close -}; - -/** - * Create a new struct mtproto_connection connection using the giving datacenter for authorization and - * session handling - */ -struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg) -{ - struct mtproto_connection *mtp = talloc0(sizeof(struct mtproto_connection)); - tg->Cs[tg->cs++] = mtp; - mtp->instance = tg; - mtp->packet_buffer = mtp->__packet_buffer + 16; - mtp->connection = fd_create_connection(DC, fd, tg, &mtproto_methods, mtp); - assert (tg->bl); - mtp->bl = tg->bl; - return mtp; -} - -/** - * Connect to the network - */ -void mtproto_connect(struct mtproto_connection *c) -{ - on_start(c); - start_ping_timer (c->connection); - c->connection->methods->ready(c->connection); -} - -/** - * Mark the connection for destruction, stop all timers and initiate - * cleanup tasks - */ -void mtproto_close(struct mtproto_connection *mtp) { - debug ("closing mtproto_connection...\n"); - mtp->destroy = 1; - - // send all pending acks on this connection so the server won't - // resend messages. We might not be able to send the acknowledgements later - // in case the session is switched and this DC is not reachable anymore - if (mtp->connection) { - if (mtp->connection->session && mtp->connection->session->ack_tree) { - struct session *S = mtp->connection->session; - send_all_acks (S); - mtp->instance->config->on_output(mtp->handle); - S->c = 0; - } - stop_ping_timer (mtp->connection); - } -} - -/** - * Close the underlying file descriptor - */ -void mtproto_destroy (struct mtproto_connection *self) { - debug("destroying mtproto_connection: %p\n", self); - self->instance->config->proxy_close_cb(self->handle); - fd_close_connection(self->connection); - tfree(self, sizeof(struct mtproto_connection)); -} - -void mtproto_close_foreign (struct telegram *instance) -{ - int i; - for (i = 0; i < 100; i++) { - struct mtproto_connection * c = instance->Cs[i]; - if (c && - !c->destroy && - c->connection->session->dc->id != instance->auth.dc_working_num) { - debug ("closing connection for working_dc=%d, dc=%d\n", - instance->auth.dc_working_num, c->connection->session->dc->id); - mtproto_close (c); - } - } -} - -/** - * Free all destroyed connections - */ -void mtproto_free_closed (struct telegram *tg, int force) { - int i; - for (i = 0; i < 100; i++) { - if (tg->Cs[i] == NULL) continue; - struct mtproto_connection *c = tg->Cs[i]; - debug ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", - i, c->c_state, c->destroy, c->queries_num); - if (c->destroy == 0) continue; - if (!force && c->connection->out_bytes > 0) { - debug ("still %d bytes ouput left, skipping connection...\n", c->connection->out_bytes); - continue; - } - mtproto_destroy (c); - if (tg->connection == c) { - tg->connection = NULL; - } - tg->Cs[i] = NULL; - } -} - diff --git a/mtproto-client.h b/mtproto-client.h deleted file mode 100644 index 073e353..0000000 --- a/mtproto-client.h +++ /dev/null @@ -1,514 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - -Copyright Nikolay Durov, Andrey Lopatin 2012-2013 - Copyright Vitaly Valtman 2013 -*/ -#ifndef __MTPROTO_CLIENT_H__ -#define __MTPROTO_CLIENT_H__ - - -/* - * COMMON - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "include.h" -#include "tools.h" -#include "constants.h" -#include "msglog.h" -#include "net.h" - -#ifdef __MACH__ -#include -#include -#endif - - -/* DH key exchange protocol data structures */ -#define CODE_req_pq 0x60469778 -#define CODE_resPQ 0x05162463 -#define CODE_req_DH_params 0xd712e4be -#define CODE_p_q_inner_data 0x83c95aec -#define CODE_server_DH_inner_data 0xb5890dba -#define CODE_server_DH_params_fail 0x79cb045d -#define CODE_server_DH_params_ok 0xd0e8075c -#define CODE_set_client_DH_params 0xf5045f1f -#define CODE_client_DH_inner_data 0x6643b654 -#define CODE_dh_gen_ok 0x3bcbf734 -#define CODE_dh_gen_retry 0x46dc1fb9 -#define CODE_dh_gen_fail 0xa69dae02 - -/* service messages */ -#define CODE_rpc_result 0xf35c6d01 -#define CODE_rpc_error 0x2144ca19 -#define CODE_msg_container 0x73f1f8dc -#define CODE_msg_copy 0xe06046b2 -#define CODE_msgs_ack 0x62d6b459 -#define CODE_bad_msg_notification 0xa7eff811 -#define CODE_bad_server_salt 0xedab447b -#define CODE_msgs_state_req 0xda69fb52 -#define CODE_msgs_state_info 0x04deb57d -#define CODE_msgs_all_info 0x8cc0d131 -#define CODE_new_session_created 0x9ec20908 -#define CODE_msg_resend_req 0x7d861a08 -#define CODE_ping 0x7abe77ec -#define CODE_pong 0x347773c5 -#define CODE_destroy_session 0xe7512126 -#define CODE_destroy_session_ok 0xe22045fc -#define CODE_destroy_session_none 0x62d350c9 -#define CODE_destroy_sessions 0x9a6face8 -#define CODE_destroy_sessions_res 0xa8164668 -#define CODE_get_future_salts 0xb921bd04 -#define CODE_future_salt 0x0949d9dc -#define CODE_future_salts 0xae500895 -#define CODE_rpc_drop_answer 0x58e4a740 -#define CODE_rpc_answer_unknown 0x5e2ad36e -#define CODE_rpc_answer_dropped_running 0xcd78e586 -#define CODE_rpc_answer_dropped 0xa43ad8b7 -#define CODE_msg_detailed_info 0x276d3ec6 -#define CODE_msg_new_detailed_info 0x809db6df -#define CODE_ping_delay_disconnect 0xf3427b8c -#define CODE_gzip_packed 0x3072cfa1 - -#define CODE_input_peer_notify_settings_old 0x3cf4b1be -#define CODE_peer_notify_settings_old 0xddbcd4a5 -#define CODE_user_profile_photo_old 0x990d1493 -#define CODE_config_old 0x232d5905 - -#define CODE_msg_new_detailed_info 0x809db6df - -#define CODE_msg_detailed_info 0x276d3ec6 -/* not really a limit, for struct encrypted_message only */ -// #define MAX_MESSAGE_INTS 16384 -#define MAX_MESSAGE_INTS 1048576 -#define MAX_PROTO_MESSAGE_INTS 1048576 -#define _FILE_OFFSET_BITS 64 - -char *rsa_public_key_name; - -#pragma pack(push,4) -struct encrypted_message { - // unencrypted header - long long auth_key_id; - char msg_key[16]; - // encrypted part, starts with encrypted header - long long server_salt; - long long session_id; - // long long auth_key_id2; // removed - // first message follows - long long msg_id; - int seq_no; - int msg_len; // divisible by 4 - int message[MAX_MESSAGE_INTS]; -}; -#pragma pack(pop) - -/* - * CONNECTION STATES - */ - -enum dc_state { - st_init, - st_reqpq_sent, - st_reqdh_sent, - st_client_dh_sent, - st_authorized, - st_error -}; - -/* - * CLIENT - */ - -// forward-declarations -struct timespec; -struct telegram; -struct mtproto_connection; -void mtproto_destroy (struct mtproto_connection *self); - -#define DECRYPT_BUFFER_INTS 16384 -#define ENCRYPT_BUFFER_INTS 16384 -#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix - -struct mtproto_connection { - struct connection *connection; - - int auth_success; - enum dc_state c_state; - char nonce[256]; - char new_nonce[256]; - char server_nonce[256]; - - int total_packets_sent; - long long total_data_sent; - - unsigned long long what; - unsigned p1, p2; - - int *in_ptr, *in_end; - - // common - - int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr; - int *packet_buffer; - - long long rsa_encrypted_chunks, rsa_decrypted_chunks; - - BN_CTX *BN_ctx; - - - // DH - - int encrypt_buffer[ENCRYPT_BUFFER_INTS]; - int decrypt_buffer[ENCRYPT_BUFFER_INTS]; - char s_power [256]; - BIGNUM dh_prime, dh_g, g_a, dh_power, auth_key_num; - - struct { - long long auth_key_id; - long long out_msg_id; - int msg_len; - } unenc_msg_header; - - - // AES IGE - - unsigned char aes_key_raw[32], aes_iv[32]; - AES_KEY aes_key; - - // authorized - - struct encrypted_message enc_msg; - long long client_last_msg_id; - long long server_last_msg_id; - - int longpoll_count, good_messages; - - // TODO: decide whether this should be in struct telegram - // or in struct mtproto_client - int unread_messages; - int our_id; - int pts; - int qts; - int last_date; - int seq; - - // extra (queries.c) - - int *encr_extra; - int *encr_ptr; - int *encr_end; - - // callbacks - - void (*on_ready)(struct mtproto_connection *self, void* data); - void *on_ready_data; - - void (*on_error)(struct mtproto_connection *self, void *data); - - // the amount of currently outgoing messages that - // have not yet received a response - int queries_num; - - // binlog that consumes all updates and events of this connection - struct binlog *bl; - - // marks this connection for destruction, so it - // will be freed once all queries received a response or timed out - int destroy; - - // - // the corresponding telegram instance - // - struct telegram *instance; - void *handle; -}; - -void mtproto_connection_init (struct mtproto_connection *c); -struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg); -void mtproto_close(struct mtproto_connection *c); -void mtproto_connect(struct mtproto_connection *c); - -void on_start (struct mtproto_connection *self); -long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful); -void work_update (struct mtproto_connection *self, long long msg_id); -void work_update_binlog (struct mtproto_connection *self); -int check_g (unsigned char p[256], BIGNUM *g); -int check_g_bn (BIGNUM *p, BIGNUM *g); -int check_DH_params (struct mtproto_connection *self, BIGNUM *p, int g); -void secure_random (void *s, int l); - -/* - * Common 2 - */ - -void prng_seed (struct mtproto_connection *self, const char *password_filename, int password_length); -int serialize_bignum (BIGNUM *b, char *buffer, int maxlen); -long long compute_rsa_key_fingerprint (RSA *key); - -static inline void out_ints (struct mtproto_connection *self, const int *what, int len) { - assert (self->packet_ptr + len <= self->packet_buffer + PACKET_BUFFER_SIZE); - memcpy (self->packet_ptr, what, len * 4); - self->packet_ptr += len; -} - - -static inline void out_int (struct mtproto_connection *self, int x) { - assert (self->packet_ptr + 1 <= self->packet_buffer + PACKET_BUFFER_SIZE); - *self->packet_ptr++ = x; -} - - -static inline void out_long (struct mtproto_connection *self, long long x) { - assert (self->packet_ptr + 2 <= self->packet_buffer + PACKET_BUFFER_SIZE); - *(long long *)self->packet_ptr = x; - self->packet_ptr += 2; -} - -static inline void clear_packet (struct mtproto_connection *self) { - self->packet_ptr = self->packet_buffer; -} - -void out_cstring (struct mtproto_connection *self, const char *str, long len); -void out_cstring_careful (struct mtproto_connection *self, const char *str, long len); -void out_data (struct mtproto_connection *self, const void *data, long len); - -static inline void out_string (struct mtproto_connection *self, const char *str) { - out_cstring (self, str, strlen (str)); -} - -static inline void out_bignum (struct mtproto_connection *self, BIGNUM *n) { - int l = serialize_bignum (n, (char *)self->packet_ptr, (PACKET_BUFFER_SIZE - (self->packet_ptr - self->packet_buffer)) * 4); - assert (l > 0); - self->packet_ptr += l >> 2; -} - - -void fetch_pts (struct mtproto_connection *self); -void fetch_qts (struct mtproto_connection *self); -void fetch_date (struct mtproto_connection *self); -void fetch_seq (struct mtproto_connection *self); -static inline int prefetch_strlen (struct mtproto_connection *self) { - if (self->in_ptr >= self->in_end) { - return -1; - } - unsigned l = *self->in_ptr; - if ((l & 0xff) < 0xfe) { - l &= 0xff; - return (self->in_end >= self->in_ptr + (l >> 2) + 1) ? (int)l : -1; - } else if ((l & 0xff) == 0xfe) { - l >>= 8; - return (l >= 254 && self->in_end >= self->in_ptr + ((l + 7) >> 2)) ? (int)l : -1; - } else { - return -1; - } -} - -extern int verbosity; -static inline char *fetch_str (struct mtproto_connection *self, int len) { - assert (len >= 0); - if (verbosity > 6) { - debug ("fetch_string: len = %d\n", len); - } - if (len < 254) { - char *str = (char *) self->in_ptr + 1; - self->in_ptr += 1 + (len >> 2); - return str; - } else { - char *str = (char *) self->in_ptr + 4; - self->in_ptr += (len + 7) >> 2; - return str; - } -} - -static inline char *fetch_str_dup (struct mtproto_connection *self) { - int l = prefetch_strlen (self); - assert (l >= 0); - int i; - char *s = fetch_str (self, l); - for (i = 0; i < l; i++) { - if (!s[i]) { break; } - } - char *r = talloc (i + 1); - memcpy (r, s, i); - r[i] = 0; - return r; -} - -static inline int fetch_update_str (struct mtproto_connection *self, char **s) { - if (!*s) { - *s = fetch_str_dup (self); - return 1; - } - int l = prefetch_strlen (self); - char *r = fetch_str (self, l); - if (memcmp (*s, r, l) || (*s)[l]) { - tfree_str (*s); - *s = talloc (l + 1); - memcpy (*s, r, l); - (*s)[l] = 0; - return 1; - } - return 0; -} - -static inline int fetch_update_int (struct mtproto_connection *self, int *value) { - if (*value == *self->in_ptr) { - self->in_ptr ++; - return 0; - } else { - *value = *(self->in_ptr ++); - return 1; - } -} - -static inline int fetch_update_long (struct mtproto_connection *self, long long *value) { - if (*value == *(long long *)self->in_ptr) { - self->in_ptr += 2; - return 0; - } else { - *value = *(long long *)(self->in_ptr); - self->in_ptr += 2; - return 1; - } -} - -static inline int set_update_int (int *value, int new_value) { - if (*value == new_value) { - return 0; - } else { - *value = new_value; - return 1; - } -} - -static inline void fetch_skip (struct mtproto_connection *self, int n) { - self->in_ptr += n; - assert (self->in_ptr <= self->in_end); -} - -static inline void fetch_skip_str (struct mtproto_connection *self) { - int l = prefetch_strlen (self); - assert (l >= 0); - fetch_str (self, l); -} - -static inline long have_prefetch_ints (struct mtproto_connection *self) { - return self->in_end - self->in_ptr; -} - -int fetch_bignum (struct mtproto_connection *self, BIGNUM *x); - -static inline int fetch_int (struct mtproto_connection *self) { - assert (self->in_ptr + 1 <= self->in_end); - if (verbosity > 6) { - debug ("fetch_int: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); - } - return *(self->in_ptr ++); -} - -static inline int fetch_bool (struct mtproto_connection *self) { - if (verbosity > 6) { - debug ("fetch_bool: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr); - } - assert (self->in_ptr + 1 <= self->in_end); - assert (*(self->in_ptr) == (int)CODE_bool_true || *(self->in_ptr) == (int)CODE_bool_false); - return *(self->in_ptr ++) == (int)CODE_bool_true; -} - -static inline int prefetch_int (struct mtproto_connection *self) { - assert (self->in_ptr < self->in_end); - return *(self->in_ptr); -} - -static inline void prefetch_data (struct mtproto_connection *self, void *data, int size) { - assert (self->in_ptr + (size >> 2) <= self->in_end); - memcpy (data, self->in_ptr, size); -} - -static inline void fetch_data (struct mtproto_connection *self, void *data, int size) { - assert (self->in_ptr + (size >> 2) <= self->in_end); - memcpy (data, self->in_ptr, size); - assert (!(size & 3)); - self->in_ptr += (size >> 2); -} - -static inline long long fetch_long (struct mtproto_connection *self) { - assert (self->in_ptr + 2 <= self->in_end); - long long r = *(long long *)self->in_ptr; - self->in_ptr += 2; - return r; -} - -static inline double fetch_double (struct mtproto_connection *self) { - assert (self->in_ptr + 2 <= self->in_end); - double r = *(double *)self->in_ptr; - self->in_ptr += 2; - return r; -} - -static inline void fetch_ints (struct mtproto_connection *self, void *data, int count) { - assert (self->in_ptr + count <= self->in_end); - memcpy (data, self->in_ptr, 4 * count); - self->in_ptr += count; -} - -int get_random_bytes (unsigned char *buf, int n); - -int pad_rsa_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E); -int pad_rsa_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D); - -void init_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32], int encrypt); -void init_aes_auth (struct mtproto_connection *self, char auth_key[192], char msg_key[16], int encrypt); -int pad_aes_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size); -int pad_aes_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size); - -static inline void hexdump_in (struct mtproto_connection *self) { - hexdump (self->in_ptr, self->in_end); -} - -static inline void hexdump_out (struct mtproto_connection *self) { - hexdump (self->packet_buffer, self->packet_ptr); -} - -#ifdef __MACH__ -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#endif -void my_clock_gettime (int clock_id, struct timespec *T); - -void mtproto_close_foreign (struct telegram *instance); -void mtproto_free_closed (struct telegram *tg, int force); - -#endif - diff --git a/mtproto-common.c b/mtproto-common.c deleted file mode 100644 index e2db1a5..0000000 --- a/mtproto-common.c +++ /dev/null @@ -1,357 +0,0 @@ -#include "mtproto-client.h" - -/* - * struct mtproto_connection-Common.c - */ - -int verbosity; - -#ifndef __MTPROTO_COMMON_C__ -#define __MTPROTO_COMMON_C__ - -int get_random_bytes (unsigned char *buf, int n) { - int r = 0, h = open ("/dev/random", O_RDONLY | O_NONBLOCK); - if (h >= 0) { - r = read (h, buf, n); - if (r > 0) { - if (verbosity >= 3) { - debug ( "added %d bytes of real entropy to secure random numbers seed\n", r); - } - } else { - r = 0; - } - close (h); - } - - if (r < n) { - h = open ("/dev/urandom", O_RDONLY); - if (h < 0) { - return r; - } - int s = read (h, buf + r, n - r); - close (h); - if (s > 0) { - r += s; - } - } - - if (r >= (int) sizeof (long)) { - *(long *)buf ^= lrand48 (); - srand48 (*(long *)buf); - } - - return r; -} - -void my_clock_gettime (int clock_id UU, struct timespec *T) { -#ifdef __MACH__ - // We are ignoring MONOTONIC and hope time doesn't go back to often - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - T->tv_sec = mts.tv_sec; - T->tv_nsec = mts.tv_nsec; -#else - assert (clock_gettime(clock_id, T) >= 0); -#endif -} - -/* RDTSC */ -#if defined(__i386__) -#define HAVE_RDTSC -static __inline__ unsigned long long rdtsc (void) { - unsigned long long int x; - __asm__ volatile ("rdtsc" : "=A" (x)); - return x; -} -#elif defined(__x86_64__) -#define HAVE_RDTSC -static __inline__ unsigned long long rdtsc (void) { - unsigned hi, lo; - __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); - return ((unsigned long long) lo) | (((unsigned long long) hi) << 32); -} -#endif - -void prng_seed (struct mtproto_connection *self, const char *password_filename, int password_length) { - struct timespec T; - my_clock_gettime (CLOCK_REALTIME, &T); - RAND_add (&T, sizeof (T), 4.0); -#ifdef HAVE_RDTSC - unsigned long long r = rdtsc (); - RAND_add (&r, 8, 4.0); -#endif - unsigned short p = getpid (); - RAND_add (&p, sizeof (p), 0.0); - p = getppid (); - RAND_add (&p, sizeof (p), 0.0); - unsigned char rb[32]; - int s = get_random_bytes (rb, 32); - if (s > 0) { - RAND_add (rb, s, s); - } - memset (rb, 0, sizeof (rb)); - if (password_filename && password_length > 0) { - int fd = open (password_filename, O_RDONLY); - if (fd < 0) { - debug ( "Warning: fail to open password file - \"%s\", %m.\n", password_filename); - } else { - unsigned char *a = talloc0 (password_length); - int l = read (fd, a, password_length); - if (l < 0) { - debug ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename); - } else { - debug ( "read %d bytes from password file.\n", l); - RAND_add (a, l, l); - } - close (fd); - tfree_secure (a, password_length); - } - } - self->BN_ctx = BN_CTX_new (); - ensure_ptr (self->BN_ctx); -} - -int serialize_bignum (BIGNUM *b, char *buffer, int maxlen) { - int itslen = BN_num_bytes (b); - int reqlen; - if (itslen < 254) { - reqlen = itslen + 1; - } else { - reqlen = itslen + 4; - } - int newlen = (reqlen + 3) & -4; - int pad = newlen - reqlen; - reqlen = newlen; - if (reqlen > maxlen) { - return -reqlen; - } - if (itslen < 254) { - *buffer++ = itslen; - } else { - *(int *)buffer = (itslen << 8) + 0xfe; - buffer += 4; - } - int l = BN_bn2bin (b, (unsigned char *)buffer); - assert (l == itslen); - buffer += l; - while (pad --> 0) { - *buffer++ = 0; - } - return reqlen; -} - - -long long compute_rsa_key_fingerprint (RSA *key) { - static char tempbuff[4096]; - static unsigned char sha[20]; - assert (key->n && key->e); - int l1 = serialize_bignum (key->n, tempbuff, 4096); - assert (l1 > 0); - int l2 = serialize_bignum (key->e, tempbuff + l1, 4096 - l1); - assert (l2 > 0 && l1 + l2 <= 4096); - SHA1 ((unsigned char *)tempbuff, l1 + l2, sha); - return *(long long *)(sha + 12); -} - -void out_cstring (struct mtproto_connection *self, const char *str, long len) { - assert (len >= 0 && len < (1 << 24)); - assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE)); - char *dest = (char *) self->packet_ptr; - if (len < 254) { - *dest++ = len; - } else { - *self->packet_ptr = (len << 8) + 0xfe; - dest += 4; - } - memcpy (dest, str, len); - dest += len; - while ((long) dest & 3) { - *dest++ = 0; - } - self->packet_ptr = (int *) dest; -} - -void out_cstring_careful (struct mtproto_connection *self, const char *str, long len) { - assert (len >= 0 && len < (1 << 24)); - assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE)); - char *dest = (char *) self->packet_ptr; - if (len < 254) { - dest++; - if (dest != str) { - memmove (dest, str, len); - } - dest[-1] = len; - } else { - dest += 4; - if (dest != str) { - memmove (dest, str, len); - } - *self->packet_ptr = (len << 8) + 0xfe; - } - dest += len; - while ((long) dest & 3) { - *dest++ = 0; - } - self->packet_ptr = (int *) dest; -} - - -void out_data (struct mtproto_connection *self, const void *data, long len) { - assert (len >= 0 && len < (1 << 24) && !(len & 3)); - assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE)); - memcpy (self->packet_ptr, data, len); - self->packet_ptr += len >> 2; -} - - -int fetch_bignum (struct mtproto_connection *self, BIGNUM *x) { - int l = prefetch_strlen (self); - if (l < 0) { - return l; - } - char *str = fetch_str (self, l); - assert (BN_bin2bn ((unsigned char *) str, l, x) == x); - return l; -} - -int pad_rsa_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E) { - int pad = (255000 - from_len - 32) % 255 + 32; - int chunks = (from_len + pad) / 255; - int bits = BN_num_bits (N); - assert (bits >= 2041 && bits <= 2048); - assert (from_len > 0 && from_len <= 2550); - assert (size >= chunks * 256); - assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, pad) >= 0); - int i; - BIGNUM x, y; - BN_init (&x); - BN_init (&y); - self->rsa_encrypted_chunks += chunks; - for (i = 0; i < chunks; i++) { - BN_bin2bn ((unsigned char *) from, 255, &x); - assert (BN_mod_exp (&y, &x, E, N, self->BN_ctx) == 1); - unsigned l = 256 - BN_num_bytes (&y); - assert (l <= 256); - memset (to, 0, l); - BN_bn2bin (&y, (unsigned char *) to + l); - to += 256; - } - BN_free (&x); - BN_free (&y); - return chunks * 256; -} - -int pad_rsa_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D) { - if (from_len < 0 || from_len > 0x1000 || (from_len & 0xff)) { - return -1; - } - int chunks = (from_len >> 8); - int bits = BN_num_bits (N); - assert (bits >= 2041 && bits <= 2048); - assert (size >= chunks * 255); - int i; - BIGNUM x, y; - BN_init (&x); - BN_init (&y); - for (i = 0; i < chunks; i++) { - ++self->rsa_decrypted_chunks; - BN_bin2bn ((unsigned char *) from, 256, &x); - assert (BN_mod_exp (&y, &x, D, N, self->BN_ctx) == 1); - int l = BN_num_bytes (&y); - if (l > 255) { - BN_free (&x); - BN_free (&y); - return -1; - } - assert (l >= 0 && l <= 255); - memset (to, 0, 255 - l); - BN_bn2bin (&y, (unsigned char *) to + 255 - l); - to += 255; - } - BN_free (&x); - BN_free (&y); - return chunks * 255; -} - -void init_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32], int encrypt) { - static unsigned char buffer[64], hash[20]; - memcpy (buffer, hidden_client_nonce, 32); - memcpy (buffer + 32, server_nonce, 16); - SHA1 (buffer, 48, self->aes_key_raw); - memcpy (buffer + 32, hidden_client_nonce, 32); - SHA1 (buffer, 64, self->aes_iv + 8); - memcpy (buffer, server_nonce, 16); - memcpy (buffer + 16, hidden_client_nonce, 32); - SHA1 (buffer, 48, hash); - memcpy (self->aes_key_raw + 20, hash, 12); - memcpy (self->aes_iv, hash + 12, 8); - memcpy (self->aes_iv + 28, hidden_client_nonce, 4); - if (encrypt == AES_ENCRYPT) { - AES_set_encrypt_key (self->aes_key_raw, 32*8, &self->aes_key); - } else { - AES_set_decrypt_key (self->aes_key_raw, 32*8, &self->aes_key); - } - memset (self->aes_key_raw, 0, sizeof (self->aes_key_raw)); -} - -void init_aes_auth (struct mtproto_connection *self, char auth_key[192], char msg_key[16], int encrypt) { - static unsigned char buffer[48], hash[20]; - // sha1_a = SHA1 (msg_key + substr (auth_key, 0, 32)); - // sha1_b = SHA1 (substr (auth_key, 32, 16) + msg_key + substr (auth_key, 48, 16)); - // sha1_с = SHA1 (substr (auth_key, 64, 32) + msg_key); - // sha1_d = SHA1 (msg_key + substr (auth_key, 96, 32)); - // aes_key = substr (sha1_a, 0, 8) + substr (sha1_b, 8, 12) + substr (sha1_c, 4, 12); - // aes_iv = substr (sha1_a, 8, 12) + substr (sha1_b, 0, 8) + substr (sha1_c, 16, 4) + substr (sha1_d, 0, 8); - memcpy (buffer, msg_key, 16); - memcpy (buffer + 16, auth_key, 32); - SHA1 (buffer, 48, hash); - memcpy (self->aes_key_raw, hash, 8); - memcpy (self->aes_iv, hash + 8, 12); - - memcpy (buffer, auth_key + 32, 16); - memcpy (buffer + 16, msg_key, 16); - memcpy (buffer + 32, auth_key + 48, 16); - SHA1 (buffer, 48, hash); - memcpy (self->aes_key_raw + 8, hash + 8, 12); - memcpy (self->aes_iv + 12, hash, 8); - - memcpy (buffer, auth_key + 64, 32); - memcpy (buffer + 32, msg_key, 16); - SHA1 (buffer, 48, hash); - memcpy (self->aes_key_raw + 20, hash + 4, 12); - memcpy (self->aes_iv + 20, hash + 16, 4); - - memcpy (buffer, msg_key, 16); - memcpy (buffer + 16, auth_key + 96, 32); - SHA1 (buffer, 48, hash); - memcpy (self->aes_iv + 24, hash, 8); - - if (encrypt == AES_ENCRYPT) { - AES_set_encrypt_key (self->aes_key_raw, 32*8, &self->aes_key); - } else { - AES_set_decrypt_key (self->aes_key_raw, 32*8, &self->aes_key); - } - memset (self->aes_key_raw, 0, sizeof (self->aes_key_raw)); -} - -int pad_aes_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size) { - int padded_size = (from_len + 15) & -16; - assert (from_len > 0 && padded_size <= size); - if (from_len < padded_size) { - assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, padded_size - from_len) >= 0); - } - AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, padded_size, &self->aes_key, self->aes_iv, AES_ENCRYPT); - return padded_size; -} - -int pad_aes_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size) { - if (from_len <= 0 || from_len > size || (from_len & 15)) { - return -1; - } - AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, from_len, &self->aes_key, self->aes_iv, AES_DECRYPT); - return from_len; -} -#endif diff --git a/net.c b/net.c deleted file mode 100644 index 97763cc..0000000 --- a/net.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "net.h" -#include "include.h" -#include "mtproto-client.h" -#include "tree.h" - -#ifndef POLLRDHUP -#define POLLRDHUP 0 -#endif - -#define long_cmp(a,b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1) -DEFINE_TREE(long,long long,long_cmp,0) -double get_utime (int clock_id); - -int verbosity; -extern struct connection_methods auth_methods; -//extern FILE *log_net_f; -FILE *log_net_f = 0; - -void fail_connection (struct connection *c); - -/* - * - */ - -#define PING_TIMEOUT 10 - -void start_ping_timer (struct connection *c); -int ping_alarm (struct connection *c) { - assert (c->state == conn_ready || c->state == conn_connecting); - if (get_double_time () - c->last_receive_time > 20 * PING_TIMEOUT) { - warning ( "fail connection: reason: ping timeout\n"); - c->state = conn_failed; - fail_connection (c); - } else if (get_double_time () - c->last_receive_time > 5 * PING_TIMEOUT && c->state == conn_ready) { - debug ("sending PING...\n"); - int x[3]; - x[0] = CODE_ping; - *(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 (); - encrypt_send_message (c->mtconnection, x, 3, 0); - start_ping_timer (c); - } else { - start_ping_timer (c); - } - return 0; -} - -void stop_ping_timer (struct connection *c) { - if (c->ev.self) { - remove_event_timer (c->instance, &c->ev); - } else { - warning ("trying to stop non-existing ping timer fd: #%d\n", c->fd); - } -} - -void start_ping_timer (struct connection *c) { - c->ev.timeout = get_double_time () + PING_TIMEOUT; - c->ev.alarm = (void *)ping_alarm; - c->ev.self = c; - insert_event_timer (c->instance, &c->ev); -} - -void restart_connection (struct connection *c); -int fail_alarm (void *ev) { - ((struct connection *)ev)->in_fail_timer = 0; - restart_connection (ev); - return 0; -} -void start_fail_timer (struct connection *c) { - if (c->in_fail_timer) { return; } - c->in_fail_timer = 1; - c->ev.timeout = get_double_time () + 10; - c->ev.alarm = (void *)fail_alarm; - c->ev.self = c; - insert_event_timer (c->instance, &c->ev); -} - -struct connection_buffer *new_connection_buffer (int size) { - struct connection_buffer *b = talloc0 (sizeof (*b)); - b->start = talloc (size); - b->end = b->start + size; - b->rptr = b->wptr = b->start; - return b; -} - -void delete_connection_buffer (struct connection_buffer *b) { - tfree (b->start, b->end - b->start); - tfree (b, sizeof (*b)); -} - -int write_out (struct connection *c, const void *_data, int len) { - const unsigned char *data = _data; - if (!len) { return 0; } - assert (len > 0); - int x = 0; - if (!c->out_head) { - struct connection_buffer *b = new_connection_buffer (1 << 20); - c->out_head = c->out_tail = b; - } - while (len) { - if (c->out_tail->end - c->out_tail->wptr >= len) { - memcpy (c->out_tail->wptr, data, len); - c->out_tail->wptr += len; - c->out_bytes += len; - return x + len; - } else { - int y = c->out_tail->end - c->out_tail->wptr; - assert (y < len); - memcpy (c->out_tail->wptr, data, y); - x += y; - len -= y; - data += y; - struct connection_buffer *b = new_connection_buffer (1 << 20); - c->out_tail->next = b; - b->next = 0; - c->out_tail = b; - c->out_bytes += y; - } - } - return x; -} - -int read_in (struct connection *c, void *_data, int len) { - unsigned char *data = _data; - if (!len) { return 0; } - assert (len > 0); - if (len > c->in_bytes) { - len = c->in_bytes; - } - int x = 0; - while (len) { - int y = c->in_head->wptr - c->in_head->rptr; - if (y > len) { - memcpy (data, c->in_head->rptr, len); - c->in_head->rptr += len; - c->in_bytes -= len; - return x + len; - } else { - memcpy (data, c->in_head->rptr, y); - c->in_bytes -= y; - x += y; - data += y; - len -= y; - void *old = c->in_head; - c->in_head = c->in_head->next; - if (!c->in_head) { - c->in_tail = 0; - } - delete_connection_buffer (old); - } - } - return x; -} - -int read_in_lookup (struct connection *c, void *_data, int len) { - unsigned char *data = _data; - if (!len || !c->in_bytes) { return 0; } - assert (len > 0); - if (len > c->in_bytes) { - len = c->in_bytes; - } - int x = 0; - struct connection_buffer *b = c->in_head; - while (len) { - int y = b->wptr - b->rptr; - if (y >= len) { - memcpy (data, b->rptr, len); - return x + len; - } else { - memcpy (data, b->rptr, y); - x += y; - data += y; - len -= y; - b = b->next; - } - } - return x; -} - -void flush_out (struct connection *c UU) { -} - -#define MAX_CONNECTIONS 100 -struct connection *Connections[MAX_CONNECTIONS]; -int max_connection_fd; - -void rotate_port (struct connection *c) { - switch (c->port) { - case 443: - c->port = 80; - break; - case 80: - c->port = 25; - break; - case 25: - c->port = 443; - break; - } -} - -void restart_connection (struct connection *c) { - if (c->last_connect_time == time (0)) { - start_fail_timer (c); - return; - } - - c->last_connect_time = time (0); - int fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd == -1) { - debug ("Can not create socket: %m\n"); - exit (1); - } - assert (fd >= 0 && fd < MAX_CONNECTIONS); - if (fd > max_connection_fd) { - max_connection_fd = fd; - } - int flags = -1; - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); - setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags)); - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags)); - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons (c->port); - addr.sin_addr.s_addr = inet_addr (c->ip); - - - fcntl (fd, F_SETFL, O_NONBLOCK); - - if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { - if (errno != EINPROGRESS) { - debug ( "Can not connect to %s:%d %m\n", c->ip, c->port); - start_fail_timer (c); - close (fd); - return; - } - } - - c->fd = fd; - c->state = conn_connecting; - c->last_receive_time = get_double_time (); - start_ping_timer (c); - Connections[fd] = c; - - char byte = 0xef; - assert (write_out (c, &byte, 1) == 1); - flush_out (c); -} - -void fail_connection (struct connection *c) { - warning ("Lost connection to server... %s:%d\n", c->ip, c->port); - telegram_change_state(c->mtconnection->instance, STATE_ERROR, "Lost connection to server\n"); -} - -extern FILE *log_net_f; -int try_write (struct connection *c) { - debug ( "try write: fd = %d\n", c->fd); - int x = 0; - while (c->out_head) { - int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); - - // Log all written packages - if (r > 0 && log_net_f) { - // fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); - int i; - for (i = 0; i < r; i++) { - // fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i)); - } - fprintf (log_net_f, "\n"); - fflush (log_net_f); - } - - if (r >= 0) { - x += r; - c->out_head->rptr += r; - if (c->out_head->rptr != c->out_head->wptr) { - break; - } - struct connection_buffer *b = c->out_head; - c->out_head = b->next; - if (!c->out_head) { - c->out_tail = 0; - } - delete_connection_buffer (b); - } else { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - debug ("fail_connection: write_error %m\n"); - fail_connection (c); - return 0; - } else { - break; - } - } - } - debug ( "Sent %d bytes to %d\n", x, c->fd); - c->out_bytes -= x; - return x; -} - -void hexdump_buf (struct connection_buffer *b) { - // TODO: figure out how to log hexdumps to purple log - int pos = 0; - int rem = 8; - while (b) { - unsigned char *c = b->rptr; - while (c != b->wptr) { - if (rem == 8) { - //if (pos) { printf ("\n"); } - //printf ("%04d", pos); - } - //printf (" %02x", (int)*c); - rem --; - pos ++; - if (!rem) { - rem = 8; - } - c ++; - } - b = b->next; - } - //printf ("\n"); - -} - -void try_rpc_read (struct connection *c) { - assert (c->in_head); - if (verbosity >= 3) { - hexdump_buf (c->in_head); - } - - while (1) { - if (c->in_bytes < 1) { return; } - unsigned len = 0; - unsigned t = 0; - assert (read_in_lookup (c, &len, 1) == 1); - if (len >= 1 && len <= 0x7e) { - if (c->in_bytes < (int)(1 + 4 * len)) { return; } - } else { - if (c->in_bytes < 4) { return; } - assert (read_in_lookup (c, &len, 4) == 4); - len = (len >> 8); - if (c->in_bytes < (int)(4 + 4 * len)) { return; } - len = 0x7f; - } - - if (len >= 1 && len <= 0x7e) { - assert (read_in (c, &t, 1) == 1); - assert (t == len); - assert (len >= 1); - } else { - assert (len == 0x7f); - assert (read_in (c, &len, 4) == 4); - len = (len >> 8); - assert (len >= 1); - } - len *= 4; - int op; - assert (read_in_lookup (c, &op, 4) == 4); - c->methods->execute (c, op, len); - } -} - -void try_read (struct connection *c) { - debug ( "try read: fd = %d\n", c->fd); - if (!c->in_tail) { - c->in_head = c->in_tail = new_connection_buffer (1 << 20); - } - int x = 0; - while (1) { - int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); - if (r > 0 && log_net_f) { - fprintf (log_net_f, "%.02lf %d IN %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port); - int i; - for (i = 0; i < r; i++) { - fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i)); - } - fprintf (log_net_f, "\n"); - fflush (log_net_f); - } - if (r > 0) { - c->last_receive_time = get_double_time (); - stop_ping_timer (c); - start_ping_timer (c); - } - if (r >= 0) { - c->in_tail->wptr += r; - x += r; - if (c->in_tail->wptr != c->in_tail->end) { - break; - } - struct connection_buffer *b = new_connection_buffer (1 << 20); - c->in_tail->next = b; - c->in_tail = b; - } else { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - debug ("fail_connection: read_error %m\n"); - fail_connection (c); - return; - } else { - break; - } - } - } - debug ( "Received %d bytes from fd=#%d and DC %d(%s, %d)\n", x, - c->fd, c->session->dc->id, c->session->dc->ip, c->session->dc->port); - c->in_bytes += x; - if (x) { - try_rpc_read (c); - } -} - -int send_all_acks (struct session *S) { - info ("send_all_acks(dc=%d)\n", S->dc->id); - if (!S->c) { - warning ("WARNING: cannot send acks, session has no active connection"); - return -1; - } - struct mtproto_connection *mt = S->c->mtconnection; - - clear_packet (mt); - out_int (mt, CODE_msgs_ack); - out_int (mt, CODE_vector); - out_int (mt, tree_count_long (S->ack_tree)); - while (S->ack_tree) { - long long x = tree_get_min_long (S->ack_tree); - out_long (mt, x); - S->ack_tree = tree_delete_long (S->ack_tree, x); - } - encrypt_send_message (mt, mt->packet_buffer, mt->packet_ptr - mt->packet_buffer, 0); - return 0; -} - -void insert_msg_id (struct session *S, long long id) { - if (!S->ack_tree) { - debug ("Creating ack_tree pointing to session %p\n"); - S->ev.alarm = (void *)send_all_acks; - S->ev.self = (void *)S; - S->ev.timeout = get_double_time () + ACK_TIMEOUT; - insert_event_timer (S->c->instance, &S->ev); - } - if (!tree_lookup_long (S->ack_tree, id)) { - S->ack_tree = tree_insert_long (S->ack_tree, id, lrand48 ()); - } -} - -struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) { - assert (!DC_list[id]); - struct dc *DC = talloc0 (sizeof (*DC)); - DC->id = id; - DC->ip = ip; - DC->port = port; - DC_list[id] = DC; - return DC; -} - -/** - * Wrap an existing socket file descriptor and make it usable as a connection, - */ -struct connection *fd_create_connection (struct dc *DC, int fd, - struct telegram *instance, struct connection_methods *methods, - struct mtproto_connection *mtp) { - - // create a connection - struct connection *c = talloc0 (sizeof (*c)); - c->fd = fd; - c->ip = tstrdup (DC->ip); - c->flags = 0; - c->state = conn_ready; - c->port = DC->port; - c->methods = methods; - c->instance = instance; - c->last_receive_time = get_double_time (); - debug ( "connect to %s:%d successful\n", DC->ip, DC->port); - - if (!DC->sessions[0]) { - struct session *S = talloc0 (sizeof (*S)); - assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); - S->dc = DC; - S->c = c; - DC->sessions[0] = S; - } - if (!DC->sessions[0]->c) { - DC->sessions[0]->c = c; - } - // add backreference to session - c->session = DC->sessions[0]; - - // add backreference to used mtproto-connection - c->mtconnection = mtp; - return c; -} - -/** - * Close the connection by freeing all attached buffers and setting - * the state to conn_stopped, but does NOT close the attached file descriptor - */ -void fd_close_connection(struct connection *c) { - struct connection_buffer *b = c->out_head; - while (b) { - struct connection_buffer *d = b; - b = b->next; - delete_connection_buffer (d); - } - while (b) { - struct connection_buffer *d = b; - b = b->next; - delete_connection_buffer (d); - } - c->out_head = c->out_tail = c->in_head = c->in_tail = 0; - c->state = conn_stopped; - c->out_bytes = c->in_bytes = 0; - tfree(c, sizeof(struct connection)); -} - diff --git a/net.h b/net.h deleted file mode 100644 index e6ddd63..0000000 --- a/net.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of telegram-client. - - struct telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - struct telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __NET_H__ -#define __NET_H__ - -#pragma once - -#include -struct dc; -#include "mtproto-client.h" -#include "telegram.h" -#include "queries.h" - -#define TG_SERVER "149.154.167.50" -#define TG_DC_NUM 2 -#define TG_SERVER_TEST "149.154.167.40" -#define TG_TEST_DC_NUM 2 -#define TG_APP_HASH "99428c722d0ed59b9cd844e4577cb4bb" -#define TG_APP_ID 16154 -#define TG_PORT 443 - -#define ACK_TIMEOUT 1 -#define MAX_DC_ID 10 - -// typedef struct mtproto_connection not available right now -struct mtproto_connection; - -struct connection; -struct connection_methods { - int (*ready) (struct connection *c); - int (*close) (struct connection *c); - int (*execute) (struct connection *c, int op, int len); -}; - - -#define MAX_DC_SESSIONS 3 - -struct session { - struct dc *dc; - long long session_id; - int seq_no; - struct connection *c; - struct tree_long *ack_tree; - struct event_timer ev; -}; - -struct dc { - int id; - int port; - int flags; - char *ip; - char *user; - struct session *sessions[MAX_DC_SESSIONS]; - char auth_key[256]; - long long auth_key_id; - long long server_salt; - - int server_time_delta; - double server_time_udelta; - int has_auth; -}; - -#define DC_SERIALIZED_MAGIC 0x64582faa -#define DC_SERIALIZED_MAGIC_V2 0x94032abb -#define STATE_FILE_MAGIC 0x84217a0d -#define SECRET_CHAT_FILE_MAGIC 0xa9840add - -struct dc_serialized { - int magic; - int port; - char ip[64]; - char user[64]; - char auth_key[256]; - long long auth_key_id, server_salt; - int authorized; -}; - -struct connection_buffer { - unsigned char *start; - unsigned char *end; - unsigned char *rptr; - unsigned char *wptr; - struct connection_buffer *next; -}; - -enum conn_state { - conn_none, - conn_connecting, - conn_ready, - conn_failed, - conn_stopped -}; - -struct connection { - int fd; - char *ip; - int port; - int flags; - enum conn_state state; - int ipv6[4]; - struct connection_buffer *in_head; - struct connection_buffer *in_tail; - struct connection_buffer *out_head; - struct connection_buffer *out_tail; - int in_bytes; - int out_bytes; - int packet_num; - int out_packet_num; - int last_connect_time; - int in_fail_timer; - struct connection_methods *methods; - struct session *session; - void *extra; - struct event_timer ev; - double last_receive_time; - struct telegram *instance; - struct mtproto_connection *mtconnection; -}; - -extern struct connection *Connections[]; - -int write_out (struct connection *c, const void *data, int len); -void flush_out (struct connection *c); -int read_in (struct connection *c, void *data, int len); - -void create_all_outbound_connections (void); - -void dc_create_session (struct dc *DC); -void insert_msg_id (struct session *S, long long id); -struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port); - -#define GET_DC(c) (c->session->dc) - -// export read and write methods to redirect network control -void try_read (struct connection *c); -void try_rpc_read (struct connection *c); -int try_write (struct connection *c); - -struct connection *fd_create_connection (struct dc *DC, int fd, struct telegram *instance, - struct connection_methods *methods, struct mtproto_connection *mtp); -void fd_close_connection(struct connection *c); - -void start_ping_timer (struct connection *c); -void stop_ping_timer (struct connection *c); -int send_all_acks (struct session *S); - -#endif diff --git a/no-preview.h b/no-preview.h deleted file mode 100644 index ee6bc7e..0000000 --- a/no-preview.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -// Just sample jpg file 90x90 - -int thumb_file_size = (82 * 6 - 2) * 4; -int thumb_file [] = { -0xe0ffd8ff, 0x464a1000, 0x01004649, 0x64000101, 0x00006400, 0xa002e2ff, -0x5f434349, 0x464f5250, 0x00454c49, 0x00000101, 0x636c9002, 0x3004736d, -0x6e6d0000, 0x47527274, 0x59582042, 0xdd07205a, 0x04000b00, 0x1b001600, -0x63612400, 0x50417073, 0x00004c50, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x0100d6f6, 0x00000000, 0x636c2dd3, -0x0000736d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x65640b00, 0x00006373, 0x00000801, 0x70633800, 0x00007472, 0x00004001, -0x74774e00, 0x00007470, 0x00009001, 0x68631400, 0x00006461, 0x0000a401, -0x58722c00, 0x00005a59, 0x0000d001, 0x58621400, 0x00005a59, 0x0000e401, -0x58671400, 0x00005a59, 0x0000f801, 0x54721400, 0x00004352, 0x00000c02, -0x54672000, 0x00004352, 0x00002c02, 0x54622000, 0x00004352, 0x00004c02, -0x68632000, 0x00006d72, 0x00006c02, 0x6c6d2400, 0x00006375, 0x00000000, -0x00000100, 0x6e650c00, 0x00005355, 0x00001c00, 0x73001c00, 0x47005200, -0x20004200, 0x75006200, 0x6c006900, 0x2d007400, 0x6e006900, 0x6c6d0000, -0x00006375, 0x00000000, 0x00000100, 0x6e650c00, 0x00005355, 0x00003200, -0x4e001c00, 0x20006f00, 0x6f006300, 0x79007000, 0x69007200, 0x68006700, -0x2c007400, 0x75002000, 0x65007300, 0x66002000, 0x65007200, 0x6c006500, -0x00007900, 0x59580000, 0x0000205a, 0x00000000, 0x0100d6f6, 0x00000000, -0x66732dd3, 0x00003233, 0x01000000, 0x00004a0c, 0xffffe305, 0x00002af3, -0x00009b07, 0xffff87fd, 0xffffa2fb, 0x0000a3fd, 0x0000d803, 0x595894c0, -0x0000205a, 0x00000000, 0x0000946f, 0x0000ee38, 0x59589003, 0x0000205a, -0x00000000, 0x00009d24, 0x0000830f, 0x5958beb6, 0x0000205a, 0x00000000, -0x0000a562, 0x000090b7, 0x6170de18, 0x00006172, 0x03000000, 0x02000000, -0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, 0x61705b0a, 0x00006172, -0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, -0x61705b0a, 0x00006172, 0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, -0x0000590d, 0x0000d013, 0x68635b0a, 0x00006d72, 0x03000000, 0x00000000, -0x0000d7a3, 0x00007b54, 0x0000cd4c, 0x00009a99, 0x00006626, 0xdbff5c0f, -0x14004300, 0x0f120f0e, 0x1112140d, 0x14161712, 0x21331f18, 0x1f1c1c1f, -0x252f2d3f, 0x4e414a33, 0x4841494d, 0x765c5246, 0x6f575264, 0x66484658, -0x7a6f688c, 0x8485847d, 0x9b91634f, 0x769a808f, 0xff7f8481, 0x014300db, -0x1f171716, 0x213c1f1b, 0x547f3c21, 0x7f7f5448, 0x7f7f7f7f, 0x7f7f7f7f, -0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, -0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x1100c0ff, 0x005a0008, -0x2201035a, 0x01110200, 0xff011103, 0x001900c4, 0x01010101, 0x00000101, -0x00000000, 0x00000000, 0x02030400, 0xc4ff0605, 0x00103600, 0x02010401, -0x06050304, 0x00000306, 0x01000000, 0x11030200, 0x05211204, 0x13514131, -0x32146122, 0x23918171, 0x72423424, 0x432515a1, 0xa2827444, 0xc4fff0b3, -0x01011400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1400c4ff, -0x00000111, 0x00000000, 0x00000000, 0x00000000, 0xdaff0000, 0x01030c00, -0x03110200, 0x003f0011, 0x404434fb, 0xbcb4875c, 0x006b38b0, 0x03dcdb12, -0xf4637f74, 0xe519f153, 0x09d7c5c7, 0x47d29160, 0x20692f18, 0xd06d786a, -0x53f7f922, 0x17b3e260, 0x2fe8668c, 0x1786a473, 0x9775efbd, 0xe917e43a, -0x1d0a1bb0, 0x114d0f82, 0x14651110, 0x35f299ed, 0xe9b09680, 0xf5a4fc2f, -0xe975bd03, 0xb506737b, 0x04444440, 0x5c444044, 0x8e8dedbd, 0xc61adc7b, -0x689c738b, 0x92a0dc01, 0x58e2b77f, 0x7bfb37d1, 0xb5b5e79d, 0xdbf968cc, -0xead3f48d, 0x38ed1313, 0xdea77c86, 0xae089963, 0xc743435a, 0x403fe4ce, -0x392ee1b9, 0xed39e718, 0xd6517e2d, 0x7fc4aa03, 0xb7ad7590, 0x77e7e6ab, -0x34bf705d, 0x7c77ca53, 0x3dea1299, 0x7fb0bcf4, 0x241fadc5, 0x95a7a816, -0x13fbe6f3, 0x3182b135, 0xd1b4b224, 0x1b0d48a2, 0xbf9d26d8, 0x82dc3640, -0x63569a2a, 0xbbd224c3, 0xb9b4714c, 0x1680aec6, 0x3d311856, 0x9b59be91, -0x09876ca6, 0x61d86564, 0x5a9f06d2, 0x36f51b0d, 0x8682e476, 0xacb1b131, -0xd1584363, 0x00456b4d, 0x22d2053b, 0x22202202, 0xf3f30222, 0xe3e513e5, -0xf1e6e1f0, 0x2380496e, 0x5fdcdb68, 0x549b3a27, 0x825e6a6c, 0x6522028b, -0xaf91ccc8, 0x341cf26b, 0x58dbc4b5, 0xf2289add, 0x0854ddbd, 0x0b9247d5, -0xf02b5c54, 0x3f917f92, 0xaf56affd, 0xe3760637, 0x05cebde0, 0xed4c76ce, -0x3cef1b63, 0x7fd8aff8, 0xa0c902ea, 0x7e730d0a, 0x435834f3, 0x26edbb76, -0xd3ec00fd, 0x76d48efa, 0xa8560f2d, 0x0e766331, 0xd319993c, 0x20243209, -0x61b7e6c8, 0x998331d0, 0x640ee802, 0x47a3d493, 0xfab99413, 0x4fd871f1, -0xe9443792, 0x627e051c, 0xd8f3051c, 0x2f28f558, 0x64b51745, 0x1b2bfee3, -0xb8783953, 0x9900fff6, 0xd8176a65, 0x5a3bf56a, 0x1b331fdb, 0x64b3572f, -0xd59a3643, 0xaf3abce1, 0x11dd20bd, 0x01111110, 0x5c141011, 0xb3e3083f, -0xd9b19cc4, 0x17edb20e, 0xa78e9aa1, 0x4ef4de06, 0x00c0bfe7, 0x7e1e442d, -0x9221fe38, 0xedb5c7dc, 0x6338078a, 0x62495b8d, 0xc11d9b8c, 0x49e81b16, -0x51d02bea, 0x3eb86d70, 0xc8bc4f13, 0xa10ec758, 0xd40751c0, 0x5ac94710, -0xc4c8b080, 0x95492b83, 0x975ee696, 0xb7bd96b4, 0x17379cce, 0x82e856e8, -0xe4c2c82a, 0x398e935f, 0x632437ea, 0x7c9c87d2, 0xdc1ddb7c, 0x65a80a48, -0x2309f164, 0x51fab475, 0x081dc11d, 0xda45573b, 0x6622f3f3, 0x48f1b214, -0x676c4edb, 0x243468c7, 0x00ffde60, 0xf1630350, 0xa0076c1d, 0x8f2c0c8b, -0x2383c26b, 0x361a8f4e, 0xaceea6c9, 0x01dd5a5d, 0x11111011, 0xc3780c04, -0xbf093ee2, 0xc7972c0b, 0x00d99040, 0xc0c20eb7, 0x659d3bd4, 0x269ab85e, -0x468e114f, 0x11ad4fdb, 0x83d083d8, 0x8c52f4bd, 0x3c9664bf, 0xa4f9c77c, -0x22a68876, 0xadb18784, 0xf480be83, 0x885a00ea, 0x220e0a88, 0xc303e4f6, -0xc866e058, 0xdddbd661, 0xdf395db1, 0xbad64343, 0xe6e65b03, 0x668e81c3, -0xad619e98, 0xeeb94563, 0xd4d19a3c, 0x3316ce95, 0x9d65f1e1, 0x3bf324fe, -0x0e468f53, 0xc386068c, 0xa89e24f7, 0xf0c7c73b, 0xb60e391f, 0x1b8827cb, -0x58601954, 0xc54f90f9, 0x80886ec5, 0x88088888, 0x1b7bb980, 0xb4c71c23, -0xe6148e39, 0xb12358b8, 0xbd08225d, 0x0ffef085, 0x72b4f025, 0x635ce389, -0xb90277e4, 0x0d05e000, 0x9bf9dbb9, 0x8e749fbc, 0x7ee6abbf, 0x4ddbf4af, -0x728df7f3, 0x10b59adf, 0xe3c38f49, 0xb23c638a, 0xdb3d9349, 0x66899a64, -0x00004dd5, 0xf51b5adf, 0x2220a255, 0xd9ff0f22}; diff --git a/purple-plugin/telegram.svg b/purple-plugin/telegram.svg deleted file mode 100644 index 1331624..0000000 --- a/purple-plugin/telegram.svg +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/queries.c b/queries.c deleted file mode 100644 index 633ca26..0000000 --- a/queries.c +++ /dev/null @@ -1,3095 +0,0 @@ -/* - This file is part of telegram-client. - - struct telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - struct telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#define _FILE_OFFSET_BITS 64 -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -#include "include.h" -#include "mtproto-client.h" -#include "queries.h" -#include "tree.h" -#include "loop.h" -#include "structures.h" -#include "net.h" -#include -#include -#include -#include -#include - -#include "no-preview.h" -#include "binlog.h" -#include "telegram.h" -#include "msglog.h" -#include "purple-plugin/telegram-purple.h" - -#define sha1 SHA1 - -#ifdef __APPLE__ -#define OPEN_BIN "open %s" -#else -#define OPEN_BIN "xdg-open %s" -#endif - -char *get_downloads_directory (void); -int verbosity; -int offline_mode = 0; - -#define memcmp8(a,b) memcmp ((a), (b), 8) -DEFINE_TREE (query, struct query *, memcmp8, 0) ; - -#define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) -DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) - -void out_peer_id (struct mtproto_connection *self, peer_id_t id); -#define QUERY_TIMEOUT 6.0 - -/** - * Get the struct mtproto_connection connection this connection was attached to - */ -struct mtproto_connection *query_get_mtproto(struct query *q) { - return q->DC->sessions[0]->c->mtconnection; -} - -double get_double_time (void) { - struct timespec tv; - my_clock_gettime (CLOCK_REALTIME, &tv); - return tv.tv_sec + 1e-9 * tv.tv_nsec; -} - -struct query *query_get (struct telegram *instance, long long id) { - return tree_lookup_query (instance->queries_tree, (void *)&id); -} - -int alarm_query (struct query *q) { - assert (q); - struct mtproto_connection *mtp = query_get_mtproto(q); - debug ("Alarm query %lld\n", q->msg_id); - q->ev.timeout = get_double_time () + QUERY_TIMEOUT; - insert_event_timer (mtp->connection->instance, &q->ev); - - if (q->session->c->out_bytes >= 100000) { - return 0; - } - - clear_packet (mtp); - out_int (mtp, CODE_msg_container); - out_int (mtp, 1); - out_long (mtp, q->msg_id); - out_int (mtp, q->seq_no); - out_int (mtp, 4 * q->data_len); - out_ints (mtp, q->data, q->data_len); - - encrypt_send_message (mtp, mtp->packet_buffer, mtp->packet_ptr - mtp->packet_buffer, 0); - return 0; -} - -void query_restart (struct telegram *instance, long long id) { - struct query *q = query_get (instance, id); - if (q) { - remove_event_timer (instance, &q->ev); - alarm_query (q); - } -} - -struct query *send_query (struct telegram *instance, struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { - info ("SEND_QUERY() size %d to DC %d(%s:%d)\n", 4 * ints, DC->id, DC->ip, DC->port); - struct query *q = talloc0 (sizeof (*q)); - q->data_len = ints; - q->data = talloc (4 * ints); - memcpy (q->data, data, 4 * ints); - q->msg_id = encrypt_send_message (DC->sessions[0]->c->mtconnection, data, ints, 1); - q->session = DC->sessions[0]; - q->seq_no = DC->sessions[0]->seq_no - 1; - //debug ( "Msg_id is %lld %p\n", q->msg_id, q); - q->methods = methods; - q->DC = DC; - if (instance->queries_tree) { - if (verbosity >= 2) { - debug ( "%lld %lld\n", q->msg_id, instance->queries_tree->x->msg_id); - } - } - - instance->queries_tree = tree_insert_query (instance->queries_tree, q, lrand48 ()); - struct mtproto_connection *mtp = query_get_mtproto(q); - ++ mtp->queries_num; - - q->ev.alarm = (void *)alarm_query; - q->ev.timeout = get_double_time () + QUERY_TIMEOUT; - q->ev.self = (void *)q; - insert_event_timer (instance, &q->ev); - - q->extra = extra; - return q; -} - -void query_ack (struct telegram *instance, long long id) { - struct query *q = query_get (instance, id); - if (q && !(q->flags & QUERY_ACK_RECEIVED)) { - assert (q->msg_id == id); - q->flags |= QUERY_ACK_RECEIVED; - remove_event_timer (instance, &q->ev); - } -} - -void query_error (struct telegram *instance, long long id) { - struct query *q = query_get (instance, id); - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_rpc_error); - int error_code = fetch_int (mtp); - int error_len = prefetch_strlen (mtp); - char *err = fetch_str (mtp, error_len); - failure ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, err); - if (!q) { - failure ( "No such query\n"); - } else { - if (!(q->flags & QUERY_ACK_RECEIVED)) { - remove_event_timer (instance, &q->ev); - } - instance->queries_tree = tree_delete_query (instance->queries_tree, q); - -- mtp->queries_num; - - if (q->methods && q->methods->on_error) { - q->methods->on_error (q, error_code, error_len, err); - } else { - failure ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, err); - } - tfree (q->data, q->data_len * 4); - tfree (q, sizeof (*q)); - return; - } - -} - -void query_result (struct telegram *instance, long long id UU) { - struct query *q = query_get (instance, id); - struct mtproto_connection *mtp = query_get_mtproto(q); - - debug ( "result for query #%lld\n", id); - if (verbosity >= 4) { - debug ( "result: "); - hexdump_in (mtp); - } - - int op = prefetch_int (mtp); - int *end = 0; - int *eend = 0; - if (op == CODE_gzip_packed) { - fetch_int (mtp); - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - int total_out = tinflate (s, l, instance->packed_buffer, MAX_PACKED_SIZE); - end = mtp->in_ptr; - eend = mtp->in_end; - //assert (total_out % 4 == 0); - mtp->in_ptr = instance->packed_buffer; - mtp->in_end = mtp->in_ptr + total_out / 4; - if (verbosity >= 4) { - debug ( "Unzipped data: "); - hexdump_in (mtp); - } - } - if (!q) { - warning ( "No such query\n"); - mtp->in_ptr = mtp->in_end; - } else { - if (!(q->flags & QUERY_ACK_RECEIVED)) { - remove_event_timer (instance, &q->ev); - } - instance->queries_tree = tree_delete_query (instance->queries_tree, q); - debug("queries_num: %d\n", -- mtp->queries_num); - - if (q->methods && q->methods->on_answer) { - q->methods->on_answer (q); - assert (mtp->in_ptr == mtp->in_end); - } - tfree (q->data, 4 * q->data_len); - tfree (q, sizeof (*q)); - } - if (end) { - mtp->in_ptr = end; - mtp->in_end = eend; - } -} - - -void insert_event_timer (struct telegram *instance, struct event_timer *ev) { - // debug ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - instance->timer_tree = tree_insert_timer (instance->timer_tree, ev, lrand48 ()); -} - -void remove_event_timer (struct telegram *instance, struct event_timer *ev) { - // debug ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - instance->timer_tree = tree_delete_timer (instance->timer_tree, ev); -} - -double next_timer_in (struct telegram *instance) { - if (!instance->timer_tree) { return 1e100; } - return tree_get_min_timer (instance->timer_tree)->timeout; -} - -void work_timers (struct telegram *instance) { - debug ("work_timers ()\n"); - double t = get_double_time (); - while (instance->timer_tree) { - struct event_timer *ev = tree_get_min_timer (instance->timer_tree); - assert (ev); - if (ev->timeout > t) { break; } - remove_event_timer (instance, ev); - assert (ev->alarm); - debug ("Alarm\n"); - ev->alarm (ev->self); - } -} - -void free_timers (struct telegram *instance) -{ - while (instance->timer_tree) { - struct event_timer *ev = tree_get_min_timer (instance->timer_tree); - assert (ev); - debug ("freeing event timer with timeout: %d\n", ev->timeout); - remove_event_timer (instance, ev); - //tfree (ev, sizeof(struct event_timer)); - } -} - -void free_queries (struct telegram *instance) -{ - while (instance->queries_tree) { - struct query *q = tree_get_min_query (instance->queries_tree); - assert (q); - debug ("freeing query with msg_id %d and len\n", q->msg_id, q->data_len); - tfree (q->data, 4 * q->data_len); - instance->queries_tree = tree_delete_query (instance->queries_tree, q); - //tfree (q, sizeof (struct query)); - } -} - -//extern struct dc *DC_list[]; -//extern struct dc *DC_working; - -void out_random (struct mtproto_connection *mtp, int n) { - assert (n <= 32); - static char buf[32]; - secure_random (buf, n); - out_cstring (mtp, buf, n); -} - -int allow_send_linux_version; -void do_insert_header (struct mtproto_connection *mtp) { - out_int (mtp, CODE_invoke_with_layer12); - out_int (mtp, CODE_init_connection); - out_int (mtp, TG_APP_ID); - if (allow_send_linux_version) { - struct utsname st; - uname (&st); - out_string (mtp, st.machine); - static char buf[4096]; - tsnprintf (buf, sizeof (buf), "%.999s %.999s %.999s\n", st.sysname, st.release, st.version); - out_string (mtp, buf); - out_string (mtp, TG_VERSION " (build " TG_BUILD ")"); - out_string (mtp, "En"); - } else { - out_string (mtp, "x86"); - out_string (mtp, "Linux"); - out_string (mtp, TG_VERSION); - out_string (mtp, "en"); - } -} - -/* {{{ Get config */ - -void fetch_dc_option (struct telegram *instance) { - info ("fetch_dc_option()\n"); - struct mtproto_connection *mtp = instance->connection; - - assert (fetch_int (mtp) == CODE_dc_option); - int id = fetch_int (mtp); - int l1 = prefetch_strlen (mtp); - char *name = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - char *ip = fetch_str (mtp, l2); - int port = fetch_int (mtp); - debug ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - - bl_do_dc_option (mtp->bl, mtp, id, l1, name, l2, ip, port, instance); -} - -int help_get_config_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - unsigned op = fetch_int (mtp); - assert (op == CODE_config || op == CODE_config_old); - fetch_int (mtp); - - unsigned test_mode = fetch_int (mtp); - assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false); - assert (test_mode == CODE_bool_false || test_mode == CODE_bool_true); - int this_dc = fetch_int (mtp); - debug ( "this_dc = %d\n", this_dc); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - assert (n <= 10); - int i; - for (i = 0; i < n; i++) { - fetch_dc_option (instance); - } - instance->max_chat_size = fetch_int (mtp); - if (op == CODE_config) { - instance->max_bcast_size = fetch_int (mtp); - } - debug ( "max_chat_size = %d\n", instance->max_chat_size); - - telegram_change_state(instance, STATE_CONFIG_RECEIVED, NULL); - return 0; -} - -struct query_methods help_get_config_methods = { - .on_answer = help_get_config_on_answer -}; - -void do_help_get_config (struct telegram *instance) { - info ("do_help_get_config()\n"); - struct mtproto_connection *mtp = instance->connection; - - debug ("mtp: %p:%p\n", mtp->packet_ptr, mtp->packet_buffer); - clear_packet (mtp); - out_int (mtp, CODE_help_get_config); - struct dc *DC_working = telegram_get_working_dc(instance); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, - mtp->packet_buffer, &help_get_config_methods, instance); -} -/* }}} */ - -/* {{{ Send code */ -int send_code_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_auth_sent_code); - fetch_bool (mtp); - int l = prefetch_strlen (mtp); - char *phone_code_hash = tstrndup (fetch_str (mtp, l), l); - instance->phone_code_hash = phone_code_hash; - debug("telegram: phone_code_hash: %s\n", phone_code_hash); - fetch_int (mtp); - fetch_bool (mtp); - instance->want_dc_num = -1; - if (instance->session_state == STATE_PHONE_CODE_REQUESTED) { - telegram_change_state(instance, STATE_PHONE_CODE_NOT_ENTERED, NULL); - } else if (instance->session_state == STATE_CLIENT_CODE_REQUESTED) { - telegram_change_state(instance, STATE_CLIENT_CODE_NOT_ENTERED, NULL); - } else { - debug("send_code_on_answer(): Invalid State %d ", instance->session_state); - telegram_change_state(instance, STATE_ERROR, NULL); - } - return 0; -} - -int send_code_on_error (struct query *q UU, int error_code, int l, char *error) { - struct telegram *tg = q->extra; - - int s = strlen ("PHONE_MIGRATE_"); - int s2 = strlen ("NETWORK_MIGRATE_"); - if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { - int want_dc_num = error[s] - '0'; - tg->auth.dc_working_num = want_dc_num; - telegram_change_state(tg, STATE_DISCONNECTED_SWITCH_DC, error); - } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { - int want_dc_num = error[s2] - '0'; - tg->auth.dc_working_num = want_dc_num; - telegram_change_state(tg, STATE_DISCONNECTED_SWITCH_DC, error); - } else { - fatal ( "error_code = %d, error = %.*s\n", error_code, l, error); - telegram_change_state(tg, STATE_ERROR, error); - } - return 0; -} - -struct query_methods send_code_methods = { - .on_answer = send_code_on_answer, - .on_error = send_code_on_error -}; - -void do_send_code (struct telegram *instance, const char *user) { - info ("do_send_code()\n"); - struct mtproto_connection *mtp = instance->connection; - - instance->suser = tstrdup (user); - instance->want_dc_num = 0; - clear_packet (mtp); - do_insert_header (mtp); - out_int (mtp, CODE_auth_send_code); - out_string (mtp, user); - out_int (mtp, 0); - out_int (mtp, TG_APP_ID); - out_string (mtp, TG_APP_HASH); - out_string (mtp, "en"); - - debug ("send_code: dc_num = %d\n", instance->auth.dc_working_num); - send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_code_methods, instance); - if (instance->session_state == STATE_PHONE_NOT_REGISTERED) { - telegram_change_state(instance, STATE_PHONE_CODE_REQUESTED, NULL); - } else if (instance->session_state == STATE_CLIENT_NOT_REGISTERED) { - telegram_change_state(instance, STATE_CLIENT_CODE_REQUESTED, NULL); - } else { - fatal ("do_send_code() Invalid State %d, erroring\n", instance->session_state); - telegram_change_state(instance, STATE_ERROR, NULL); - } -} - - -int phone_call_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - fetch_bool (mtp); - return 0; -} - -int phone_call_on_error (struct query *q UU, int error_code, int l, char *error) { - fatal ( "error_code = %d, error = %.*s\n", error_code, l, error); - telegram_change_state(q->data, STATE_ERROR, error); - return 0; -} - -struct query_methods phone_call_methods = { - .on_answer = phone_call_on_answer, - .on_error = phone_call_on_error -}; - -void do_phone_call (struct telegram *instance, const char *user) { - struct mtproto_connection *mtp = instance->connection; - - debug ("calling user\n"); - instance->suser = tstrdup (user); - instance->want_dc_num = 0; - clear_packet (mtp); - do_insert_header (mtp); - out_int (mtp, CODE_auth_send_call); - out_string (mtp, user); - out_string (mtp, instance->phone_code_hash); - - info ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); - send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &phone_call_methods, instance); -} -/* }}} */ - -/* {{{ Check phone */ -int check_phone_result; -int cr_f (void) { - return check_phone_result >= 0; -} - -int check_phone_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_auth_checked_phone); - check_phone_result = fetch_bool (mtp); - fetch_bool (mtp); - - assert (mtp->connection->instance->session_state == STATE_CONFIG_RECEIVED); - debug ("check_phone_result=%d\n", check_phone_result); - telegram_change_state (mtp->connection->instance, - check_phone_result ? STATE_CLIENT_NOT_REGISTERED : STATE_PHONE_NOT_REGISTERED, NULL); - 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_"); - struct telegram* instance = q->extra; - - if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { - // update used data centre - int i = error[s] - '0'; - instance->auth.dc_working_num = i; - - //bl_do_set_working_dc (i); - //check_phone_result = 1; - } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { - // update used data centre - int i = error[s2] - '0'; - instance->auth.dc_working_num = i; - //bl_do_set_working_dc (i); - - //check_phone_result = 1; - } else { - failure ( "error_code = %d, error = %.*s\n", error_code, l, error); - telegram_change_state(instance, STATE_ERROR, error); - return -1; - } - telegram_change_state(instance, - STATE_DISCONNECTED_SWITCH_DC, &instance->auth.dc_working_num); - return 0; -} - -struct query_methods check_phone_methods = { - .on_answer = check_phone_on_answer, - .on_error = check_phone_on_error -}; - -void do_auth_check_phone (struct telegram *instance, const char *user) { - struct mtproto_connection *mtp = instance->connection; - - instance->suser = tstrdup (user); - clear_packet (mtp); - out_int (mtp, CODE_auth_check_phone); - out_string (mtp, user); - check_phone_result = -1; - struct dc *DC_working = telegram_get_working_dc(instance); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, - &check_phone_methods, instance); -} -/* }}} */ - -/* {{{ Nearest DC */ - -int nearest_dc_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - - assert (fetch_int (mtp) == (int)CODE_nearest_dc); - char *country = fetch_str_dup (mtp); - debug ("Server thinks that you are in %s\n", country); - fetch_int (mtp); // this_dc - instance->nearest_dc_num = fetch_int (mtp); - assert (instance->nearest_dc_num >= 0); - return 0; -} - -int fail_on_error (struct query *q UU, int error_code UU, int l UU, char *error UU) { - fatal ("error #%d: %.*s\n", error_code, l, error); - telegram_change_state(q->data, STATE_ERROR, error); - return 0; -} - -struct query_methods nearest_dc_methods = { - .on_answer = nearest_dc_on_answer, - .on_error = fail_on_error -}; - -void do_get_nearest_dc (struct telegram *instance) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (mtp); - out_int (mtp, CODE_help_get_nearest_dc); - instance->nearest_dc_num = -1; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &nearest_dc_methods, instance); - //net_loop (0, nr_f); - //return nearest_dc_num; -} -/* }}} */ - -/* {{{ Sign in / Sign up */ - -int sign_in_on_answer (struct query *q) { - info ("sign_in_on_answer()\n"); - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - - struct dc *DC_working = telegram_get_working_dc(mtp->connection->instance); - assert (fetch_int (mtp) == (int)CODE_auth_authorization); - int expires = fetch_int (mtp); - fetch_user (mtp, &instance->User); - if (!instance->our_id) { - instance->our_id = get_peer_id (instance->User.id); - bl_do_set_our_id (mtp->bl, mtp, instance->our_id); - } - debug ( "telegram: authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", - instance->User.first_name, instance->User.last_name, instance->User.phone, (int)(expires - get_double_time ())); - DC_working->has_auth = 1; - - bl_do_dc_signed (mtp->bl, mtp, DC_working->id); - telegram_change_state (mtp->connection->instance, STATE_READY, NULL); - return 0; -} - -int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { - info ("sign_in_on_error()\n"); - struct mtproto_connection *mtp = query_get_mtproto(q); - failure ( "error_code = %d, error = %.*s\n", error_code, l, error); - int state = STATE_CLIENT_CODE_NOT_ENTERED; - if (mtp->instance->session_state == STATE_PHONE_CODE_NOT_ENTERED) { - state = STATE_PHONE_CODE_NOT_ENTERED; - } - telegram_change_state (mtp->connection->instance, state, NULL); - return 0; -} - -struct query_methods sign_in_methods = { - .on_answer = sign_in_on_answer, - .on_error = sign_in_on_error -}; - -void do_send_code_result (struct telegram *instance, const char *code) { - info ("do_send_code_result()\n"); - struct mtproto_connection *mtp = instance->connection; - assert (instance->session_state == STATE_CLIENT_CODE_NOT_ENTERED); - - struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (mtp); - out_int (mtp, CODE_auth_sign_in); - out_string (mtp, instance->suser); - out_string(mtp, instance->phone_code_hash); - out_string (mtp, code); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, - &sign_in_methods, instance); -} - -void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_auth_sign_up); - out_string (mtp, instance->suser); - out_string (mtp, instance->phone_code_hash); - out_string (mtp, code); - out_string (mtp, first_name); - out_string (mtp, last_name); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); -} -/* }}} */ - -/* {{{ Get contacts */ -extern char *user_list[]; - -int get_contacts_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - int i; - assert (fetch_int (mtp) == (int)CODE_contacts_contacts); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == (int)CODE_contact); - fetch_int (mtp); // id - fetch_int (mtp); // mutual - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - return 0; -} - -struct query_methods get_contacts_methods = { - .on_answer = get_contacts_on_answer, -}; - -void do_update_contact_list (struct telegram *instance) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - - clear_packet (mtp); - out_int (mtp, CODE_contacts_get_contacts); - out_string (mtp, ""); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_contacts_methods, instance); -} - - -/* }}} */ - -/* {{{ Encrypt decrypted */ - -char *encrypt_decrypted_message (struct mtproto_connection *mtp, struct secret_chat *E) { - static int msg_key[4]; - static unsigned char sha1a_buffer[20]; - static unsigned char sha1b_buffer[20]; - static unsigned char sha1c_buffer[20]; - static unsigned char sha1d_buffer[20]; - int x = *(mtp->encr_ptr); - assert (x >= 0 && !(x & 3)); - sha1 ((void *)mtp->encr_ptr, 4 + x, sha1a_buffer); - memcpy (msg_key, sha1a_buffer + 4, 16); - - static unsigned char buf[64]; - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key, 32); - sha1 (buf, 48, sha1a_buffer); - - memcpy (buf, E->key + 8, 16); - memcpy (buf + 16, msg_key, 16); - memcpy (buf + 32, E->key + 12, 16); - sha1 (buf, 48, sha1b_buffer); - - memcpy (buf, E->key + 16, 32); - memcpy (buf + 32, msg_key, 16); - sha1 (buf, 48, sha1c_buffer); - - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key + 24, 32); - sha1 (buf, 48, sha1d_buffer); - - static unsigned char key[32]; - memcpy (key, sha1a_buffer + 0, 8); - memcpy (key + 8, sha1b_buffer + 8, 12); - memcpy (key + 20, sha1c_buffer + 4, 12); - - static unsigned char iv[32]; - memcpy (iv, sha1a_buffer + 8, 12); - memcpy (iv + 12, sha1b_buffer + 0, 8); - memcpy (iv + 20, sha1c_buffer + 16, 4); - memcpy (iv + 24, sha1d_buffer + 0, 8); - - AES_KEY aes_key; - AES_set_encrypt_key (key, 256, &aes_key); - AES_ige_encrypt ((void *)mtp->encr_ptr, (void *)mtp->encr_ptr, 4 * (mtp->encr_end - mtp->encr_ptr), &aes_key, iv, 1); - memset (&aes_key, 0, sizeof (aes_key)); - - return (void *)msg_key; -} - -void encr_start (struct mtproto_connection *mtp) { - mtp->encr_extra = mtp->packet_ptr; - mtp->packet_ptr += 1; // str len - mtp->packet_ptr += 2; // fingerprint - mtp->packet_ptr += 4; // msg_key - mtp->packet_ptr += 1; // len -} - - -void encr_finish (struct mtproto_connection *mtp, struct secret_chat *E) { - int l = mtp->packet_ptr - (mtp->encr_extra + 8); - while (((mtp->packet_ptr - mtp->encr_extra) - 3) & 3) { - int t; - secure_random (&t, 4); - out_int (mtp, t); - } - - *mtp->encr_extra = ((mtp->packet_ptr - mtp->encr_extra) - 1) * 4 * 256 + 0xfe; - mtp->encr_extra ++; - *(long long *)mtp->encr_extra = E->key_fingerprint; - mtp->encr_extra += 2; - mtp->encr_extra[4] = l * 4; - mtp->encr_ptr = mtp->encr_extra + 4; - mtp->encr_end = mtp->packet_ptr; - memcpy (mtp->encr_extra, encrypt_decrypted_message (mtp, E), 16); -} -/* }}} */ - -/* {{{ Seng msg (plain text) */ -int msg_send_encr_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int (mtp) == CODE_messages_sent_encrypted_message); - debug ("Sent\n"); - struct message *M = q->extra; - //M->date = fetch_int (mtp); - fetch_int (mtp); - bl_do_set_message_sent (mtp->bl, mtp, M); - return 0; -} - -int msg_send_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_sent_message || x == CODE_messages_sent_message_link); - int id = fetch_int (mtp); // id - struct message *M = q->extra; - bl_do_set_msg_id (mtp->bl, mtp, M, id); - fetch_date (mtp); - fetch_pts (mtp); - fetch_seq (mtp); - if (x == CODE_messages_sent_message_link) { - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - unsigned a, b; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == (int)CODE_contacts_link); - a = fetch_int (mtp); - assert (a == CODE_contacts_my_link_empty || a == CODE_contacts_my_link_requested || a == CODE_contacts_my_link_contact); - if (a == CODE_contacts_my_link_requested) { - fetch_bool (mtp); - } - b = fetch_int (mtp); - assert (b == CODE_contacts_foreign_link_unknown || b == CODE_contacts_foreign_link_requested || b == CODE_contacts_foreign_link_mutual); - if (b == CODE_contacts_foreign_link_requested) { - fetch_bool (mtp); - } - struct tgl_user *U = fetch_alloc_user (mtp); - - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (a == CODE_contacts_my_link_contact) { - U->flags |= FLAG_USER_IN_CONTACT; - } - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (b == CODE_contacts_foreign_link_mutual) { - U->flags |= FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT; - } - if (b == CODE_contacts_foreign_link_requested) { - U->flags |= FLAG_USER_OUT_CONTACT; - } - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Link with user "); - //print_user_name (U->id, (void *)U); - debug (" changed\n"); - //pop_color (); - //print_end (); - } - } - debug ("Sent: id = %d\n", id); - bl_do_set_message_sent (mtp->bl, mtp, M); - return 0; -} - -int msg_send_on_error (struct query *q, int error_code, int error_len, char *error) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - debug ( "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error); - struct message *M = q->extra; - bl_do_delete_msg (mtp->bl, mtp, M); - return 0; -} - -struct query_methods msg_send_methods = { - .on_answer = msg_send_on_answer, - .on_error = msg_send_on_error -}; - -struct query_methods msg_send_encr_methods = { - .on_answer = msg_send_encr_on_answer -}; - -void do_send_encr_msg (struct telegram *instance, struct message *M) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - - peer_t *P = user_chat_get (mtp->bl, M->to_id); - if (!P || P->encr_chat.state != sc_ok) { return; } - - clear_packet (mtp); - out_int (mtp, CODE_messages_send_encrypted); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (M->to_id)); - out_long (mtp, P->encr_chat.access_hash); - out_long (mtp, M->id); - encr_start (mtp); - out_int (mtp, CODE_decrypted_message); - out_long (mtp, M->id); - static int buf[4]; - secure_random (buf, 16); - out_cstring (mtp, (void *)buf, 16); - out_cstring (mtp, (void *)M->message, M->message_len); - out_int (mtp, CODE_decrypted_message_media_empty); - encr_finish (mtp, &P->encr_chat); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, - &msg_send_encr_methods, M); -} - -void do_send_msg (struct telegram *instance, struct message *M) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { - do_send_encr_msg (instance ,M); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_send_message); - out_peer_id (mtp, M->to_id); - out_cstring (mtp, M->message, M->message_len); - out_long (mtp, M->id); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_send_methods, M); -} - -void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len) { - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT) { - peer_t *P = user_chat_get (mtp->bl, id); - if (!P) { - warning ("Can not send to unknown encrypted chat\n"); - return; - } - if (P->encr_chat.state != sc_ok) { - warning ("Chat is not yet initialized\n"); - return; - } - } - long long t; - secure_random (&t, 8); - debug ("t = %lld, len = %d\n", t, len); - bl_do_send_message_text (mtp->bl, mtp, t, instance->our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); - struct message *M = message_get (mtp->bl, t); - assert (M); - do_send_msg (instance, M); - //print_message (M); -} -/* }}} */ - -/* {{{ Send text file */ -void do_send_text (struct telegram *instance, peer_id_t id, char *file_name) { - int fd = open (file_name, O_RDONLY); - if (fd < 0) { - warning ("No such file '%s'\n", file_name); - tfree_str (file_name); - return; - } - static char buf[(1 << 20) + 1]; - int x = read (fd, buf, (1 << 20) + 1); - assert (x >= 0); - if (x == (1 << 20) + 1) { - warning ("Too big file '%s'\n", file_name); - tfree_str (file_name); - close (fd); - } else { - buf[x] = 0; - do_send_message (instance, id, buf, x); - tfree_str (file_name); - close (fd); - } -} -/* }}} */ - -/* {{{ Mark read */ -int mark_read_on_receive (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_messages_affected_history); - fetch_pts (mtp); - fetch_seq (mtp); - fetch_int (mtp); // offset - return 0; -} - -int mark_read_encr_on_receive (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - fetch_bool (mtp); - return 0; -} - -struct query_methods mark_read_methods = { - .on_answer = mark_read_on_receive -}; - -struct query_methods mark_read_encr_methods = { - .on_answer = mark_read_encr_on_receive -}; - -void do_messages_mark_read (struct telegram *instance, peer_id_t id, int max_id) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_read_history); - out_peer_id (mtp, id); - out_int (mtp, max_id); - out_int (mtp, 0); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_methods, 0); -} - -void do_messages_mark_read_encr (struct telegram *instance, peer_id_t id, long long access_hash, int last_time) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_read_encrypted_history); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (id)); - out_long (mtp, access_hash); - out_int (mtp, last_time); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_encr_methods, 0); -} - -void do_mark_read (struct telegram *instance, peer_id_t id) { - struct mtproto_connection *mtp = instance->connection; - - peer_t *P = user_chat_get (mtp->bl, id); - if (!P) { - debug ("Unknown peer\n"); - return; - } - if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) { - if (!P->last) { - debug ("Unknown last peer message\n"); - return; - } - do_messages_mark_read (instance, id, P->last->id); - return; - } - assert (get_peer_type (id) == PEER_ENCR_CHAT); - if (P->last) { - do_messages_mark_read_encr (instance, id, P->encr_chat.access_hash, P->last->date); - } else { - do_messages_mark_read_encr (instance, id, P->encr_chat.access_hash, time (0) - 10); - - } -} -/* }}} */ - -struct get_hist_extra { - struct telegram *instance; - peer_id_t peer_id; -}; - -/* {{{ Get history */ -int get_history_on_answer (struct query *q UU) { - struct get_hist_extra *extra = q->extra; - struct telegram *instance = extra->instance; - struct mtproto_connection *mtp = query_get_mtproto(q); - peer_id_t peer_id = extra->peer_id; - - static struct message *ML[10000]; - int i; - int x = fetch_int (mtp); - if (x == (int)CODE_messages_messages_slice) { - fetch_int (mtp); - debug ("...\n"); - } else { - assert (x == (int)CODE_messages_messages); - } - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - for (i = 0; i < n; i++) { - struct message *M = fetch_alloc_message (mtp, instance); - if (i <= 9999) { - ML[i] = M; - } - } - if (n > 10000) { n = 10000; } - int sn = n; - for (i = n - 1; i >= 0; i--) { - //print_message (ML[i]); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - - if (sn > 0 && q->extra) { - do_messages_mark_read (instance, peer_id, ML[0]->id); - } - free(extra); - return 0; -} - -struct query_methods get_history_methods = { - .on_answer = get_history_on_answer, -}; - -void do_get_local_history (struct telegram *instance, peer_id_t id, int limit) { - struct mtproto_connection *mtp = instance->connection; - peer_t *P = user_chat_get (mtp->bl, id); - if (!P || !P->last) { return; } - struct message *M = P->last; - int count = 1; - assert (!M->prev); - while (count < limit && M->next) { - M = M->next; - count ++; - } - while (M) { - //print_message (M); - M = M->prev; - } -} - -void do_get_history (struct telegram *instance, peer_id_t id, int limit) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT || offline_mode) { - do_get_local_history (instance, id, limit); - do_mark_read (instance, id); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_get_history); - out_peer_id (mtp, id); - out_int (mtp, 0); - out_int (mtp, 0); - out_int (mtp, limit); - - struct get_hist_extra *extra = malloc(sizeof(struct get_hist_extra)); - extra->instance = instance; - extra->peer_id = id; - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_history_methods, extra); -} -/* }}} */ - -/* {{{ Get dialogs */ -int dialog_list_got; -int get_dialogs_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); - if (x == CODE_messages_dialogs_slice) { - fetch_int (mtp); // total_count - } - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - static int dlist[2 * 100]; - static peer_id_t plist[100]; - int dl_size = n; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == CODE_dialog); - if (i < 100) { - plist[i] = fetch_peer_id (mtp); - dlist[2 * i + 0] = fetch_int (mtp); - dlist[2 * i + 1] = fetch_int (mtp); - } else { - fetch_peer_id (mtp); - fetch_int (mtp); - fetch_int (mtp); - } - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_message (mtp, instance); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - //print_start (); - //push_color (COLOR_YELLOW); - for (i = dl_size - 1; i >= 0; i--) { - - // TODO: use peer - peer_t *UC UU; - switch (get_peer_type (plist[i])) { - case PEER_USER: - UC = user_chat_get (mtp->bl, plist[i]); - debug ("User "); - //print_user_name (plist[i], UC); - debug (": %d unread\n", dlist[2 * i + 1]); - break; - case PEER_CHAT: - UC = user_chat_get (mtp->bl, plist[i]); - debug ("Chat "); - //print_chat_name (plist[i], UC); - debug (": %d unread\n", dlist[2 * i + 1]); - break; - } - } - //pop_color (); - //print_end (); - - dialog_list_got = 1; - return 0; -} - -struct query_methods get_dialogs_methods = { - .on_answer = get_dialogs_on_answer, -}; - - -void do_get_dialog_list (struct telegram *instance) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (mtp); - out_int (mtp, CODE_messages_get_dialogs); - out_int (mtp, 0); - out_int (mtp, 0); - out_int (mtp, 1000); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dialogs_methods, instance); -} -/* }}} */ - -int allow_send_linux_version = 1; - -/* {{{ Send photo/video file */ -struct send_file { - int fd; - long long size; - long long offset; - int part_num; - int part_size; - long long id; - long long thumb_id; - peer_id_t to_id; - unsigned media_type; - char *file_name; - int encr; - unsigned char *iv; - unsigned char *init_iv; - unsigned char *key; -}; - -void out_peer_id (struct mtproto_connection *self, peer_id_t id) { - peer_t *U; - switch (get_peer_type (id)) { - case PEER_CHAT: - out_int (self, CODE_input_peer_chat); - out_int (self, get_peer_id (id)); - break; - case PEER_USER: - U = user_chat_get (self->bl, id); - if (U && U->user.access_hash) { - out_int (self, CODE_input_peer_foreign); - out_int (self, get_peer_id (id)); - out_long (self, U->user.access_hash); - } else { - out_int (self, CODE_input_peer_contact); - out_int (self, get_peer_id (id)); - } - break; - default: - assert (0); - } -} - -struct send_file_extra { - struct telegram *instance; - struct send_file *file; -}; - -void send_part (struct telegram *instance, struct send_file *f); - -int send_file_part_on_answer (struct query *q) { - struct mtproto_connection *mtp = query_get_mtproto (q); - struct send_file_extra *extra = q->extra; - assert (fetch_int (mtp) == (int)CODE_bool_true); - send_part (extra->instance, extra->file); - return 0; -} - -int send_file_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int (mtp) == (int)CODE_messages_stated_message); - - // TODO: use message - struct message *M UU = fetch_alloc_message (mtp, instance); - - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - fetch_pts (mtp); - fetch_seq (mtp); - //print_message (M); - return 0; -} - -int send_encr_file_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - if (prefetch_int (mtp) != (int)CODE_messages_sent_encrypted_file) { - hexdump_in (mtp); - } - assert (fetch_int (mtp) == (int)CODE_messages_sent_encrypted_file); - struct message *M = q->extra; - M->date = fetch_int (mtp); - assert (fetch_int (mtp) == CODE_encrypted_file); - M->media.encr_photo.id = fetch_long (mtp); - M->media.encr_photo.access_hash = fetch_long (mtp); - //M->media.encr_photo.size = fetch_int (mtp); - fetch_int (mtp); - M->media.encr_photo.dc_id = fetch_int (mtp); - assert (fetch_int (mtp) == M->media.encr_photo.key_fingerprint); - //print_message (M); - message_insert (M); - return 0; -} - -struct query_methods send_file_part_methods = { - .on_answer = send_file_part_on_answer -}; - -struct query_methods send_file_methods = { - .on_answer = send_file_on_answer -}; - -struct query_methods send_encr_file_methods = { - .on_answer = send_encr_file_on_answer -}; - -void send_part (struct telegram *instance, struct send_file *f) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - if (f->fd >= 0) { - if (!f->part_num) { - instance->cur_uploading_bytes += f->size; - } - clear_packet (mtp); - if (f->size < (16 << 20)) { - out_int (mtp, CODE_upload_save_file_part); - out_long (mtp, f->id); - out_int (mtp, f->part_num ++); - } else { - out_int (mtp, CODE_upload_save_big_file_part); - out_long (mtp, f->id); - out_int (mtp, f->part_num ++); - out_int (mtp, (f->size + f->part_size - 1) / f->part_size); - } - static char buf[512 << 10]; - int x = read (f->fd, buf, f->part_size); - assert (x > 0); - f->offset += x; - instance->cur_uploaded_bytes += x; - - if (f->encr) { - if (x & 15) { - assert (f->offset == f->size); - secure_random (buf + x, (-x) & 15); - x = (x + 15) & ~15; - } - - AES_KEY aes_key; - AES_set_encrypt_key (f->key, 256, &aes_key); - AES_ige_encrypt ((void *)buf, (void *)buf, x, &aes_key, f->iv, 1); - memset (&aes_key, 0, sizeof (aes_key)); - } - out_cstring (mtp, buf, x); - if (verbosity >= 2) { - debug ("offset=%lld size=%lld\n", f->offset, f->size); - } - if (f->offset == f->size) { - close (f->fd); - f->fd = -1; - } else { - assert (f->part_size == x); - } - //update_prompt (); - - struct send_file_extra *extra = malloc(sizeof(struct send_file_extra)); - extra->instance = instance; - extra->file = f; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, extra); - } else { - instance->cur_uploaded_bytes -= f->size; - instance->cur_uploading_bytes -= f->size; - //update_prompt (); - clear_packet (mtp); - assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_audio || f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document); - if (!f->encr) { - out_int (mtp, CODE_messages_send_media); - out_peer_id (mtp, f->to_id); - out_int (mtp, f->media_type); - if (f->size < (16 << 20)) { - out_int (mtp, CODE_input_file); - } else { - out_int (mtp, CODE_input_file_big); - } - out_long (mtp, f->id); - out_int (mtp, f->part_num); - char *s = f->file_name + strlen (f->file_name); - while (s >= f->file_name && *s != '/') { s --;} - out_string (mtp, s + 1); - if (f->size < (16 << 20)) { - out_string (mtp, ""); - } - if (f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_thumb_document) { - out_int (mtp, CODE_input_file); - out_long (mtp, f->thumb_id); - out_int (mtp, 1); - out_string (mtp, "thumb.jpg"); - out_string (mtp, ""); - } - if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video) { - out_int (mtp, 100); - out_int (mtp, 100); - out_int (mtp, 100); - } - if (f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document) { - out_string (mtp, s + 1); - out_string (mtp, "text"); - } - if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (mtp, 60); - } - - out_long (mtp, -lrand48 () * (1ll << 32) - lrand48 ()); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_methods, instance); - } else { - struct message *M = talloc0 (sizeof (*M)); - - out_int (mtp, CODE_messages_send_encrypted_file); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (f->to_id)); - peer_t *P = user_chat_get (mtp->bl, f->to_id); - assert (P); - out_long (mtp, P->encr_chat.access_hash); - long long r = -lrand48 () * (1ll << 32) - lrand48 (); - out_long (mtp, r); - encr_start (mtp); - out_int (mtp, CODE_decrypted_message); - out_long (mtp, r); - out_random (mtp, 15 + 4 * (lrand48 () % 3)); - out_string (mtp, ""); - if (f->media_type == CODE_input_media_uploaded_photo) { - out_int (mtp, CODE_decrypted_message_media_photo); - M->media.type = CODE_decrypted_message_media_photo; - } else if (f->media_type == CODE_input_media_uploaded_video) { - out_int (mtp, CODE_decrypted_message_media_video); - M->media.type = CODE_decrypted_message_media_video; - } else if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (mtp, CODE_decrypted_message_media_audio); - M->media.type = CODE_decrypted_message_media_audio; - } else if (f->media_type == CODE_input_media_uploaded_document) { - out_int (mtp, CODE_decrypted_message_media_document); - M->media.type = CODE_decrypted_message_media_document;; - } else { - assert (0); - } - if (f->media_type != CODE_input_media_uploaded_audio) { - out_cstring (mtp, (void *)thumb_file, thumb_file_size); - out_int (mtp, 90); - out_int (mtp, 90); - } - if (f->media_type == CODE_input_media_uploaded_video) { - out_int (mtp, 0); - } - if (f->media_type == CODE_input_media_uploaded_document) { - out_string (mtp, f->file_name); - out_string (mtp, "text"); - } - if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (mtp, 60); - } - if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_photo) { - out_int (mtp, 100); - out_int (mtp, 100); - } - out_int (mtp, f->size); - out_cstring (mtp, (void *)f->key, 32); - out_cstring (mtp, (void *)f->init_iv, 32); - encr_finish (mtp, &P->encr_chat); - if (f->size < (16 << 20)) { - out_int (mtp, CODE_input_encrypted_file_uploaded); - } else { - out_int (mtp, CODE_input_encrypted_file_big_uploaded); - } - out_long (mtp, f->id); - out_int (mtp, f->part_num); - if (f->size < (16 << 20)) { - out_string (mtp, ""); - } - - unsigned char md5[16]; - unsigned char str[64]; - memcpy (str, f->key, 32); - memcpy (str + 32, f->init_iv, 32); - MD5 (str, 64, md5); - out_int (mtp, (*(int *)md5) ^ (*(int *)(md5 + 4))); - - tfree_secure (f->iv, 32); - - M->media.encr_photo.key = f->key; - M->media.encr_photo.iv = f->init_iv; - M->media.encr_photo.key_fingerprint = (*(int *)md5) ^ (*(int *)(md5 + 4)); - M->media.encr_photo.size = f->size; - - M->flags = FLAG_ENCRYPTED; - M->from_id = MK_USER (instance->our_id); - M->to_id = f->to_id; - M->unread = 1; - M->message = tstrdup (""); - M->out = 1; - M->id = r; - M->date = time (0); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_file_methods, M); - } - tfree_str (f->file_name); - tfree (f, sizeof (*f)); - } -} - -void send_file_thumb (struct telegram *instance, struct send_file *f) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - f->thumb_id = lrand48 () * (1ll << 32) + lrand48 (); - out_int (mtp, CODE_upload_save_file_part); - out_long (mtp, f->thumb_id); - out_int (mtp, 0); - out_cstring (mtp, (void *)thumb_file, thumb_file_size); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, f); -} - -void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name) { - int fd = open (file_name, O_RDONLY); - if (fd < 0) { - warning ("No such file '%s'\n", file_name); - tfree_str (file_name); - return; - } - struct stat buf; - fstat (fd, &buf); - long long size = buf.st_size; - if (size <= 0) { - debug ("File has zero length\n"); - tfree_str (file_name); - close (fd); - return; - } - struct send_file *f = talloc0 (sizeof (*f)); - f->fd = fd; - f->size = size; - f->offset = 0; - f->part_num = 0; - int tmp = ((size + 2999) / 3000); - f->part_size = (1 << 10); - while (f->part_size < tmp) { - f->part_size *= 2; - } - - if (f->part_size > (512 << 10)) { - close (fd); - failure ("Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000); - tfree (f, sizeof (*f)); - tfree_str (file_name); - return; - } - - f->id = lrand48 () * (1ll << 32) + lrand48 (); - f->to_id = to_id; - f->media_type = type; - f->file_name = file_name; - if (get_peer_type (f->to_id) == PEER_ENCR_CHAT) { - f->encr = 1; - f->iv = talloc (32); - secure_random (f->iv, 32); - f->init_iv = talloc (32); - memcpy (f->init_iv, f->iv, 32); - f->key = talloc (32); - secure_random (f->key, 32); - } - if (f->media_type == CODE_input_media_uploaded_video && !f->encr) { - f->media_type = CODE_input_media_uploaded_thumb_video; - send_file_thumb (instance, f); - } else if (f->media_type == CODE_input_media_uploaded_document && !f->encr) { - f->media_type = CODE_input_media_uploaded_thumb_document; - send_file_thumb (instance, f); - } else { - send_part (instance, f); - } -} -/* }}} */ - -/* {{{ Forward */ -int fwd_msg_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_messages_stated_message); - - // TODO: use message - struct message *M UU = fetch_alloc_message (mtp, instance); - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - fetch_pts (mtp); - fetch_seq (mtp); - //print_message (M); - return 0; -} - -struct query_methods fwd_msg_methods = { - .on_answer = fwd_msg_on_answer -}; - -void do_forward_message (struct telegram *instance, peer_id_t id, int n) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT) { - warning ("Can not forward messages from secret chat\n"); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_forward_message); - out_peer_id (mtp, id); - out_int (mtp, n); - out_long (mtp, lrand48 () * (1ll << 32) + lrand48 ()); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &fwd_msg_methods, instance); -} -/* }}} */ - -/* {{{ Rename chat */ -int rename_chat_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_messages_stated_message); - - // TODO: use message - struct message *M UU = fetch_alloc_message (mtp, instance); - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - fetch_pts (mtp); - fetch_seq (mtp); - //print_message (M); - return 0; -} - -struct query_methods rename_chat_methods = { - .on_answer = rename_chat_on_answer -}; - -void do_rename_chat (struct telegram *instance, peer_id_t id, char *name UU) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_edit_chat_title); - assert (get_peer_type (id) == PEER_CHAT); - out_int (mtp, get_peer_id (id)); - out_string (mtp, name); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &rename_chat_methods, instance); -} -/* }}} */ - -/* {{{ Chat info */ -void print_chat_info (struct chat *C) { - - // TODO: use peer_t - peer_t *U UU = (void *)C; - - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Chat "); - //print_chat_name (U->id, U); - debug (" members:\n"); - int i; - for (i = 0; i < C->user_list_size; i++) { - debug ("\t\t"); - //print_user_name (MK_USER (C->user_list[i].user_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].user_id))); - debug (" invited by "); - //print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].inviter_id))); - debug (" at "); - //print_date_full (C->user_list[i].date); - if (C->user_list[i].user_id == C->admin_id) { - debug (" admin"); - } - debug ("\n"); - } - //pop_color (); - //print_end (); -} - -int chat_info_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct chat *C = fetch_alloc_chat_full (mtp); - mtp->instance->config->on_chat_info_received (mtp->instance, C->id); - return 0; -} - -struct query_methods chat_info_methods = { - .on_answer = chat_info_on_answer -}; - -void do_get_chat_info (struct telegram *instance, peer_id_t id) { - debug ("do_get_chat_info (peer_id=%d)", id.id); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (offline_mode) { - peer_t *C = user_chat_get (mtp->bl, id); - if (!C) { - warning ("No such chat\n"); - } else { - //print_chat_info (&C->chat); - } - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_get_full_chat); - assert (get_peer_type (id) == PEER_CHAT); - out_int (mtp, get_peer_id (id)); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &chat_info_methods, 0); -} -/* }}} */ - -/* {{{ User info */ - -void print_user_info (struct tgl_user *U) { - // TODO: use peer - peer_t *C UU = (void *)U; - - //print_start (); - //push_color (COLOR_YELLOW); - debug ("User "); - //print_user_name (U->id, C); - debug (":\n"); - debug ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); - debug ("\tphone: %s\n", U->phone); - if (U->status.online > 0) { - debug ("\tonline\n"); - } else { - debug ("\toffline (was online "); - //print_date_full (U->status.when); - debug (")\n"); - } - //pop_color (); - //print_end (); -} - -struct show_info_extra { - int show_info; -}; - -int user_info_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct show_info_extra *extra = q->extra; - - struct tgl_user *U = fetch_alloc_user_full (mtp); - event_user_info_received_handler (mtp->instance, U, extra->show_info); - tfree (extra, sizeof(struct show_info_extra)); - //print_user_info (U); - return 0; -} - -struct query_methods user_info_methods = { - .on_answer = user_info_on_answer -}; - -void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo) { - info ("do_get_user_info\n"); - struct show_info_extra *extra = talloc(sizeof(struct show_info_extra)); - extra->show_info = showInfo; - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_users_get_full_user); - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, extra); - debug ("do_get_user_info ready\n"); -} -/* }}} */ - -/* {{{ Get user info silently */ -int user_list_info_silent_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - return 0; -} - -struct query_methods user_list_info_silent_methods = { - .on_answer = user_list_info_silent_on_answer -}; - -void do_get_user_list_info_silent (struct telegram *instance, int num, int *list) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_users_get_users); - out_int (mtp, CODE_vector); - out_int (mtp, num); - int i; - for (i = 0; i < num; i++) { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, list[i]); - //out_long (0); - } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_list_info_silent_methods, 0); -} -/* }}} */ - - -void end_load (struct telegram *instance, struct download *D) { - instance->cur_downloading_bytes -= D->size; - instance->cur_downloaded_bytes -= D->size; - //update_prompt (); - close (D->fd); - debug ("Done: %s\n", D->name); - event_download_finished (instance, D); - instance->dl_curr = 0; - if (D->dc != telegram_get_working_dc(instance)->id) { - debug ("%d Not the working dc %d, closing...\n", D->dc, - telegram_get_working_dc(instance)->id); - } - if (D->iv) { - tfree_secure (D->iv, 32); - } - tfree_str (D->name); - tfree (D, sizeof (*D)); - telegram_dl_next (instance); -} - -struct download_extra { - struct telegram *instance; - struct download *dl; -}; - -void load_next_part (struct telegram *instance, struct download *D); -int download_on_answer (struct query *q) { - struct download_extra *extra = q->extra; - struct telegram *instance = extra->instance; - struct mtproto_connection *mtp = query_get_mtproto(q); - - struct download *D = extra->dl; - free(extra); - - assert (fetch_int (mtp) == (int)CODE_upload_file); - unsigned x = fetch_int (mtp); - assert (x); - if (D->fd == -1) { - D->fd = open (D->name, O_CREAT | O_WRONLY, 0640); - } - fetch_int (mtp); // mtime - int len = prefetch_strlen (mtp); - assert (len >= 0); - instance->cur_downloaded_bytes += len; - //update_prompt (); - if (D->iv) { - unsigned char *ptr = (void *)fetch_str (mtp, len); - assert (!(len & 15)); - AES_KEY aes_key; - AES_set_decrypt_key (D->key, 256, &aes_key); - AES_ige_encrypt (ptr, ptr, len, &aes_key, D->iv, 0); - memset (&aes_key, 0, sizeof (aes_key)); - if (len > D->size - D->offset) { - len = D->size - D->offset; - } - assert (write (D->fd, ptr, len) == len); - } else { - assert (write (D->fd, fetch_str (mtp, len), len) == len); - } - D->offset += len; - if (D->offset < D->size) { - load_next_part (instance, D); - return 0; - } else { - end_load (instance, D); - return 0; - } -} - -struct query_methods download_methods = { - .on_answer = download_on_answer -}; - -void load_next_part (struct telegram *instance, struct download *D) { - struct mtproto_connection *mtp = instance->connection; - if (!D->offset) { - static char buf[PATH_MAX]; - int l; - - if (!D->id) { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", instance->download_path, D->volume, D->local_id); - } else { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", instance->download_path, D->id); - } - if (l >= (int) sizeof (buf)) { - fatal ("Download filename is too long"); - exit (1); - } - D->name = tstrdup (buf); - struct stat st; - if (stat (buf, &st) >= 0) { - D->offset = st.st_size; - if (D->offset >= D->size) { - instance->cur_downloading_bytes += D->size; - instance->cur_downloaded_bytes += D->offset; - info ("Already downloaded\n"); - end_load (instance, D); - return; - } - } - - instance->cur_downloading_bytes += D->size; - instance->cur_downloaded_bytes += D->offset; - //update_prompt (); - } - info ("do_upload_get_file()\n"); - clear_packet (mtp); - out_int (mtp, CODE_upload_get_file); - if (!D->id) { - out_int (mtp, CODE_input_file_location); - out_long (mtp, D->volume); - out_int (mtp, D->local_id); - out_long (mtp, D->secret); - } else { - if (D->iv) { - out_int (mtp, CODE_input_encrypted_file_location); - } else { - out_int (mtp, D->type); - } - out_long (mtp, D->id); - out_long (mtp, D->access_hash); - } - out_int (mtp, D->offset); - out_int (mtp, 1 << 14); - - struct download_extra *extra = malloc(sizeof(struct download_extra)); - extra->instance = instance; - extra->dl = D; - - send_query (instance, instance->auth.DC_list[D->dc], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &download_methods, extra); - //send_query (instance, DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); -} - -void do_load_photo_size (struct telegram *instance, struct photo_size *P, void *extra) { - if (!P->loc.dc) { - failure ("Bad video thumb\n"); - return; - } - assert (P); - struct download *D = talloc0 (sizeof (*D)); - D->id = 0; - D->offset = 0; - D->size = P->size; - D->volume = P->loc.volume; - D->dc = P->loc.dc; - D->local_id = P->loc.local_id; - D->secret = P->loc.secret; - D->extra = extra; - D->name = 0; - D->fd = -1; - - telegram_dl_add (instance, D); - telegram_dl_next (instance); -} - -void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig, void *extra) { - if (!photo->sizes_num) { return; } - int size = -1; - int sizei = 0; - int i; - for (i = 0; i < photo->sizes_num; i++) { - if (photoBig == 0) - { - if (photo->sizes[i].w + photo->sizes[i].h < size) { - size = photo->sizes[i].w + photo->sizes[i].h; - sizei = i; - } - } else { - if (photo->sizes[i].w + photo->sizes[i].h > size) { - size = photo->sizes[i].w + photo->sizes[i].h; - sizei = i; - } - } - } - do_load_photo_size (instance, &photo->sizes[sizei], extra); -} - -void do_load_video_thumb (struct telegram *instance, struct video *video, void *extra) { - do_load_photo_size (instance, &video->thumb, extra); -} - -void do_load_document_thumb (struct telegram *instance, struct document *video, void *extra) { - do_load_photo_size (instance, &video->thumb, extra); -} - -void do_load_video (struct telegram *instance, struct video *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->type = CODE_input_video_file_location; - load_next_part (instance, D); -} - -void do_load_audio (struct telegram *instance, struct video *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->type = CODE_input_audio_file_location; - load_next_part (instance, D); -} - -void do_load_document (struct telegram *instance, struct document *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->type = CODE_input_document_file_location; - load_next_part (instance, D); -} - -void do_load_encr_video (struct telegram *instance, struct encr_video *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->key = V->key; - D->iv = talloc (32); - memcpy (D->iv, V->iv, 32); - load_next_part (instance, D); - - unsigned char md5[16]; - unsigned char str[64]; - memcpy (str, V->key, 32); - memcpy (str + 32, V->iv, 32); - MD5 (str, 64, md5); - assert (V->key_fingerprint == ((*(int *)md5) ^ (*(int *)(md5 + 4)))); -} -/* }}} */ - -/* {{{ Export auth */ - -struct export_info { - void *extra; - void (*cb)(char *export_auth_str, int len, void *extra); -}; - -int export_auth_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - - assert (fetch_int (mtp) == (int)CODE_auth_exported_authorization); - int l = fetch_int (mtp); - if (!instance->our_id) { - instance->our_id = l; - } else { - assert (instance->our_id == l); - } - l = prefetch_strlen (mtp); - char *s = talloc (l); - memcpy (s, fetch_str (mtp, l), l); - instance->export_auth_str_len = l; - instance->export_auth_str = s; - - struct export_info *info = q->extra; - info->cb(instance->export_auth_str, instance->export_auth_str_len, info->extra); - tfree(info, sizeof(struct export_info)); - return 0; -} - -struct query_methods export_auth_methods = { - .on_answer = export_auth_on_answer, - .on_error = fail_on_error -}; - -void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra) { - info ("do_export_auth(num=%d)\n", num); - instance->export_auth_str = 0; - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_auth_export_authorization); - out_int (mtp, num); - - struct export_info *info = talloc0(sizeof(struct export_info)); - info->cb = cb; - info->extra = extra; - - send_query (instance, telegram_get_working_dc(instance), - mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, info); -} -/* }}} */ - -struct import_info { - void *extra; - void (*cb)(void* extra); -}; - -/* {{{ Import auth */ -int import_auth_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - struct import_info *info = q->extra; - - assert (fetch_int (mtp) == (int)CODE_auth_authorization); - fetch_int (mtp); // expires - fetch_alloc_user (mtp); - tfree_str (instance->export_auth_str); - instance->export_auth_str = 0; - info->cb(info->extra); - tfree (info, sizeof(struct import_info)); - return 0; -} - -struct query_methods import_auth_methods = { - .on_answer = import_auth_on_answer, - .on_error = fail_on_error -}; - -void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra) { - info ("do_import_auth(num=%d, our_id=%d, export_auth_str=)\n", num, instance->our_id); - struct import_info *info = talloc0(sizeof (struct import_info)); - info->cb = cb; - info->extra = extra; - - struct dc *target_dc = instance->auth.DC_list[num]; - assert (target_dc); - struct mtproto_connection *dc_conn = target_dc->sessions[0]->c->mtconnection; - assert (dc_conn); - - clear_packet (dc_conn); - out_int (dc_conn, CODE_auth_import_authorization); - out_int (dc_conn, instance->our_id); - out_cstring (dc_conn, instance->export_auth_str, instance->export_auth_str_len); - - send_query (instance, target_dc, dc_conn->packet_ptr - dc_conn->packet_buffer, - dc_conn->packet_buffer, &import_auth_methods, info); -} -/* }}} */ - -/* {{{ Add contact */ -int add_contact_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_contacts_imported_contacts); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - if (n > 0) { - debug ("Added successfully"); - } else { - debug ("Not added"); - } - int i; - for (i = 0; i < n ; i++) { - assert (fetch_int (mtp) == (int)CODE_imported_contact); - fetch_int (mtp); // uid - fetch_long (mtp); // client_id - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n ; i++) { - struct tgl_user *U = fetch_alloc_user (mtp); - //print_start (); - //push_color (COLOR_YELLOW); - debug ("User #%d: ", get_peer_id (U->id)); - //print_user_name (U->id, (peer_t *)U); - //push_color (COLOR_GREEN); - debug (" ("); - debug ("%s", U->print_name); - if (U->phone) { - debug (" "); - debug ("%s", U->phone); - } - debug (") "); - //pop_color (); - if (U->status.online > 0) { - debug ("online\n"); - } else { - if (U->status.online < 0) { - debug ("offline. Was online "); - //print_date_full (U->status.when); - } else { - debug ("offline permanent"); - } - debug ("\n"); - } - //pop_color (); - //print_end (); - - } - return 0; -} - -struct query_methods add_contact_methods = { - .on_answer = add_contact_on_answer, -}; - -void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_contacts_import_contacts); - out_int (mtp, CODE_vector); - out_int (mtp, 1); - out_int (mtp, CODE_input_phone_contact); - out_long (mtp, lrand48 () * (1ll << 32) + lrand48 ()); - out_cstring (mtp, phone, phone_len); - out_cstring (mtp, first_name, first_name_len); - out_cstring (mtp, last_name, last_name_len); - out_int (mtp, force ? CODE_bool_true : CODE_bool_false); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_contact_methods, 0); -} -/* }}} */ - -/* {{{ Msg search */ -int msg_search_on_answer (struct query *q UU) { - return get_history_on_answer (q); -} - -struct query_methods msg_search_methods = { - .on_answer = msg_search_on_answer -}; - -void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT) { - warning ("Can not search in secure chat\n"); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_search); - if (get_peer_type (id) == PEER_UNKNOWN) { - out_int (mtp, CODE_input_peer_empty); - } else { - out_peer_id (mtp, id); - } - out_string (mtp, s); - out_int (mtp, CODE_input_messages_filter_empty); - out_int (mtp, from); - out_int (mtp, to); - out_int (mtp, 0); // offset - out_int (mtp, 0); // max_id - out_int (mtp, limit); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_search_methods, 0); -} -/* }}} */ - -/* {{{ Contacts search */ -int contacts_search_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_contacts_found); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == (int)CODE_contact_found); - fetch_int (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - //print_start (); - //push_color (COLOR_YELLOW); - for (i = 0; i < n; i++) { - struct tgl_user *U = fetch_alloc_user (mtp); - debug ("User "); - //push_color (COLOR_RED); - debug ("%s %s", U->first_name, U->last_name); - //pop_color (); - debug (". Phone %s\n", U->phone); - } - //pop_color (); - //print_end (); - return 0; -} - -struct query_methods contacts_search_methods = { - .on_answer = contacts_search_on_answer -}; - -void do_contacts_search (struct telegram *instance, int limit, const char *s) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_contacts_search); - out_string (mtp, s); - out_int (mtp, limit); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &contacts_search_methods, 0); -} -/* }}} */ - -/* {{{ Encr accept */ -int send_encr_accept_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct secret_chat *E = fetch_alloc_encrypted_chat (mtp); - - if (E->state == sc_ok) { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Encrypted connection with "); - ////print_encr_chat_name (E->id, (void *)E); - debug (" established\n"); - //pop_color (); - //print_end (); - } else { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Encrypted connection with "); - ////print_encr_chat_name (E->id, (void *)E); - debug (" failed\n"); - //pop_color (); - //print_end (); - } - return 0; -} - -int send_encr_request_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct secret_chat *E = fetch_alloc_encrypted_chat (mtp); - if (E->state == sc_deleted) { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Encrypted connection with "); - //print_encr_chat_name (E->id, (void *)E); - debug (" can not be established\n"); - //pop_color (); - //print_end (); - } else { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Establishing connection with "); - //print_encr_chat_name (E->id, (void *)E); - debug ("\n"); - //pop_color (); - //print_end (); - - assert (E->state == sc_waiting); - } - return 0; -} - -struct query_methods send_encr_accept_methods = { - .on_answer = send_encr_accept_on_answer -}; - -struct query_methods send_encr_request_methods = { - .on_answer = send_encr_request_on_answer -}; - -void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, unsigned char *random) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - int i; - int ok = 0; - for (i = 0; i < 64; i++) { - if (E->key[i]) { - ok = 1; - break; - } - } - if (ok) { return; } // Already generated key for this chat - unsigned char random_here[256]; - secure_random (random_here, 256); - for (i = 0; i < 256; i++) { - random[i] ^= random_here[i]; - } - BIGNUM *b = BN_bin2bn (random, 256, 0); - ensure_ptr (b); - BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0); - ensure_ptr (g_a); - assert (check_g (instance->encr_prime, g_a) >= 0); - if (!instance->ctx) { - instance->ctx = BN_CTX_new (); - ensure_ptr (instance->ctx); - } - BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); - ensure_ptr (p); - BIGNUM *r = BN_new (); - ensure_ptr (r); - ensure (BN_mod_exp (r, g_a, b, p, instance->ctx)); - static unsigned char kk[256]; - memset (kk, 0, sizeof (kk)); - BN_bn2bin (r, kk); - for (i = 0; i < 256; i++) { - kk[i] ^= E->nonce[i]; - } - static unsigned char sha_buffer[20]; - sha1 (kk, 256, sha_buffer); - - bl_do_set_encr_chat_key (mtp->bl, mtp, E, kk, *(long long *)(sha_buffer + 12)); - - clear_packet (mtp); - out_int (mtp, CODE_messages_accept_encryption); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (E->id)); - out_long (mtp, E->access_hash); - - ensure (BN_set_word (g_a, instance->encr_root)); - ensure (BN_mod_exp (r, g_a, b, p, instance->ctx)); - static unsigned char buf[256]; - memset (buf, 0, sizeof (buf)); - BN_bn2bin (r, buf); - out_cstring (mtp, (void *)buf, 256); - - out_long (mtp, E->key_fingerprint); - BN_clear_free (b); - BN_clear_free (g_a); - BN_clear_free (p); - BN_clear_free (r); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_accept_methods, E); -} - -void do_create_keys_end (struct telegram *instance, struct secret_chat *U) { - assert (instance->encr_prime); - BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); - ensure_ptr (g_b); - assert (check_g (instance->encr_prime, g_b) >= 0); - if (!instance->ctx) { - instance->ctx = BN_CTX_new (); - ensure_ptr (instance->ctx); - } - BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); - ensure_ptr (p); - BIGNUM *r = BN_new (); - ensure_ptr (r); - BIGNUM *a = BN_bin2bn ((void *)U->key, 256, 0); - ensure_ptr (a); - ensure (BN_mod_exp (r, g_b, a, p, instance->ctx)); - - unsigned char *t = talloc (256); - memcpy (t, U->key, 256); - - memset (U->key, 0, sizeof (U->key)); - BN_bn2bin (r, (void *)U->key); - int i; - for (i = 0; i < 64; i++) { - U->key[i] ^= *(((int *)U->nonce) + i); - } - - static unsigned char sha_buffer[20]; - sha1 ((void *)U->key, 256, sha_buffer); - long long k = *(long long *)(sha_buffer + 12); - if (k != U->key_fingerprint) { - debug ("version = %d\n", instance->encr_param_version); - hexdump ((void *)U->nonce, (void *)(U->nonce + 256)); - hexdump ((void *)U->g_key, (void *)(U->g_key + 256)); - hexdump ((void *)U->key, (void *)(U->key + 64)); - hexdump ((void *)t, (void *)(t + 256)); - hexdump ((void *)sha_buffer, (void *)(sha_buffer + 20)); - failure ("!!Key fingerprint mismatch (my 0x%llx 0x%llx)\n", (unsigned long long)k, (unsigned long long)U->key_fingerprint); - U->state = sc_deleted; - } - - tfree_secure (t, 256); - - BN_clear_free (p); - BN_clear_free (g_b); - BN_clear_free (r); - BN_clear_free (a); -} - -void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char *random) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - int user_id = (long)x; - int i; - unsigned char random_here[256]; - secure_random (random_here, 256); - for (i = 0; i < 256; i++) { - random[i] ^= random_here[i]; - } - if (!instance->ctx) { - instance->ctx = BN_CTX_new (); - ensure_ptr (instance->ctx); - } - BIGNUM *a = BN_bin2bn (random, 256, 0); - ensure_ptr (a); - BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); - ensure_ptr (p); - - BIGNUM *g = BN_new (); - ensure_ptr (g); - - ensure (BN_set_word (g, instance->encr_root)); - - BIGNUM *r = BN_new (); - ensure_ptr (r); - - ensure (BN_mod_exp (r, g, a, p, instance->ctx)); - - BN_clear_free (a); - - memset (instance->g_a, 0, 256); - - BN_bn2bin (r, (void *)instance->g_a); - - int t = lrand48 (); - while (user_chat_get (mtp->bl, MK_ENCR_CHAT (t))) { - t = lrand48 (); - } - - bl_do_encr_chat_init (mtp->bl, mtp, t, user_id, (void *)random, (void *)instance->g_a); - peer_t *_E = user_chat_get (mtp->bl, MK_ENCR_CHAT (t)); - assert (_E); - struct secret_chat *E = &_E->encr_chat; - - clear_packet (mtp); - out_int (mtp, CODE_messages_request_encryption); - peer_t *U = user_chat_get (mtp->bl, MK_USER (E->user_id)); - assert (U); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, E->user_id); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, E->user_id); - } - out_int (mtp, get_peer_id (E->id)); - out_cstring (mtp, instance->g_a, 256); - write_secret_chat_file (instance, instance->secret_path); - - BN_clear_free (g); - BN_clear_free (p); - BN_clear_free (r); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_request_methods, E); -} - -struct create_encr_chat_extra { - void (*callback) (struct telegram *instance, struct secret_chat *E, unsigned char *random); - void *data; - struct telegram *instance; -}; - -int get_dh_config_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); - if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { - int a = fetch_int (mtp); - int l = prefetch_strlen (mtp); - assert (l == 256); - char *s = fetch_str (mtp, l); - int v = fetch_int (mtp); - bl_do_set_dh_params (mtp->bl, mtp, a, (void *)s, v); - - BIGNUM *p = BN_bin2bn ((void *)s, 256, 0); - ensure_ptr (p); - assert (check_DH_params (mtp, p, a) >= 0); - BN_free (p); - } - if (x == LOG_DH_CONFIG) { return 0; } - int l = prefetch_strlen (mtp); - assert (l == 256); - unsigned char *random = talloc (256); - memcpy (random, fetch_str (mtp, 256), 256); - if (q->extra) { - //((void (*)(void *, void *))(*x))(x[1], random); - - struct create_encr_chat_extra *extra = q->extra; - extra->callback(extra->instance, extra->data, random); - free(extra); - //tfree (x, 2 * sizeof (void *)); - - tfree_secure (random, 256); - } else { - tfree_secure (random, 256); - } - return 0; -} - -struct query_methods get_dh_config_methods = { - .on_answer = get_dh_config_on_answer -}; - -void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - assert (E->state == sc_request); - - clear_packet (mtp); - out_int (mtp, CODE_messages_get_dh_config); - out_int (mtp, instance->encr_param_version); - out_int (mtp, 256); - - struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); - extra->callback = do_send_accept_encr_chat; - extra->instance = instance; - extra->data = (void*)E; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); -} - -void do_create_encr_chat_request (struct telegram *instance, int user_id) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_get_dh_config); - out_int (mtp, instance->encr_param_version); - out_int (mtp, 256); - - struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); - extra->callback = do_send_accept_encr_chat; - extra->instance = instance; - extra->data = (void *)(long)user_id; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); -} -/* }}} */ - -/* {{{ Get difference */ -//int difference_got; -//int seq, pts, qts, last_date; -int get_state_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = q->extra; - - debug("get_state_on_answer()\n"); - assert (fetch_int (mtp) == (int)CODE_updates_state); - bl_do_set_pts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - instance->unread_messages = fetch_int (mtp); - //write_state_file (); - telegram_store_session (instance); - return 0; -} - -int get_difference_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = q->extra; - - debug("get_difference_on_answer()\n"); - instance->get_difference_active = 0; - unsigned x = fetch_int (mtp); - if (x == CODE_updates_difference_empty) { - bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - } else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) { - int n, i; - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - int ml_pos = 0; - for (i = 0; i < n; i++) { - if (ml_pos < 10000) { - instance->ML[ml_pos ++] = fetch_alloc_message (mtp, instance); - } else { - fetch_alloc_message (mtp, instance); - } - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - if (ml_pos < 10000) { - instance->ML[ml_pos ++] = fetch_alloc_encrypted_message (mtp, instance); - } else { - fetch_alloc_encrypted_message (mtp, instance); - } - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - work_update (mtp, 0); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - debug("Found %d chats\n", n); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - debug("Found %d users\n", n); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - assert (fetch_int (mtp) == (int)CODE_updates_state); - bl_do_set_pts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - instance->unread_messages = fetch_int (mtp); - debug ("UNREAD MESSAGES: %d\n", ml_pos); - //write_state_file (); - for (i = 0; i < ml_pos; i++) { - event_update_new_message (instance, instance->ML[i]); - ////print_message (ML[i]); - } - if (x == CODE_updates_difference_slice) { - do_get_difference (instance, 0); - } else { - //difference_got = 1; - } - } else { - assert (0); - } - telegram_store_session (instance); - return 0; -} - -struct query_methods get_state_methods = { - .on_answer = get_state_on_answer -}; - -struct query_methods get_difference_methods = { - .on_answer = get_difference_on_answer -}; - -void do_get_difference (struct telegram *instance, int sync_from_start) { - info ("do_get_difference()\n"); - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - - instance->get_difference_active = 1; - //difference_got = 0; - clear_packet (mtp); - do_insert_header (mtp); - debug("do_get_difference(pts:%d, last_date:%d, qts: %d)\n", instance->proto.pts, instance->proto.last_date, instance->proto.qts); - if (instance->proto.seq > 0 || sync_from_start) { - if (instance->proto.pts == 0) { instance->proto.pts = 1; } - if (instance->proto.qts == 0) { instance->proto.qts = 1; } - if (instance->proto.last_date == 0) { instance->proto.last_date = 1; } - - out_int (mtp, CODE_updates_get_difference); - out_int (mtp, instance->proto.pts); - out_int (mtp, instance->proto.last_date); - out_int (mtp, instance->proto.qts); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); - } else { - debug("do_updates_get_state()\n", - instance->proto.pts, instance->proto.last_date, instance->proto.qts); - out_int (mtp, CODE_updates_get_state); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, instance); - } -} -/* }}} */ - -/* {{{ Visualize key */ -//char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN}; - -void do_visualize_key (struct binlog *bl, peer_id_t id) { - assert (get_peer_type (id) == PEER_ENCR_CHAT); - peer_t *P = user_chat_get (bl, id); - assert (P); - if (P->encr_chat.state != sc_ok) { - warning ("Chat is not initialized yet\n"); - return; - } - unsigned char buf[20]; - SHA1 ((void *)P->encr_chat.key, 256, buf); - //print_start (); - int i; - for (i = 0; i < 16; i++) { - int x = buf[i]; - int j; - for (j = 0; j < 4; j ++) { - ////push_color (colors[x & 3]); - ////push_color (COLOR_INVERSE); - //debug (" "); - ////pop_color (); - ////pop_color (); - x = x >> 2; - } - if (i & 1) { debug ("\n"); } - } - //print_end (); -} -/* }}} */ - -/* {{{ Get suggested */ -int get_suggested_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_contacts_suggested); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - debug ("n = %d\n", n); - assert (n <= 200); - int l[400]; - int i; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == CODE_contact_suggested); - l[2 * i] = fetch_int (mtp); - l[2 * i + 1] = fetch_int (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - int m = fetch_int (mtp); - assert (n == m); - //print_start (); - //push_color (COLOR_YELLOW); - for (i = 0; i < m; i++) { - peer_t *U = (void *)fetch_alloc_user (mtp); - assert (get_peer_id (U->id) == l[2 * i]); - //print_user_name (U->id, U); - debug (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); - } - //pop_color (); - //print_end (); - return 0; -} - -struct query_methods get_suggested_methods = { - .on_answer = get_suggested_on_answer -}; - -void do_get_suggested (struct telegram *instance) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_contacts_get_suggested); - out_int (mtp, 100); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_suggested_methods, 0); -} -/* }}} */ - -/* {{{ Add user to chat */ - -struct query_methods add_user_to_chat_methods = { - .on_answer = fwd_msg_on_answer -}; - -void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit) { - info ("do_add_user_to_chat()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_add_chat_user); - out_int (mtp, get_peer_id (chat_id)); - - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - out_int (mtp, limit); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); -} - -void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id) { - info ("do_del_user_from_chat()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_delete_chat_user); - out_int (mtp, get_peer_id (chat_id)); - - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); -} -/* }}} */ - -/* {{{ Create secret chat */ -char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); - -void do_create_secret_chat (struct telegram *instance, peer_id_t id) { - info ("do_create_secret_chat()\n"); - struct mtproto_connection *mtp = instance->connection; - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (!U) { - warning ("Can not create chat with unknown user\n"); - return; - } - - do_create_encr_chat_request (instance, get_peer_id (id)); -} -/* }}} */ - -/* {{{ Create group chat */ -struct query_methods create_group_chat_methods = { - .on_answer = fwd_msg_on_answer -}; - -void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic) { - info ("do_create_group_chat()\n"); - struct mtproto_connection *mtp = instance->connection; - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (!U) { - warning ("Can not create chat with unknown user\n"); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_create_chat); - out_int (mtp, CODE_vector); - out_int (mtp, 1); // Number of users, currently we support only 1 user. - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - out_string (mtp, chat_topic); - send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &create_group_chat_methods, 0); -} -/* }}} */ - - -/* {{{ Delete msg */ - -int delete_msg_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - fetch_skip (mtp, n); - debug ("Deleted %d messages\n", n); - return 0; -} - -struct query_methods delete_msg_methods = { - .on_answer = delete_msg_on_answer -}; - -void do_delete_msg (struct telegram *instance, long long id) { - info ("do_delete_msg()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_delete_messages); - out_int (mtp, CODE_vector); - out_int (mtp, 1); - out_int (mtp, id); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &delete_msg_methods, 0); -} -/* }}} */ - -/* {{{ Restore msg */ - -int restore_msg_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - fetch_skip (mtp, n); - debug ("Restored %d messages\n", n); - return 0; -} - -struct query_methods restore_msg_methods = { - .on_answer = restore_msg_on_answer -}; - -void do_restore_msg (struct telegram *instance, long long id) { - info ("do_restore_msg()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_restore_messages); - out_int (mtp, CODE_vector); - out_int (mtp, 1); - out_int (mtp, id); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &restore_msg_methods, 0); -} -/* }}} */ -int update_status_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - fetch_bool (mtp); - return 0; -} - -struct query_methods update_status_methods = { - .on_answer = update_status_on_answer -}; - -void do_update_status (struct telegram *instance, int online UU) { - info ("do_update_status()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_account_update_status); - out_int (mtp, online ? CODE_bool_false : CODE_bool_true); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); -} - -int update_typing_on_answer (struct query *q UU) { - fetch_bool (query_get_mtproto (q)); - return 0; -} - -struct query_methods update_typing_methods = { - .on_answer = update_typing_on_answer -}; - -void do_update_typing (struct telegram *instance, peer_id_t id) { - info ("do_update_typing()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_set_typing); - out_peer_id (mtp, id); - out_int (mtp, CODE_bool_true); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_typing_methods, 0); -} - diff --git a/queries.h b/queries.h deleted file mode 100644 index c8c93b7..0000000 --- a/queries.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - This file is part of telegram-client. - - struct telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - struct telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __QUERIES_H__ -#define __QUERIES_H__ - -#pragma once -#include "structures.h" - -struct telegram; -struct encr_video; -struct document; -struct secret_chat; -struct tree_query; -struct tree_timer; -#define QUERY_ACK_RECEIVED 1 - -struct query; -struct query_methods { - int (*on_answer)(struct query *q); - int (*on_error)(struct query *q, int error_code, int len, char *error); - int (*on_timeout)(struct query *q); -}; - -struct download_desc{ - void *data; - int type; -}; - -struct download { - int offset; - int size; - long long volume; - long long secret; - long long access_hash; - int local_id; - int dc; - void *extra; - int fd; - char *name; - long long id; - unsigned char *iv; - unsigned char *key; - int type; - struct mtproto_connection *c; -}; -void load_next_part (struct telegram *instance, struct download *D); - -struct event_timer { - double timeout; - int (*alarm)(void *self); - void *self; -}; - -struct query { - long long msg_id; - int data_len; - int flags; - int seq_no; - void *data; - struct query_methods *methods; - struct event_timer ev; - struct dc *DC; - struct session *session; - void *extra; -}; - - -struct query *send_query (struct telegram *instance, struct dc *DC, int len, void *data, struct query_methods *methods, void *extra); -void query_ack (struct telegram *instance, long long id); -void query_error (struct telegram *instance, long long id); -void query_result (struct telegram *instance, long long id); -void query_restart (struct telegram *instance, long long id); - -void insert_event_timer (struct telegram *instance, struct event_timer *ev); -void remove_event_timer (struct telegram *instance, struct event_timer *ev); -double next_timer_in (struct telegram *instance); -void work_timers (struct telegram *instance); - -extern struct query_methods help_get_config_methods; - -void do_send_code (struct telegram *instance, const char *user); -void do_phone_call (struct telegram *instance, const char *user); -void do_send_code_result (struct telegram *instance, const char *code); -double get_double_time (void); - -void do_update_contact_list (struct telegram *instance); -union user_chat; -void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len); -void do_send_text (struct telegram *instance, peer_id_t id, char *file); -void do_get_history (struct telegram *instance, peer_id_t id, int limit); -void do_get_dialog_list (struct telegram*); -void do_get_dialog_list_ex (struct telegram*); -void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name); -void do_get_chat_info (struct telegram *instance, peer_id_t id); -void do_get_user_list_info_silent (struct telegram *instance, int num, int *list); -void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo); -void do_forward_message (struct telegram *instance, peer_id_t id, int n); -void do_rename_chat (struct telegram *instance, peer_id_t id, char *name); -void do_load_encr_video (struct telegram *instance, struct encr_video *V, void *extra); -void do_create_encr_chat_request (struct telegram *instance, int user_id); -void do_create_secret_chat (struct telegram *instance, peer_id_t id); -void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic); -void do_get_suggested (struct telegram*); - -struct photo; -struct video; -void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig, void *extra); -void do_load_video_thumb (struct telegram *instance, struct video *video, void *extra); -void do_load_audio (struct telegram *instance, struct video *V, void *extra); -void do_load_video (struct telegram *instance, struct video *V, void *extra); -void do_load_document (struct telegram *instance, struct document *V, void *extra); -void do_load_document_thumb (struct telegram *instance, struct document *video, void *extra); -void do_help_get_config (struct telegram *instance); -void do_auth_check_phone (struct telegram *instance, const char *user); -void do_get_nearest_dc (struct telegram*); -void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name); -void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra); -void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra); -void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force); -void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s); -void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E); -void do_get_difference (struct telegram*, int sync_from_start); -void do_mark_read (struct telegram *instance, peer_id_t id); -void do_visualize_key (struct binlog *bl, peer_id_t id); -void do_create_keys_end (struct telegram *, struct secret_chat *U); - -void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit); -void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id); -void do_update_status (struct telegram *instance, int online); -void do_contacts_search (struct telegram *instance, int limit, const char *s); -void do_send_msg (struct telegram *instance, struct message *M); -void do_delete_msg (struct telegram *instance, long long id); -void do_restore_msg (struct telegram *instance, long long id); - -// For binlog - -int get_dh_config_on_answer (struct query *q); -void fetch_dc_option (struct telegram *instance); -void free_queries (struct telegram *instance); -void free_timers (struct telegram *instance); -#endif - -const char *get_last_err(); - -int all_queries_done(); diff --git a/structures.c b/structures.c deleted file mode 100644 index 4073ae0..0000000 --- a/structures.c +++ /dev/null @@ -1,2090 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#include -#include -#include "constants.h" -#include "structures.h" -#include "telegram.h" -#include "tree.h" -#include "loop.h" -#include -#include -#include "queries.h" -#include "binlog.h" -#include "net.h" - -#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 peer_cmp_name(a,b) (strcmp (a->print_name, b->print_name)) -DEFINE_TREE(peer,peer_t *,peer_cmp,0) -DEFINE_TREE(peer_by_name,peer_t *,peer_cmp_name,0) -DEFINE_TREE(message,struct message *,id_cmp,0) - -struct message message_list = { - .next_use = &message_list, - .prev_use = &message_list -}; - -int verbosity; - -void fetch_skip_photo (struct mtproto_connection *mtp); - -#define code_assert(x) if (!(x)) { fatal ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } -#define code_try(x) if ((x) == -1) { return -1; } - -/* - * - * Fetch simple structures (immediate fetch into buffer) - * - */ - -int fetch_file_location (struct mtproto_connection *mtp, struct file_location *loc) { - int x = fetch_int (mtp); - code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); - - if (x == CODE_file_location_unavailable) { - loc->dc = -1; - loc->volume = fetch_long (mtp); - loc->local_id = fetch_int (mtp); - loc->secret = fetch_long (mtp); - } else { - loc->dc = fetch_int (mtp); - loc->volume = fetch_long (mtp); - loc->local_id = fetch_int (mtp); - loc->secret = fetch_long (mtp); - } - return 0; -} - -int fetch_user_status (struct mtproto_connection *mtp, struct user_status *S) { - unsigned x = fetch_int (mtp); - code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); - switch (x) { - case CODE_user_status_empty: - S->online = 0; - S->when = 0; - break; - case CODE_user_status_online: - S->online = 1; - S->when = fetch_int (mtp); - break; - case CODE_user_status_offline: - S->online = -1; - S->when = fetch_int (mtp); - break; - default: - assert (0); - } - return 0; -} - -/* - * - * Skip simple structures - * - */ - -int fetch_skip_file_location (struct mtproto_connection *mtp) { - int x = fetch_int (mtp); - code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); - - if (x == CODE_file_location_unavailable) { - mtp->in_ptr += 5; - } else { - mtp->in_ptr += 6; - } - return 0; -} - -int fetch_skip_user_status (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); - if (x != CODE_user_status_empty) { - fetch_int (mtp); - } - return 0; -} - -char *create_print_name (struct binlog *bl, 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; - static char buf[10000]; - buf[0] = 0; - int i; - int p = 0; - for (i = 0; i < 4; i++) { - if (d[i] && strlen (d[i])) { - p += tsnprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]); - assert (p < 9990); - } - } - char *s = buf; - while (*s) { - if (*s == ' ') { *s = '_'; } - s++; - } - s = buf; - int fl = strlen (s); - int cc = 0; - while (1) { - peer_t *P = peer_lookup_name (bl, s); - if (!P || !cmp_peer_id (P->id, id)) { - break; - } - cc ++; - assert (cc <= 9999); - tsnprintf (s + fl, 9999 - fl, "#%d", cc); - } - return tstrdup (s); -} - -/* - * - * Fetch with log event - * - */ - -long long fetch_user_photo (struct mtproto_connection *mtp, struct tgl_user *U) { - unsigned x = fetch_int (mtp); - code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); - if (x == CODE_user_profile_photo_empty) { - bl_do_set_user_profile_photo (mtp->bl, mtp, U, 0, 0, 0); - return 0; - } - long long photo_id = 1; - if (x == CODE_user_profile_photo) { - photo_id = fetch_long (mtp); - } - struct file_location big; - struct file_location small; - code_try (fetch_file_location (mtp, &small)); - code_try (fetch_file_location (mtp, &big)); - - bl_do_set_user_profile_photo (mtp->bl, mtp, U, photo_id, &big, &small); - return 0; -} - -void sanitize_alias(char *buffer) -{ - size_t len = strlen(buffer); - gchar *curr; - while ((curr = g_utf8_strchr(buffer, len, '\n'))) { - *curr = 0x20; - } -} - -int user_get_alias(peer_t *user, char *buffer, int maxlen) -{ - char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; - char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; - sanitize_alias (last_name); - sanitize_alias(first_name); - if (strlen(first_name) && strlen(last_name)) { - return snprintf(buffer, maxlen, "%s %s", first_name, last_name); - } else if (strlen(first_name)) { - return snprintf(buffer, maxlen, "%s", first_name); - } else if (strlen(last_name)) { - return snprintf(buffer, maxlen, "%s", last_name); - } else { - return snprintf(buffer, maxlen, "%d", get_peer_id(user->id)); - } -} - -int fetch_user (struct mtproto_connection *mtp, struct tgl_user *U) { - struct telegram *instance = mtp->instance; - - unsigned x = fetch_int (mtp); - code_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 = MK_USER (fetch_int (mtp)); - if (x == CODE_user_empty) { - return 0; - } - - if (x == CODE_user_self) { - assert (!instance->our_id || (instance->our_id == get_peer_id (U->id))); - if (!instance->our_id) { - bl_do_set_our_id (mtp->bl, mtp, get_peer_id (U->id)); - // TODO: What to do here? - //write_auth_file (); - } - } - - int new = 0; - if (!(U->flags & FLAG_CREATED)) { - new = 1; - } - if (new) { - int l1 = prefetch_strlen (mtp); - code_assert (l1 >= 0); - char *s1 = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - code_assert (l2 >= 0); - char *s2 = fetch_str (mtp, l2); - - if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_new_user (mtp->bl, mtp, get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); - bl_do_user_delete (mtp->bl, mtp, U); - } - if (x != CODE_user_deleted) { - long long access_token = 0; - if (x != CODE_user_self) { - access_token = fetch_long (mtp); - } - int phone_len = 0; - char *phone = 0; - if (x != CODE_user_foreign) { - phone_len = prefetch_strlen (mtp); - code_assert (phone_len >= 0); - phone = fetch_str (mtp, phone_len); - } - bl_do_new_user (mtp->bl, mtp, get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); - if (fetch_user_photo (mtp, U) < 0) { return -1; } - - if (fetch_user_status (mtp, &U->status) < 0) { return -1; } - if (x == CODE_user_self) { - fetch_bool (mtp); - } - } - } else { - int l1 = prefetch_strlen (mtp); - char *s1 = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - char *s2 = fetch_str (mtp, l2); - - bl_do_set_user_name (mtp->bl, mtp, U, s1, l1, s2, l2); - - if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_user_delete (mtp->bl, mtp, U); - } - if (x != CODE_user_deleted) { - if (x != CODE_user_self) { - bl_do_set_user_access_token (mtp->bl, mtp, U, fetch_long (mtp)); - } - if (x != CODE_user_foreign) { - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - bl_do_set_user_phone (mtp->bl, mtp, U, s, l); - } - if (fetch_user_photo (mtp, U) < 0) { return -1; } - - fetch_user_status (mtp, &U->status); - if (x == CODE_user_self) { - fetch_bool (mtp); - } - - if (x == CODE_user_contact) { - bl_do_set_user_friend (mtp->bl, mtp, U, 1); - } else { - bl_do_set_user_friend (mtp->bl, mtp, U, 0); - } - } - } - return 0; -} - -void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U) { - struct telegram *instance = mtp->instance; - - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); - U->id = MK_ENCR_CHAT (fetch_int (mtp)); - if (x == CODE_encrypted_chat_empty) { - return; - } - int new = !(U->flags & FLAG_CREATED); - - if (x == CODE_encrypted_chat_discarded) { - if (new) { - warning ("Unknown chat in deleted state. May be we forgot something...\n"); - return; - } - bl_do_encr_chat_delete (mtp->bl, mtp, U); - - write_secret_chat_file (instance, instance->secret_path); - return; - } - - static char g_key[256]; - static char nonce[256]; - if (new) { - long long access_hash = fetch_long (mtp); - int date = fetch_int (mtp); - int admin_id = fetch_int (mtp); - int user_id = fetch_int (mtp) + admin_id - instance->our_id; - - if (x == CODE_encrypted_chat_waiting) { - warning ("Unknown chat in waiting state. May be we forgot something...\n"); - return; - } - if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { - memset (g_key, 0, sizeof (g_key)); - memset (nonce, 0, sizeof (nonce)); - } - - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (g_key + 256 - l, s, l); - } else { - memcpy (g_key, s + (l - 256), 256); - } - - /*l = prefetch_strlen (mtp); - s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (nonce + 256 - l, s, l); - } else { - memcpy (nonce, s + (l - 256), 256); - }*/ - - if (x == CODE_encrypted_chat) { - fetch_long (mtp); // fingerprint - } - - if (x == CODE_encrypted_chat) { - warning ("Unknown chat in ok state. May be we forgot something...\n"); - return; - } - - bl_do_encr_chat_requested (mtp->bl, mtp, U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); - write_secret_chat_file (instance, instance->secret_path); - } else { - bl_do_set_encr_chat_access_hash (mtp->bl, mtp, U, fetch_long (mtp)); - bl_do_set_encr_chat_date (mtp->bl, mtp, U, fetch_int (mtp)); - if (fetch_int (mtp) != U->admin_id) { - failure ("Changed admin in secret chat. WTF?\n"); - return; - } - if (U->user_id != U->admin_id + fetch_int (mtp) - instance->our_id) { - failure ("Changed partner in secret chat. WTF?\n"); - return; - } - if (x == CODE_encrypted_chat_waiting) { - bl_do_set_encr_chat_state (mtp->bl, mtp, U, sc_waiting); - write_secret_chat_file (instance, instance->secret_path); - return; // We needed only access hash from here - } - - if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { - memset (g_key, 0, sizeof (g_key)); - memset (nonce, 0, sizeof (nonce)); - } - - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (g_key + 256 - l, s, l); - } else { - memcpy (g_key, s + (l - 256), 256); - } - - /*l = prefetch_strlen (mtp); - s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (nonce + 256 - l, s, l); - } else { - memcpy (nonce, s + (l - 256), 256); - }*/ - - if (x == CODE_encrypted_chat_requested) { - return; // Duplicate? - } - bl_do_encr_chat_accepted (mtp->bl, mtp, U, (void *)g_key, (void *)nonce, fetch_long (mtp)); - } - write_secret_chat_file (instance, instance->secret_path); -} - -void fetch_notify_settings (struct mtproto_connection *mtp); -void fetch_user_full (struct mtproto_connection *mtp, struct tgl_user *U) { - assert (fetch_int (mtp) == CODE_user_full); - fetch_alloc_user (mtp); - unsigned x; - assert (fetch_int (mtp) == (int)CODE_contacts_link); - x = fetch_int (mtp); - assert (x == CODE_contacts_my_link_empty || x == CODE_contacts_my_link_requested || x == CODE_contacts_my_link_contact); - if (x == CODE_contacts_my_link_requested) { - fetch_bool (mtp); - } - x = fetch_int (mtp); - assert (x == CODE_contacts_foreign_link_unknown || x == CODE_contacts_foreign_link_requested || x == CODE_contacts_foreign_link_mutual); - if (x == CODE_contacts_foreign_link_requested) { - fetch_bool (mtp); - } - fetch_alloc_user (mtp); - - int *start = mtp->in_ptr; - fetch_photo (mtp, &U->photo); - bl_do_set_user_full_photo (mtp->bl, mtp, U, start, 4 * (mtp->in_ptr - start)); - - fetch_notify_settings (mtp); - - bl_do_set_user_blocked (mtp->bl, mtp, U, fetch_bool (mtp)); - int l1 = prefetch_strlen (mtp); - char *s1 = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - char *s2 = fetch_str (mtp, l2); - bl_do_set_user_real_name (mtp->bl, mtp, U, s1, l1, s2, l2); -} - -void fetch_chat (struct mtproto_connection *mtp, struct chat *C) { - unsigned x = fetch_int (mtp); - assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); - C->id = MK_CHAT (fetch_int (mtp)); - if (x == CODE_chat_empty) { - return; - } - int new = !(C->flags & FLAG_CREATED); - if (new) { - int y = 0; - if (x == CODE_chat_forbidden) { - y |= FLAG_FORBIDDEN; - } - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, 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 z = fetch_int (mtp); - if (z == CODE_chat_photo_empty) { - small.dc = -2; - big.dc = -2; - } else { - assert (z == CODE_chat_photo); - fetch_file_location (mtp, &small); - fetch_file_location (mtp, &big); - } - users_num = fetch_int (mtp); - date = fetch_int (mtp); - if (fetch_bool (mtp)) { - y |= FLAG_CHAT_IN_CHAT; - } - version = fetch_int (mtp); - } else { - small.dc = -2; - big.dc = -2; - users_num = -1; - date = fetch_int (mtp); - version = -1; - } - - bl_do_create_chat (mtp->bl, mtp, C, y, s, l, users_num, date, version, &big, &small); - } else { - if (x == CODE_chat_forbidden) { - bl_do_chat_forbid (mtp->bl, mtp, C, 1); - } else { - bl_do_chat_forbid (mtp->bl, mtp, C, 0); - } - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - bl_do_set_chat_title (mtp->bl, mtp, 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 (mtp); - if (y == CODE_chat_photo_empty) { - small.dc = -2; - big.dc = -2; - } else { - assert (y == CODE_chat_photo); - fetch_file_location (mtp, &small); - fetch_file_location (mtp, &big); - } - bl_do_set_chat_photo (mtp->bl, mtp, C, &big, &small); - int users_num = fetch_int (mtp); - bl_do_set_chat_date (mtp->bl, mtp, C, fetch_int (mtp)); - bl_do_set_chat_set_in_chat (mtp->bl, mtp, C, fetch_bool (mtp)); - bl_do_set_chat_version (mtp->bl, mtp, C, users_num, fetch_int (mtp)); - } else { - bl_do_set_chat_date (mtp->bl, mtp, C, fetch_int (mtp)); - } - } -} - -void fetch_notify_settings (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_peer_notify_settings || x == CODE_peer_notify_settings_empty || x == CODE_peer_notify_settings_old); - if (x == CODE_peer_notify_settings_old) { - fetch_int (mtp); // mute_until - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_bool (mtp); // show_previews - fetch_int (mtp); // peer notify events - } - if (x == CODE_peer_notify_settings) { - fetch_int (mtp); // mute_until - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_bool (mtp); // show_previews - fetch_int (mtp); // events_mask - } -} - -void fetch_chat_full (struct mtproto_connection *mtp, struct chat *C) { - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_chat_full); - assert (fetch_int (mtp) == CODE_chat_full); - C->id = MK_CHAT (fetch_int (mtp)); - //C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); - //C->flags |= FLAG_CREATED; - x = fetch_int (mtp); - int version = 0; - struct chat_user *users = 0; - int users_num = 0; - int admin_id = 0; - - if (x == CODE_chat_participants) { - assert (fetch_int (mtp) == get_peer_id (C->id)); - admin_id = fetch_int (mtp); - assert (fetch_int (mtp) == CODE_vector); - users_num = fetch_int (mtp); - users = talloc (sizeof (struct chat_user) * users_num); - int i; - for (i = 0; i < users_num; i++) { - assert (fetch_int (mtp) == (int)CODE_chat_participant); - users[i].user_id = fetch_int (mtp); - users[i].inviter_id = fetch_int (mtp); - users[i].date = fetch_int (mtp); - } - version = fetch_int (mtp); - } - int *start = mtp->in_ptr; - fetch_skip_photo (mtp); - int *end = mtp->in_ptr; - fetch_notify_settings (mtp); - - int n, i; - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - if (admin_id) { - bl_do_set_chat_admin (mtp->bl, mtp, C, admin_id); - } - if (version > 0) { - bl_do_set_chat_participants (mtp->bl, mtp, C, version, users_num, users); - tfree (users, sizeof (struct chat_user) * users_num); - } - bl_do_set_chat_full_photo (mtp->bl, mtp, C, start, 4 * (end - start)); -} - -void fetch_photo_size (struct mtproto_connection *mtp, struct photo_size *S) { - memset (S, 0, sizeof (*S)); - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); - S->type = fetch_str_dup (mtp); - debug("s->type %s\n", S->type); - if (x != CODE_photo_size_empty) { - fetch_file_location (mtp, &S->loc); - S->w = fetch_int (mtp); - S->h = fetch_int (mtp); - if (x == CODE_photo_size) { - S->size = fetch_int (mtp); - } else { - S->size = prefetch_strlen (mtp); -// S->data = talloc (S->size); - fetch_str (mtp, S->size); -// memcpy (S->data, fetch_str (mtp, S->size), S->size); - } - } -} - -void fetch_skip_photo_size (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // type - if (x != CODE_photo_size_empty) { - fetch_skip_file_location (mtp); - mtp->in_ptr += 2; // w, h - if (x == CODE_photo_size) { - mtp->in_ptr ++; - } else { - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - } - } -} - -void fetch_geo (struct mtproto_connection *mtp, struct geo *G) { - unsigned x = fetch_int (mtp); - if (x == CODE_geo_point) { - G->longitude = fetch_double (mtp); - G->latitude = fetch_double (mtp); - } else { - assert (x == CODE_geo_point_empty); - G->longitude = 0; - G->latitude = 0; - } -} - -void fetch_skip_geo (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_geo_point || x == CODE_geo_point_empty); - if (x == CODE_geo_point) { - mtp->in_ptr += 4; - } -} - -void fetch_photo (struct mtproto_connection *mtp, struct photo *P) { - memset (P, 0, sizeof (*P)); - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_empty || x == CODE_photo); - P->id = fetch_long (mtp); - if (x == CODE_photo_empty) { return; } - P->access_hash = fetch_long (mtp); - P->user_id = fetch_int (mtp); - P->date = fetch_int (mtp); - P->caption = fetch_str_dup (mtp); - fetch_geo (mtp, &P->geo); - assert (fetch_int (mtp) == CODE_vector); - P->sizes_num = fetch_int (mtp); - debug("sizes_num %d \n", P->sizes_num); - P->sizes = talloc (sizeof (struct photo_size) * P->sizes_num); - int i; - for (i = 0; i < P->sizes_num; i++) { - fetch_photo_size (mtp, &P->sizes[i]); - } -} - -void fetch_skip_photo (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_empty || x == CODE_photo); - mtp->in_ptr += 2; // id - if (x == CODE_photo_empty) { return; } - mtp->in_ptr += 2 +1 + 1; // access_hash, user_id, date - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // caption - fetch_skip_geo (mtp); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - for (i = 0; i < n; i++) { - fetch_skip_photo_size (mtp); - } -} - -void fetch_video (struct mtproto_connection *mtp, struct video *V) { - memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (mtp); - V->id = fetch_long (mtp); - if (x == CODE_video_empty) { return; } - V->access_hash = fetch_long (mtp); - V->user_id = fetch_int (mtp); - V->date = fetch_int (mtp); - V->caption = fetch_str_dup (mtp); - V->duration = fetch_int (mtp); - V->size = fetch_int (mtp); - fetch_photo_size (mtp, &V->thumb); - V->dc_id = fetch_int (mtp); - V->w = fetch_int (mtp); - V->h = fetch_int (mtp); -} - -void fetch_skip_video (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - fetch_long (mtp); - if (x == CODE_video_empty) { return; } - fetch_skip (mtp, 4); - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_skip (mtp, 2); - fetch_skip_photo_size (mtp); - fetch_skip (mtp, 3); -} - -void fetch_audio (struct mtproto_connection *mtp, struct audio *V) { - memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (mtp); - V->id = fetch_long (mtp); - if (x == CODE_audio_empty) { return; } - V->access_hash = fetch_long (mtp); - V->user_id = fetch_int (mtp); - V->date = fetch_int (mtp); - V->duration = fetch_int (mtp); - V->size = fetch_int (mtp); - V->dc_id = fetch_int (mtp); -} - -void fetch_skip_audio (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - fetch_skip (mtp, 2); - if (x == CODE_audio_empty) { return; } - fetch_skip (mtp, 7); -} - -void fetch_document (struct mtproto_connection *mtp, struct document *V) { - memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (mtp); - V->id = fetch_long (mtp); - if (x == CODE_document_empty) { return; } - V->access_hash = fetch_long (mtp); - V->user_id = fetch_int (mtp); - V->date = fetch_int (mtp); - V->caption = fetch_str_dup (mtp); - V->mime_type = fetch_str_dup (mtp); - V->size = fetch_int (mtp); - fetch_photo_size (mtp, &V->thumb); - V->dc_id = fetch_int (mtp); -} - -void fetch_skip_document (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - fetch_skip (mtp, 2); - if (x == CODE_document_empty) { return; } - fetch_skip (mtp, 4); - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_skip (mtp, 1); - fetch_skip_photo_size (mtp); - fetch_skip (mtp, 1); -} - -void fetch_message_action (struct mtproto_connection *mtp, struct message_action *M) { - memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (mtp); - M->type = x; - switch (x) { - case CODE_message_action_empty: - break; - case CODE_message_action_geo_chat_create: - { - int l = prefetch_strlen (mtp); // title - char *s = fetch_str (mtp, l); - int l2 = prefetch_strlen (mtp); // checkin - char *s2 = fetch_str (mtp, l2); - debug ("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 (mtp); - assert (fetch_int (mtp) == (int)CODE_vector); - M->user_num = fetch_int (mtp); - M->users = talloc (M->user_num * 4); - fetch_ints (mtp, M->users, M->user_num); - break; - case CODE_message_action_chat_edit_title: - M->new_title = fetch_str_dup (mtp); - break; - case CODE_message_action_chat_edit_photo: - fetch_photo (mtp, &M->photo); - break; - case CODE_message_action_chat_delete_photo: - break; - case CODE_message_action_chat_add_user: - M->user = fetch_int (mtp); - break; - case CODE_message_action_chat_delete_user: - M->user = fetch_int (mtp); - break; - default: - assert (0); - } -} - -void fetch_skip_message_action (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - int l; - switch (x) { - case CODE_message_action_empty: - break; - case CODE_message_action_geo_chat_create: - { - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - } - break; - case CODE_message_action_geo_chat_checkin: - break; - case CODE_message_action_chat_create: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - assert (fetch_int (mtp) == (int)CODE_vector); - l = fetch_int (mtp); - fetch_skip (mtp, l); - break; - case CODE_message_action_chat_edit_title: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_message_action_chat_edit_photo: - fetch_skip_photo (mtp); - break; - case CODE_message_action_chat_delete_photo: - break; - case CODE_message_action_chat_add_user: - fetch_int (mtp); - break; - case CODE_message_action_chat_delete_user: - fetch_int (mtp); - break; - default: - assert (0); - } -} - -void fetch_message_short (struct mtproto_connection *mtp, struct message *M) { - struct telegram *instance = mtp->instance; - - int new = !(M->flags & FLAG_CREATED); - - if (new) { - int id = fetch_int (mtp); - int from_id = fetch_int (mtp); - int to_id = instance->our_id; - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - - fetch_pts (mtp); - - int date = fetch_int (mtp); - fetch_seq (mtp); - - bl_do_create_message_text (mtp->bl, mtp, id, from_id, PEER_USER, to_id, date, l, s); - } else { - fetch_int (mtp); // id - fetch_int (mtp); // from_id - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // text - - fetch_pts (mtp); - fetch_int (mtp); - fetch_seq (mtp); - } -} - -void fetch_message_short_chat (struct mtproto_connection *mtp, struct message *M) { - int new = !(M->flags & FLAG_CREATED); - - if (new) { - int id = fetch_int (mtp); - int from_id = fetch_int (mtp); - int to_id = fetch_int (mtp); - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - - fetch_pts (mtp); - - int date = fetch_int (mtp); - fetch_seq (mtp); - - bl_do_create_message_text (mtp->bl, mtp, id, from_id, PEER_CHAT, to_id, date, l, s); - } else { - fetch_int (mtp); // id - fetch_int (mtp); // from_id - fetch_int (mtp); // to_id - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // text - - fetch_pts (mtp); - fetch_int (mtp); - fetch_seq (mtp); - } -} - - -void fetch_message_media (struct mtproto_connection *mtp, struct message_media *M) { - memset (M, 0, sizeof (*M)); - M->type = fetch_int (mtp); - switch (M->type) { - case CODE_message_media_empty: - break; - case CODE_message_media_photo: - fetch_photo (mtp, &M->photo); - break; - case CODE_message_media_video: - fetch_video (mtp, &M->video); - break; - case CODE_message_media_audio: - fetch_audio (mtp, &M->audio); - break; - case CODE_message_media_document: - fetch_document (mtp, &M->document); - break; - case CODE_message_media_geo: - fetch_geo (mtp, &M->geo); - break; - case CODE_message_media_contact: - M->phone = fetch_str_dup (mtp); - M->first_name = fetch_str_dup (mtp); - M->last_name = fetch_str_dup (mtp); - M->user_id = fetch_int (mtp); - break; - case CODE_message_media_unsupported: - M->data_size = prefetch_strlen (mtp); - M->data = talloc (M->data_size); - memcpy (M->data, fetch_str (mtp, M->data_size), M->data_size); - break; - default: - debug ("type = 0x%08x\n", M->type); - assert (0); - } -} - -void fetch_skip_message_media (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - switch (x) { - case CODE_message_media_empty: - break; - case CODE_message_media_photo: - fetch_skip_photo (mtp); - break; - case CODE_message_media_video: - fetch_skip_video (mtp); - break; - case CODE_message_media_audio: - fetch_skip_audio (mtp); - break; - case CODE_message_media_document: - fetch_skip_document (mtp); - break; - case CODE_message_media_geo: - fetch_skip_geo (mtp); - break; - case CODE_message_media_contact: - { - int l; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_int (mtp); - } - break; - case CODE_message_media_unsupported: - { - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - } - break; - default: - debug ("type = 0x%08x\n", x); - assert (0); - } -} - -void fetch_skip_message_media_encrypted (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - int l; - switch (x) { - case CODE_decrypted_message_media_empty: - break; - case CODE_decrypted_message_media_photo: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_skip (mtp, 5); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_video: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - - fetch_skip (mtp, 6); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_audio: - fetch_skip (mtp, 2); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_document: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - - fetch_skip (mtp, 2); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_skip (mtp, 1); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_geo_point: - fetch_skip (mtp, 4); - break; - case CODE_decrypted_message_media_contact: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_skip (mtp, 1); - break; - default: - debug ("type = 0x%08x\n", x); - assert (0); - } -} - -void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct message_media *M) { - memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (mtp); - int l; - switch (x) { - case CODE_decrypted_message_media_empty: - M->type = CODE_message_media_empty; - break; - case CODE_decrypted_message_media_photo: - M->type = x; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_int (mtp); // thumb_w - fetch_int (mtp); // thumb_h - M->encr_photo.w = fetch_int (mtp); - M->encr_photo.h = fetch_int (mtp); - M->encr_photo.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_photo.key = talloc (32); - memset (M->encr_photo.key, 0, 32); - if (l <= 32) { - memcpy (M->encr_photo.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_photo.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_photo.iv = talloc (32); - l = prefetch_strlen (mtp); - assert (l > 0); - memset (M->encr_photo.iv, 0, 32); - if (l <= 32) { - memcpy (M->encr_photo.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_photo.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; - case CODE_decrypted_message_media_video: - M->type = x; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_int (mtp); // thumb_w - fetch_int (mtp); // thumb_h - M->encr_video.duration = fetch_int (mtp); - M->encr_video.w = fetch_int (mtp); - M->encr_video.h = fetch_int (mtp); - M->encr_video.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_video.key = talloc0 (32); - if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_video.iv = talloc (32); - l = prefetch_strlen (mtp); - assert (l > 0); - memset (M->encr_video.iv, 0, 32); - if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; - case CODE_decrypted_message_media_audio: - M->type = x; - M->encr_audio.duration = fetch_int (mtp); - M->encr_audio.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_video.key = talloc0 (32); - if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_video.iv = talloc0 (32); - l = prefetch_strlen (mtp); - assert (l > 0); - if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; - case CODE_decrypted_message_media_document: - M->type = x; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_int (mtp); // thumb_w - fetch_int (mtp); // thumb_h - M->encr_document.file_name = fetch_str_dup (mtp); - M->encr_document.mime_type = fetch_str_dup (mtp); - M->encr_video.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_video.key = talloc0 (32); - if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_video.iv = talloc0 (32); - l = prefetch_strlen (mtp); - assert (l > 0); - if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; -/* case CODE_decrypted_message_media_file: - M->type = x; - M->encr_file.filename = fetch_str_dup (mtp); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = fetch_int (mtp); - assert (l > 0); - M->encr_file.key = talloc (l); - memcpy (M->encr_file.key, fetch_str (mtp, l), l); - - l = fetch_int (mtp); - assert (l > 0); - M->encr_file.iv = talloc (l); - memcpy (M->encr_file.iv, fetch_str (mtp, l), l); - break; - */ - case CODE_decrypted_message_media_geo_point: - M->geo.longitude = fetch_double (mtp); - M->geo.latitude = fetch_double (mtp); - M->type = CODE_message_media_geo; - break; - case CODE_decrypted_message_media_contact: - M->type = CODE_message_media_contact; - M->phone = fetch_str_dup (mtp); - M->first_name = fetch_str_dup (mtp); - M->last_name = fetch_str_dup (mtp); - M->user_id = fetch_int (mtp); - break; - default: - debug ("type = 0x%08x\n", x); - assert (0); - } -} - -void fetch_skip_message_action_encrypted (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - switch (x) { - case CODE_decrypted_message_action_set_message_t_t_l: - fetch_skip (mtp, 1); - break; - default: - debug ("x = 0x%08x\n", x); - assert (0); - } -} - -void fetch_message_action_encrypted (struct mtproto_connection *mtp, struct message_action *M) { - unsigned x = fetch_int (mtp); - switch (x) { - case CODE_decrypted_message_action_set_message_t_t_l: - M->type = x; - M->ttl = fetch_int (mtp); - break; - default: - debug ("x = 0x%08x\n", x); - assert (0); - } -} - -peer_id_t fetch_peer_id (struct mtproto_connection *mtp) { - unsigned x =fetch_int (mtp); - if (x == CODE_peer_user) { - return MK_USER (fetch_int (mtp)); - } else { - assert (CODE_peer_chat); - return MK_CHAT (fetch_int (mtp)); - } -} - -void fetch_message (struct mtproto_connection *mtp, struct message *M) { - unsigned x = fetch_int (mtp); - assert (x == CODE_message_empty || x == CODE_message || x == CODE_message_forwarded || x == CODE_message_service); - int id = fetch_int (mtp); - assert (M->id == id); - if (x == CODE_message_empty) { - return; - } - int fwd_from_id = 0; - int fwd_date = 0; - - if (x == CODE_message_forwarded) { - fwd_from_id = fetch_int (mtp); - fwd_date = fetch_int (mtp); - } - int from_id = fetch_int (mtp); - peer_id_t to_id = fetch_peer_id (mtp); - - fetch_bool (mtp); // out. - - int unread = fetch_bool (mtp); - int date = fetch_int (mtp); - - int new = !(M->flags & FLAG_CREATED); - - if (x == CODE_message_service) { - int *start = mtp->in_ptr; - fetch_skip_message_action (mtp); - if (new) { - if (fwd_from_id) { - bl_do_create_message_service_fwd (mtp->bl, mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), - date, fwd_from_id, fwd_date, start, (mtp->in_ptr - start)); - } else { - bl_do_create_message_service (mtp->bl, mtp, id, from_id, get_peer_type (to_id), - get_peer_id (to_id), date, start, (mtp->in_ptr - start)); - } - } - } else { - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - int *start = mtp->in_ptr; - fetch_skip_message_media (mtp); - if (new) { - if (fwd_from_id) { - bl_do_create_message_media_fwd (mtp->bl, mtp, id, from_id, get_peer_type (to_id), - get_peer_id (to_id), date, fwd_from_id, fwd_date, l, s, start, mtp->in_ptr - start); - } else { - bl_do_create_message_media (mtp->bl, mtp, id, from_id, get_peer_type (to_id), - get_peer_id (to_id), date, l, s, start, mtp->in_ptr - start); - } - } - } - bl_do_set_unread (mtp->bl, mtp, M, unread); -} - -void fetch_geo_message (struct mtproto_connection *mtp, struct message *M) { - memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (mtp); - assert (x == CODE_geo_chat_message_empty || x == CODE_geo_chat_message || x == CODE_geo_chat_message_service); - M->to_id = MK_GEO_CHAT (fetch_int (mtp)); - M->id = fetch_int (mtp); - if (x == CODE_geo_chat_message_empty) { - M->flags |= 1; - return; - } - M->from_id = MK_USER (fetch_int (mtp)); - M->date = fetch_int (mtp); - if (x == CODE_geo_chat_message_service) { - M->service = 1; - fetch_message_action (mtp, &M->action); - } else { - M->message = fetch_str_dup (mtp); - M->message_len = strlen (M->message); - fetch_message_media (mtp, &M->media); - } -} - -static int *decr_ptr; -static int *decr_end; - -int decrypt_encrypted_message (struct secret_chat *E) { - int *msg_key = decr_ptr; - decr_ptr += 4; - assert (decr_ptr < decr_end); - static unsigned char sha1a_buffer[20]; - static unsigned char sha1b_buffer[20]; - static unsigned char sha1c_buffer[20]; - static unsigned char sha1d_buffer[20]; - - static unsigned char buf[64]; - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key, 32); - sha1 (buf, 48, sha1a_buffer); - - memcpy (buf, E->key + 8, 16); - memcpy (buf + 16, msg_key, 16); - memcpy (buf + 32, E->key + 12, 16); - sha1 (buf, 48, sha1b_buffer); - - memcpy (buf, E->key + 16, 32); - memcpy (buf + 32, msg_key, 16); - sha1 (buf, 48, sha1c_buffer); - - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key + 24, 32); - sha1 (buf, 48, sha1d_buffer); - - static unsigned char key[32]; - memcpy (key, sha1a_buffer + 0, 8); - memcpy (key + 8, sha1b_buffer + 8, 12); - memcpy (key + 20, sha1c_buffer + 4, 12); - - static unsigned char iv[32]; - memcpy (iv, sha1a_buffer + 8, 12); - memcpy (iv + 12, sha1b_buffer + 0, 8); - memcpy (iv + 20, sha1c_buffer + 16, 4); - memcpy (iv + 24, sha1d_buffer + 0, 8); - - AES_KEY aes_key; - AES_set_decrypt_key (key, 256, &aes_key); - AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); - memset (&aes_key, 0, sizeof (aes_key)); - - int x = *(decr_ptr); - if (x < 0 || (x & 3)) { - return -1; - } - assert (x >= 0 && !(x & 3)); - sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer); - - if (memcmp (sha1a_buffer + 4, msg_key, 16)) { - failure ("Sha1 mismatch\n"); - return -1; - } - return 0; -} - -void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) { - struct binlog *bl = mtp->bl; - - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service); - unsigned sx = x; - int new = !(M->flags & FLAG_CREATED); - long long id = fetch_long (mtp); - int to_id = fetch_int (mtp); - peer_id_t chat = MK_ENCR_CHAT (to_id); - int date = fetch_int (mtp); - - peer_t *P = user_chat_get (bl, chat); - if (!P) { - warning ("Encrypted message to unknown chat. Dropping\n"); - M->flags |= FLAG_MESSAGE_EMPTY; - } - - - int len = prefetch_strlen (mtp); - assert ((len & 15) == 8); - decr_ptr = (void *)fetch_str (mtp, len); - decr_end = decr_ptr + (len / 4); - int ok = 0; - if (P) { - if (*(long long *)decr_ptr != P->encr_chat.key_fingerprint) { - warning ("Encrypted message with bad fingerprint to chat %s\n", P->print_name); - P = 0; - } - decr_ptr += 2; - } - int l = 0; - char *s = 0; - int *start = 0; - int *end = 0; - x = 0; - if (P && decrypt_encrypted_message (&P->encr_chat) >= 0 && new) { - ok = 1; - int *save_in_ptr = mtp->in_ptr; - int *save_in_end = mtp->in_end; - mtp->in_ptr = decr_ptr; - int ll = fetch_int (mtp); - mtp->in_end = mtp->in_ptr + ll; - x = fetch_int (mtp); - if (x == CODE_decrypted_message_layer) { - int layer = fetch_int (mtp); - assert (layer >= 0); - x = fetch_int (mtp); - } - assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service); - //assert (id == fetch_long (mtp)); - fetch_long (mtp); - ll = prefetch_strlen (mtp); - fetch_str (mtp, ll); // random_bytes - if (x == CODE_decrypted_message) { - l = prefetch_strlen (mtp); - s = fetch_str (mtp, l); - start = mtp->in_ptr; - fetch_skip_message_media_encrypted (mtp); - end = mtp->in_ptr; - } else { - start = mtp->in_ptr; - fetch_skip_message_action_encrypted (mtp); - end = mtp->in_ptr; - } - mtp->in_ptr = save_in_ptr; - mtp->in_end = save_in_end; - } - - if (sx == CODE_encrypted_message) { - if (ok) { - int *start_file = mtp->in_ptr; - fetch_skip_encrypted_message_file (mtp); - if (x == CODE_decrypted_message) { - bl_do_create_message_media_encr (mtp->bl, mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, mtp->in_ptr - start_file); - } - } else { - x = fetch_int (mtp); - if (x == CODE_encrypted_file) { - fetch_skip (mtp, 7); - } else { - assert (x == CODE_encrypted_file_empty); - } - M->media.type = CODE_message_media_empty; - } - } else { - if (ok && x == CODE_decrypted_message_service) { - bl_do_create_message_service_encr (mtp->bl, mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, start, end - start); - } - } -} - -void fetch_encrypted_message_file (struct mtproto_connection *mtp, struct message_media *M) { - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); - if (x == CODE_encrypted_file_empty) { - assert (M->type != CODE_decrypted_message_media_photo && M->type != CODE_decrypted_message_media_video); - } else { - assert (M->type == CODE_decrypted_message_media_document || M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video || M->type == CODE_decrypted_message_media_audio); - - M->encr_photo.id = fetch_long(mtp); - M->encr_photo.access_hash = fetch_long(mtp); - if (!M->encr_photo.size) { - M->encr_photo.size = fetch_int (mtp); - } else { - fetch_int (mtp); - } - M->encr_photo.dc_id = fetch_int(mtp); - M->encr_photo.key_fingerprint = fetch_int(mtp); - } -} - -void fetch_skip_encrypted_message_file (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); - if (x == CODE_encrypted_file_empty) { - } else { - fetch_skip (mtp, 7); - } -} - -static int id_cmp (struct message *M1, struct message *M2) { - if (M1->id < M2->id) { return -1; } - else if (M1->id > M2->id) { return 1; } - else { return 0; } -} - -struct tgl_user *fetch_alloc_user (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->instance->bl; - - debug("fetch_alloc_user()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (bl, MK_USER (data[1])); - if (!U) { - bl->users_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_USER (data[1]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - fetch_user (mtp, &U->user); - event_update_user_status(mtp->connection->instance, U); - event_peer_allocated(mtp->connection->instance, U); - } else { - fetch_user (mtp, &U->user); - event_update_user_status(mtp->connection->instance, U); - } - return &U->user; -} - -struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - - debug("fetch_alloc_encrypted_chat()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (bl, MK_ENCR_CHAT (data[1])); - if (!U) { - U = talloc0 (sizeof (*U)); - U->id = MK_ENCR_CHAT (data[1]); - bl->encr_chats_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - } - fetch_encrypted_chat (mtp, &U->encr_chat); - event_peer_allocated(mtp->connection->instance, U); - return &U->encr_chat; -} - -void insert_encrypted_chat (struct binlog *bl, peer_t *P) { - bl->encr_chats_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; -} - -void insert_user (struct binlog *bl, peer_t *P) { - bl->users_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; -} - -void insert_chat (struct binlog *bl, peer_t *P) { - bl->chats_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; -} - -struct tgl_user *fetch_alloc_user_full (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - int data[3]; - prefetch_data (mtp, data, 12); - peer_t *U = user_chat_get (bl, MK_USER (data[2])); - if (U) { - fetch_user_full (mtp, &U->user); - return &U->user; - } else { - bl->users_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_USER (data[2]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - fetch_user_full (mtp, &U->user); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - return &U->user; - } -} - -void free_user (struct tgl_user *U) { - if (U->first_name) { tfree_str (U->first_name); } - if (U->last_name) { tfree_str (U->last_name); } - if (U->print_name) { tfree_str (U->print_name); } - if (U->phone) { tfree_str (U->phone); } -} - -void free_photo_size (struct photo_size *S) { - tfree_str (S->type); - if (S->data) { - tfree (S->data, S->size); - } -} - -void free_photo (struct photo *P) { - if (!P->access_hash) { return; } - if (P->caption) { tfree_str (P->caption); } - if (P->sizes) { - int i; - for (i = 0; i < P->sizes_num; i++) { - free_photo_size (&P->sizes[i]); - } - tfree (P->sizes, sizeof (struct photo_size) * P->sizes_num); - } -} - -void free_video (struct video *V) { - if (!V->access_hash) { return; } - tfree_str (V->caption); - free_photo_size (&V->thumb); -} - -void free_document (struct document *D) { - if (!D->access_hash) { return; } - tfree_str (D->caption); - tfree_str (D->mime_type); - free_photo_size (&D->thumb); -} - -void free_message_media (struct message_media *M) { - switch (M->type) { - case CODE_message_media_empty: - case CODE_message_media_geo: - case CODE_message_media_audio: - 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: - tfree_str (M->phone); - tfree_str (M->first_name); - tfree_str (M->last_name); - return; - case CODE_message_media_document: - free_document (&M->document); - return; - case CODE_message_media_unsupported: - tfree (M->data, M->data_size); - return; - case CODE_decrypted_message_media_photo: - case CODE_decrypted_message_media_video: - case CODE_decrypted_message_media_audio: - case CODE_decrypted_message_media_document: - tfree_secure (M->encr_photo.key, 32); - tfree_secure (M->encr_photo.iv, 32); - return; - case 0: - break; - default: - debug ("%08x\n", M->type); - 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: - tfree_str (M->title); - tfree (M->users, M->user_num * 4); - break; - case CODE_message_action_chat_edit_title: - tfree_str (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; - case 0: - break; - default: - assert (0); - } -} - -void free_message (struct message *M) { - if (!M->service) { - if (M->message) { tfree (M->message, M->message_len + 1); } - 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; -} - -void message_add_peer (struct message *M) { - struct binlog *bl = M->instance->bl; - peer_id_t id; - if (!cmp_peer_id (M->to_id, MK_USER (M->instance->our_id))) { - id = M->from_id; - } else { - id = M->to_id; - } - peer_t *P = user_chat_get (bl, id); - if (!P) { - P = talloc0 (sizeof (*P)); - P->id = id; - switch (get_peer_type (id)) { - case PEER_USER: - bl->users_allocated ++; - break; - case PEER_CHAT: - bl->chats_allocated ++; - break; - case PEER_GEO_CHAT: - bl->geo_chats_allocated ++; - break; - case PEER_ENCR_CHAT: - bl->encr_chats_allocated ++; - break; - } - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; - } - if (!P->last) { - P->last = M; - M->prev = M->next = 0; - } else { - if (get_peer_type (P->id) != PEER_ENCR_CHAT) { - struct message *N = P->last; - struct message *NP = 0; - while (N && N->id > M->id) { - NP = N; - N = N->next; - } - if (N) { assert (N->id < M->id); } - M->next = N; - M->prev = NP; - if (N) { N->prev = M; } - if (NP) { NP->next = M; } - else { P->last = M; } - } else { - struct message *N = P->last; - struct message *NP = 0; - M->next = N; - M->prev = NP; - if (N) { N->prev = M; } - if (NP) { NP->next = M; } - else { P->last = M; } - } - } -} - -void message_del_peer (struct message *M) { - peer_id_t id; - if (!cmp_peer_id (M->to_id, MK_USER (M->instance->our_id))) { - id = M->from_id; - } else { - id = M->to_id; - } - peer_t *P = user_chat_get (M->instance->bl, id); - if (M->prev) { - M->prev->next = M->next; - } - if (M->next) { - M->next->prev = M->prev; - } - if (P && P->last == M) { - P->last = M->next; - } -} - -struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct telegram *instance) { - struct binlog *bl = mtp->bl; - - debug("fetch_alloc_message()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - struct message *M = message_get (bl, data[1]); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = data[1]; - message_insert_tree (M); - mtp->bl->messages_allocated ++; - fetch_message (mtp, M); - return M; - } - fetch_message (mtp, M); - return M; -} - -struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct telegram *instance) { - debug("fetch_alloc_geo_message()\n"); - struct message *M = talloc (sizeof (*M)); - M->instance = instance; - fetch_geo_message (mtp, M); - struct message *M1 = tree_lookup_message (mtp->bl->message_tree, M); - mtp->bl->messages_allocated ++; - if (M1) { - message_del_use (M1); - message_del_peer (M1); - free_message (M1); - memcpy (M1, M, sizeof (*M)); - tfree (M, sizeof (*M)); - message_add_use (M1); - message_add_peer (M1); - mtp->bl->messages_allocated --; - return M1; - } else { - message_add_use (M); - message_add_peer (M); - mtp->bl->message_tree = tree_insert_message (mtp->bl->message_tree, M, lrand48 ()); - return M; - } -} - -struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, - struct telegram *instance) { - struct binlog *bl = mtp->bl; - debug("fetch_alloc_encrypted_message()\n"); - int data[3]; - prefetch_data (mtp, data, 12); - struct message *M = message_get (bl, *(long long *)(data + 1)); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = *(long long *)(data + 1); - message_insert_tree (M); - mtp->bl->messages_allocated ++; - assert (message_get (bl, M->id) == M); - debug ("id = %lld\n", M->id); - } - fetch_encrypted_message (mtp, M); - return M; -} - -struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, - struct telegram *instance) { - struct binlog *bl = mtp->bl; - int data[1]; - prefetch_data (mtp, data, 4); - struct message *M = message_get (bl, data[0]); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = data[0]; - message_insert_tree (M); - mtp->bl->messages_allocated ++; - } - fetch_message_short (mtp, M); - return M; -} - -struct message *fetch_alloc_message_short_chat (struct mtproto_connection *mtp, struct telegram *instance) { - struct binlog *bl = mtp->bl; - int data[1]; - prefetch_data (mtp, data, 4); - struct message *M = message_get (bl, data[0]); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = data[0]; - message_insert_tree (M); - mtp->bl->messages_allocated ++; - } - fetch_message_short_chat (mtp, M); - return M; -} - -struct chat *fetch_alloc_chat (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - debug("fetch_alloc_chat()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (bl, MK_CHAT (data[1])); - debug("id %d\n", U->id.id); - debug("type %d\n", U->id.type); - if (!U) { - bl->chats_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_CHAT (data[1]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - } - fetch_chat (mtp, &U->chat); - event_peer_allocated(mtp->connection->instance, U); - return &U->chat; -} - -struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - int data[3]; - prefetch_data (mtp, data, 12); - peer_t *U = user_chat_get (bl, MK_CHAT (data[2])); - if (U) { - fetch_chat_full (mtp, &U->chat); - return &U->chat; - } else { - bl->chats_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_CHAT (data[2]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - fetch_chat_full (mtp, &U->chat); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - return &U->chat; - } -} - -void free_chat (struct chat *U) { - if (U->title) { tfree_str (U->title); } - if (U->print_title) { tfree_str (U->print_title); } -} - -int print_stat (struct binlog *bl, char *s, int len) { - return tsnprintf (s, len, - "bl->users_allocated\t%d\n" - "bl->chats_allocated\t%d\n" - "secret_bl->chats_allocated\t%d\n" - "bl->peer_num\t%d\n" - "bl->messages_allocated\t%d\n", - bl->users_allocated, - bl->chats_allocated, - bl->encr_chats_allocated, - bl->peer_num, - bl->messages_allocated - ); -} - -peer_t *user_chat_get (struct binlog *bl, peer_id_t id) { - static peer_t U; - U.id = id; - return tree_lookup_peer (bl->peer_tree, &U); -} - -struct message *message_get (struct binlog *bl, long long id) { - struct message M; - M.id = id; - return tree_lookup_message (bl->message_tree, &M); -} - -void update_message_id (struct message *M, long long id) { - struct binlog *bl = M->instance->bl; - bl->message_tree = tree_delete_message (bl->message_tree, M); - M->id = id; - bl->message_tree = tree_insert_message (bl->message_tree, M, lrand48 ()); -} - -void message_insert_tree (struct message *M) { - struct binlog *bl = M->instance->bl; - assert (M->id); - bl->message_tree = tree_insert_message (bl->message_tree, M, lrand48 ()); -} - -void message_remove_tree (struct message *M) { - struct binlog *bl = M->instance->bl; - assert (M->id); - bl->message_tree = tree_delete_message (bl->message_tree, M); -} - -void message_insert (struct message *M) { - message_add_use (M); - message_add_peer (M); -} - -void message_insert_unsent (struct message *M) { - struct binlog *bl = M->instance->bl; - bl->message_unsent_tree = tree_insert_message (bl->message_unsent_tree, M, lrand48 ()); -} - -void message_remove_unsent (struct message *M) { - struct binlog *bl = M->instance->bl; - bl->message_unsent_tree = tree_delete_message (bl->message_unsent_tree, M); -} - -void __send_msg (struct message *M) { - debug ("Resending message...\n"); - //print_message (M); - - assert(M->instance); - do_send_msg (M->instance, M); -} - -void send_all_unsent (struct binlog *bl) { - tree_act_message (bl->message_unsent_tree, __send_msg); -} - -void peer_insert_name (struct binlog *bl, peer_t *P) { - //if (!P->print_name || !strlen (P->print_name)) { return; } - //debug ("+%s\n", P->print_name); - bl->peer_by_name_tree = tree_insert_peer_by_name (bl->peer_by_name_tree, P, lrand48 ()); -} - -void peer_delete_name (struct binlog *bl, peer_t *P) { - //if (!P->print_name || !strlen (P->print_name)) { return; } - //debug ("-%s\n", P->print_name); - bl->peer_by_name_tree = tree_delete_peer_by_name (bl->peer_by_name_tree, P); -} - -peer_t *peer_lookup_name (struct binlog *bl, const char *s) { - static peer_t P; - P.print_name = (void *)s; - peer_t *R = tree_lookup_peer_by_name (bl->peer_by_name_tree, &P); - return R; -} - -void free_messages (struct binlog *bl) -{ - while (bl->message_tree) { - struct message *M = tree_get_min_message (bl->message_tree); - assert (M); - debug ("freeing message: %lld\n", M->id); - bl->message_tree = tree_delete_message (bl->message_tree, M); - bl->messages_allocated --; - free_message (M); - } -} - -void free_peers (struct binlog *bl) -{ - while (bl->peer_by_name_tree) { - bl->peer_by_name_tree = tree_delete_peer_by_name (bl->peer_by_name_tree, - tree_get_min_peer_by_name(bl->peer_by_name_tree)); - } - while (bl->peer_tree) { - union peer *P = tree_get_min_peer (bl->peer_tree); - assert (P); - bl->peer_tree = tree_delete_peer (bl->peer_tree, P); - bl->peer_num --; - free (P->print_name); - tfree (P, sizeof (union peer)); - } -} - diff --git a/structures.h b/structures.h deleted file mode 100644 index cc4ce08..0000000 --- a/structures.h +++ /dev/null @@ -1,423 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __STRUCTURES_H__ -#define __STRUCTURES_H__ -#pragma once - -// forward-declrataions -struct mtproto_connection; -struct binlog; -typedef struct { int type; int id; } peer_id_t; - -#include - -//#define FLAG_EMPTY 1 -#define FLAG_MESSAGE_EMPTY 1 -#define FLAG_DELETED 2 -#define FLAG_FORBIDDEN 4 -#define FLAG_HAS_PHOTO 8 -#define FLAG_CREATED 16 - -#define FLAG_USER_SELF 128 -#define FLAG_USER_FOREIGN 256 -#define FLAG_USER_CONTACT 512 -#define FLAG_USER_IN_CONTACT 1024 -#define FLAG_USER_OUT_CONTACT 2048 - -#define FLAG_CHAT_IN_CHAT 128 - -#define FLAG_ENCRYPTED 4096 -#define FLAG_PENDING 8192 - - -struct file_location { - int dc; - long long volume; - int local_id; - long long secret; -}; - -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 encr_photo { - long long id; - long long access_hash; - int dc_id; - int size; - int key_fingerprint; - - unsigned char *key; - unsigned char *iv; - int w; - int h; -}; - -struct encr_video { - long long id; - long long access_hash; - int dc_id; - int size; - int key_fingerprint; - - unsigned char *key; - unsigned char *iv; - int w; - int h; - int duration; -}; - -struct encr_audio { - long long id; - long long access_hash; - int dc_id; - int size; - int key_fingerprint; - - unsigned char *key; - unsigned char *iv; - int duration; -}; - -struct encr_document { - long long id; - long long access_hash; - int dc_id; - int size; - int key_fingerprint; - - unsigned char *key; - unsigned char *iv; - char *file_name; - char *mime_type; -}; - -struct encr_file { - char *filename; - unsigned char *key; - unsigned char *iv; -}; - - -struct user_status { - int online; - int when; -}; - -struct tgl_user { - peer_id_t id; - int flags; - struct message *last; - char *print_name; - int structure_version; - struct file_location photo_big; - struct file_location photo_small; - long long photo_id; - struct photo photo; - char *first_name; - char *last_name; - char *phone; - long long access_hash; - struct user_status status; - int blocked; - char *real_first_name; - char *real_last_name; -}; - - -struct chat_user { - int user_id; - int inviter_id; - int date; -}; - -struct chat { - peer_id_t id; - int flags; - struct message *last; - char *print_title; - int structure_version; - struct file_location photo_big; - struct file_location photo_small; - struct photo photo; - char *title; - int users_num; - int user_list_size; - int user_list_version; - struct chat_user *user_list; - int date; - int version; - int admin_id; -}; - -enum secret_chat_state { - sc_none, - sc_waiting, - sc_request, - sc_ok, - sc_deleted -}; - -struct secret_chat { - peer_id_t id; - int flags; - struct message *last; - char *print_name; - int structure_version; - struct file_location photo_big; - struct file_location photo_small; - struct photo photo; - int user_id; - int admin_id; - int date; - int ttl; - long long access_hash; - unsigned char *g_key; - unsigned char *nonce; - - enum secret_chat_state state; - int key[64]; - long long key_fingerprint; -}; - -typedef union peer { - struct { - peer_id_t id; - int flags; - struct message *last; - char *print_name; - int structure_version; - struct file_location photo_big; - struct file_location photo_small; - struct photo photo; - }; - struct tgl_user user; - struct chat chat; - struct secret_chat encr_chat; -} peer_t; - -struct video { - long long id; - long long access_hash; - int user_id; - int date; - int size; - int dc_id; - struct photo_size thumb; - char *caption; - int duration; - int w; - int h; -}; - -struct audio { - long long id; - long long access_hash; - int user_id; - int date; - int size; - int dc_id; - int duration; -}; - -struct document { - long long id; - long long access_hash; - int user_id; - int date; - int size; - int dc_id; - struct photo_size thumb; - char *caption; - char *mime_type; -}; - -struct message_action { - unsigned type; - union { - struct { - char *title; - int user_num; - int *users; - }; - char *new_title; - struct photo photo; - int user; - int ttl; - }; -}; - -struct message_media { - unsigned type; - union { - struct photo photo; - struct video video; - struct audio audio; - struct document document; - struct geo geo; - struct { - char *phone; - char *first_name; - char *last_name; - int user_id; - }; - struct encr_photo encr_photo; - struct encr_video encr_video; - struct encr_audio encr_audio; - struct encr_document encr_document; - struct encr_file encr_file; - struct { - void *data; - int data_size; - }; - }; -}; - -struct message { - struct message *next_use, *prev_use; - struct message *next, *prev; - long long id; - int flags; - peer_id_t fwd_from_id; - int fwd_date; - peer_id_t from_id; - peer_id_t to_id; - int out; - int unread; - int date; - int service; - struct telegram *instance; - union { - struct message_action action; - struct { - char *message; - int message_len; - struct message_media media; - }; - }; -}; - -int fetch_file_location (struct mtproto_connection *mtp, struct file_location *loc); -int fetch_user_status (struct mtproto_connection *mtp, struct user_status *S); -int fetch_user (struct mtproto_connection *mtp, struct tgl_user *U); -struct tgl_user *fetch_alloc_user (struct mtproto_connection *mtp); -struct tgl_user *fetch_alloc_user_full (struct mtproto_connection *mtp); -struct chat *fetch_alloc_chat (struct mtproto_connection *mtp); -struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp); -struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp); -struct message *fetch_alloc_message (struct mtproto_connection *self, struct telegram *instance); -struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct telegram *instance); -struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, struct telegram *instance); -struct message *fetch_alloc_message_short_chat (struct mtproto_connection *self, struct telegram *instance); -struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, struct telegram *instance); -void fetch_encrypted_message_file (struct mtproto_connection *mtp, struct message_media *M); -void fetch_skip_encrypted_message_file (struct mtproto_connection *mtp); -void fetch_message_action_encrypted (struct mtproto_connection *mtp, struct message_action *M); -peer_id_t fetch_peer_id (struct mtproto_connection *mtp); - -void fetch_message_media (struct mtproto_connection *mtp, struct message_media *M); -void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct message_media *M); -void fetch_message_action (struct mtproto_connection *mtp, struct message_action *M); -void message_insert_tree (struct message *M); - -void free_user (struct tgl_user *U); -void free_chat (struct chat *U); - -char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); - -int print_stat (struct binlog *bl, char *s, int len); -peer_t *user_chat_get (struct binlog *bl, peer_id_t id); -struct message *message_get (struct binlog *bl, long long id); -void update_message_id (struct message *M, long long id); -void message_insert (struct message *M); -void fetch_photo (struct mtproto_connection *mtp, struct photo *P); -void insert_encrypted_chat (struct binlog *bl, peer_t *P); -void insert_user (struct binlog *bl, peer_t *P); -void insert_chat (struct binlog *bl, peer_t *P); -void free_photo (struct photo *P); -void message_insert_unsent (struct message *M); -void message_remove_unsent (struct message *M); -void send_all_unsent (struct binlog *bl); -void message_remove_tree (struct message *M); -void message_add_peer (struct message *M); -void message_del_peer (struct message *M); -void free_message (struct message *M); -void message_del_use (struct message *M); -void peer_insert_name (struct binlog *bl, peer_t *P); -void peer_delete_name (struct binlog *bl, peer_t *P); -peer_t *peer_lookup_name (struct binlog *bl, const char *s); - -int user_get_alias(peer_t *user, char *buffer, int maxlen); - -#define PEER_USER 1 -#define PEER_CHAT 2 -#define PEER_GEO_CHAT 3 -#define PEER_ENCR_CHAT 4 -#define PEER_UNKNOWN 0 - -#define MK_USER(id) set_peer_id (PEER_USER,id) -#define MK_CHAT(id) set_peer_id (PEER_CHAT,id) -#define MK_GEO_CHAT(id) set_peer_id (PEER_GEO_CHAT,id) -#define MK_ENCR_CHAT(id) set_peer_id (PEER_ENCR_CHAT,id) - -static inline int get_peer_type (peer_id_t id) { - return id.type; -} - -static inline int get_peer_id (peer_id_t id) { - return id.id; -} - -static inline peer_id_t set_peer_id (int type, int id) { - peer_id_t ID; - ID.id = id; - ID.type = type; - return ID; -} - -static inline int cmp_peer_id (peer_id_t a, peer_id_t b) { - return memcmp (&a, &b, sizeof (a)); -} - -void free_messages (struct binlog *bl); -void free_peers (struct binlog *bl); -#endif - diff --git a/telegram-base.c b/telegram-base.c new file mode 100644 index 0000000..abae430 --- /dev/null +++ b/telegram-base.c @@ -0,0 +1,372 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "telegram-purple.h" +#include "msglog.h" + +#define DC_SERIALIZED_MAGIC 0x868aa81d +#define STATE_FILE_MAGIC 0x28949a93 +#define SECRET_CHAT_FILE_MAGIC 0x37a1988a + + +void read_state_file (struct tgl_state *TLS) { + char *name = 0; + if (asprintf (&name, "%s/%s", TLS->base_path, "state") < 0) { + return; + } + + int state_file_fd = open (name, O_CREAT | O_RDWR, 0600); + free (name); + + if (state_file_fd < 0) { + return; + } + int version, magic; + if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; } + if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; } + if (read (state_file_fd, &version, 4 || version < 0) < 4) { close (state_file_fd); return; } + int x[4]; + if (read (state_file_fd, x, 16) < 16) { + close (state_file_fd); + return; + } + int pts = x[0]; + int qts = x[1]; + int seq = x[2]; + int date = x[3]; + close (state_file_fd); + bl_do_set_seq (TLS, seq); + bl_do_set_pts (TLS, pts); + bl_do_set_qts (TLS, qts); + bl_do_set_date (TLS, date); +} + +void write_state_file (struct tgl_state *TLS) { + int wseq; + int wpts; + int wqts; + int wdate; + wseq = TLS->seq; wpts = TLS->pts; wqts = TLS->qts; wdate = TLS->date; + + char *name = 0; + if (asprintf (&name, "%s/%s", TLS->base_path, "state") < 0) { + return; + } + + int state_file_fd = open (name, O_CREAT | O_RDWR, 0600); + free (name); + + if (state_file_fd < 0) { + return; + } + int x[6]; + x[0] = STATE_FILE_MAGIC; + x[1] = 0; + x[2] = wpts; + x[3] = wqts; + x[4] = wseq; + x[5] = wdate; + assert (write (state_file_fd, x, 24) == 24); + close (state_file_fd); +} + +void write_dc (struct tgl_dc *DC, void *extra) { + int auth_file_fd = *(int *)extra; + if (!DC) { + int x = 0; + assert (write (auth_file_fd, &x, 4) == 4); + return; + } else { + int x = 1; + assert (write (auth_file_fd, &x, 4) == 4); + } + + assert (DC->has_auth); + + assert (write (auth_file_fd, &DC->port, 4) == 4); + int l = strlen (DC->ip); + assert (write (auth_file_fd, &l, 4) == 4); + assert (write (auth_file_fd, DC->ip, l) == l); + assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); + assert (write (auth_file_fd, DC->auth_key, 256) == 256); +} + +void write_auth_file (struct tgl_state *TLS) { + char *name = 0; + if (asprintf (&name, "%s/%s", TLS->base_path, "auth") < 0) { + return; + } + int auth_file_fd = open (name, O_CREAT | O_RDWR, 0600); + free (name); + if (auth_file_fd < 0) { return; } + int x = DC_SERIALIZED_MAGIC; + assert (write (auth_file_fd, &x, 4) == 4); + assert (write (auth_file_fd, &TLS->max_dc_num, 4) == 4); + assert (write (auth_file_fd, &TLS->dc_working_num, 4) == 4); + + tgl_dc_iterator_ex (TLS, write_dc, &auth_file_fd); + + assert (write (auth_file_fd, &TLS->our_id, 4) == 4); + close (auth_file_fd); +} + +void read_dc (struct tgl_state *TLS, int auth_file_fd, int id, unsigned ver) { + int port = 0; + assert (read (auth_file_fd, &port, 4) == 4); + int l = 0; + assert (read (auth_file_fd, &l, 4) == 4); + assert (l >= 0 && l < 100); + char ip[100]; + assert (read (auth_file_fd, ip, l) == l); + ip[l] = 0; + + long long auth_key_id; + static unsigned char auth_key[256]; + assert (read (auth_file_fd, &auth_key_id, 8) == 8); + assert (read (auth_file_fd, auth_key, 256) == 256); + + //bl_do_add_dc (id, ip, l, port, auth_key_id, auth_key); + bl_do_dc_option (TLS, id, 2, "DC", l, ip, port); + bl_do_set_auth_key_id (TLS, id, auth_key); + bl_do_dc_signed (TLS, id); +} + +void empty_auth_file (struct tgl_state *TLS) { + if (TLS->test_mode) { + bl_do_dc_option (TLS, 1, 0, "", strlen (TG_SERVER_TEST_1), TG_SERVER_TEST_1, 443); + bl_do_dc_option (TLS, 2, 0, "", strlen (TG_SERVER_TEST_2), TG_SERVER_TEST_2, 443); + bl_do_dc_option (TLS, 3, 0, "", strlen (TG_SERVER_TEST_3), TG_SERVER_TEST_3, 443); + bl_do_set_working_dc (TLS, TG_SERVER_TEST_DEFAULT); + } else { + bl_do_dc_option (TLS, 1, 0, "", strlen (TG_SERVER_1), TG_SERVER_1, 443); + bl_do_dc_option (TLS, 2, 0, "", strlen (TG_SERVER_2), TG_SERVER_2, 443); + bl_do_dc_option (TLS, 3, 0, "", strlen (TG_SERVER_3), TG_SERVER_3, 443); + bl_do_dc_option (TLS, 4, 0, "", strlen (TG_SERVER_4), TG_SERVER_4, 443); + bl_do_dc_option (TLS, 5, 0, "", strlen (TG_SERVER_5), TG_SERVER_5, 443); + bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT);; + } +} + +void read_auth_file (struct tgl_state *TLS) { + char *name = 0; + if (asprintf (&name, "%s/%s", TLS->base_path, "auth") < 0) { + return; + } + int auth_file_fd = open (name, O_CREAT | O_RDWR, 0600); + free (name); + if (auth_file_fd < 0) { + empty_auth_file (TLS); + return; + } + assert (auth_file_fd >= 0); + unsigned x; + unsigned m; + if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC)) { + close (auth_file_fd); + empty_auth_file (TLS); + return; + } + assert (read (auth_file_fd, &x, 4) == 4); + assert (x > 0); + int dc_working_num; + assert (read (auth_file_fd, &dc_working_num, 4) == 4); + + int i; + for (i = 0; i <= (int)x; i++) { + int y; + assert (read (auth_file_fd, &y, 4) == 4); + if (y) { + read_dc (TLS, auth_file_fd, i, m); + } + } + bl_do_set_working_dc (TLS, dc_working_num); + int our_id; + int l = read (auth_file_fd, &our_id, 4); + if (l < 4) { + assert (!l); + } + if (our_id) { + bl_do_set_our_id (TLS, our_id); + } + close (auth_file_fd); +} + +void telegram_export_authorization (struct tgl_state *TLS); +void export_auth_callback (struct tgl_state *TLS, void *extra, int success) { + assert (success); + telegram_export_authorization (TLS); +} + +void telegram_export_authorization (struct tgl_state *TLS) { + int i; + for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i] && !tgl_signed_dc (TLS, TLS->DC_list[i])) { + tgl_do_export_auth (TLS, i, export_auth_callback, (void*)(long)TLS->DC_list[i]); + return; + } + write_auth_file (TLS); + telegram_on_ready (TLS); +} + +static void request_code (struct tgl_state *TLS); +static void request_name_and_code (struct tgl_state *TLS); +static void code_receive_result (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) { + if (!success) { + debug ("Bad code...\n"); + request_code (TLS); + } else { + telegram_export_authorization (TLS); + } +} + +static void code_auth_receive_result (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) { + if (!success) { + debug ("Bad code...\n"); + request_name_and_code (TLS); + } else { + telegram_export_authorization (TLS); + } +} + +static void request_code_entered (gpointer data, const gchar *code) { + struct tgl_state *TLS = data; + telegram_conn *conn = TLS->ev_base; + char const *username = purple_account_get_username(conn->pa); + tgl_do_send_code_result (TLS, username, conn->hash, code, code_receive_result, 0) ; +} + +static void request_code_canceled (gpointer data) { + struct tgl_state *TLS = data; + telegram_conn *conn = TLS->ev_base; + + purple_connection_error_reason(conn->gc, + PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled"); +} + +static void request_name_code_entered (PurpleConnection* gc, PurpleRequestFields* fields) { + telegram_conn *conn = purple_connection_get_protocol_data(gc); + struct tgl_state *TLS = conn->TLS; + char const *username = purple_account_get_username(conn->pa); + + const char* first = purple_request_fields_get_string(fields, "first_name"); + const char* last = purple_request_fields_get_string(fields, "last_name"); + const char* code = purple_request_fields_get_string(fields, "code"); + if (!first || !last || !code) { + request_name_and_code (TLS); + return; + } + + tgl_do_send_code_result_auth (TLS, username, conn->hash, code, first, last, code_auth_receive_result, NULL); +} + +static void request_code (struct tgl_state *TLS) { + debug ("Client is not registered, registering...\n"); + telegram_conn *conn = TLS->ev_base; + + purple_request_input ( + conn->gc, // handle (the PurpleAccount) + "Telegram Code", // title + "Enter Telegram Code", // primary + "Telegram wants to verify your identity, please enter the code, that you have received via SMS.", // secondary + NULL, // default_value + 0, // multiline + 0, // masked + "code", // hint + "OK", // ok_text + G_CALLBACK(request_code_entered), // ok_cb + "Cancel", // cancel_text + G_CALLBACK(request_code_canceled), // cancel_cb + conn->pa, // account + NULL, // who + NULL, // conv + TLS // user_data + ); +} + +static void request_name_and_code (struct tgl_state *TLS) { + telegram_conn *conn = TLS->ev_base; + + debug ("Phone is not registered, registering...\n"); + + PurpleRequestFields* fields = purple_request_fields_new(); + PurpleRequestField* field = 0; + + PurpleRequestFieldGroup* group = purple_request_field_group_new("Registration"); + field = purple_request_field_string_new("first_name", "First Name", "", 0); + purple_request_field_group_add_field(group, field); + field = purple_request_field_string_new("last_name", "Last Name", "", 0); + purple_request_field_group_add_field(group, field); + purple_request_fields_add_group(fields, group); + + group = purple_request_field_group_new("Authorization"); + field = purple_request_field_string_new("code", "Telegram Code", "", 0); + purple_request_field_group_add_field(group, field); + purple_request_fields_add_group(fields, group); + + purple_request_fields(conn->gc, "Register", "Please register your phone number.", NULL, fields, "Ok", + G_CALLBACK( request_name_code_entered ), "Cancel", NULL, conn->pa, NULL, NULL, conn->gc); +} + +static void sign_in_callback (struct tgl_state *TLS, void *extra, int success, int registered, const char *mhash) { + assert (success); // TODO proper error handle + telegram_conn *conn = TLS->ev_base; + conn->hash = strdup (mhash); + + if (registered) { + request_code (TLS); + } else { + request_name_and_code (TLS); + } +} + +static void telegram_send_sms (struct tgl_state *TLS) { + if (tgl_signed_dc (TLS, TLS->DC_working)) { + telegram_export_authorization (TLS); + return; + } + telegram_conn *conn = TLS->ev_base; + char const *username = purple_account_get_username(conn->pa); + tgl_do_send_code (TLS, username, sign_in_callback, 0); +} + +static int all_authorized (struct tgl_state *TLS) { + int i; + for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) { + if (!tgl_authorized_dc (TLS, TLS->DC_list[i])) { + return 0; + } + } + return 1; +} + +static int check_all_authorized (gpointer arg) { + struct tgl_state *TLS = arg; + if (all_authorized (TLS)) { + telegram_send_sms (TLS); + return FALSE; + } else { + return TRUE; + } +} + +void telegram_login (struct tgl_state *TLS) { + read_auth_file (TLS); + read_state_file (TLS); + if (all_authorized (TLS)) { + telegram_send_sms (TLS); + return; + } + purple_timeout_add (100, check_all_authorized, TLS); +} + diff --git a/telegram-base.h b/telegram-base.h new file mode 100644 index 0000000..1496ba6 --- /dev/null +++ b/telegram-base.h @@ -0,0 +1,9 @@ +#ifndef __TELEGRAM_BASE_H__ +#define __TELEGRAM_BASE_H__ +void read_state_file (struct tgl_state *TLS); +void read_auth_file (struct tgl_state *TLS); +void write_auth_file (struct tgl_state *TLS); +void write_state_file (struct tgl_state *TLS); + +void telegram_login (struct tgl_state *TLS); +#endif diff --git a/purple-plugin/telegram-purple.c b/telegram-purple.c similarity index 57% rename from purple-plugin/telegram-purple.c rename to telegram-purple.c index 166a15e..d78dec4 100644 --- a/purple-plugin/telegram-purple.c +++ b/telegram-purple.c @@ -48,10 +48,13 @@ #include "request.h" // telegram-purple includes -#include "telegram.h" +#include #include "telegram-purple.h" -#include "structures.h" -#include "net.h" +//#include "structures.h" +#include "tgp-net.h" +#include "tgp-timers.h" +#include "msglog.h" +#include "telegram-base.h" #define CONFIG_DIR ".telegram-purple" #define BUDDYNAME_MAX_LENGTH 128 @@ -61,17 +64,11 @@ PurpleGroup *tggroup; void tgprpl_login_on_connected(); -void message_allocated_handler (struct telegram *instance, struct message *M); -void peer_allocated_handler (struct telegram *instance, void *user); -void user_info_received_handler (struct telegram *instance, struct tgl_user *user, int showInfo); -void download_finished_handler (struct telegram *instance, struct download *D); -void telegram_on_phone_registration (struct telegram *instance); -void telegram_on_client_registration (struct telegram *instance); -void on_new_user_status(struct telegram *instance, void *user); -void on_user_typing(struct telegram *instance, void *user); -void on_chat_joined (struct telegram *instance, peer_id_t chatid); static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id); -static void tgprpl_has_output(void *handle); +//static void tgprpl_has_output(void *handle); +void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C); +void on_user_get_info (struct tgl_state *TLS, void *show_info, int success, struct tgl_user *U); +static int user_get_alias (tgl_peer_t *user, char *buffer, int maxlen); static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *value) { @@ -82,6 +79,7 @@ static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *val return g_hash_table_lookup(table, value); } + /** * Assure that the given chat is opened */ @@ -105,21 +103,20 @@ static PurpleConversation *chat_show (PurpleConnection *gc, int id) g_hash_table_insert(conn->joining_chats, name, 0); // join chat first - do_get_chat_info (conn->tg, MK_CHAT(id)); - telegram_flush (conn->tg); + tgl_do_get_chat_info (conn->TLS, TGL_MK_CHAT(id), 0, on_chat_get_info, NULL); } g_free(name); } return convo; } - +/* static PurpleChat *get_chat_by_id (PurpleConnection *gc, int id) { gchar *name = g_strdup_printf ("%d", id); PurpleChat *chat = blist_find_chat_by_id (gc, name); g_free (name); return chat; -} +}*/ /** * Returns the base icon name for the given buddy and account. @@ -149,13 +146,14 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); debug ("purple_buddy_get_protocol_data: %s\n", buddy->name); - peer_id_t *peer = purple_buddy_get_protocol_data(buddy); + tgl_peer_id_t *peer = purple_buddy_get_protocol_data(buddy); if(peer == NULL) { purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline"); return; } - peer_t *P = user_chat_get (get_conn_from_buddy(buddy)->tg->bl, *peer); + tgl_peer_t *P = tgl_peer_get (get_conn_from_buddy(buddy)->TLS, *peer); + purple_notify_user_info_add_pair_plaintext(info, "Status", P->user.status.online == 1 ? "Online" : "Offline"); struct tm *tm = localtime ((void *)&P->user.status.when); char buffer [21]; @@ -163,350 +161,108 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); } - -/* OUTPUT */ - -/** - * Libpurple announced that new output should be written to the write-handle - */ -static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - mtproto_handle *conn = data; - if (!conn->mtp) { - debug ("connection no longer existing, do nothing. \n"); - return; - } - if (mtp_write_output(conn->mtp) == 0) { - debug("no output, removing output...\n"); - purple_input_remove(conn->wh); - conn->wh = 0; - } -} - -/** - * Telegram announced new output in its buffers - */ -static void tgprpl_has_output(void *handle) -{ - debug("tgprpl_has_output(%p)\n", handle); - mtproto_handle *conn = handle; - if (! conn->wh) { - conn->wh = purple_input_add(conn->fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, handle); - } -} - -/* - * Libpurple announced that new input should be read from the read-handle - */ -static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - mtproto_handle *conn = data; - debug("tgprpl_input_cb()\n"); - if (!conn->fd) { - debug("conn for handle no longer existing, not reading input\n"); - return; - } - mtp_read_input(conn->mtp); - - if (conn->mtp) { - // processing of the answer may have inserted new queries - telegram_flush (conn->mtp->instance); - - // free all mtproto_connections that may have errored - mtproto_free_closed(conn->mtp->instance, 0); - } -} - -/** - * Telegram requests a new connectino to our configured proxy - */ -void telegram_on_proxy_request(struct telegram *tg, struct proxy_request *req) -{ - telegram_conn *conn = tg->extra; - req->extra = tg; - purple_proxy_connect (conn->gc, conn->pa, req->DC->ip, req->DC->port, - tgprpl_login_on_connected, req); -} - /** * Handle a proxy-close of telegram * * Remove all open inputs added to purple */ -void telegram_on_proxy_close(void *handle) -{ - mtproto_handle *conn = handle; - debug ("Closing proxy-handles - fd: %d, write-handle: %d, read-handle: %d\n", - conn->fd, conn->wh, conn->rh); - if (conn->rh) { - purple_input_remove (conn->rh); - } - if (conn->wh) { - purple_input_remove (conn->wh); - } - conn->rh = conn->wh = 0; - conn->mtp = 0; - tfree (conn, sizeof(mtproto_handle)); -} - -void phone_registration_entered (PurpleConnection* gc, PurpleRequestFields* fields) -{ - telegram_conn *conn = purple_connection_get_protocol_data(gc); - const char* first = purple_request_fields_get_string(fields, "first_name"); - const char* last = purple_request_fields_get_string(fields, "last_name"); - const char* code = purple_request_fields_get_string(fields, "code"); - if (!first || !last || !code) { - telegram_on_phone_registration (conn->tg); - return; - } - - do_send_code_result_auth (conn->tg, code, first, last); - telegram_flush (conn->tg); -} - - -void telegram_on_phone_registration (struct telegram *instance) -{ - telegram_conn *conn = instance->extra; - - purple_debug_info(PLUGIN_ID, "Phone is not registered, registering...\n"); - - PurpleRequestFields* fields = purple_request_fields_new(); - PurpleRequestField* field = 0; - - PurpleRequestFieldGroup* group = purple_request_field_group_new("Registration"); - field = purple_request_field_string_new("first_name", "First Name", "", 0); - purple_request_field_group_add_field(group, field); - field = purple_request_field_string_new("last_name", "Last Name", "", 0); - purple_request_field_group_add_field(group, field); - purple_request_fields_add_group(fields, group); - - group = purple_request_field_group_new("Authorization"); - field = purple_request_field_string_new("code", "Telegram Code", "", 0); - purple_request_field_group_add_field(group, field); - purple_request_fields_add_group(fields, group); - - purple_request_fields(conn->gc, "Register", "Please register your phone number.", NULL, fields, "Ok", - G_CALLBACK( phone_registration_entered ), "Cancel", NULL, conn->pa, NULL, NULL, conn->gc); -} - -void client_registration_entered (gpointer data, const gchar *code) -{ - struct telegram *tg = data; - do_send_code_result (tg, code); - telegram_flush (tg); -} - -void client_registration_canceled (gpointer data) -{ - struct telegram *tg = data; - telegram_conn *conn = tg->extra; - - purple_connection_error_reason(conn->gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled"); -} gboolean queries_timerfunc (gpointer data) { debug ("queries_timerfunc()\n"); telegram_conn *conn = data; - work_timers (conn->tg); - telegram_flush (conn->tg); if (conn->updated) { debug ("State updated, storing current session...\n"); conn->updated = 0; - telegram_store_session (conn->tg); + write_state_file (conn->TLS); } return 1; } -void telegram_on_client_registration (struct telegram *instance) -{ - purple_debug_info(PLUGIN_ID, "Client is not registered, registering...\n"); - telegram_conn *conn = instance->extra; - - purple_request_input( - conn->gc, // handle (the PurpleAccount) - "Telegram Code", // title - "Enter Telegram Code", // primary - "Telegram wants to verify your identity, please enter the code, that you have received via SMS.", // secondary - NULL, // default_value - 0, // multiline - 0, // masked - "code", // hint - "OK", // ok_text - G_CALLBACK(client_registration_entered), // ok_cb - "Cancel", // cancel_text - G_CALLBACK(client_registration_canceled), // cancel_cb - conn->pa, // account - NULL, // who - NULL, // conv - conn->tg // user_data - ); +void telegram_on_ready (struct tgl_state *TLS) { + debug ("telegram_on_ready().\n"); + telegram_conn *conn = TLS->ev_base; + purple_connection_set_state(conn->gc, PURPLE_CONNECTED); + purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa)); + purple_blist_add_account(conn->pa); + tggroup = purple_find_group("Telegram"); + if (tggroup == NULL) { + purple_debug_info (PLUGIN_ID, "PurpleGroup = NULL, creating"); + tggroup = purple_group_new ("Telegram"); + purple_blist_add_group (tggroup, NULL); + } + + tgl_do_get_difference (TLS, 0, 0, 0); + tgl_do_get_dialog_list (TLS, 0, 0); + tgl_do_update_contact_list (TLS, 0, 0); + + conn->timer = purple_timeout_add (5000, queries_timerfunc, conn); } -void telegram_on_ready (struct telegram *instance) -{ - purple_debug_info(PLUGIN_ID, "telegram_on_ready().\n"); - telegram_conn *conn = instance->extra; - purple_connection_set_state(conn->gc, PURPLE_CONNECTED); - purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa)); - purple_blist_add_account(conn->pa); - tggroup = purple_find_group("Telegram"); - if (tggroup == NULL) { - purple_debug_info (PLUGIN_ID, "PurpleGroup = NULL, creating"); - tggroup = purple_group_new ("Telegram"); - purple_blist_add_group (tggroup, NULL); - } - do_get_difference(instance, 0); - do_get_dialog_list(instance); - do_update_contact_list(instance); - telegram_flush (conn->tg); - conn->timer = purple_timeout_add (5000, queries_timerfunc, conn); -} - -/** - * A proxy connection was created by purple - * - * Use the connection to create a new mtproto-connection and create a handle, - * with additional info for libpurple associated with the new connection - */ -void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) -{ - purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); - struct proxy_request *req = (struct proxy_request*)data; - struct telegram *tg = req->tg; - - if (fd == -1) { - failure("purple_proxy_connect failed: %s\n", error_message); - telegram_destroy(tg); - return; - } - - mtproto_handle *conn = talloc(sizeof (mtproto_handle)); - conn->fd = fd; - conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, conn); - conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, conn); - conn->mtp = telegram_add_proxy(tg, req, fd, conn); -} - -void telegram_on_error (struct telegram *tg, const char *err) -{ - debug ("telegram_on_error()\n"); - telegram_conn *conn = tg->extra; - - purple_connection_error_reason(conn->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, - err); -} - -void on_update_user_name (struct telegram *tg, peer_t *user) -{ - // debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); - // Update user name -} - -void on_update_user_photo (struct telegram *tg, peer_t *user) -{ - // debug("on_update_user_photo(id=%d, type=%d)\n", user->id.id, user->id.type); - // Update user photo -} - -void on_update_user_registered (struct telegram *tg, peer_t *user) -{ - // debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); - // Notify about a new user -} - -void on_update_chat_participants (struct telegram *tg, peer_t *chat) -{ - // debug("on_update_chat_participants(chat.id=%d)\n", chat->id.id); - // Refresh chat participants -} - -void on_update_chat_add_participant (struct telegram *tg, peer_t *chat, peer_id_t user, peer_id_t inviter) -{ - // debug("on_update_chat_add_participant(chat.id=%d)\n", chat->id.id); - // Add chat participant -} - -void on_update_chat_del_participant (struct telegram *tg, peer_t *chat, peer_id_t user, void *_ UU) -{ - // debug("on_update_chat_del_participant(chat.id=%d)\n", chat->id.id); - // Remove chat participant -} - -void on_update_chat_user_typing (struct telegram *tg, peer_t *chat, peer_t *user, void *_ UU) -{ - // debug("on_update_chat_user_typing(chat.id=%d, user.id=%d)\n", chat->id.id, user->id.id); - // Set or unset user in chat typing -} - -void on_update_auth_new (struct telegram *tg, char *location) -{ - // debug("un_update_auth_new(location=%s)\n", location); - // Info: new device authenticated for this phone number -} - -struct telegram_config tgconf = { - NULL, - tgprpl_has_output, // on output - telegram_on_proxy_request, - telegram_on_proxy_close, - telegram_on_phone_registration, - telegram_on_client_registration, - telegram_on_ready, - telegram_on_error, - - // user - peer_allocated_handler, - on_new_user_status, - on_user_typing, - on_update_user_name, - on_update_user_photo, - on_update_user_registered, - - // chat - on_update_chat_participants, - on_update_chat_add_participant, - on_update_chat_del_participant, - on_update_chat_user_typing, - - // misc - on_update_auth_new, - message_allocated_handler, - download_finished_handler, - user_info_received_handler, - on_chat_joined +static void message_received_handler (struct tgl_state *TLS, struct tgl_message *M); +static void user_update_handler (struct tgl_state *TLS, struct tgl_user *U, unsigned flags); +static void chat_update_handler (struct tgl_state *TLS, struct tgl_chat *C, unsigned flags); +void on_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status); +struct tgl_update_callback tgp_callback = { + .logprintf = debug, + .new_msg = message_received_handler, + .msg_receive = message_received_handler, + .user_update = user_update_handler, + .chat_update = chat_update_handler, + .type_notification = on_user_typing }; - /** * This must be implemented. */ static void tgprpl_login(PurpleAccount * acct) { - purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); + purple_debug_info (PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); char const *username = purple_account_get_username(acct); - // create a new instance of telegram - struct telegram *tg = telegram_new (username, &tgconf); - telegram_restore_session(tg); + struct tgl_state *TLS = tgl_state_alloc (); + + const char *dir = CONFIG_DIR; + struct passwd *pw = getpwuid(getuid()); + int len = strlen (dir) + strlen (pw->pw_dir) + 2 + strlen (username); + TLS->base_path = malloc (len); + snprintf (TLS->base_path, len, "%s/%s/%s", pw->pw_dir, dir, username); + debug ("base configuration path: '%s'", TLS->base_path); + g_mkdir_with_parents(TLS->base_path, 0700); + + len += strlen ("/downloads"); + char *ddir = malloc (len); + sprintf (ddir, "%s/downloads", TLS->base_path); + tgl_set_download_directory (TLS, ddir); + g_mkdir_with_parents(ddir, 0700); + free (ddir); + + tgl_set_verbosity (TLS, 4); + tgl_set_rsa_key (TLS, "/etc/telegram-purple/server.pub"); + + // create handle to store additional info for libpurple in // the new telegram instance telegram_conn *conn = g_new0(telegram_conn, 1); - conn->tg = tg; + conn->TLS = TLS; conn->gc = gc; conn->pa = acct; conn->new_messages = g_queue_new(); - conn->joining_chats = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - purple_connection_set_protocol_data(gc, conn); + purple_connection_set_protocol_data (gc, conn); + + tgl_set_ev_base (TLS, conn); + tgl_set_net_methods (TLS, &tgp_conn_methods); + tgl_set_timer_methods (TLS, &tgp_timers); + tgl_set_callback (TLS, &tgp_callback); - tg->extra = conn; + tgl_init (TLS); purple_connection_set_state (conn->gc, PURPLE_CONNECTING); - telegram_connect (tg); + + + telegram_login (TLS); } /** @@ -517,23 +273,23 @@ static void tgprpl_close(PurpleConnection * gc) purple_debug_info(PLUGIN_ID, "tgprpl_close()\n"); telegram_conn *conn = purple_connection_get_protocol_data(gc); purple_timeout_remove(conn->timer); - telegram_destroy(conn->tg); + tgl_free_all (conn->TLS); } -static int chat_add_message(struct telegram *tg, struct message *M) +static int chat_add_message(struct tgl_state *TLS, struct tgl_message *M) { - telegram_conn *conn = tg->extra; + telegram_conn *conn = TLS->ev_base; if (chat_show (conn->gc, M->to_id.id)) { // chat initialies, add message now - if (M->from_id.id == tg->our_id) { - serv_got_chat_in(conn->gc, get_peer_id(M->to_id), "You", + if (tgl_get_peer_id (M->from_id) == TLS->our_id) { + serv_got_chat_in(conn->gc, tgl_get_peer_id (M->to_id), "You", PURPLE_MESSAGE_RECV, M->message, M->date); } else { - peer_t *fromPeer = user_chat_get (tg->bl, M->from_id); + tgl_peer_t *fromPeer = tgl_peer_get (TLS, M->from_id); char *alias = malloc(BUDDYNAME_MAX_LENGTH); - user_get_alias(fromPeer, alias, BUDDYNAME_MAX_LENGTH); - serv_got_chat_in(conn->gc, get_peer_id(M->to_id), alias, + user_get_alias (fromPeer, alias, BUDDYNAME_MAX_LENGTH); + serv_got_chat_in (conn->gc, tgl_get_peer_id (M->to_id), alias, PURPLE_MESSAGE_RECV, M->message, M->date); g_free(alias); } @@ -545,10 +301,10 @@ static int chat_add_message(struct telegram *tg, struct message *M) } } -void message_allocated_handler(struct telegram *tg, struct message *M) +void message_received_handler(struct tgl_state *TLS, struct tgl_message *M) { debug ("message_allocated_handler\n"); - telegram_conn *conn = tg->extra; + telegram_conn *conn = TLS->ev_base; PurpleConnection *gc = conn->gc; if (M->service || (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED))) { @@ -558,40 +314,40 @@ void message_allocated_handler(struct telegram *tg, struct message *M) return; } - int id = get_peer_id(M->from_id); - peer_id_t to_id = M->to_id; + int id = tgl_get_peer_id (M->from_id); + tgl_peer_id_t to_id = M->to_id; char *from = g_strdup_printf("%d", id); char *to = g_strdup_printf("%d", to_id.id); - switch (to_id.type) { - case PEER_CHAT: + switch (tgl_get_peer_type (to_id)) { + case TGL_PEER_CHAT: debug ("PEER_CHAT\n"); - chat_add_message(tg, M); + chat_add_message (TLS, M); break; - case PEER_USER: + case TGL_PEER_USER: debug ("PEER_USER\n"); - if (M->from_id.id == tg->our_id) { + if (tgl_get_peer_id (M->from_id) == TLS->our_id) { serv_got_im(gc, to, M->message, PURPLE_MESSAGE_SEND, M->date); } else { serv_got_im(gc, from, M->message, PURPLE_MESSAGE_RECV, M->date); } break; - case PEER_ENCR_CHAT: + case TGL_PEER_ENCR_CHAT: break; - case PEER_GEO_CHAT: + case TGL_PEER_GEO_CHAT: break; } g_free(from); conn->updated = 1; } -void on_new_user_status(struct telegram *tg, void *peer) +void on_new_user_status (struct tgl_state *TLS, void *peer) { - telegram_conn *conn = tg->extra; - peer_t *p = peer; - char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + telegram_conn *conn = TLS->ev_base; + tgl_peer_t *p = peer; + char *who = g_strdup_printf("%d", tgl_get_peer_id (p->user.id)); PurpleAccount *account = purple_connection_get_account(conn->gc); if (p->user.status.online == 1) purple_prpl_got_user_status(account, who, "available", "message", "", NULL); @@ -600,12 +356,11 @@ void on_new_user_status(struct telegram *tg, void *peer) g_free(who); } -void on_user_typing(struct telegram *tg, void *peer) +void on_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status) { - telegram_conn *conn = tg->extra; - peer_t *p = peer; + telegram_conn *conn = TLS->ev_base; - char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + char *who = g_strdup_printf("%d", tgl_get_peer_id (U->id)); serv_got_typing(conn->gc, who, 2, PURPLE_TYPING); g_free(who); } @@ -642,98 +397,120 @@ static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id) return blist_find_chat_by_hasht_cond(gc, hasht_cmp_id, &id); } -static char *peer_get_peer_id_as_string(peer_t *user) +static char *peer_get_peer_id_as_string(tgl_peer_t *user) { - return g_strdup_printf("%d", get_peer_id(user->id)); + return g_strdup_printf("%d", tgl_get_peer_id (user->id)); } -void peer_allocated_handler(struct telegram *tg, void *usr) + +static void sanitize_alias(char *buffer) { - telegram_conn *conn = tg->extra; + size_t len = strlen(buffer); + gchar *curr; + while ((curr = g_utf8_strchr(buffer, len, '\n'))) { + *curr = 0x20; + } +} + +static int user_get_alias (tgl_peer_t *user, char *buffer, int maxlen) +{ + char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; + char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; + sanitize_alias (last_name); + sanitize_alias (first_name); + if (strlen(first_name) && strlen(last_name)) { + return snprintf(buffer, maxlen, "%s %s", first_name, last_name); + } else if (strlen(first_name)) { + return snprintf(buffer, maxlen, "%s", first_name); + } else if (strlen(last_name)) { + return snprintf(buffer, maxlen, "%s", last_name); + } else { + return snprintf(buffer, maxlen, "%d", tgl_get_peer_id (user->id)); + } +} + +void user_update_handler (struct tgl_state *TLS, struct tgl_user *user, unsigned flags) +{ + if (!(flags & FLAG_CREATED)) { return; } + + telegram_conn *conn = TLS->ev_base; PurpleConnection *gc = conn->gc; PurpleAccount *pa = conn->pa; - peer_t *user = usr; - gchar *name = peer_get_peer_id_as_string(user); //g_strdup_printf("%d", get_peer_id(user->id)); - debug("Allocated peer: %s\n", name); - switch (user->id.type) { - case PEER_USER: { - debug("Peer type: user.\n"); - // TODO: this should probably be freed again somwhere - char *alias = malloc(BUDDYNAME_MAX_LENGTH); - if (user_get_alias(user, alias, BUDDYNAME_MAX_LENGTH) < 0) { - purple_debug_info(PLUGIN_ID, "Buddyalias of (%d) too long, not adding to buddy list.\n", - get_peer_id(user->id)); - return; - } - PurpleBuddy *buddy = purple_find_buddy(pa, name); - if (!buddy) { - char *actual = user->id.id == tg->our_id ? "You" : alias; - purple_debug_info(PLUGIN_ID, "Adding %s to buddy list\n", name); - purple_debug_info(PLUGIN_ID, "Alias %s\n", actual); - buddy = purple_buddy_new(pa, name, actual); - purple_blist_add_buddy(buddy, NULL, tggroup, NULL); - do_get_user_info(conn->tg, user->id, 0); - } - purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); - - PurpleAccount *account = purple_connection_get_account(gc); - if (user->user.status.online == 1) - purple_prpl_got_user_status(account, name, "available", "message", "", NULL); - else - purple_prpl_got_user_status(account, name, "mobile", "message", "", NULL); - - g_free(alias); - g_free(name); - } - break; - case PEER_CHAT: { - debug("Peer type: chat.\n"); - PurpleChat *ch = blist_find_chat_by_id(gc, name); - if (!ch) { - gchar *admin = g_strdup_printf("%d", user->chat.admin_id); - GHashTable *htable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_insert(htable, g_strdup("subject"), user->chat.title); - g_hash_table_insert(htable, g_strdup("id"), name); - g_hash_table_insert(htable, g_strdup("owner"), admin); - debug("Adding chat to blist: %s (%s, %s)\n", user->chat.title, name, admin); - ch = purple_chat_new(pa, user->chat.title, htable); - purple_blist_add_chat(ch, NULL, NULL); - } - - GHashTable *gh = purple_chat_get_components(ch); - //char const *id = g_hash_table_lookup(gh, "id"); - char const *owner = g_hash_table_lookup(gh, "owner"); - - PurpleConversation *conv = purple_find_chat(gc, atoi(name)); + gchar *name = peer_get_peer_id_as_string ((tgl_peer_t *)user); //g_strdup_printf("%d", get_peer_id(user->id)); + debug("Allocated user: %s\n", name); + // TODO: this should probably be freed again somwhere + char *alias = malloc(BUDDYNAME_MAX_LENGTH); + if (user_get_alias((tgl_peer_t *)user, alias, BUDDYNAME_MAX_LENGTH) < 0) { + purple_debug_info(PLUGIN_ID, "Buddyalias of (%d) too long, not adding to buddy list.\n", + tgl_get_peer_id(user->id)); + return; + } + PurpleBuddy *buddy = purple_find_buddy(pa, name); + if (!buddy) { + char *actual = tgl_get_peer_id (user->id) == TLS->our_id ? "You" : alias; + purple_debug_info(PLUGIN_ID, "Adding %s to buddy list\n", name); + purple_debug_info(PLUGIN_ID, "Alias %s\n", actual); + buddy = purple_buddy_new(pa, name, actual); + purple_blist_add_buddy(buddy, NULL, tggroup, NULL); + tgl_do_get_user_info (TLS, user->id, 0, on_user_get_info, 0); + } + purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); - purple_conv_chat_clear_users(purple_conversation_get_chat_data(conv)); - if (conv) { - struct chat_user *usr = user->chat.user_list; - int size = user->chat.user_list_size; - int i; - for (i = 0; i < size; i++) { - struct chat_user *cu = (usr + i); - // TODO: Inviter ID - // peer_id_t u = MK_USER (cu->user_id); - // peer_t *uchat = user_chat_get(u); - const char *cuname = g_strdup_printf("%d", cu->user_id); - debug("Adding user %s to chat %s\n", cuname, name); - purple_conv_chat_add_user(purple_conversation_get_chat_data(conv), cuname, "", - PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), 0); - } - } - } - break; - case PEER_GEO_CHAT: - debug("Peer type: geo-chat.\n"); - break; - case PEER_ENCR_CHAT: - debug("Peer type: encrypted chat.\n"); - break; - case PEER_UNKNOWN: - debug("Peer type: unknown.\n"); - break; + PurpleAccount *account = purple_connection_get_account(gc); + if (user->status.online == 1) + purple_prpl_got_user_status(account, name, "available", "message", "", NULL); + else + purple_prpl_got_user_status(account, name, "mobile", "message", "", NULL); + + g_free(alias); + g_free(name); +} + +void chat_update_handler (struct tgl_state *TLS, struct tgl_chat *chat, unsigned flags) +{ + if (!(flags & FLAG_CREATED)) { return; } + tgl_do_get_chat_info (TLS, chat->id, 0, on_chat_get_info, 0); + + telegram_conn *conn = TLS->ev_base; + PurpleConnection *gc = conn->gc; + PurpleAccount *pa = conn->pa; + + gchar *name = peer_get_peer_id_as_string ((tgl_peer_t *)chat); //g_strdup_printf("%d", get_peer_id(user->id)); + debug("Allocated chat: %s\n", name); + PurpleChat *ch = blist_find_chat_by_id(gc, name); + if (!ch) { + gchar *admin = g_strdup_printf("%d", chat->admin_id); + GHashTable *htable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert(htable, g_strdup("subject"), chat->title); + g_hash_table_insert(htable, g_strdup("id"), name); + g_hash_table_insert(htable, g_strdup("owner"), admin); + debug("Adding chat to blist: %s (%s, %s)\n", chat->title, name, admin); + ch = purple_chat_new(pa, chat->title, htable); + purple_blist_add_chat(ch, NULL, NULL); + } + + GHashTable *gh = purple_chat_get_components(ch); + //char const *id = g_hash_table_lookup(gh, "id"); + char const *owner = g_hash_table_lookup(gh, "owner"); + + PurpleConversation *conv = purple_find_chat(gc, atoi(name)); + + purple_conv_chat_clear_users(purple_conversation_get_chat_data(conv)); + if (conv) { + struct tgl_chat_user *usr = chat->user_list; + int size = chat->user_list_size; + int i; + for (i = 0; i < size; i++) { + struct tgl_chat_user *cu = (usr + i); + // TODO: Inviter ID + // tgl_peer_id_t u = MK_USER (cu->user_id); + // tgl_peer_t *uchat = user_chat_get(u); + const char *cuname = g_strdup_printf("%d", cu->user_id); + debug("Adding user %s to chat %s\n", cuname, name); + purple_conv_chat_add_user(purple_conversation_get_chat_data(conv), cuname, "", + PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), 0); + } } } @@ -747,54 +524,52 @@ PurpleNotifyUserInfo *create_user_notify_info(struct tgl_user *usr) return info; } -void user_info_received_handler(struct telegram *tg, struct tgl_user *usr, int show_info) +void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success, char *filename) { + telegram_conn *conn = TLS->ev_base; + + gchar *data = NULL; + size_t len; + GError *err = NULL; + g_file_get_contents (filename, &data, &len, &err); + int imgStoreId = purple_imgstore_add_with_id (g_memdup(data, len), len, NULL); + debug("Imagestore id: %d\n", imgStoreId); + //Create user info + struct download_desc *dld = extra; + struct tgl_user *U = dld->data; + + char *who = g_strdup_printf("%d", tgl_get_peer_id (U->id)); + + if(dld->type == 1) + { + PurpleNotifyUserInfo *info = create_user_notify_info(U); + char *profile_image = profile_image = g_strdup_printf("
", imgStoreId); + purple_notify_user_info_add_pair(info, "Profile image", profile_image); + purple_notify_userinfo(conn->gc, who, info, NULL, NULL); + g_free(profile_image); + } + purple_buddy_icons_set_for_user(conn->pa, who, g_memdup(data, len), len, NULL); + g_free(who); +} + +void on_user_get_info (struct tgl_state *TLS, void *show_info, int success, struct tgl_user *U) { + assert (success); debug("Get user info. \n %d", show_info); - char *who = g_strdup_printf("%d", usr->id.id); - if (usr->photo.sizes_num == 0 && show_info) + char *who = g_strdup_printf("%d", tgl_get_peer_id (U->id)); + if (U->photo.sizes_num == 0 && show_info) { - telegram_conn *conn = tg->extra; - PurpleNotifyUserInfo *info = create_user_notify_info(usr); + telegram_conn *conn = TLS->ev_base; + PurpleNotifyUserInfo *info = create_user_notify_info(U); purple_notify_userinfo(conn->gc, who, info, NULL, NULL); } else { - struct download_desc *dld = talloc(sizeof(struct download_desc)); - dld->data = usr; - dld->type = show_info == 1 ? 1 : 2; - do_load_photo(tg, &usr->photo, 0, dld); + struct download_desc *dld = malloc (sizeof(struct download_desc)); + dld->data = U; + dld->type = show_info ? 1 : 2; + tgl_do_load_photo (TLS, &U->photo, on_userpic_loaded, dld); } g_free(who); } - -void download_finished_handler(struct telegram *tg, struct download *D) -{ - debug("download_finished_handler %s type %d\n", D->name, D->type); - //TODO: We need a type for user-photos! - if(D->type == 0) - { - struct download_desc *dl_desc = D->extra; - struct tgl_user *usr = dl_desc->data; - gchar *data = NULL; - size_t len; - GError *err = NULL; - g_file_get_contents(D->name, &data, &len, &err); - int imgStoreId = purple_imgstore_add_with_id(g_memdup(data, len), len, NULL); - debug("Imagestore id: %d\n", imgStoreId); - //Create user info - char *who = g_strdup_printf("%d", usr->id.id); - telegram_conn *conn = tg->extra; - if(dl_desc->type == 1) - { - PurpleNotifyUserInfo *info = create_user_notify_info(usr); - char *profile_image = profile_image = g_strdup_printf("
", imgStoreId); - purple_notify_user_info_add_pair(info, "Profile image", profile_image); - purple_notify_userinfo(conn->gc, who, info, NULL, NULL); - g_free(profile_image); - } - purple_buddy_icons_set_for_user(conn->pa, who, g_memdup(data, len), len, NULL); - g_free(who); - } -} /** * This PRPL function should return a positive value on success. * If the message is too big to be sent, return -E2BIG. If @@ -811,9 +586,9 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me purple_debug_info (PLUGIN_ID, "tgprpl_send_im()\n"); PurpleBuddy *b = purple_find_buddy (pa, who); - peer_id_t *peer = purple_buddy_get_protocol_data (b); - do_send_message (conn->tg, *peer, message, strlen(message)); - telegram_flush (conn->tg); + tgl_peer_id_t *peer = purple_buddy_get_protocol_data (b); + + tgl_do_send_message (conn->TLS, *peer, message, strlen (message), 0, 0); return 1; } @@ -838,11 +613,11 @@ static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, purple_debug_info(PLUGIN_ID, "tgprpl_send_chat()\n"); telegram_conn *conn = purple_connection_get_protocol_data (gc); //PurpleConversation *convo = purple_find_chat(gc, id); - do_send_message (conn->tg, MK_CHAT(id), message, strlen(message)); + tgl_do_send_message (conn->TLS, TGL_MK_CHAT(id), message, strlen(message), 0, 0); - char *who = g_strdup_printf("%d", id); - serv_got_chat_in(gc, id, "You", PURPLE_MESSAGE_RECV, message, time(NULL)); - g_free(who); + //char *who = g_strdup_printf("%d", id); + //serv_got_chat_in(gc, id, "You", PURPLE_MESSAGE_RECV, message, time(NULL)); + //g_free(who); return 1; } @@ -906,14 +681,14 @@ static void tgprpl_rem_deny(PurpleConnection * gc, const char *name) static unsigned int tgprpl_send_typing(PurpleConnection * gc, const char *who, PurpleTypingState typing) { purple_debug_info(PLUGIN_ID, "tgprpl_send_typing()\n"); - telegram_conn *conn = purple_connection_get_protocol_data(gc); + /*telegram_conn *conn = purple_connection_get_protocol_data(gc); PurpleBuddy *b = purple_find_buddy(conn->pa, who); if (b) { - peer_id_t *peer = purple_buddy_get_protocol_data(b); + tgl_peer_id_t *peer = purple_buddy_get_protocol_data(b); if (peer) { - do_update_typing (conn->tg, *peer); + tgl_do_update_typing (conn->tg, *peer); } - } + }*/ return 0; } @@ -987,8 +762,8 @@ static void tgprpl_get_info(PurpleConnection * gc, const char *username) purple_debug_info(PLUGIN_ID, "tgprpl_get_info()\n"); telegram_conn *conn = purple_connection_get_protocol_data(gc); - peer_id_t u = MK_USER(atoi(username)); - do_get_user_info(conn->tg, u, 1); + tgl_peer_id_t u = TGL_MK_USER(atoi(username)); + tgl_do_get_user_info (conn->TLS, u, 0, on_user_get_info, (void *)1l); purple_debug_info(PLUGIN_ID, "tgprpl_get_info ready()\n"); //fetch_alloc_user_full(tg->connection); //fetch_user_full(tg->connection, user); @@ -1072,37 +847,27 @@ static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) } if (!purple_find_chat(gc, atoi(id))) { debug ("chat now known\n"); - char *subject, *owner, *part; - do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); - telegram_flush (conn->tg); + //char *subject, *owner, *part; + tgl_do_get_chat_info (conn->TLS, TGL_MK_CHAT(atoi(id)), 0, on_chat_get_info, 0); } else { debug ("chat already known\n"); serv_got_joined_chat(conn->gc, atoi(id), groupname); } } -void on_chat_joined (struct telegram *instance, peer_id_t chatid) -{ - debug ("on_chat_joined(%d)\n", chatid.id); - telegram_conn *conn = instance->extra; - - peer_t *peer = user_chat_get (instance->bl, chatid); - if (!peer) { - warning ("WARNING: chat with given id %d is not existing.\n", chatid.id); - return; - } - if (!peer->id.type == PEER_CHAT) { - warning ("WARNING: peer with given id %d and type %d is not a chat.\n", peer->id.id, peer->id.type); - return; - } - PurpleConversation *conv = serv_got_joined_chat(conn->gc, chatid.id, peer->chat.title); - int cnt = peer->chat.user_list_size; - struct chat_user *curr = peer->chat.user_list; +void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C) { + assert (success); + debug ("on_chat_joined(%d)\n", tgl_get_peer_id (C->id)); + telegram_conn *conn = TLS->ev_base; + + PurpleConversation *conv = serv_got_joined_chat(conn->gc, tgl_get_peer_id (C->id), C->title); + int cnt = C->user_list_size; + struct tgl_chat_user *curr = C->user_list; int i; for (i = 0; i < cnt; i++) { - peer_id_t part_id = MK_USER((curr + i)->user_id); + tgl_peer_id_t part_id = TGL_MK_USER((curr + i)->user_id); char *name = g_strdup_printf ("%d", part_id.id); - int flags = PURPLE_CBFLAGS_NONE | ((peer->chat.admin_id == part_id.id) ? PURPLE_CBFLAGS_FOUNDER : 0); + int flags = PURPLE_CBFLAGS_NONE | ((C->admin_id == tgl_get_peer_id (part_id)) ? PURPLE_CBFLAGS_FOUNDER : 0); debug ("purple_conv_chat_add_user (..., name=%s, ..., flags=%d)", name, flags); purple_conv_chat_add_user( purple_conversation_get_chat_data(conv), @@ -1114,18 +879,18 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) } debug ("g_queue_pop_head()\n"); - struct message *M = 0; + struct tgl_message *M = 0; while ((M = g_queue_pop_head (conn->new_messages))) { debug ("adding msg-id\n"); - int id = get_peer_id(M->from_id); - if (!chat_add_message(instance, M)) { + //int id = tgl_get_peer_id (M->from_id); + if (!chat_add_message(TLS, M)) { // chat still not working? - warning ("WARNING, chat %d still not existing... \n", chatid.id); + warning ("WARNING, chat %d still not existing... \n", tgl_get_peer_id (C->id)); break; } } - gchar *name = g_strdup_printf ("%d", chatid.id); + gchar *name = g_strdup_printf ("%d", tgl_get_peer_id (C->id)); g_hash_table_remove (conn->joining_chats, name); g_free (name); } @@ -1258,14 +1023,6 @@ static PurplePluginProtocolInfo prpl_info = { static void tgprpl_init(PurplePlugin *plugin) { - const char *dir = CONFIG_DIR; - if (!tgconf.base_config_path) { - struct passwd *pw = getpwuid(getuid()); - int len = strlen (dir) + strlen (pw->pw_dir) + 2; - tgconf.base_config_path = talloc (len); - tsnprintf (tgconf.base_config_path, len, "%s/%s", pw->pw_dir, dir); - debug ("base configuration path: %s", tgconf.base_config_path); - } PurpleAccountOption *option; GList *verification_values = NULL; diff --git a/purple-plugin/telegram-purple.h b/telegram-purple.h similarity index 58% rename from purple-plugin/telegram-purple.h rename to telegram-purple.h index bc4cd7b..6c12a8d 100644 --- a/purple-plugin/telegram-purple.h +++ b/telegram-purple.h @@ -26,62 +26,45 @@ #define TG_BUILD "8" #include -#include "notify.h" -#include "plugin.h" -#include "version.h" -#include "account.h" -#include "connection.h" -#include "mtproto-client.h" +#include +#include +#include +#include +#include typedef struct { - struct telegram *tg; - PurpleAccount *pa; + struct tgl_state *TLS; + + /* + * Used during login + */ + char *hash; + + PurpleAccount *pa; PurpleConnection *gc; - /** - * Whether the state of the protocol has changed since the last save - */ - int updated; + /** + * Whether the state of the protocol has changed since the last save + */ + int updated; - /** - * The used purple timeout handler - */ - guint timer; - - /** - * Queue of all new messages that need to be added to a chat - */ - GQueue *new_messages; + /** + * Queue of all new messages that need to be added to a chat + */ + GQueue *new_messages; - /** - * Queue of all joined chats - */ - GHashTable *joining_chats; + /** + * Queue of all joined chats + */ + GHashTable *joining_chats; + guint timer; } telegram_conn; -typedef struct { - - /** - * The mtproto_connection associated with this handle - */ - struct mtproto_connection *mtp; - - /** - * Write handler returned by purple_input_add - */ - guint wh; - - /** - * Read handler returned by purple_input_add - */ - guint rh; - - /** - * The file descriptor of the used socket - */ - int fd; - -} mtproto_handle; +struct download_desc { + int type; + void *data; +}; +void telegram_on_ready (struct tgl_state *TLS); #endif diff --git a/telegram.c b/telegram.c deleted file mode 100755 index 0bd80d3..0000000 --- a/telegram.c +++ /dev/null @@ -1,480 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "telegram.h" -#include "msglog.h" -#include "glib.h" -#include "tools.h" -#include "mtproto-client.h" -#include "binlog.h" -#include "loop.h" - - -/* - * Events - */ -void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int show_info) -{ - if (instance->config->on_user_info_received_handler) { - instance->config->on_user_info_received_handler (instance, peer, show_info); - } -} - -DEFINE_EVENT_HANDLER (peer_allocated, void); -DEFINE_EVENT_HANDLER (update_user_status, void); -DEFINE_EVENT_HANDLER (update_user_typing, void); - -DEFINE_EVENT_HANDLER (update_user_name, peer_t); -DEFINE_EVENT_HANDLER (update_user_photo, peer_t); -DEFINE_EVENT_HANDLER (update_user_registered, peer_t); - -DEFINE_EVENT_HANDLER (update_chat_participants, peer_t); -DEFINE_EVENT_HANDLER_3(update_chat_add_participant, peer_t *, peer_id_t, peer_id_t); -DEFINE_EVENT_HANDLER_3(update_chat_del_participant, peer_t *, peer_id_t, void *); -DEFINE_EVENT_HANDLER_3(update_chat_user_typing, peer_t *, peer_t *, void *); -DEFINE_EVENT_HANDLER (update_auth_new, char); - -DEFINE_EVENT_HANDLER (update_new_message, struct message); -DEFINE_EVENT_HANDLER (download_finished, struct download); - - -/** - * Calculate the configuration path for the given config file and the given instance - * - * @returns The full path to the configuration. - * - * NOTE: the returned string must be freed manually using gfree - */ -char *telegram_get_config(struct telegram *instance, char *config) -{ - return g_strdup_printf("%s/%s", instance->config_path, config); -} - -/** - * Return whether the current client is registered. - */ -int telegram_is_registered(struct telegram *tg) -{ - return telegram_get_working_dc(tg)->has_auth; -} - - -/** - * Handle state changes of the telegram instance - * - * Execute all actions necessary when a certain state is reached. The state machine executes - * the authorization and registration steps needed to connect the client to the telegram network, - * and will either trigger RPC queries or callbacks to the GUI to request input from the user. - */ -void telegram_change_state (struct telegram *instance, int state, void *data) -{ - instance->session_state = state; - debug("on_state_change: %d\n", state); - switch (state) { - case STATE_ERROR: { - const char* err = data; - if (err == NULL) { - err = ""; - } - debug("telegram errored: %s\n", err); - mtproto_close (instance->connection); - instance->config->on_error (instance, err); - } - break; - - case STATE_AUTHORIZED: - debug("requesting configuration\n"); - telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL); - if (telegram_is_registered(instance)) { - telegram_change_state (instance, STATE_READY, NULL); - return; - } - do_help_get_config (instance); - break; - - case STATE_CONFIG_RECEIVED: - debug("received network configuration, checking whether phone is registered.\n"); - telegram_store_session(instance); - do_auth_check_phone(instance, instance->login); - break; - - case STATE_PHONE_NOT_REGISTERED: - debug("phone is not registered, need to register phone number.\n"); - do_send_code(instance, instance->login); - break; - - case STATE_PHONE_CODE_NOT_ENTERED: - debug("phone authenticion, user needs to enter code, first and last name.\n"); - assert (instance->config->on_phone_registration_required); - instance->config->on_phone_registration_required (instance); - break; - - case STATE_CLIENT_NOT_REGISTERED: - debug("phone is already registered, need to register client.\n"); - do_send_code(instance, instance->login); - break; - - case STATE_CLIENT_CODE_NOT_ENTERED: - debug("client authentication, user needs to enter code.\n"); - assert (instance->config->on_client_registration_required); - instance->config->on_client_registration_required (instance); - // wait for user input ... - break; - - case STATE_READY: - debug("telegram is registered and ready.\n"); - telegram_store_session (instance); - instance->config->on_ready (instance); - break; - - case STATE_DISCONNECTED_SWITCH_DC: { - // telegram demands that we use a different data center, which caused - // the current mtproto_connection to be disconnected - - int target_dc = *(int*) data; - debug ("Disconnected: Migrate to data center %d\n", target_dc); - - // close old connection and mark it for destruction - mtproto_close (instance->connection); - assert (instance->config->proxy_request_cb); - - // remove all left over queries and timers - free_timers (instance); - free_queries (instance); - - // start a new connection to the demanded data center. The pointer to the - // new dc should was already updated by the on_error function of the query - telegram_connect (instance); - } - break; - } -} - -struct telegram *telegram_new(const char* login, struct telegram_config *config) -{ - struct telegram *this = talloc0(sizeof(struct telegram)); - this->protocol_data = NULL; - this->bl = talloc0 (sizeof(struct binlog)); - this->config = config; - - this->login = g_strdup(login); - this->config_path = g_strdup_printf("%s/%s", config->base_config_path, login); - this->download_path = telegram_get_config(this, "downloads"); - this->auth_path = telegram_get_config(this, "auth"); - this->state_path = telegram_get_config(this, "state"); - this->secret_path = telegram_get_config(this, "secret"); - - debug("%s\n", this->login); - debug("%s\n", this->config_path); - debug("%s\n", this->download_path); - debug("%s\n", this->auth_path); - debug("%s\n", this->state_path); - debug("%s\n", this->secret_path); - - telegram_change_state(this, STATE_INITIALISED, NULL); - return this; -} - -void free_bl (struct binlog *bl); -void free_auth (struct dc* DC_list[], int count); -void telegram_destroy(struct telegram *this) -{ - // close all open connections - int i = 0; - for (; i < 100; i++) { - if (this->Cs[i] != NULL && !this->Cs[i]->destroy) { - mtproto_close (this->Cs[i]); - } - } - free_queries (this); - free_timers (this); - mtproto_free_closed (this, 1); - - free_bl (this->bl); - free_auth (this->auth.DC_list, 11); - - g_free(this->login); - g_free(this->config_path); - g_free(this->download_path); - g_free(this->auth_path); - g_free(this->state_path); - g_free(this->secret_path); - - // TODO: BN_CTX *ctx - if (this->phone_code_hash) free (this->phone_code_hash); - if (this->suser) free (this->suser); - if (this->export_auth_str) free (this->export_auth_str); - //tfree (this->ML, sizeof(struct message) * MSG_STORE_SIZE); - tfree(this, sizeof(struct telegram)); -} - -void free_bl (struct binlog *bl) -{ - // TODO: rptr, wptr - free_peers (bl); - free_messages (bl); - tfree (bl, sizeof (struct binlog)); -} - -void free_auth (struct dc* DC_list[], int count) -{ - int i; - for (i = 0; i < count; i++ ) if (DC_list[i]) { - tfree (DC_list[i], sizeof(struct dc)); - } -} - -void assert_file_usable(const char *file) -{ - debug ("assert_file_usable (%s)\n", file); - assert(access(file, W_OK | R_OK | F_OK) != -1); -} - -void assure_file_exists(const char *dir, const char *file) -{ - g_mkdir_with_parents(dir, 0700); - char *f = g_strdup_printf("%s/%s", dir, file); - close(open(f, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)); - assert_file_usable(f); - g_free(f); -} - -/** - * Get the currently used connection - * - * Will only work after telegram_connect has been called and the connection has - * not errored. - */ -struct connection *telegram_get_connection(struct telegram *instance) -{ - assert(instance->session_state != STATE_ERROR); - - struct dc *DC = telegram_get_working_dc(instance); - assert(DC); - assert(DC->sessions[0]); - assert(DC->sessions[0]->c); - return DC->sessions[0]->c; -} - -/** - * Get the currently used DC - * - * Will only work after restore_session has been called and the data center configuration - * was properly loaded - */ -struct dc *telegram_get_working_dc(struct telegram *instance) -{ - assert(instance->session_state != STATE_ERROR); - - assert(instance->auth.DC_list); - assert(instance->auth.dc_working_num > 0); - struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num]; - return DC; -} - -/** - * Store the current session state to a file - */ -void telegram_restore_session(struct telegram *instance) -{ - g_mkdir_with_parents(instance->config_path, 0700); - g_mkdir_with_parents(instance->download_path, 0700); - instance->auth = read_auth_file(instance->auth_path); - instance->proto = read_state_file(instance->state_path); - read_secret_chat_file (instance, instance->secret_path); -} - -/** - * Load the current session state - */ -void telegram_store_session(struct telegram *instance) -{ - assure_file_exists(instance->config_path, "auth"); - assure_file_exists(instance->config_path, "state"); - assure_file_exists(instance->config_path, "secret"); - write_auth_file(&instance->auth, instance->auth_path); - write_state_file(&instance->proto, instance->state_path); - write_secret_chat_file(instance, instance->secret_path); -} - -void on_authorized(struct mtproto_connection *c, void* data); - -void telegram_main_connected (struct proxy_request *req) -{ - struct telegram *instance = req->data; - debug("Authorized... storing current session %d.\n", - instance->connection->connection->session[0]); - telegram_store_session(instance); - telegram_change_state(instance, STATE_AUTHORIZED, NULL); -} - -/** - * Connect to the nearest data center - */ -void telegram_connect (struct telegram *instance) -{ - debug ("telegram_network_connect()\n"); - if (! instance->auth.DC_list) { - debug("telegram_network_connect(): cannot connect, restore / init a session first.\n"); - assert(0); - } - struct dc *DC_working = telegram_get_working_dc (instance); - - struct proxy_request *req = talloc0(sizeof(struct proxy_request)); - req->type = REQ_CONNECTION; - req->tg = instance; - req->data = instance; - req->DC = DC_working; - req->done = telegram_main_connected; - - assert (instance->config->proxy_request_cb); - instance->config->proxy_request_cb (instance, req); -} - -void on_auth_imported (void *extra) -{ - debug ("on_auth_imported()\n"); - struct download *dl = extra; - struct mtproto_connection *c = dl->c; - struct telegram *tg = c->instance; - bl_do_dc_signed (tg->bl, c, dl->dc); - write_auth_file (&tg->auth, tg->auth_path); - load_next_part (tg, dl); - telegram_flush (tg); -} - -void on_auth_exported (char *export_auth_str UU, int len UU, void *extra) -{ - debug ("on_auth_exported()\n"); - struct download *dl = extra; - do_import_auth (dl->c->instance, dl->dc, on_auth_imported, extra); - telegram_flush (dl->c->instance); -} - -void telegram_dl_connected (struct proxy_request *req) -{ - debug ("telegram_dl_connected(dc=%d)\n", req->DC->id); - struct telegram *tg = req->tg; - // TODO: error handling - - struct download *dl = req->data; - dl->c = req->conn; - struct dc *DC = tg->auth.DC_list[dl->dc]; - if (!DC->has_auth) { - do_export_auth (tg, dl->dc, on_auth_exported, dl); - telegram_flush (tg); - } else { - on_auth_imported (dl); - } -} - - -/** - * Create a connection for the given download - */ -void telegram_dl_add (struct telegram *instance, struct download *dl) -{ - debug ("telegram_connect_dl(dc_num=%d, dc=%d)\n", dl->dc, instance->auth.DC_list[dl->dc]); - if (!instance->dl_queue) { - instance->dl_queue = g_queue_new (); - } - g_queue_push_tail(instance->dl_queue, dl); -} - -void telegram_dl_next (struct telegram *instance) -{ - assert (instance->dl_queue); - assert (instance->config->proxy_request_cb); - if (!instance->dl_curr) { - struct download *dl = g_queue_pop_head (instance->dl_queue); - if (dl) { - struct proxy_request *req = talloc0(sizeof(struct proxy_request)); - req->type = REQ_DOWNLOAD; - req->DC = instance->auth.DC_list[dl->dc]; - req->tg = instance; - req->done = telegram_dl_connected; - req->data = dl; - instance->dl_curr = dl; - - debug ("telegrma_dl_start(workin_dc=%d, ): starting new download..\n", instance->auth.dc_working_num); - if (dl->dc == instance->auth.dc_working_num) { - debug ("is working DC, start download...\n"); - assert (telegram_get_working_dc(instance)->sessions[0]->c); - req->conn = instance->connection; - dl->c = req->conn; - telegram_dl_connected (req); - } else { - debug ("is remote DC, requesting connection...\n"); - instance->config->proxy_request_cb (instance, req); - } - } else { - debug ("telegrma_dl_start(): no more downloads, DONE!\n"); - mtproto_close_foreign (instance); - } - } else { - debug ("telegrma_dl_start(): download busy...\n"); - } -} - -void on_authorized(struct mtproto_connection *c UU, void *data) -{ - debug ("on_authorized()...\n"); - struct proxy_request *req = data; - assert (req->done); - req->done (req); - tfree (req, sizeof(struct proxy_request)); -} - -struct mtproto_connection *telegram_add_proxy(struct telegram *instance, struct proxy_request *req, - int fd, void *handle) -{ - struct mtproto_connection *c = mtproto_new (req->DC, fd, instance); - c->handle = handle; - c->on_ready = on_authorized; - c->on_ready_data = req; - req->conn = c; - if (req->type == REQ_CONNECTION) { - req->tg->connection = c; - } - mtproto_connect (c); - return c; -} - -void mtp_read_input (struct mtproto_connection *mtp) -{ - try_read (mtp->connection); -} - -int mtp_write_output (struct mtproto_connection *mtp) -{ - return try_write(mtp->connection); -} - -int telegram_authenticated (struct telegram *instance) -{ - return telegram_get_working_dc (instance)->auth_key_id > 0; -} - -void telegram_flush (struct telegram *instance) -{ - debug ("telegram flush()\n"); - int i; - for (i = 0; i < 100; i++) { - struct mtproto_connection *c = instance->Cs[i]; - if (!c) continue; - if (!c->connection) continue; - if (c->connection->out_bytes) { - debug ("connection %d has %d bytes, triggering on_output.\n", - i, c->connection->out_bytes); - instance->config->on_output(c->handle); - } else { - debug ("connection %d has no bytes, skipping\n", i); - } - } -} - diff --git a/telegram.h b/telegram.h deleted file mode 100644 index eebf435..0000000 --- a/telegram.h +++ /dev/null @@ -1,484 +0,0 @@ -#ifndef __TELEGRAM_H__ -#define __TELEGRAM_H__ - -#define MAX_PACKED_SIZE (1 << 24) -#define MAX_DC_NUM 9 -#define MAX_PEER_NUM 100000 - -#ifndef PROG_NAME -#define PROG_NAME "telegram-purple" -#endif - -#include -#include "glib.h" -#include "loop.h" -#include "tree.h" -#include "queries.h" -#include - -// forward declarations -struct message; -struct protocol_state; -struct authorization_state; -struct tree_query; -struct tree_timer; - - -/* - * telegram states - */ - -#define STATE_INITIALISED 0 -#define STATE_DISCONNECTED 1 -#define STATE_ERROR 2 -#define STATE_AUTHORIZED 6 - - -// dc discovery -#define STATE_CONFIG_REQUESTED 7 -#define STATE_EXPORTING_CONFIG 8 -#define STATE_DISCONNECTED_SWITCH_DC 9 -#define STATE_CONFIG_RECEIVED 11 - -// login - -// - Phone Registration -#define STATE_PHONE_NOT_REGISTERED 13 -#define STATE_PHONE_CODE_REQUESTED 14 -#define STATE_PHONE_CODE_NOT_ENTERED 15 -#define STATE_PHONE_CODE_ENTERED 16 - -// - Client Registration -#define STATE_CLIENT_IS_REGISTERED_SENT 17 -#define STATE_CLIENT_NOT_REGISTERED 18 -#define STATE_CLIENT_CODE_REQUESTED 19 -#define STATE_CLIENT_CODE_NOT_ENTERED 20 -#define STATE_CLIENT_CODE_ENTERED 21 - -// Ready for sending and receiving messages -#define STATE_READY 22 - -struct tree_peer; -struct tree_peer_by_name; -struct tree_message; - -#define BINLOG_BUFFER_SIZE (1 << 20) - -/** - * Binary log - */ -struct binlog { - int binlog_buffer[BINLOG_BUFFER_SIZE]; - int *rptr; - int *wptr; - int test_dc; // = 0 - int in_replay_log; - int binlog_enabled; // = 0; - int binlog_fd; - long long binlog_pos; - - int s[1000]; - - // - struct tree_peer *peer_tree; - struct tree_peer_by_name *peer_by_name_tree; - struct tree_message *message_tree; - struct tree_message *message_unsent_tree; - - int users_allocated; - int chats_allocated; - int messages_allocated; - int peer_num; - int encr_chats_allocated; - int geo_chats_allocated; - - peer_t *Peers[MAX_PEER_NUM]; -}; - -#define REQ_CONNECTION 1 -#define REQ_DOWNLOAD 2 -struct proxy_request { - struct telegram *tg; - struct dc *DC; - struct mtproto_connection *conn; - int type; - void *data; - void (*done) (struct proxy_request *req); - void *extra; -}; - -struct telegram; -struct download; - -/* - * Events 1 arg - */ - -#define DEFINE_EVENT_LISTENER(E_NAME, D_TYPE) void (*on_ ## E_NAME) (struct telegram *tg, D_TYPE *data); - -#define DECLARE_EVENT_HANDLER(E_NAME, D_TYPE) \ -void event_ ## E_NAME (struct telegram *tg, D_TYPE *data) - -#define DEFINE_EVENT_HANDLER(E_NAME, D_TYPE) \ -void event_ ## E_NAME (struct telegram *tg, D_TYPE *data) \ -{ \ - if (tg->config->on_ ## E_NAME) { \ - tg->config->on_ ## E_NAME (tg, data); \ - } else { \ - warning ("Trying to execute non-existing event listener %s\n", "E_NAME"); \ - } \ -} - -/* - * Events 3 args - */ - -#define DEFINE_EVENT_LISTENER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) void (*on_ ## E_NAME) (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3); - -#define DECLARE_EVENT_HANDLER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) \ -void event_ ## E_NAME (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3) - -#define DEFINE_EVENT_HANDLER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) \ -void event_ ## E_NAME (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3) \ -{ \ - if (tg->config->on_ ## E_NAME) { \ - tg->config->on_ ## E_NAME (tg, data, data2, data3); \ - } else { \ - warning ("Trying to execute non-existing event listener %s\n", "E_NAME"); \ - } \ -} - - -/** - * Contains all options and pointer to callback functions required by telegram - */ -struct telegram_config { - - /** - * The base path containing the telegram configuration - */ - char* base_config_path; - - /** - * Called when there is pending network output - */ - void (*on_output)(void *handle); - - /** - * A callback function that delivers a connections to the given hostname - * and port by calling telegram_set_proxy. This is useful for tunelling - * the connection through a proxy server. - */ - void (*proxy_request_cb) (struct telegram *instance, struct proxy_request *req); - - /** - * A callback function that is called once the proxy connection is no longer - * needed. This is useful for freeing all used resources. - */ - void (*proxy_close_cb) (void *handle); - - /** - * A callback function that is called when a phone registration is required. - * - * This callback must query first name, last name and the - * authentication code from the user and call do_send_code_result_auth once done - */ - void (*on_phone_registration_required) (struct telegram *instance); - - /** - * A callback function that is called when a client registration is required. - * - * This callback must query the authentication code from the user and - * call do_send_code_result once done - */ - void (*on_client_registration_required) (struct telegram *instance); - - /** - * A callback function that is called when telegram is ready - */ - void (*on_ready) (struct telegram *instance); - - /** - * A callback function that is called when telegram is disconnected - */ - void (*on_error) (struct telegram *instance, const char *err); - - /** - * A callback function that is called when a new peer was allocated. This is useful - * for populating the GUI with new peers. - */ - DEFINE_EVENT_LISTENER(peer_allocated, void); - - /** - * A callback function that is called when a user's status has changed - */ - DEFINE_EVENT_LISTENER(update_user_status, void); - - /** - * A callback function that is called when a user starts or stops typing - */ - DEFINE_EVENT_LISTENER(update_user_typing, void); - DEFINE_EVENT_LISTENER(update_user_name, peer_t); - DEFINE_EVENT_LISTENER(update_user_photo, peer_t); - DEFINE_EVENT_LISTENER(update_user_registered, peer_t); - - DEFINE_EVENT_LISTENER(update_chat_participants, peer_t); - - /** - * A new user is added to a chat - * - * @param data1 The chat - * @param data2 The added user - * @param data3 The inviter - */ - DEFINE_EVENT_LISTENER_3(update_chat_add_participant, peer_t *, peer_id_t, peer_id_t); - - /** - * A user is deleted from a chat - * - * @param data1 The chat - * @param data2 The added user - * @param data3 NULL - */ - DEFINE_EVENT_LISTENER_3(update_chat_del_participant, peer_t *, peer_id_t, void *); - - /** - * A user in a chat is typing - * - * @param data1 The chat - * @param data2 The user - * @param data3 NULL - */ - DEFINE_EVENT_LISTENER_3(update_chat_user_typing, peer_t *, peer_t *, void *); - - /** - * A new device was registered for @location - * - * @param tg - * @param location - */ - DEFINE_EVENT_LISTENER(update_auth_new, char); - - /** - * A callback function that is called when a new message was allocated. This is useful - * for adding new messages to the GUI. - */ - DEFINE_EVENT_LISTENER(update_new_message, struct message); - - /** - * A callback function that is called when a download is completed. This is useful - * for populating the GUI with new user photos. - */ - DEFINE_EVENT_LISTENER(download_finished, struct download); - - /** - * A callback function that is called when a peer user info was received. This is useful - * for populating the GUI with new user photos. - */ - void (*on_user_info_received_handler) (struct telegram *instance, struct tgl_user *peer, int showInfo); - - /** - * A callback function that is called when chat info is received - */ - void (*on_chat_info_received) (struct telegram *instance, peer_id_t chatid); -}; - -DECLARE_EVENT_HANDLER (peer_allocated, void); -DECLARE_EVENT_HANDLER (update_user_status, void); -DECLARE_EVENT_HANDLER (update_user_typing, void); - -DECLARE_EVENT_HANDLER (update_user_name, peer_t); -DECLARE_EVENT_HANDLER (update_user_photo, peer_t); -DECLARE_EVENT_HANDLER (update_user_registered, peer_t); - -DECLARE_EVENT_HANDLER (update_chat_participants, peer_t); -DECLARE_EVENT_HANDLER_3 (update_chat_add_participant, peer_t *, peer_id_t, peer_id_t); -DECLARE_EVENT_HANDLER_3 (update_chat_del_participant, peer_t *, peer_id_t, void *); -DECLARE_EVENT_HANDLER_3 (update_chat_user_typing, peer_t *, peer_t *, void *); -DECLARE_EVENT_HANDLER (update_auth_new, char); - -DECLARE_EVENT_HANDLER (update_new_message, struct message); -DECLARE_EVENT_HANDLER (download_finished, struct download); - -#define MSG_STORE_SIZE 10000 - -/** - * A telegram session - * - * Contains all globals from the telegram-cli application is passed to every - * query call - */ -struct telegram { - void *protocol_data; - //int curr_dc; - - char *login; - char *config_path; - char *download_path; - char *auth_path; - char *state_path; - char *secret_path; - - int session_state; - struct telegram_config *config; - - /* - * protocol state - */ - struct protocol_state proto; - struct authorization_state auth; - - /* - * connection - */ - struct mtproto_connection *connection; - - /* - * binlog - */ - struct binlog *bl; - - // TODO: Bind this to the current data center, since the code hash is only - // valid in its context - char *phone_code_hash; - - int unread_messages; - long long cur_uploading_bytes; - long long cur_uploaded_bytes; - long long cur_downloading_bytes; - long long cur_downloaded_bytes; - int our_id; - struct tgl_user User; - BN_CTX *ctx; - int encr_root; - unsigned char *encr_prime; - int encr_param_version; - int max_chat_size; - int max_bcast_size; - int want_dc_num; - int new_dc_num; - int out_message_num; - char *suser; - int nearest_dc_num; - int packed_buffer[MAX_PACKED_SIZE / 4]; - struct tree_query *queries_tree; - struct tree_timer *timer_tree; - char *export_auth_str; - int export_auth_str_len; - char g_a[256]; - // do_get_difference - int get_difference_active; - struct message *ML[MSG_STORE_SIZE]; - - /* - * All active MtProto connections - */ - int cs; - struct mtproto_connection *Cs[100]; - - /* - * Downloads - */ - GQueue *dl_queue; - struct download *dl_curr; - - /* - * additional user data - */ - void *extra; -}; - -/** - * Create a new telegram application - * - * @param login The phone number to use as login name - * @param config Contains all callbacks used for the telegram instance - */ -struct telegram *telegram_new(const char* login, struct telegram_config *config); - -void telegram_restore_session(struct telegram *instance); -void telegram_store_session(struct telegram *instance); -void telegram_destroy(struct telegram *instance); - -/** - * Get the currently active connection - */ -struct connection *telegram_get_connection(struct telegram *instance); - -/** - * Return the current working dc - */ -struct dc *telegram_get_working_dc(struct telegram *instance); - -/* - * Events - */ - -/** - * Change the state of the given telegram instance and execute all event handlers - * - * @param instance The telegram instance that changed its state - * @param state The changed state - * @param data Extra data that depends on switched state - */ -void telegram_change_state(struct telegram *instance, int state, void *data); - -/** - * Connect to the telegram network with the given configuration - */ -void telegram_connect(struct telegram *instance); - -/** - * Read and process all available input from the network - */ -void mtp_read_input (struct mtproto_connection *mtp); - -/** - * Write all available output to the network - */ -int mtp_write_output (struct mtproto_connection *mtp); - -/** - * Try to interpret RPC calls and apply the changes to the current telegram state - */ -void try_rpc_interpret(struct telegram *instance, int op, int len); - -/** - * Request a registration code - */ -char* network_request_registration(); - -/** - * Verify the registration with the given registration code - */ -int network_verify_registration(const char *code, const char *sms_hash); - -/** - * Verify the registration with the given registration code - */ -int network_verify_phone_registration(const char *code, const char *sms_hash, - const char *first, const char *last); - -/* - * Load known users and chats on connect - */ -void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int showInfo); - -/** - * Set the connection after a proxy_request_cb - * - * @param fd The file-descriptor of the acquired connection - * @param handle A handle that will be passed back on output and close callbacks - */ -struct mtproto_connection *telegram_add_proxy(struct telegram *tg, struct proxy_request *req, int fd, void *handle); - -/** - * Return wether telegram is authenticated with the currently active data center - */ -int telegram_authenticated (struct telegram *instance); - -void telegram_flush (struct telegram *instance); -void telegram_dl_add (struct telegram *instance, struct download *dl); -void telegram_dl_next (struct telegram *instance); - -#endif diff --git a/tg-server.pub b/tg-server.pub index 4e006b4..5e38bb0 100644 --- a/tg-server.pub +++ b/tg-server.pub @@ -6,4 +6,3 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB -----END RSA PUBLIC KEY----- - diff --git a/tgp-net.c b/tgp-net.c new file mode 100644 index 0000000..92a9614 --- /dev/null +++ b/tgp-net.c @@ -0,0 +1,584 @@ +/* + This file is part of tgl-library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Copyright Vitaly Valtman 2013-2014 +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tgp-net.h" +//#include "include.h" +#include +#include +//#include "mtproto-client.h" +//#include "mtproto-common.h" +//#include "tree.h" +//#include "tools.h" + +#include +#include + +#include "telegram-purple.h" + +#ifndef POLLRDHUP +#define POLLRDHUP 0 +#endif + +//double get_utime (int clock_id); + +//extern struct mtproto_methods auth_methods; + +static void fail_connection (struct connection *c); + +#define PING_TIMEOUT 10 + +static void start_ping_timer (struct connection *c); +static int ping_alarm (gpointer arg) { + struct connection *c = arg; + struct tgl_state *TLS = c->TLS; + vlogprintf (E_DEBUG + 2,"ping alarm\n"); + assert (c->state == conn_ready || c->state == conn_connecting); + if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) { + vlogprintf (E_WARNING, "fail connection: reason: ping timeout\n"); + c->state = conn_failed; + fail_connection (c); + return FALSE; + } else if (tglt_get_double_time () - c->last_receive_time > 3 * PING_TIMEOUT && c->state == conn_ready) { + tgl_do_send_ping (c->TLS, c); + return TRUE; + } else { + return TRUE; + } +} + +static void stop_ping_timer (struct connection *c) { + purple_timeout_remove (c->ping_ev); +} + +static void start_ping_timer (struct connection *c) { + c->ping_ev = purple_timeout_add_seconds (PING_TIMEOUT, ping_alarm, c); +} + +static void restart_connection (struct connection *c); + +static int fail_alarm (gpointer arg) { + struct connection *c = arg; + c->in_fail_timer = 0; + restart_connection (c); + return FALSE; +} + +static void start_fail_timer (struct connection *c) { + if (c->in_fail_timer) { return; } + c->in_fail_timer = 1; + + c->fail_ev = purple_timeout_add_seconds (10, fail_alarm, c); +} + +static struct connection_buffer *new_connection_buffer (int size) { + struct connection_buffer *b = malloc (sizeof (*b)); + memset (b, 0, sizeof (*b)); + b->start = malloc (size); + b->end = b->start + size; + b->rptr = b->wptr = b->start; + return b; +} + +static void delete_connection_buffer (struct connection_buffer *b) { + free (b->start); + free (b); +} + +static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond); +int tgln_write_out (struct connection *c, const void *_data, int len) { + struct tgl_state *TLS = c->TLS; + vlogprintf (E_DEBUG, "write_out: %d bytes\n", len); + const unsigned char *data = _data; + if (!len) { return 0; } + assert (len > 0); + int x = 0; + if (!c->out_bytes) { + assert (c->write_ev == -1); + c->write_ev = purple_input_add (c->fd, PURPLE_INPUT_WRITE, conn_try_write, c); + } + if (!c->out_head) { + struct connection_buffer *b = new_connection_buffer (1 << 20); + c->out_head = c->out_tail = b; + } + while (len) { + if (c->out_tail->end - c->out_tail->wptr >= len) { + memcpy (c->out_tail->wptr, data, len); + c->out_tail->wptr += len; + c->out_bytes += len; + return x + len; + } else { + int y = c->out_tail->end - c->out_tail->wptr; + assert (y < len); + memcpy (c->out_tail->wptr, data, y); + x += y; + len -= y; + data += y; + struct connection_buffer *b = new_connection_buffer (1 << 20); + c->out_tail->next = b; + b->next = 0; + c->out_tail = b; + c->out_bytes += y; + } + } + return x; +} + +int tgln_read_in (struct connection *c, void *_data, int len) { + unsigned char *data = _data; + if (!len) { return 0; } + assert (len > 0); + if (len > c->in_bytes) { + len = c->in_bytes; + } + int x = 0; + while (len) { + int y = c->in_head->wptr - c->in_head->rptr; + if (y > len) { + memcpy (data, c->in_head->rptr, len); + c->in_head->rptr += len; + c->in_bytes -= len; + return x + len; + } else { + memcpy (data, c->in_head->rptr, y); + c->in_bytes -= y; + x += y; + data += y; + len -= y; + void *old = c->in_head; + c->in_head = c->in_head->next; + if (!c->in_head) { + c->in_tail = 0; + } + delete_connection_buffer (old); + } + } + return x; +} + +int tgln_read_in_lookup (struct connection *c, void *_data, int len) { + unsigned char *data = _data; + if (!len || !c->in_bytes) { return 0; } + assert (len > 0); + if (len > c->in_bytes) { + len = c->in_bytes; + } + int x = 0; + struct connection_buffer *b = c->in_head; + while (len) { + int y = b->wptr - b->rptr; + if (y >= len) { + memcpy (data, b->rptr, len); + return x + len; + } else { + memcpy (data, b->rptr, y); + x += y; + data += y; + len -= y; + b = b->next; + } + } + return x; +} + +void tgln_flush_out (struct connection *c) { +} + +//#define MAX_CONNECTIONS 100 +//static struct connection *Connections[MAX_CONNECTIONS]; +//static int max_connection_fd; + +static void rotate_port (struct connection *c) { + switch (c->port) { + case 443: + c->port = 80; + break; + case 80: + c->port = 25; + break; + case 25: + c->port = 443; + break; + } +} + +static void try_read (struct connection *c); +static void try_write (struct connection *c); + +static void conn_try_read (gpointer arg, gint source, PurpleInputCondition cond) { + struct connection *c = arg; + struct tgl_state *TLS = c->TLS; + vlogprintf (E_DEBUG + 1, "Try read. Fd = %d\n", c->fd); + try_read (c); +} + +static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond) { + struct connection *c = arg; + struct tgl_state *TLS = c->TLS; + if (c->state == conn_connecting) { + c->state = conn_ready; + c->methods->ready (TLS, c); + } + try_write (c); + if (!c->out_bytes) { + purple_input_remove (c->write_ev); + c->write_ev = -1; + } +} + +static void net_on_connected (gpointer arg, gint fd, const gchar *error_message) { + struct connection *c = arg; + struct tgl_state *TLS = c->TLS; + vlogprintf (E_DEBUG - 2, "connect result: %d\n", fd); + + if (fd == -1) { + fail_connection (c); + return; + } + + c->fd = fd; + c->read_ev = purple_input_add (fd, PURPLE_INPUT_READ, conn_try_read, c); + + char byte = 0xef; + assert (tgln_write_out (c, &byte, 1) == 1); + + c->last_receive_time = tglt_get_double_time (); + start_ping_timer (c); +} + +struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods) { + struct connection *c = malloc (sizeof (*c)); + memset (c, 0, sizeof (*c)); + c->TLS = TLS; + + + c->fd = -1; + c->state = conn_connecting; + + c->last_receive_time = tglt_get_double_time (); + c->ip = strdup (host); + c->flags = 0; + c->port = port; + + c->ping_ev = -1; + c->fail_ev = -1; + c->write_ev = -1; + c->read_ev = -1; + + c->dc = dc; + c->session = session; + c->methods = methods; + + telegram_conn *conn = TLS->ev_base; + c->prpl_data = purple_proxy_connect (conn->gc, conn->pa, host, port, net_on_connected, c); + + return c; +} + +static void restart_connection (struct connection *c) { + struct tgl_state *TLS = c->TLS; + if (c->last_connect_time == time (0)) { + start_fail_timer (c); + return; + } + + telegram_conn *conn = TLS->ev_base; + c->prpl_data = purple_proxy_connect (conn->gc, conn->pa, c->ip, c->port, net_on_connected, c); +} + +static void fail_connection (struct connection *c) { + struct tgl_state *TLS = c->TLS; + if (c->state == conn_ready) { + stop_ping_timer (c); + } + if (c->write_ev >= 0) { + purple_input_remove (c->write_ev); + c->write_ev = -1; + } + if (c->read_ev >= 0) { + purple_input_remove (c->write_ev); + c->read_ev = -1; + } + + rotate_port (c); + + struct connection_buffer *b = c->out_head; + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + b = c->in_head; + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + c->out_head = c->out_tail = c->in_head = c->in_tail = 0; + c->state = conn_failed; + c->out_bytes = c->in_bytes = 0; + + if (c->state == conn_ready) { + telegram_conn *conn = TLS->ev_base; + purple_connection_error_reason(conn->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, "connection fail"); + } + c->prpl_data = NULL; // Did not find any destroy code. What should be done here? + + vlogprintf (E_NOTICE, "Lost connection to server... %s:%d\n", c->ip, c->port); + restart_connection (c); +} + +//extern FILE *log_net_f; +static void try_write (struct connection *c) { + struct tgl_state *TLS = c->TLS; + vlogprintf (E_DEBUG, "try write: fd = %d\n", c->fd); + int x = 0; + while (c->out_head) { + int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); + if (r >= 0) { + x += r; + c->out_head->rptr += r; + if (c->out_head->rptr != c->out_head->wptr) { + break; + } + struct connection_buffer *b = c->out_head; + c->out_head = b->next; + if (!c->out_head) { + c->out_tail = 0; + } + delete_connection_buffer (b); + } else { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + vlogprintf (E_NOTICE, "fail_connection: write_error %m\n"); + fail_connection (c); + return; + } else { + break; + } + } + } + vlogprintf (E_DEBUG, "Sent %d bytes to %d\n", x, c->fd); + c->out_bytes -= x; +} + +static void try_rpc_read (struct connection *c) { + assert (c->in_head); + struct tgl_state *TLS = c->TLS; + + while (1) { + if (c->in_bytes < 1) { return; } + unsigned len = 0; + unsigned t = 0; + assert (tgln_read_in_lookup (c, &len, 1) == 1); + if (len >= 1 && len <= 0x7e) { + if (c->in_bytes < (int)(1 + 4 * len)) { return; } + } else { + if (c->in_bytes < 4) { return; } + assert (tgln_read_in_lookup (c, &len, 4) == 4); + len = (len >> 8); + if (c->in_bytes < (int)(4 + 4 * len)) { return; } + len = 0x7f; + } + + if (len >= 1 && len <= 0x7e) { + assert (tgln_read_in (c, &t, 1) == 1); + assert (t == len); + assert (len >= 1); + } else { + assert (len == 0x7f); + assert (tgln_read_in (c, &len, 4) == 4); + len = (len >> 8); + assert (len >= 1); + } + len *= 4; + int op; + assert (tgln_read_in_lookup (c, &op, 4) == 4); + c->methods->execute (TLS, c, op, len); + } +} + +static void try_read (struct connection *c) { + struct tgl_state *TLS = c->TLS; + vlogprintf (E_DEBUG, "try read: fd = %d\n", c->fd); + if (!c->in_tail) { + c->in_head = c->in_tail = new_connection_buffer (1 << 20); + } + #ifdef EVENT_V1 + struct timeval tv = {5, 0}; + event_add (c->read_ev, &tv); + #endif + int x = 0; + while (1) { + int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr); + if (r > 0) { + c->last_receive_time = tglt_get_double_time (); + stop_ping_timer (c); + start_ping_timer (c); + } + if (r >= 0) { + c->in_tail->wptr += r; + x += r; + if (c->in_tail->wptr != c->in_tail->end) { + break; + } + struct connection_buffer *b = new_connection_buffer (1 << 20); + c->in_tail->next = b; + c->in_tail = b; + } else { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + vlogprintf (E_NOTICE, "fail_connection: read_error %m\n"); + fail_connection (c); + return; + } else { + break; + } + } + } + vlogprintf (E_DEBUG, "Received %d bytes from %d\n", x, c->fd); + c->in_bytes += x; + if (x) { + try_rpc_read (c); + } +} +/* +int tgl_connections_make_poll_array (struct pollfd *fds, int max) { + int _max = max; + int i; + for (i = 0; i <= max_connection_fd; i++) { + if (Connections[i] && Connections[i]->state == conn_failed) { + restart_connection (Connections[i]); + } + if (Connections[i] && Connections[i]->state != conn_failed) { + assert (max > 0); + struct connection *c = Connections[i]; + fds[0].fd = c->fd; + fds[0].events = POLLERR | POLLHUP | POLLRDHUP | POLLIN; + if (c->out_bytes || c->state == conn_connecting) { + fds[0].events |= POLLOUT; + } + fds ++; + max --; + } + } + return _max - max; +} + +void tgl_connections_poll_result (struct pollfd *fds, int max) { + int i; + for (i = 0; i < max; i++) { + struct connection *c = Connections[fds[i].fd]; + if (fds[i].revents & POLLIN) { + try_read (c); + } + if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) { + vlogprintf (E_NOTICE, "fail_connection: events_mask=0x%08x\n", fds[i].revents); + fail_connection (c); + } else if (fds[i].revents & POLLOUT) { + if (c->state == conn_connecting) { + vlogprintf (E_DEBUG, "connection ready\n"); + c->state = conn_ready; + c->last_receive_time = tglt_get_double_time (); + } + if (c->out_bytes) { + try_write (c); + } + } + } +}*/ + +static void incr_out_packet_num (struct connection *c) { + c->out_packet_num ++; +} + +static struct tgl_dc *get_dc (struct connection *c) { + return c->dc; +} + +static struct tgl_session *get_session (struct connection *c) { + return c->session; +} + +static void tgln_free (struct connection *c) { + if (c->ip) { free (c->ip); } + struct connection_buffer *b = c->out_head; + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + b = c->in_head; + while (b) { + struct connection_buffer *d = b; + b = b->next; + delete_connection_buffer (d); + } + + if (c->ping_ev >= 0) { + purple_timeout_remove (c->ping_ev); + c->ping_ev = -1; + } + if (c->fail_ev >= 0) { + purple_timeout_remove (c->fail_ev); + c->fail_ev = -1; + } + + if (c->read_ev >= 0) { + purple_input_remove (c->read_ev); + } + if (c->write_ev >= 0) { + purple_input_remove (c->write_ev); + } + + c->fd = -1; +} + +struct tgl_net_methods tgp_conn_methods = { + .write_out = tgln_write_out, + .read_in = tgln_read_in, + .read_in_lookup = tgln_read_in_lookup, + .flush_out = tgln_flush_out, + .incr_out_packet_num = incr_out_packet_num, + .get_dc = get_dc, + .get_session = get_session, + .create_connection = tgln_create_connection, + .free = tgln_free +}; diff --git a/tgp-net.h b/tgp-net.h new file mode 100644 index 0000000..258a045 --- /dev/null +++ b/tgp-net.h @@ -0,0 +1,88 @@ +/* + This file is part of tgl-library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Copyright Vitaly Valtman 2013-2014 +*/ +#ifndef __NET_H__ +#define __NET_H__ + +struct connection_buffer { + unsigned char *start; + unsigned char *end; + unsigned char *rptr; + unsigned char *wptr; + struct connection_buffer *next; +}; + +enum conn_state { + conn_none, + conn_connecting, + conn_ready, + conn_failed, + conn_stopped +}; + +struct connection { + int fd; + char *ip; + int port; + int flags; + enum conn_state state; + int ipv6[4]; + struct connection_buffer *in_head; + struct connection_buffer *in_tail; + struct connection_buffer *out_head; + struct connection_buffer *out_tail; + int in_bytes; + int out_bytes; + int packet_num; + int out_packet_num; + int last_connect_time; + int in_fail_timer; + struct mtproto_methods *methods; + struct tgl_state *TLS; + struct tgl_session *session; + struct tgl_dc *dc; + void *extra; + int ping_ev; + int fail_ev; + int read_ev; + int write_ev; + double last_receive_time; + void *prpl_data; +}; + +//extern struct connection *Connections[]; + +int tgln_write_out (struct connection *c, const void *data, int len); +void tgln_flush_out (struct connection *c); +int tgln_read_in (struct connection *c, void *data, int len); +int tgln_read_in_lookup (struct connection *c, void *data, int len); + +//void tgln_insert_msg_id (struct tgl_session *S, long long id); + +extern struct tgl_net_methods tgp_conn_methods; + +//void create_all_outbound_connections (void); + +//struct connection *create_connection (const char *host, int port, struct tgl_session *session, struct connection_methods *methods); +//struct tgl_dc *tgln_alloc_dc (int id, char *ip, int port); +//void tgln_dc_create_session (struct tgl_dc *DC, struct mtproto_methods *methods); +struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods); + +#define GET_DC(c) (c->session->dc) +#endif diff --git a/tgp-timers.c b/tgp-timers.c new file mode 100644 index 0000000..eec0456 --- /dev/null +++ b/tgp-timers.c @@ -0,0 +1,75 @@ +/* + This file is part of tgl-library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Copyright Vitaly Valtman 2013-2014 +*/ +#include +#include +#include +#include + +struct tgl_timer { + struct tgl_state *TLS; + void (*cb)(struct tgl_state *, void *); + void *arg; + int fd; +}; + +static int timer_alarm (gpointer arg) { + struct tgl_timer *t = arg; + t->cb (t->TLS, t->arg); + return FALSE; +} + +static struct tgl_timer *tgl_timer_alloc (struct tgl_state *TLS, void (*cb)(struct tgl_state *TLS, void *arg), void *arg) { + struct tgl_timer *t = malloc (sizeof (*t)); + t->TLS = TLS; + t->cb = cb; + t->arg = arg; + t->fd = -1; + return t; +} + +static void tgl_timer_insert (struct tgl_timer *t, double p) { + if (p < 0) { p = 0; } + if (p < 1) { + t->fd = purple_timeout_add (1000 * p, timer_alarm, t); + } else { + t->fd = purple_timeout_add_seconds (p, timer_alarm, t); + } +} + +static void tgl_timer_delete (struct tgl_timer *t) { + if (t->fd >= 0) { + purple_timeout_remove (t->fd); + t->fd = -1; + } +} + +static void tgl_timer_free (struct tgl_timer *t) { + if (t->fd >= 0) { + tgl_timer_delete (t); + } + free (t); +} + +struct tgl_timer_methods tgp_timers = { + .alloc = tgl_timer_alloc, + .insert = tgl_timer_insert, + .delete = tgl_timer_delete, + .free = tgl_timer_free +}; diff --git a/tgp-timers.h b/tgp-timers.h new file mode 100644 index 0000000..6791ec1 --- /dev/null +++ b/tgp-timers.h @@ -0,0 +1,27 @@ +/* + This file is part of tgl-library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Copyright Vitaly Valtman 2013-2014 +*/ + +#ifndef __TGL_TIMERS_H__ +#define __TGL_TIMERS_H__ + +#include "tgl.h" +extern struct tgl_timer_methods tgp_timers; + +#endif diff --git a/tools.c b/tools.c deleted file mode 100644 index 130c3cb..0000000 --- a/tools.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include "tools.h" -#include "msglog.h" - -#ifdef DEBUG -#define RES_PRE 8 -#define RES_AFTER 8 -#define MAX_BLOCKS 1000000 -void *blocks[MAX_BLOCKS]; -void *free_blocks[MAX_BLOCKS]; -int used_blocks; -int free_blocks_cnt; -#endif - -extern int verbosity; - -long long total_allocated_bytes; - -static void out_of_memory (void) { - fprintf (stderr, "Out of memory\n"); - exit (1); -} - -int tsnprintf (char *buf, int len, const char *format, ...) { - va_list ap; - va_start (ap, format); - int r = vsnprintf (buf, len, format, ap); - va_end (ap); - assert (r <= len && "tsnprintf buffer overflow"); - return r; -} - -int tasprintf (char **res, const char *format, ...) { - va_list ap; - va_start (ap, format); - int r = vasprintf (res, format, ap); - assert (r >= 0); - va_end (ap); - void *rs = talloc (strlen (*res) + 1); - memcpy (rs, *res, strlen (*res) + 1); - free (*res); - *res = rs; - return r; -} - -void print_backtrace (void); -void tfree (void *ptr, int size __attribute__ ((unused))) { -#ifdef DEBUG - total_allocated_bytes -= size; - ptr -= RES_PRE; - if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { - debug ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); - } - assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); - assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); - assert (*(int *)(ptr + 4) == size); - int block_num = *(int *)(ptr + 4 + RES_PRE + size); - if (block_num >= used_blocks) { - debug ("block_num = %d, used = %d\n", block_num, used_blocks); - } - assert (block_num < used_blocks); - if (block_num < used_blocks - 1) { - void *p = blocks[used_blocks - 1]; - int s = (*(int *)p) ^ 0xbedabeda; - *(int *)(p + 4 + RES_PRE + s) = block_num; - blocks[block_num] = p; - } - blocks[--used_blocks] = 0; - memset (ptr, 0, size + RES_PRE + RES_AFTER); - *(int *)ptr = size + 12; - free_blocks[free_blocks_cnt ++] = ptr; -#else - free (ptr); -#endif -} - -void tfree_str (void *ptr) { - if (!ptr) { return; } - tfree (ptr, strlen (ptr) + 1); -} - -void tfree_secure (void *ptr, int size) { - memset (ptr, 0, size); - tfree (ptr, size); -} - -void *trealloc (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) { -#ifdef DEBUG - void *p = talloc (size); - memcpy (p, ptr, size >= old_size ? old_size : size); - tfree (ptr, old_size); - return p; -#else - void *p = realloc (ptr, size); - ensure_ptr (p); - return p; -#endif -} - -void *talloc (size_t size) { -#ifdef DEBUG - total_allocated_bytes += size; - void *p = malloc (size + RES_PRE + RES_AFTER); - ensure_ptr (p); - *(int *)p = size ^ 0xbedabeda; - *(int *)(p + 4) = size; - *(int *)(p + RES_PRE + size) = size ^ 0x7bed7bed; - *(int *)(p + RES_AFTER + 4 + size) = used_blocks; - blocks[used_blocks ++] = p; - return p + 8; -#else - void *p = malloc (size); - ensure_ptr (p); - return p; -#endif -} - -void *talloc0 (size_t size) { - void *p = talloc (size); - memset (p, 0, size); - return p; -} - -char *tstrdup (const char *s) { -#ifdef DEBUG - int l = strlen (s); - char *p = talloc (l + 1); - memcpy (p, s, l + 1); - return p; -#else - char *p = strdup (s); - if (p == NULL) { - out_of_memory (); - } - return p; -#endif -} - -char *tstrndup (const char *s, size_t n) { -#ifdef DEBUG - size_t l = 0; - for (l = 0; l < n && s[l]; l++) { } - char *p = talloc (l + 1); - memcpy (p, s, l); - p[l] = 0; - return p; -#else - char *p = strndup (s, n); - if (p == NULL) { - out_of_memory (); - } - return p; -#endif -} - -void ensure (int r) { - if (!r) { - debug ("Open SSL error\n"); - ERR_print_errors_fp (stderr); - assert (0); - } -} - -void ensure_ptr (void *p) { - if (p == NULL) { - out_of_memory (); - } -} - -int tinflate (void *input, int ilen, void *output, int olen) { - z_stream strm; - memset (&strm, 0, sizeof (strm)); - assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); - strm.avail_in = ilen; - strm.next_in = input; - strm.avail_out = olen ; - strm.next_out = output; - int err = inflate (&strm, Z_FINISH), total_out = 0; - if (err == Z_OK || err == Z_STREAM_END) { - total_out = (int) strm.total_out; - if (err == Z_STREAM_END && verbosity >= 2) { - debug ( "inflated %d bytes\n", (int) strm.total_out); - } - } - if (err != Z_STREAM_END) { - debug ( "inflate error = %d\n", err); - debug ( "inflated %d bytes\n", (int) strm.total_out); - } - inflateEnd (&strm); - return total_out; -} - -#ifdef DEBUG -void tcheck (void) { - int i; - for (i = 0; i < used_blocks; i++) { - void *ptr = blocks[i]; - int size = (*(int *)ptr) ^ 0xbedabeda; - assert (*(int *)(ptr + 4) == size); - assert (*(int *)(ptr + RES_PRE + size) == (size ^ 0x7bed7bed)); - assert (*(int *)(ptr + RES_PRE + 4 + size) == i); - } - for (i = 0; i < free_blocks_cnt; i++) { - void *ptr = free_blocks[i]; - int l = *(int *)ptr; - int j = 0; - for (j = 0; j < l; j++) { - if (*(char *)(ptr + 4 + j)) { - hexdump (ptr + 8, ptr + 8 + l + ((-l) & 3)); - debug ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr); - assert (0); - } - } - } - debug ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt); -} - -void texists (void *ptr, int size) { - ptr -= RES_PRE; - if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { - debug ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); - } - assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); - assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); - assert (*(int *)(ptr + 4) == size); - int block_num = *(int *)(ptr + 4 + RES_PRE + size); - if (block_num >= used_blocks) { - debug ("block_num = %d, used = %d\n", block_num, used_blocks); - } - assert (block_num < used_blocks); -} -#endif diff --git a/tools.h b/tools.h deleted file mode 100644 index 3f3eca2..0000000 --- a/tools.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ - -#pragma once - -void *talloc (size_t size); -void *trealloc (void *ptr, size_t old_size, size_t size); -void *talloc0 (size_t size); -char *tstrdup (const char *s); -char *tstrndup (const char *s, size_t n); -//char *stradd(const char *, ...); -int tinflate (void *input, int ilen, void *output, int olen); -void ensure (int r); -void ensure_ptr (void *p); - -void tfree (void *ptr, int size); -void tfree_str (void *ptr); -void tfree_secure (void *ptr, int size); - - -int tsnprintf (char *buf, int len, const char *format, ...) __attribute__ ((format (printf, 3, 4))); -int tasprintf (char **res, const char *format, ...) __attribute__ ((format (printf, 2, 3))); - -#ifdef DEBUG -void tcheck (void); -void texists (void *ptr, int size); -#endif diff --git a/tree.h b/tree.h deleted file mode 100644 index fd79b75..0000000 --- a/tree.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - This file is part of telegram-client. - - Telegram-client is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Telegram-client is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this telegram-client. If not, see . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __TREE_H__ -#define __TREE_H__ -#include - -#include -#include -#include - -#pragma pack(push,4) -#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ -struct tree_ ## X_NAME { \ - struct tree_ ## X_NAME *left, *right;\ - X_TYPE x;\ - int y;\ -};\ -\ -struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ - struct tree_ ## X_NAME *T = talloc (sizeof (*T));\ - T->x = x;\ - T->y = y;\ - T->left = T->right = 0;\ - return T;\ -}\ -\ -void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ - tfree (T, sizeof (*T));\ -}\ -\ -void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ - if (!T) {\ - *L = *R = 0;\ - } else {\ - int c = X_CMP (x, T->x);\ - if (c < 0) {\ - tree_split_ ## X_NAME (T->left, x, L, &T->left);\ - *R = T;\ - } else {\ - tree_split_ ## X_NAME (T->right, x, &T->right, R);\ - *L = T;\ - }\ - }\ -}\ -\ -struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result));\ -struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ - if (!T) {\ - return new_tree_node_ ## X_NAME (x, y);\ - } else {\ - if (y > T->y) {\ - struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\ - tree_split_ ## X_NAME (T, x, &N->left, &N->right);\ - return N;\ - } else {\ - int c = X_CMP (x, T->x);\ - assert (c);\ - if (c < 0) { \ - T->left = tree_insert_ ## X_NAME (T->left, x, y);\ - } else { \ - T->right = tree_insert_ ## X_NAME (T->right, x, y);\ - } \ - return T; \ - }\ - }\ -}\ -\ -struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\ - if (!L || !R) {\ - return L ? L : R;\ - } else {\ - if (L->y > R->y) {\ - L->right = tree_merge_ ## X_NAME (L->right, R);\ - return L;\ - } else {\ - R->left = tree_merge_ ## X_NAME (L, R->left);\ - return R;\ - }\ - }\ -}\ -\ -struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result));\ -struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ - assert (T);\ - int c = X_CMP (x, T->x);\ - if (!c) {\ - struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\ - delete_tree_node_ ## X_NAME (T);\ - return N;\ - } else {\ - if (c < 0) { \ - T->left = tree_delete_ ## X_NAME (T->left, x); \ - } else { \ - T->right = tree_delete_ ## X_NAME (T->right, x); \ - } \ - return T; \ - }\ -}\ -\ -X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\ - if (!T) { return X_UNSET; } \ - while (T->left) { T = T->left; }\ - return T->x; \ -} \ -\ -X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ - int c;\ - while (T && (c = X_CMP (x, T->x))) {\ - T = (c < 0 ? T->left : T->right);\ - }\ - return T ? T->x : X_UNSET;\ -}\ -\ -void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ - if (!T) { return; } \ - tree_act_ ## X_NAME (T->left, act); \ - act (T->x); \ - tree_act_ ## X_NAME (T->right, act); \ -}\ -\ -int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ - if (!T) { return 0; }\ - return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ -}\ -void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ - if (!T) { return; }\ - if (T->left) { \ - assert (T->left->y <= T->y);\ - assert (X_CMP (T->left->x, T->x) < 0); \ - }\ - if (T->right) { \ - assert (T->right->y <= T->y);\ - assert (X_CMP (T->right->x, T->x) > 0); \ - }\ - tree_check_ ## X_NAME (T->left); \ - tree_check_ ## X_NAME (T->right); \ -}\ - -#define int_cmp(a,b) ((a) - (b)) -#pragma pack(pop) -#endif From 8ebbdfbaff657461db1b63bde586cb411cbd2606 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Tue, 11 Nov 2014 20:38:01 +0300 Subject: [PATCH 465/465] updated .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..204cd2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +tg/

0 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 Y)hT@txvB!XVUIZ{&PGJPbzb5B1y|afvH$=8 literal 0 HcmV?d00001 diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj index 5800016..4f87961 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -20,6 +20,8 @@ C4877C2619BB6D11006FA91F /* telegram16.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2119BB6D11006FA91F /* telegram16.png */; }; C4877C2719BB6D11006FA91F /* telegram22.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2219BB6D11006FA91F /* telegram22.png */; }; C4877C2819BB6D11006FA91F /* telegram48.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2319BB6D11006FA91F /* telegram48.png */; }; + C49A915619BBC278001B3DC0 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C49A915519BBC278001B3DC0 /* libcrypto.a */; }; + C49A915819BBC5C5001B3DC0 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C49A915719BBC5C5001B3DC0 /* libz.dylib */; }; C4BF98FF19BB75260038D507 /* libglib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4BF98FE19BB75250038D507 /* libglib.framework */; }; C4BF990119BB87C00038D507 /* libpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4BF990019BB87C00038D507 /* libpurple.framework */; }; C4BF991C19BB8B4D0038D507 /* binlog.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990419BB8B4D0038D507 /* binlog.c */; }; @@ -55,6 +57,8 @@ C4877C2119BB6D11006FA91F /* telegram16.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram16.png; path = "../purple-plugin/telegram16.png"; sourceTree = ""; }; C4877C2219BB6D11006FA91F /* telegram22.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram22.png; path = "../purple-plugin/telegram22.png"; sourceTree = ""; }; C4877C2319BB6D11006FA91F /* telegram48.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram48.png; path = "../purple-plugin/telegram48.png"; sourceTree = ""; }; + C49A915519BBC278001B3DC0 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcrypto.a; sourceTree = ""; }; + C49A915719BBC5C5001B3DC0 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; C4BF98FE19BB75250038D507 /* libglib.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libglib.framework; sourceTree = ""; }; C4BF990019BB87C00038D507 /* libpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libpurple.framework; sourceTree = ""; }; C4BF990419BB8B4D0038D507 /* binlog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = binlog.c; path = ../binlog.c; sourceTree = ""; }; @@ -88,8 +92,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C49A915819BBC5C5001B3DC0 /* libz.dylib in Frameworks */, C410949F19BB36A70083BF3F /* AdiumLibpurple.framework in Frameworks */, C4BF990119BB87C00038D507 /* libpurple.framework in Frameworks */, + C49A915619BBC278001B3DC0 /* libcrypto.a in Frameworks */, C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */, C4BF98FF19BB75260038D507 /* libglib.framework in Frameworks */, C410949D19BB34BE0083BF3F /* Adium.framework in Frameworks */, @@ -128,6 +134,8 @@ C410948819BB2D7D0083BF3F /* Frameworks */ = { isa = PBXGroup; children = ( + C49A915719BBC5C5001B3DC0 /* libz.dylib */, + C49A915519BBC278001B3DC0 /* libcrypto.a */, C4BF990019BB87C00038D507 /* libpurple.framework */, C4BF98FE19BB75250038D507 /* libglib.framework */, C410949E19BB36A70083BF3F /* AdiumLibpurple.framework */, @@ -332,6 +340,7 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -365,6 +374,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -394,6 +404,10 @@ ); INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = AdiumPlugin; }; @@ -422,6 +436,10 @@ ); INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = AdiumPlugin; }; From 922fe0e090429dc11955c5ab29cb2e7204660970 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 7 Sep 2014 00:59:13 +0200 Subject: [PATCH 426/465] Do not use Macros to represent Booleans --- purple-plugin/telegram-purple.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index e3cc4ab..3c60bc5 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -353,8 +353,8 @@ void telegram_on_client_registration (struct telegram *instance) "Enter Telegram Code", // primary "Telegram wants to verify your identity, please enter the code, that you have received via SMS.", // secondary NULL, // default_value - FALSE, // multiline - FALSE, // masked + 0, // multiline + 0, // masked "code", // hint "OK", // ok_text G_CALLBACK(client_registration_entered), // ok_cb @@ -591,7 +591,7 @@ static PurpleChat *blist_find_chat_by_hasht_cond(PurpleConnection *gc, int (*fn) return ch; } } - node = purple_blist_node_next(node, FALSE); + node = purple_blist_node_next(node, 0); } return NULL; } @@ -682,7 +682,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) const char *cuname = g_strdup_printf("%d", cu->user_id); debug("Adding user %s to chat %s\n", cuname, name); purple_conv_chat_add_user(purple_conversation_get_chat_data(conv), cuname, "", - PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), FALSE); + PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), 0); } } } @@ -896,19 +896,19 @@ static void tgprpl_set_buddy_icon(PurpleConnection * gc, PurpleStoredImage * img static gboolean tgprpl_can_receive_file(PurpleConnection * gc, const char *who) { purple_debug_info(PLUGIN_ID, "tgprpl_can_receive_file()\n"); - return FALSE; + return 0; } /** * Checks whether offline messages to @a buddy are supported. - * @return @c TRUE if @a buddy can be sent messages while they are - * offline, or @c FALSE if not. + * @return @c 1 if @a buddy can be sent messages while they are + * offline, or @c 0 if not. */ static gboolean tgprpl_offline_message(const PurpleBuddy * buddy) { purple_debug_info(PLUGIN_ID, "tgprpl_offline_message()\n"); - return FALSE; + return 0; } /** @@ -922,14 +922,14 @@ static GList *tgprpl_status_types(PurpleAccount * acct) GList *types = NULL; PurpleStatusType *type; type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, "available", NULL, - TRUE, TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); + 1, 1, 0, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); types = g_list_prepend(types, type); - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, "unavailable", NULL, TRUE, - TRUE, FALSE, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, "unavailable", NULL, 1, + 1, 0, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); types = g_list_prepend(types, type); - type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE); + type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL, NULL, 1); types = g_list_append(types, type); return g_list_reverse(types); From b5e242ea40ec824ce4ca862496168b42bd6aaa89 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 4 Oct 2014 23:42:08 +0200 Subject: [PATCH 427/465] Do not include framework files From 114bce7d4516c54345fe6b83e4bbbd4ef2c843a5 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 00:09:33 +0200 Subject: [PATCH 428/465] Fix dependencies and build settings in XCode project --- .../telegram-adium.xcodeproj/project.pbxproj | 118 ++++++++++++------ .../xcshareddata/telegram-adium.xccheckout | 10 +- .../xcschemes/telegram-adium.xcscheme | 14 ++- .../telegram-adium/telegram-adium-Info.plist | 2 + 4 files changed, 97 insertions(+), 47 deletions(-) diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj index 4f87961..a48c046 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -10,8 +10,6 @@ C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410948919BB2D7D0083BF3F /* CoreFoundation.framework */; }; C410949019BB2D7D0083BF3F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C410948E19BB2D7D0083BF3F /* InfoPlist.strings */; }; C410949B19BB337A0083BF3F /* TelegramPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = C410949A19BB337A0083BF3F /* TelegramPlugin.m */; }; - C410949D19BB34BE0083BF3F /* Adium.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410949C19BB34BE0083BF3F /* Adium.framework */; }; - C410949F19BB36A70083BF3F /* AdiumLibpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C410949E19BB36A70083BF3F /* AdiumLibpurple.framework */; }; C4877C1819BB37EA006FA91F /* TelegramService.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1719BB37EA006FA91F /* TelegramService.m */; }; C4877C1A19BB3D91006FA91F /* telegram-purple.c in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1919BB3D91006FA91F /* telegram-purple.c */; }; C4877C1E19BB676B006FA91F /* AdiumTelegramAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */; }; @@ -22,8 +20,16 @@ C4877C2819BB6D11006FA91F /* telegram48.png in Resources */ = {isa = PBXBuildFile; fileRef = C4877C2319BB6D11006FA91F /* telegram48.png */; }; C49A915619BBC278001B3DC0 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C49A915519BBC278001B3DC0 /* libcrypto.a */; }; C49A915819BBC5C5001B3DC0 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C49A915719BBC5C5001B3DC0 /* libz.dylib */; }; - C4BF98FF19BB75260038D507 /* libglib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4BF98FE19BB75250038D507 /* libglib.framework */; }; - C4BF990119BB87C00038D507 /* libpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4BF990019BB87C00038D507 /* libpurple.framework */; }; + C4B81AE319E084B800E9177C /* libglib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AE219E084B800E9177C /* libglib.framework */; }; + C4B81AE519E084C300E9177C /* libgmodule.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AE419E084C300E9177C /* libgmodule.framework */; }; + C4B81AE719E084D500E9177C /* libgobject.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AE619E084D500E9177C /* libgobject.framework */; }; + C4B81AE919E084DE00E9177C /* libgthread.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AE819E084DE00E9177C /* libgthread.framework */; }; + C4B81AEB19E084E500E9177C /* libintl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AEA19E084E500E9177C /* libintl.framework */; }; + C4B81AED19E084ED00E9177C /* libmeanwhile.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AEC19E084ED00E9177C /* libmeanwhile.framework */; }; + C4B81AEF19E084F600E9177C /* libpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AEE19E084F600E9177C /* libpurple.framework */; }; + C4B81AF119E087AF00E9177C /* AIUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AF019E087AF00E9177C /* AIUtilities.framework */; }; + C4B81AF319E087BA00E9177C /* AdiumLibpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AF219E087BA00E9177C /* AdiumLibpurple.framework */; }; + C4B81AF519E087C500E9177C /* Adium.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AF419E087C500E9177C /* Adium.framework */; }; C4BF991C19BB8B4D0038D507 /* binlog.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990419BB8B4D0038D507 /* binlog.c */; }; C4BF991D19BB8B4D0038D507 /* loop.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990519BB8B4D0038D507 /* loop.c */; }; C4BF991E19BB8B4D0038D507 /* msglog.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990619BB8B4D0038D507 /* msglog.c */; }; @@ -37,15 +43,13 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - C410948619BB2D7D0083BF3F /* telegram-adium.AdiumPlugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "telegram-adium.AdiumPlugin"; sourceTree = BUILT_PRODUCTS_DIR; }; + C410948619BB2D7D0083BF3F /* telegram-adium.AdiumLibpurplePlugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "telegram-adium.AdiumLibpurplePlugin"; sourceTree = BUILT_PRODUCTS_DIR; }; C410948919BB2D7D0083BF3F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; C410948D19BB2D7D0083BF3F /* telegram-adium-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "telegram-adium-Info.plist"; sourceTree = ""; }; C410948F19BB2D7D0083BF3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; C410949119BB2D7D0083BF3F /* telegram-adium-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "telegram-adium-Prefix.pch"; sourceTree = ""; }; C410949919BB337A0083BF3F /* TelegramPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramPlugin.h; sourceTree = ""; }; C410949A19BB337A0083BF3F /* TelegramPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramPlugin.m; sourceTree = ""; }; - C410949C19BB34BE0083BF3F /* Adium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Adium.framework; sourceTree = ""; }; - C410949E19BB36A70083BF3F /* AdiumLibpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AdiumLibpurple.framework; sourceTree = ""; }; C4877C1619BB37EA006FA91F /* TelegramService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramService.h; sourceTree = ""; }; C4877C1719BB37EA006FA91F /* TelegramService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramService.m; sourceTree = ""; }; C4877C1919BB3D91006FA91F /* telegram-purple.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "telegram-purple.c"; path = "../purple-plugin/telegram-purple.c"; sourceTree = ""; }; @@ -59,8 +63,16 @@ C4877C2319BB6D11006FA91F /* telegram48.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = telegram48.png; path = "../purple-plugin/telegram48.png"; sourceTree = ""; }; C49A915519BBC278001B3DC0 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcrypto.a; sourceTree = ""; }; C49A915719BBC5C5001B3DC0 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; - C4BF98FE19BB75250038D507 /* libglib.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libglib.framework; sourceTree = ""; }; - C4BF990019BB87C00038D507 /* libpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = libpurple.framework; sourceTree = ""; }; + C4B81AE219E084B800E9177C /* libglib.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libglib.framework; path = "../../adium-1.5.10/Frameworks/libglib.framework"; sourceTree = ""; }; + C4B81AE419E084C300E9177C /* libgmodule.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libgmodule.framework; path = "../../adium-1.5.10/Frameworks/libgmodule.framework"; sourceTree = ""; }; + C4B81AE619E084D500E9177C /* libgobject.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libgobject.framework; path = "../../adium-1.5.10/Frameworks/libgobject.framework"; sourceTree = ""; }; + C4B81AE819E084DE00E9177C /* libgthread.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libgthread.framework; path = "../../adium-1.5.10/Frameworks/libgthread.framework"; sourceTree = ""; }; + C4B81AEA19E084E500E9177C /* libintl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libintl.framework; path = "../../adium-1.5.10/Frameworks/libintl.framework"; sourceTree = ""; }; + C4B81AEC19E084ED00E9177C /* libmeanwhile.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libmeanwhile.framework; path = "../../adium-1.5.10/Frameworks/libmeanwhile.framework"; sourceTree = ""; }; + C4B81AEE19E084F600E9177C /* libpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libpurple.framework; path = "../../adium-1.5.10/Frameworks/libpurple.framework"; sourceTree = ""; }; + C4B81AF019E087AF00E9177C /* AIUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AIUtilities.framework; path = "../../../Library/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug/AIUtilities.framework"; sourceTree = ""; }; + C4B81AF219E087BA00E9177C /* AdiumLibpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdiumLibpurple.framework; path = "../../../Library/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug/AdiumLibpurple.framework"; sourceTree = ""; }; + C4B81AF419E087C500E9177C /* Adium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Adium.framework; path = "../../../Library/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug/Adium.framework"; sourceTree = ""; }; C4BF990419BB8B4D0038D507 /* binlog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = binlog.c; path = ../binlog.c; sourceTree = ""; }; C4BF990519BB8B4D0038D507 /* loop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loop.c; path = ../loop.c; sourceTree = ""; }; C4BF990619BB8B4D0038D507 /* msglog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = msglog.c; path = ../msglog.c; sourceTree = ""; }; @@ -93,12 +105,18 @@ buildActionMask = 2147483647; files = ( C49A915819BBC5C5001B3DC0 /* libz.dylib in Frameworks */, - C410949F19BB36A70083BF3F /* AdiumLibpurple.framework in Frameworks */, - C4BF990119BB87C00038D507 /* libpurple.framework in Frameworks */, C49A915619BBC278001B3DC0 /* libcrypto.a in Frameworks */, + C4B81AE519E084C300E9177C /* libgmodule.framework in Frameworks */, + C4B81AF319E087BA00E9177C /* AdiumLibpurple.framework in Frameworks */, + C4B81AEB19E084E500E9177C /* libintl.framework in Frameworks */, + C4B81AE319E084B800E9177C /* libglib.framework in Frameworks */, + C4B81AF519E087C500E9177C /* Adium.framework in Frameworks */, C410948A19BB2D7D0083BF3F /* CoreFoundation.framework in Frameworks */, - C4BF98FF19BB75260038D507 /* libglib.framework in Frameworks */, - C410949D19BB34BE0083BF3F /* Adium.framework in Frameworks */, + C4B81AEF19E084F600E9177C /* libpurple.framework in Frameworks */, + C4B81AF119E087AF00E9177C /* AIUtilities.framework in Frameworks */, + C4B81AED19E084ED00E9177C /* libmeanwhile.framework in Frameworks */, + C4B81AE919E084DE00E9177C /* libgthread.framework in Frameworks */, + C4B81AE719E084D500E9177C /* libgobject.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -108,25 +126,25 @@ C410947D19BB2D7D0083BF3F = { isa = PBXGroup; children = ( + C410949919BB337A0083BF3F /* TelegramPlugin.h */, + C410949A19BB337A0083BF3F /* TelegramPlugin.m */, + C4877C1619BB37EA006FA91F /* TelegramService.h */, + C4877C1719BB37EA006FA91F /* TelegramService.m */, + C4877C1C19BB676B006FA91F /* AdiumTelegramAccount.h */, + C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */, C4BF992619BB8B530038D507 /* telegram */, C4BF990319BB8B200038D507 /* telegram-purple */, C410948B19BB2D7D0083BF3F /* telegram-adium */, C410948819BB2D7D0083BF3F /* Frameworks */, C410948719BB2D7D0083BF3F /* Products */, C4877C2919BB6D22006FA91F /* Resources */, - C410949919BB337A0083BF3F /* TelegramPlugin.h */, - C4877C1619BB37EA006FA91F /* TelegramService.h */, - C4877C1719BB37EA006FA91F /* TelegramService.m */, - C4877C1C19BB676B006FA91F /* AdiumTelegramAccount.h */, - C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */, - C410949A19BB337A0083BF3F /* TelegramPlugin.m */, ); sourceTree = ""; }; C410948719BB2D7D0083BF3F /* Products */ = { isa = PBXGroup; children = ( - C410948619BB2D7D0083BF3F /* telegram-adium.AdiumPlugin */, + C410948619BB2D7D0083BF3F /* telegram-adium.AdiumLibpurplePlugin */, ); name = Products; sourceTree = ""; @@ -134,12 +152,18 @@ C410948819BB2D7D0083BF3F /* Frameworks */ = { isa = PBXGroup; children = ( + C4B81AE419E084C300E9177C /* libgmodule.framework */, + C4B81AE219E084B800E9177C /* libglib.framework */, + C4B81AF419E087C500E9177C /* Adium.framework */, + C4B81AF219E087BA00E9177C /* AdiumLibpurple.framework */, + C4B81AF019E087AF00E9177C /* AIUtilities.framework */, + C4B81AEE19E084F600E9177C /* libpurple.framework */, + C4B81AEC19E084ED00E9177C /* libmeanwhile.framework */, + C4B81AEA19E084E500E9177C /* libintl.framework */, + C4B81AE819E084DE00E9177C /* libgthread.framework */, + C4B81AE619E084D500E9177C /* libgobject.framework */, C49A915719BBC5C5001B3DC0 /* libz.dylib */, C49A915519BBC278001B3DC0 /* libcrypto.a */, - C4BF990019BB87C00038D507 /* libpurple.framework */, - C4BF98FE19BB75250038D507 /* libglib.framework */, - C410949E19BB36A70083BF3F /* AdiumLibpurple.framework */, - C410949C19BB34BE0083BF3F /* Adium.framework */, C410948919BB2D7D0083BF3F /* CoreFoundation.framework */, ); name = Frameworks; @@ -232,7 +256,7 @@ ); name = "telegram-adium"; productName = "telegram-adium"; - productReference = C410948619BB2D7D0083BF3F /* telegram-adium.AdiumPlugin */; + productReference = C410948619BB2D7D0083BF3F /* telegram-adium.AdiumLibpurplePlugin */; productType = "com.apple.product-type.bundle"; }; /* End PBXNativeTarget section */ @@ -388,19 +412,26 @@ C410949519BB2D7D0083BF3F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; + DEPLOYMENT_LOCATION = YES; + DEPLOYMENT_POSTPROCESSING = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)", + "/Users/matj/Library/Developer/Xcode/DerivedData/Adium-gdwrwbgfopymlzesvaaamabjdyym", + "/Users/matj/Development/adium-1.5.10/Frameworks", + "/Users/matj/Development/adium-1.5.10/build/Debug", + /Volumes/Workspace/adium/Frameworks, + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "telegram-adium/telegram-adium-Prefix.pch"; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(PROJECT_DIR)/libglib.framework/Headers/", - "$(PROJECT_DIR)/libpurple.framework/Headers/", - "$(PROJECT_DIR)/..", + "/Users/matj/Development/adium-1.5.10/Frameworks/libpurple.framework/Headers", + "/Users/matj/Development/adium-1.5.10/Frameworks/libglib.framework/Headers/glib", + "/Users/matj/Development/adium-1.5.10/Frameworks/libglib.framework/Headers", ); INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; @@ -408,31 +439,35 @@ "$(inherited)", "$(PROJECT_DIR)", ); + OTHER_CFLAGS = "-DPURPLE_STATIC_PRPL"; PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = AdiumPlugin; + WRAPPER_EXTENSION = AdiumLibpurplePlugin; }; name = Debug; }; C410949619BB2D7D0083BF3F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; + DEPLOYMENT_LOCATION = YES; + DEPLOYMENT_POSTPROCESSING = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)", - ); - "FRAMEWORK_SEARCH_PATHS[arch=*]" = ( - "$(inherited)", - "$(PROJECT_DIR)", + "/Users/matj/Library/Developer/Xcode/DerivedData/Adium-gdwrwbgfopymlzesvaaamabjdyym", + "/Users/matj/Development/adium-1.5.10/Frameworks", + "/Users/matj/Development/adium-1.5.10/build/Debug", + /Volumes/Workspace/adium/Frameworks, + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "telegram-adium/telegram-adium-Prefix.pch"; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(PROJECT_DIR)/Frameworks/libglib.framework/Headers/", - "$(PROJECT_DIR)/libpurple.framework/Headers/", - "$(PROJECT_DIR)/..", + "/Users/matj/Development/adium-1.5.10/Frameworks/libpurple.framework/Headers", + "/Users/matj/Development/adium-1.5.10/Frameworks/libglib.framework/Headers/glib", + "/Users/matj/Development/adium-1.5.10/Frameworks/libglib.framework/Headers", ); INFOPLIST_FILE = "telegram-adium/telegram-adium-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; @@ -440,8 +475,9 @@ "$(inherited)", "$(PROJECT_DIR)", ); + OTHER_CFLAGS = "-DPURPLE_STATIC_PRPL"; PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = AdiumPlugin; + WRAPPER_EXTENSION = AdiumLibpurplePlugin; }; name = Release; }; @@ -455,7 +491,7 @@ C410949319BB2D7D0083BF3F /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; C410949419BB2D7D0083BF3F /* Build configuration list for PBXNativeTarget "telegram-adium" */ = { isa = XCConfigurationList; @@ -464,7 +500,7 @@ C410949619BB2D7D0083BF3F /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout index 790fe0a..041fe29 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout +++ b/telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcshareddata/telegram-adium.xccheckout @@ -10,29 +10,29 @@ telegram-adium IDESourceControlProjectOriginsDictionary - 075EDEE1-AF43-4A9A-8B99-96488680535F + 2BAF9F6AF710B4D765F611851696219A50533669 ssh://bitbucket.org/telegrampurple/telegram-purple.git IDESourceControlProjectPath telegram-adium/telegram-adium.xcodeproj/project.xcworkspace IDESourceControlProjectRelativeInstallPathDictionary - 075EDEE1-AF43-4A9A-8B99-96488680535F + 2BAF9F6AF710B4D765F611851696219A50533669 ../../.. IDESourceControlProjectURL ssh://bitbucket.org/telegrampurple/telegram-purple.git IDESourceControlProjectVersion - 110 + 111 IDESourceControlProjectWCCIdentifier - 075EDEE1-AF43-4A9A-8B99-96488680535F + 2BAF9F6AF710B4D765F611851696219A50533669 IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey - 075EDEE1-AF43-4A9A-8B99-96488680535F + 2BAF9F6AF710B4D765F611851696219A50533669 IDESourceControlWCCName telegram-purple diff --git a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme index 8b109a8..1176c1d 100644 --- a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme +++ b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme @@ -15,7 +15,7 @@ @@ -39,6 +39,18 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" allowLocationSimulation = "YES"> + + + + + + diff --git a/telegram-adium/telegram-adium/telegram-adium-Info.plist b/telegram-adium/telegram-adium/telegram-adium-Info.plist index 5f9b01b..775c6b7 100644 --- a/telegram-adium/telegram-adium/telegram-adium-Info.plist +++ b/telegram-adium/telegram-adium/telegram-adium-Info.plist @@ -44,5 +44,7 @@ NSHumanReadableCopyright Copyright © 2014 Matthias Jentsch. All rights reserved. + NSPrincipalClass + TelegramPlugin From b6c9515de400ee326c7d2f7430755e30390b6cfc Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 00:11:32 +0200 Subject: [PATCH 429/465] Rename struct user to a avoid name collisions --- purple-plugin/telegram-purple.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 3c60bc5..b5d7b56 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -74,7 +74,7 @@ void tg_cli_log_cb(const char* format, va_list ap) void message_allocated_handler (struct telegram *instance, struct message *M); void peer_allocated_handler (struct telegram *instance, void *user); -void user_info_received_handler (struct telegram *instance, struct user *user, int showInfo); +void user_info_received_handler (struct telegram *instance, struct tgl_user *user, int showInfo); void download_finished_handler (struct telegram *instance, struct download *D); void telegram_on_phone_registration (struct telegram *instance); void telegram_on_client_registration (struct telegram *instance); @@ -699,7 +699,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) } } -PurpleNotifyUserInfo *create_user_notify_info(struct user *usr) +PurpleNotifyUserInfo *create_user_notify_info(struct tgl_user *usr) { PurpleNotifyUserInfo *info = purple_notify_user_info_new(); purple_notify_user_info_add_pair(info, "First name", usr->first_name); @@ -709,7 +709,7 @@ PurpleNotifyUserInfo *create_user_notify_info(struct user *usr) return info; } -void user_info_received_handler(struct telegram *tg, struct user *usr, int show_info) +void user_info_received_handler(struct telegram *tg, struct tgl_user *usr, int show_info) { debug("Get user info. \n %d", show_info); char *who = g_strdup_printf("%d", usr->id.id); @@ -735,7 +735,7 @@ void download_finished_handler(struct telegram *tg, struct download *D) if(D->type == 0) { struct download_desc *dl_desc = D->extra; - struct user *usr = dl_desc->data; + struct tgl_user *usr = dl_desc->data; gchar *data = NULL; size_t len; GError *err = NULL; From 8bc8d2477e14983071337fe43914666e4aa180da Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 00:24:41 +0200 Subject: [PATCH 430/465] Deploy bundle on run --- telegram-adium/telegram-adium.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj index a48c046..ede3757 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -414,6 +414,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; + CONFIGURATION_BUILD_DIR = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; DEPLOYMENT_LOCATION = YES; DEPLOYMENT_POSTPROCESSING = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -450,6 +451,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; + CONFIGURATION_BUILD_DIR = "$(HOME)/Library/Application Support/Adium 2.0/PlugIns/"; DEPLOYMENT_LOCATION = YES; DEPLOYMENT_POSTPROCESSING = YES; FRAMEWORK_SEARCH_PATHS = ( From cc03e5d0598609770f1f18332087836fba04693a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 12:19:15 +0200 Subject: [PATCH 431/465] Update adium wrapper settings --- purple-plugin/telegram-purple.c | 10 +- purple-plugin/telegram-purple.h | 6 +- telegram-adium/AdiumTelegramAccount.m | 30 +----- telegram-adium/TelegramPlugin.h | 7 +- telegram-adium/TelegramPlugin.m | 32 ++++++- telegram-adium/TelegramService.h | 4 +- telegram-adium/TelegramService.m | 126 ++++++++++++++++---------- 7 files changed, 125 insertions(+), 90 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index b5d7b56..ab71b66 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -1270,11 +1270,11 @@ static PurplePluginInfo plugin_info = { PURPLE_PRIORITY_DEFAULT, PLUGIN_ID, "Telegram", - "0.1", - "Telegram protocol", - "Support for the protocol of the Telegram messenger.", - "Christopher Althaus , Markus Endres , Matthias Jentsch ", - "https://bitbucket.org/telegrampurple/telegram-purple", + TG_VERSION, + "Telegram", + TG_DESCRIPTION, + TG_AUTHOR, + "https://github.com/majn/telegram-purple", NULL, // on load NULL, // on unload NULL, // on destroy diff --git a/purple-plugin/telegram-purple.h b/purple-plugin/telegram-purple.h index 66ad820..25344e9 100644 --- a/purple-plugin/telegram-purple.h +++ b/purple-plugin/telegram-purple.h @@ -16,10 +16,14 @@ #ifndef __TG_PURPLE_H__ #define __TG_PURPLE_H__ -#define PLUGIN_ID "prpl-telegram" +#define PLUGIN_ID "prpl-telegram" #define TELEGRAM_AUTH_MODE_PHONE "phone" #define TELEGRAM_AUTH_MODE_SMS "sms" +#define TG_AUTHOR "Christopher Althaus , Markus Endres , Matthias Jentsch " +#define TG_DESCRIPTION "A protocol plugin that adds support for the Telegram messenger." +#define TG_VERSION "0.2.0" +#define TG_BUILD "2" #include #include "notify.h" diff --git a/telegram-adium/AdiumTelegramAccount.m b/telegram-adium/AdiumTelegramAccount.m index 608d03a..ec90117 100644 --- a/telegram-adium/AdiumTelegramAccount.m +++ b/telegram-adium/AdiumTelegramAccount.m @@ -15,14 +15,9 @@ return "prpl-telegram"; } -- (BOOL)connectivityBasedOnNetworkReachability -{ - return YES; -} - - (NSString *)host { - return @"173.240.5.1"; + return @"149.154.167.50"; } - (int)port @@ -30,32 +25,9 @@ return 443; } -/* -- (NSString *)encodedAttributedString:(NSAttributedString *)inAttributedString forListObject:(AIListObject *)inListObject -{ - NSString *temp = [AIHTMLDecoder encodeHTML:inAttributedString - headers:YES - fontTags:NO - includingColorTags:NO - closeFontTags:NO - styleTags:NO - closeStyleTagsOnFontChange:NO - encodeNonASCII:NO - encodeSpaces:NO - imagesPath:nil - attachmentsAsText:YES - onlyIncludeOutgoingImages:NO - simpleTagsOnly:YES - bodyBackground:NO - allowJavascriptURLs:NO]; - return temp; -} -*/ - - (BOOL)canSendOfflineMessageToContact:(AIListContact *)inContact { return YES; } - @end diff --git a/telegram-adium/TelegramPlugin.h b/telegram-adium/TelegramPlugin.h index bb0e985..7f5c848 100644 --- a/telegram-adium/TelegramPlugin.h +++ b/telegram-adium/TelegramPlugin.h @@ -6,11 +6,10 @@ // Copyright (c) 2014 Matthias Jentsch. All rights reserved. // -#import #import +#import -@interface TelegramPlugin : NSObject { - id service; +@interface TelegramPlugin : AIPlugin { + } - @end diff --git a/telegram-adium/TelegramPlugin.m b/telegram-adium/TelegramPlugin.m index 96bc7b9..9875ed5 100644 --- a/telegram-adium/TelegramPlugin.m +++ b/telegram-adium/TelegramPlugin.m @@ -6,21 +6,45 @@ // Copyright (c) 2014 Matthias Jentsch. All rights reserved. // -#import "telegram-purple.h" #import "TelegramPlugin.h" #import "TelegramService.h" +#import "telegram-purple.h" + +extern void purple_init_telegram_plugin(); @implementation TelegramPlugin - (void) installPlugin { - purple_init_telegram(); - service = [[TelegramService alloc] init]; + purple_init_telegram_plugin(); + [TelegramService registerService]; +} + +- (void) installLibpurplePlugin +{ +} + +- (void) loadLibpurplePlugin +{ } - (void) uninstallPlugin { - service = nil; +} + +- (NSString *)pluginAuthor +{ + return @TG_AUTHOR; +} + +-(NSString *)pluginVersion +{ + return @TG_VERSION; +} + +-(NSString *)pluginDescription +{ + return @"Telegram"; } @end diff --git a/telegram-adium/TelegramService.h b/telegram-adium/TelegramService.h index 48b8ed6..bcda57b 100644 --- a/telegram-adium/TelegramService.h +++ b/telegram-adium/TelegramService.h @@ -9,6 +9,8 @@ #import #import -@interface TelegramService : PurpleService +@interface TelegramService : PurpleService { + +} @end diff --git a/telegram-adium/TelegramService.m b/telegram-adium/TelegramService.m index 21ee175..61ddde4 100644 --- a/telegram-adium/TelegramService.m +++ b/telegram-adium/TelegramService.m @@ -9,17 +9,40 @@ #import "TelegramService.h" #import "AdiumTelegramAccount.h" +#import +#import + @implementation TelegramService - (Class)accountClass{ - return [AdiumOkCupidAccount class]; + return [AdiumTelegramAccount class]; } -/* -- (AIAccountViewController *)accountViewController { - return [OkCupidAccountViewController accountViewController]; +//Service Description +- (NSString *)serviceCodeUniqueID{ + return @"prpl-telegram"; +} + +- (NSString *)serviceID{ + return @"Telegram"; +} + +- (NSString *)serviceClass{ + return @"Telegram"; +} + +- (NSString *)shortDescription{ + return @"Telegram"; +} + +- (NSString *)longDescription{ + return @"Telegram"; +} + +- (NSString *)userNameLabel +{ + return @"Phone Number"; } - */ - (BOOL)supportsProxySettings{ return YES; @@ -32,67 +55,78 @@ - (BOOL)requiresPassword { - return NO; + return NO; +} + +- (BOOL)canCreateGroupChats +{ + return YES; } - (NSString *)UIDPlaceholder { - return @"Telegram"; -} - -//Service Description -- (NSString *)serviceCodeUniqueID{ - return @"prpl-telegram"; -} -- (NSString *)serviceID{ - return @"Telegram"; -} -- (NSString *)serviceClass{ - return @"Telegram"; -} -- (NSString *)shortDescription{ - return @"Telegram"; -} -- (NSString *)longDescription{ - return @"Support for the protocol of the Telegram messenger."; + return @"e.g. +49157123456"; } - (BOOL)isSocialNetworkingService { - return NO; + return YES; } +- (AIServiceImportance)serviceImportance{ + return AIServiceSecondary; +} - (NSCharacterSet *)allowedCharacters{ return [[NSCharacterSet illegalCharacterSet] invertedSet]; } -- (NSCharacterSet *)ignoredCharacters{ - return [NSCharacterSet characterSetWithCharactersInString:@""]; + +- (NSCharacterSet *)allowedCharactersForAccountName +{ + return ([NSCharacterSet characterSetWithCharactersInString: @"+1234567890"]); } + +- (NSUInteger)allowedLengthForAccountName +{ + return 16; +} + +- (NSCharacterSet *)ignoredCharacters{ + return [NSCharacterSet characterSetWithCharactersInString:@"/-"]; +} + - (BOOL)caseSensitive{ return NO; } -- (AIServiceImportance)serviceImportance{ - return AIServiceSecondary; -} + - (NSImage *)defaultServiceIconOfType:(AIServiceIconType)iconType { - NSImage *image; - NSString *imagename; - NSSize imagesize; - - if (iconType == AIServiceIconLarge) - { - imagename = @"telegram"; - imagesize = NSMakeSize(48,48); - } else { - imagename = @"telegram16"; - imagesize = NSMakeSize(16,16); - } - - image = [NSImage imageNamed:(imagename)]; // TODO: forClass:[self class] loadLazily:YES] - [image setSize:imagesize]; - return image; + if ((iconType == AIServiceIconSmall) || (iconType == AIServiceIconList)) { + return [NSImage imageNamed:@"telegram16" forClass:[self class] loadLazily:YES]; + } else { + return [NSImage imageNamed:@"telegram" forClass:[self class] loadLazily:YES]; + } +} + +- (NSString *)pathForDefaultServiceIconOfType:(AIServiceIconType)iconType +{ + if ((iconType == AIServiceIconSmall) || (iconType == AIServiceIconList)) { + return [[NSBundle bundleForClass:[self class]] pathForImageResource:@"telegram16"]; + } + return [[NSBundle bundleForClass:[self class]] pathForImageResource:@"telegram"]; +} + +- (void)registerStatuses { +#define ADDSTATUS(name, type) \ +[adium.statusController registerStatus:name \ +withDescription:[adium.statusController localizedDescriptionForCoreStatusName:name] \ +ofType:type forService:self] + + [adium.statusController registerStatus:STATUS_NAME_AVAILABLE withDescription:[adium.statusController localizedDescriptionForCoreStatusName:STATUS_NAME_AVAILABLE] ofType:AIAvailableStatusType forService:self]; + + ADDSTATUS(STATUS_NAME_AVAILABLE, AIAvailableStatusType); + ADDSTATUS(STATUS_NAME_NOT_AVAILABLE, AIAvailableStatusType); + ADDSTATUS(STATUS_NAME_OFFLINE, AIOfflineStatusType); } @end From feff8675db53d98a31c233ba49c0a892fa82a2f0 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 12:21:29 +0200 Subject: [PATCH 432/465] Add missing license to adium plugin --- telegram-adium/AdiumTelegramAccount.h | 22 +++++++++++++++------- telegram-adium/AdiumTelegramAccount.m | 22 +++++++++++++++------- telegram-adium/TelegramPlugin.h | 22 +++++++++++++++------- telegram-adium/TelegramPlugin.m | 22 +++++++++++++++------- telegram-adium/TelegramService.h | 22 +++++++++++++++------- telegram-adium/TelegramService.m | 22 +++++++++++++++------- 6 files changed, 90 insertions(+), 42 deletions(-) diff --git a/telegram-adium/AdiumTelegramAccount.h b/telegram-adium/AdiumTelegramAccount.h index 540743d..7d9fe27 100644 --- a/telegram-adium/AdiumTelegramAccount.h +++ b/telegram-adium/AdiumTelegramAccount.h @@ -1,10 +1,18 @@ -// -// AdiumTelegramAccount.h -// telegram-adium -// -// Created by Matthias Jentsch on 06.09.14. -// Copyright (c) 2014 Matthias Jentsch. All rights reserved. -// +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ #import #import diff --git a/telegram-adium/AdiumTelegramAccount.m b/telegram-adium/AdiumTelegramAccount.m index ec90117..154664e 100644 --- a/telegram-adium/AdiumTelegramAccount.m +++ b/telegram-adium/AdiumTelegramAccount.m @@ -1,10 +1,18 @@ -// -// AdiumTelegramAccount.m -// telegram-adium -// -// Created by Matthias Jentsch on 06.09.14. -// Copyright (c) 2014 Matthias Jentsch. All rights reserved. -// +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ #import "AdiumTelegramAccount.h" diff --git a/telegram-adium/TelegramPlugin.h b/telegram-adium/TelegramPlugin.h index 7f5c848..cce5641 100644 --- a/telegram-adium/TelegramPlugin.h +++ b/telegram-adium/TelegramPlugin.h @@ -1,10 +1,18 @@ -// -// TelegramPlugin.h -// telegram-adium -// -// Created by Matthias Jentsch on 06.09.14. -// Copyright (c) 2014 Matthias Jentsch. All rights reserved. -// +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ #import #import diff --git a/telegram-adium/TelegramPlugin.m b/telegram-adium/TelegramPlugin.m index 9875ed5..10d4943 100644 --- a/telegram-adium/TelegramPlugin.m +++ b/telegram-adium/TelegramPlugin.m @@ -1,10 +1,18 @@ -// -// TelegramPlugin.m -// telegram-adium -// -// Created by Matthias Jentsch on 06.09.14. -// Copyright (c) 2014 Matthias Jentsch. All rights reserved. -// +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ #import "TelegramPlugin.h" #import "TelegramService.h" diff --git a/telegram-adium/TelegramService.h b/telegram-adium/TelegramService.h index bcda57b..2071314 100644 --- a/telegram-adium/TelegramService.h +++ b/telegram-adium/TelegramService.h @@ -1,10 +1,18 @@ -// -// TelegramService.h -// telegram-adium -// -// Created by Matthias Jentsch on 06.09.14. -// Copyright (c) 2014 Matthias Jentsch. All rights reserved. -// +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ #import #import diff --git a/telegram-adium/TelegramService.m b/telegram-adium/TelegramService.m index 61ddde4..c4ed743 100644 --- a/telegram-adium/TelegramService.m +++ b/telegram-adium/TelegramService.m @@ -1,10 +1,18 @@ -// -// TelegramService.m -// telegram-adium -// -// Created by Matthias Jentsch on 06.09.14. -// Copyright (c) 2014 Matthias Jentsch. All rights reserved. -// +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ #import "TelegramService.h" #import "AdiumTelegramAccount.h" From 4b7b1e001070029aab77e165ff747884cd1432a4 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 12:25:23 +0200 Subject: [PATCH 433/465] Fix includes and remove obsolete code --- Makefile | 4 +--- mtproto-client.c | 4 ++-- purple-plugin/telegram-purple.c | 4 ---- queries.c | 1 + telegram.c | 2 +- telegram.h | 4 ++-- 6 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 08317a9..ee4ff35 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,12 @@ # # Telegram Flags # -VERSION=0.2.0 -BUILD=1 srcdir=. CFLAGS=-g LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include -DEFS=-DTG_VERSION=\"${VERSION}\" -DTG_BUILD=\"${BUILD}\" +DEFS= COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=-lcrypto -lz -lm LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} diff --git a/mtproto-client.c b/mtproto-client.c index 30c6a11..8e4a76c 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -988,7 +988,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { char *f = fetch_str (self, l1); int l2 = prefetch_strlen (self); char *l = fetch_str (self, l2); - struct user *U = &UC->user; + struct tgl_user *U = &UC->user; bl_do_set_user_real_name (self->bl, self, U, f, l1, l, l2); //print_start (); //push_color (COLOR_YELLOW); @@ -1012,7 +1012,7 @@ void work_update (struct mtproto_connection *self, long long msg_id UU) { peer_t *UC = user_chat_get (bl, user_id); fetch_date (self); if (UC && (UC->flags & FLAG_CREATED)) { - struct user *U = &UC->user; + struct tgl_user *U = &UC->user; unsigned y = fetch_int (self); long long photo_id; struct file_location big; diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index ab71b66..24646aa 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -549,11 +549,7 @@ void on_new_user_status(struct telegram *tg, void *peer) { telegram_conn *conn = tg->extra; peer_t *p = peer; - - // purple_debug_info(PLUGIN_ID, "New User Status: %s\n", peer->user.status.online); - // TODO: this should probably be freed again somwhere char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); - PurpleAccount *account = purple_connection_get_account(conn->gc); if (p->user.status.online == 1) purple_prpl_got_user_status(account, who, "available", "message", "", NULL); diff --git a/queries.c b/queries.c index 63a57fe..a714543 100644 --- a/queries.c +++ b/queries.c @@ -48,6 +48,7 @@ #include "binlog.h" #include "telegram.h" #include "msglog.h" +#include "purple-plugin/telegram-purple.h" #define sha1 SHA1 diff --git a/telegram.c b/telegram.c index 8dee7d1..8c27259 100755 --- a/telegram.c +++ b/telegram.c @@ -39,7 +39,7 @@ void event_peer_allocated(struct telegram *instance, void *peer) /* * Peer user fetched full */ -void event_user_info_received_handler(struct telegram *instance, struct user *peer, int show_info) +void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int show_info) { if (instance->config->on_user_info_received_handler) { instance->config->on_user_info_received_handler (instance, peer, show_info); diff --git a/telegram.h b/telegram.h index 9e14021..5901518 100644 --- a/telegram.h +++ b/telegram.h @@ -179,7 +179,7 @@ struct telegram_config { * A callback function that is called when a peer user info was received. This is useful * for populating the GUI with new user photos. */ - void (*on_user_info_received_handler) (struct telegram *instance, struct user *peer, int showInfo); + void (*on_user_info_received_handler) (struct telegram *instance, struct tgl_user *peer, int showInfo); /** * A callback function that is called when a download is completed. This is useful @@ -404,7 +404,7 @@ void event_peer_allocated(struct telegram *instance, void *peer); /* * Load known users and chats on connect */ -void event_user_info_received_handler(struct telegram *instance, struct user *peer, int showInfo); +void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int showInfo); /* * Load known users and chats on connect From b48e1b240e35216d17151f5758c9b561fd4c1a3a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 12:29:15 +0200 Subject: [PATCH 434/465] Use mobile-state instead of unavailable, to ensure proper display in Adium --- purple-plugin/telegram-purple.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 24646aa..24e9116 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -554,7 +554,7 @@ void on_new_user_status(struct telegram *tg, void *peer) if (p->user.status.online == 1) purple_prpl_got_user_status(account, who, "available", "message", "", NULL); else - purple_prpl_got_user_status(account, who, "unavailable", "message", "", NULL); + purple_prpl_got_user_status(account, who, "mobile", "message", "", NULL); g_free(who); } @@ -639,7 +639,7 @@ void peer_allocated_handler(struct telegram *tg, void *usr) if (user->user.status.online == 1) purple_prpl_got_user_status(account, name, "available", "message", "", NULL); else - purple_prpl_got_user_status(account, name, "unavailable", "message", "", NULL); + purple_prpl_got_user_status(account, name, "mobile", "message", "", NULL); g_free(alias); g_free(name); @@ -917,11 +917,11 @@ static GList *tgprpl_status_types(PurpleAccount * acct) purple_debug_info(PLUGIN_ID, "tgprpl_status_types()\n"); GList *types = NULL; PurpleStatusType *type; - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, "available", NULL, + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, NULL, NULL, 1, 1, 0, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); types = g_list_prepend(types, type); - - type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, "unavailable", NULL, 1, + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_MOBILE, NULL, NULL, 1, 1, 0, "message", "Message", purple_value_new(PURPLE_TYPE_STRING), NULL); types = g_list_prepend(types, type); @@ -1286,4 +1286,3 @@ static PurplePluginInfo plugin_info = { PURPLE_INIT_PLUGIN(telegram, tgprpl_init, plugin_info) - From 8eacac2b877fa77d0f92ef040bd66387212f0f6a Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 14:19:05 +0200 Subject: [PATCH 435/465] Load public key from Adium bundle --- Makefile | 2 +- mtproto-client.c | 4 ++-- mtproto-client.h | 1 + telegram-adium/TelegramPlugin.m | 11 +++++++++++ .../telegram-adium.xcodeproj/project.pbxproj | 6 +++++- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ee4ff35..24b09db 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ strip: $(PRPL_LIBNAME) # TODO: Find a better place for server.pub install: $(PRPL_LIBNAME) install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME) - install -D tg-server.pub /etc/telegram/server.pub + install -D tg-server.pub /etc/telegram-purple/server.pub install -D purple-plugin/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png install -D purple-plugin/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png install -D purple-plugin/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png diff --git a/mtproto-client.c b/mtproto-client.c index 8e4a76c..1c7a635 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -117,8 +117,8 @@ int Response_len; * */ -#define TG_SERVER_PUBKEY_FILENAME "/etc/telegram/server.pub" -char *rsa_public_key_name; // = TG_SERVER_PUBKEY_FILENAME; +#define TG_SERVER_PUBKEY_FILENAME "/etc/telegram-purple/server.pub" +char *rsa_public_key_name = 0; RSA *pubKey; long long pk_fingerprint; diff --git a/mtproto-client.h b/mtproto-client.h index d90a748..fe6dcc1 100644 --- a/mtproto-client.h +++ b/mtproto-client.h @@ -114,6 +114,7 @@ Copyright Nikolay Durov, Andrey Lopatin 2012-2013 #define MAX_PROTO_MESSAGE_INTS 1048576 #define _FILE_OFFSET_BITS 64 +char *rsa_public_key_name; #pragma pack(push,4) struct encrypted_message { diff --git a/telegram-adium/TelegramPlugin.m b/telegram-adium/TelegramPlugin.m index 10d4943..acbf619 100644 --- a/telegram-adium/TelegramPlugin.m +++ b/telegram-adium/TelegramPlugin.m @@ -17,6 +17,7 @@ #import "TelegramPlugin.h" #import "TelegramService.h" #import "telegram-purple.h" +#import "mtproto-client.h" extern void purple_init_telegram_plugin(); @@ -24,6 +25,7 @@ extern void purple_init_telegram_plugin(); - (void) installPlugin { + rsa_public_key_name = [self getPkName]; purple_init_telegram_plugin(); [TelegramService registerService]; } @@ -55,4 +57,13 @@ extern void purple_init_telegram_plugin(); return @"Telegram"; } +-(char*)getPkName +{ + const char* utf8String = (char *)[[[NSBundle bundleForClass: [self class]] pathForResource: @"tg-server" ofType: @"pub"] UTF8String]; + size_t len = strlen(utf8String) + 1; + char *buf = talloc0(len); + memcpy(buf, utf8String, len); + return buf; +} + @end diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj index ede3757..069b0c7 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ C4B81AF119E087AF00E9177C /* AIUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AF019E087AF00E9177C /* AIUtilities.framework */; }; C4B81AF319E087BA00E9177C /* AdiumLibpurple.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AF219E087BA00E9177C /* AdiumLibpurple.framework */; }; C4B81AF519E087C500E9177C /* Adium.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4B81AF419E087C500E9177C /* Adium.framework */; }; + C4B81AF919E15E0D00E9177C /* tg-server.pub in Resources */ = {isa = PBXBuildFile; fileRef = C4B81AF619E0B67600E9177C /* tg-server.pub */; }; C4BF991C19BB8B4D0038D507 /* binlog.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990419BB8B4D0038D507 /* binlog.c */; }; C4BF991D19BB8B4D0038D507 /* loop.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990519BB8B4D0038D507 /* loop.c */; }; C4BF991E19BB8B4D0038D507 /* msglog.c in Sources */ = {isa = PBXBuildFile; fileRef = C4BF990619BB8B4D0038D507 /* msglog.c */; }; @@ -73,6 +74,7 @@ C4B81AF019E087AF00E9177C /* AIUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AIUtilities.framework; path = "../../../Library/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug/AIUtilities.framework"; sourceTree = ""; }; C4B81AF219E087BA00E9177C /* AdiumLibpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdiumLibpurple.framework; path = "../../../Library/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug/AdiumLibpurple.framework"; sourceTree = ""; }; C4B81AF419E087C500E9177C /* Adium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Adium.framework; path = "../../../Library/Developer/Xcode/DerivedData/Adium-gdszlkyrczkyzvfhyhsigfyepffb/Build/Products/Debug/Adium.framework"; sourceTree = ""; }; + C4B81AF619E0B67600E9177C /* tg-server.pub */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "tg-server.pub"; path = "../tg-server.pub"; sourceTree = ""; }; C4BF990419BB8B4D0038D507 /* binlog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = binlog.c; path = ../binlog.c; sourceTree = ""; }; C4BF990519BB8B4D0038D507 /* loop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loop.c; path = ../loop.c; sourceTree = ""; }; C4BF990619BB8B4D0038D507 /* msglog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = msglog.c; path = ../msglog.c; sourceTree = ""; }; @@ -132,8 +134,8 @@ C4877C1719BB37EA006FA91F /* TelegramService.m */, C4877C1C19BB676B006FA91F /* AdiumTelegramAccount.h */, C4877C1D19BB676B006FA91F /* AdiumTelegramAccount.m */, - C4BF992619BB8B530038D507 /* telegram */, C4BF990319BB8B200038D507 /* telegram-purple */, + C4BF992619BB8B530038D507 /* telegram */, C410948B19BB2D7D0083BF3F /* telegram-adium */, C410948819BB2D7D0083BF3F /* Frameworks */, C410948719BB2D7D0083BF3F /* Products */, @@ -211,6 +213,7 @@ C4BF992619BB8B530038D507 /* telegram */ = { isa = PBXGroup; children = ( + C4B81AF619E0B67600E9177C /* tg-server.pub */, C4BF990419BB8B4D0038D507 /* binlog.c */, C4BF990519BB8B4D0038D507 /* loop.c */, C4BF990619BB8B4D0038D507 /* msglog.c */, @@ -290,6 +293,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C4B81AF919E15E0D00E9177C /* tg-server.pub in Resources */, C410949019BB2D7D0083BF3F /* InfoPlist.strings in Resources */, C4877C2619BB6D11006FA91F /* telegram16.png in Resources */, C4877C2519BB6D11006FA91F /* telegram.png in Resources */, From ac266fb1f5fecc9d7f8c8b93f2e70fcf48b562f1 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 14:19:40 +0200 Subject: [PATCH 436/465] Set "Release" build as default in XCode Project --- .gitignore | 1 + .../matj.xcuserdatad/xcschemes/telegram-adium.xcscheme | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 851e8a3..1fbc4b6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ core core* telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad +telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/* diff --git a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme index 1176c1d..843ae82 100644 --- a/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme +++ b/telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad/xcschemes/telegram-adium.xcscheme @@ -35,7 +35,7 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0" useCustomWorkingDirectory = "NO" - buildConfiguration = "Debug" + buildConfiguration = "Release" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" allowLocationSimulation = "YES"> From bfb663088d0f85f7df5b918ac01a9cfee82c5666 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sun, 5 Oct 2014 15:34:51 +0200 Subject: [PATCH 437/465] Don't include libcrypto in working tree --- telegram-adium/libcrypto.a | Bin 3455640 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 telegram-adium/libcrypto.a diff --git a/telegram-adium/libcrypto.a b/telegram-adium/libcrypto.a deleted file mode 100644 index 234df55380da0e03e73e02322692a5ec8d31b08d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3455640 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ℜ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�e2qhbDx#`!b+G*lisPaR=~$48j!8Aeb%<}{JvWCR&WMv(vslBLMf zWDFTg#*y)40tu0cWD;41OeW1_Su%x$$yBl&S)NQIE07h*N+d$26I=6{WMwjotU_j! zC|Q-PMph?lkTuC#WDbduwaGeUU9ujTOV%eFkT~If@ysI|k&VeFWK*&kNs!IS7Gz7Z z71^3>L$)PJvK`r;yOsOU%l+r&{_}GGdAaYr+;stlZm-dX`jQ&!XztTP=?(=VhUxJl(*wpD90g zx_>#cJmF$~F6IB-i9FZwKDEC32HZPrKHHA%dX6o>4X8}91Krf()61}4b-j8QGEVOm z$FYODESKelcwF_Jr?>iM-dlYu@2$R(_XhNgTUUKjud6<(*Hxd?c{e)qG~fK0^Jm(- zT6 zv3#Te+6}O=?S>d_N7ZOMAV%B!Fxsw%(e^uxW4S53!{w~e&L-Pgvz;~BncvQqwX-R9 z7Phmgb~fD3mb0_v?aXIq4R$u(&L-HI*UswfY_y$)>};Z)O|r9P?5y6-f_Ao)olUc| z73^$9J6nl6*ypvgdOPDD_xc*_jE%wTYqT@Joi*9na621eXCpcM;%RA~+S0t%j0OIM zS8d7bKQH}*ll4QBzWN(hZK(G)dBt(!bg?==r18pPy*NSSh)z>W^W>K1<{1knExc;u z$~kW+$|K%TR5(nmykX#J;rzRJet)8^?b@9^d`@wZ1wD|h!gQLDK z^3t$+&zu=&*7J^pv!?P?efiv1KCd*x%hO}Z=VQy~hkrv856 zQMDxI`Q(jrcn$LGvskrGwq8wSg<2Bx>^?JZ6^G}SH^<@GvMh0jH(cK44sQhW?QdfL zzEkUDpIx%QiTxXOt&{y7>~CWKc2w&WV5WKYIiOl6`z)Gy_L;p}C;QBmd3)B9m}j3; zGjDH)XP;j)&pyvp>okU$wr$O?B{6R-vA^-b4$rnv`}-c{@a!|#=AGp5CdjjYldE+K zG1Hc3pHZlFn#fG^uBat3Z<4&C!&`>=cE8-}@Fp|guGc>ER_kPsTYC&YR7+ysvhwWn zE45Bjm}$#V zmc+bS#MbXihv#}ds9t|e+3TrYuYH!S*2zBOXDxIx`y7@1-BJ$E zK3`>C+TpE-vm~dvOCsT{zl7cfOX$V%Y`f1mZpVf=c0V8L@aAcG_PMfJr;X&D=qt;v0vX@58SOk}Ooe#|t_KL1$jv_CV=v(H=pPn>MO$d+fHzpQo2Fw>q- z?emtkP6sm6mS>-vtaUnwndaH&C~KV#W~O=e8OmCxLzrpXseQJy*6Gk%GZ&e6*do)l zCJ(PQbCG%W*=t)r`^;yp(-F+H_b>At-jTHyvdBE!Pqn|BeHOOX>1bx!_1foKYn_f^ zrY+AtC;LBfI*x_du^RilYpqk3ndSFk4)6F{3t42|35!hEnmn=A%thwee!krf`@D3m z)5**nK@M|xr{LIjf4svx700gkB!`#7vA^%>4(~J^yPwZ-c&E#|$l)!JccsHSL*Dfc z?@W2OI=r*+>=@hK4)1Jv4?Dazc~3dKbL73`@XnR@hQm7#&z?8_=I|Ec*!J>?!#iKz zXAbWId0#lZ3-Rpv;NK1}k7Iw2?;PGm@_cqXAyes9|e^*@Vbd@~&Zv$$bu9j!t z*HG(p4Kr;!wf~Nw*6BCQH19NrcP)|csJuM$>|m(yS=YCme(%tO^0`@ybm1SZSp>Kc(>!( z-|cIMcZZf&ev{Aiubu8>hApbeb_Qyke#boXMmoH^aO`z;w8JaO8}IP$#>2JI=tWGEy?MAB-;g@>sa0cICej;@9;Ws>~&^ChxZ_ky&u}t;XQ<7 z_w!Z`?_qg6I=n~l>~XZa!}|k{ZO{8Vyhr67?(iOycf7;vl()d)JudHjhxdfMD;(Y* zDK6QA1k~iS+o|ji| z50V~T55Uc73Y{?0t}#yh+ZXAIV$U z;q}RzZr@XBl-pBG%4(}6r`#QW&Dt|ujKH)lJ~H~`?tKO9p2aSUUqoj$a~A-4aob*;e9Lb3y1feydNFj_wxMq zCcnn%2jN(O&A6@K1`f}QXYY%*aCr9JHKuIu@a%hQ zOxeZZ`Q)V?o_%kQDf1nkeLs;YhdI1PdB-?Bzr2$io_%h^lm!mYzK_Y2a~+<2|Bopb zIlPhb3Jz}+p8b8Vb9nZBMCRS%@a(&b%)86s1?4^9@RpMIn8UNrz1a0WC8z=8whc{l{M-Fd-yw4n7NZvONZ=$^aIJ`;n8tqQ3ak9@1nKIhpO_n#o;Wf*f z;_#N0x01t~B5$_C3(K41@TSV!z~L6>6Z%e%$lZ6oh4hqtY~2OM5f-eV5WKDTSz%QFsddwDN8ydC7d?(lY$_pZZh zk@u0q+ezMM4sU09-#9$`oU+|7|8aP`$ZNEJWTX(q zHCFwcr&2}s=EpLv)+gsiS4sRcMn>oCF!`olpUJma7dGj6Ke0hgE zyo|i#9NvNQPIY(($vfNO9W3uchj)m)D;(aTc=iyw&fy&c*n{6*5PIG?4Q8u>>yT+)A4wANPd{Z zI|0u=iZsIEoruT(J)<1nNm^dO;hl_U|K1&Rc&Fgm?H%LrPL(&o;pOBlxDZp55N#9o|LqPI7n`%RANK zT_W#vhj%I7lAJEXv+eIp$MP=6vqNy_I=n07UF7fz@(K>`N<91fUgz+xl6Q;4yIS5| z4(}Ry4>-Kv$a~D;T`TVyhj*R4mmFRZ&;A~-JG|@h>~Zvt!@EJ=M-K0|^736jl+9Y-pvm0FY-zb?=^W3IlR~9J?Zdz|dtcsa4)1UB)^m6t$lKK6{as$t z;e9A?SBLkJy!{+rpS;5y-aq7J9o|3Xo$l~HmbcL1eIoC2hxe(xqQm=_yxSb!XY%fI zc>VGob$Fl4>vDKs$a}@%eJSrPhxe7d4;|jW<@GzfujPH`@V>#b_ou$mwIAmLc(&i& z=y%TiW4$k7w`iLk{l;c~czTk9c-_S9Ewk$(!!*Sk#i8IM`{&J6Cor z&x>U1w~E8F?~O2TRfktEZw-fMzgcC=o8$28dnn9X$Kl!UWtlhE;n{CB+3~fw!?WLV zGH+vtXTSSoUc%wo??jommBX{&jWRFk@a%V`%-hl7*>6vomvVUaeH!NN?(jy-OFKOK z?Jry2ehzObc^QXi-{WD+JH+AH?`xUY>hSEhxy(D-;n{C>nU{5V_I)4bo#gQBx6#bY zIXwIQH1p1IcoXHdIXwGaG+W+6hiAW+W?tUm+4qr{cd5g(-+nW%;PC9X;mo_n;o0|= zm{)XoVR<(?Jo`;KTVA`vv+qGM?+%A&zei_Y$>G^=)|q#o!?WMDGq1zp*>BgG_lU!@ z?`biw)8W}~;FBxiaCisEd&J?*m)Gg=?0e1Z@A0I=J5XMi!#hac^A7J| zdEE~05P7dUyhG*nI6V7)HoLuVIlRN=^*X#(JUf2%fx|mO-aj1Pk@EiK@Q#xArNcW~ z-hjh9M&6GO?^t9R)yonC)M0ryjo_+tGZ7(Z0 zyp!ckcX+4Bo8|CMmA9(H%gI~Q;hiRLZHIR{o^8)_9o_;w`@FzBhj#{^eO_P-hj%94 zlAO+3Lho!m4z+rAa9nR2o_$_mM~8QgygeP>xl6cy=PjYPa0$Khm(aUl3B3!K(918O zchM4h7cZfA$r5^(;@R=yjN|WinY@D?-sO1q?*@lCyeshR@o|j9E66+9;aw^3Oow+B zp55N_9p2SiUf$tdgJ+N5g2Vfbyz3p_weoIrc-P6h*WnfAJ>u}Lm-m#zyFuQI4)3?} zUUzsm;@R_1ufw|u&;D-jIlP%_D7Yj-%j$K~Da@Sc!&zr*{ZyoVj$lkz$p-c$0Pa(GY6d(PoKBkv`L z*Cp>&hxe?!Hyqw`^4@WHf0Fk%hxfd^K8N>$yiXn8i}Jp3crVHO#^H6#`@!M8EYCZp z#*;m>UXeG<;r&_O2#5Eoyr9GTi@b3T?=^Xo9Nz2lrZ~JFdD9%;8}g<*yuZp@#o@gv zZ*_s z_IG$6$~(y6eI)O2hu0_XXovR?dB;1vf8yEkl2aVs$9VRB_jHH%iM%r%-lup=a{AX2 zdY|Fhf3nl&xZZwwmpHu777M<=OG#@BW9Dx1`tW=X&k_EB{bzjSDr&^N+0|F>AQIpu-y> zFXZq>$_qQZQSu@V&wf|K_T!@tZ?wF%9bQn^JI~=QC2tFdw=|wT?{4q##>m^l;f=+! z+naHCD|aZ&`T{I=m_J9(QR}Y(M^U zhqt1y58>{UPPXE99LfBG+kb!!9EZ0$o;`2Ob$DyY+t}f)DQ`=MXTN)7*So#Lnyv+9V+{~ zUFY!T$-CL%Z6xnbhqtl3`yAdT@*Z}0o638_;cX`GS%;U9*X{5&m-o8E+d|$u4sT0& ze|LEHyI}Tr`^4dGE$>T*w~f5-9NxC_yyLm@8mFW@zr))O&)&a`c6i&%o8a(vkT=EQ z?I>?0hu0!+w!_;=-W-SL`kl7wU7BKf_I_gn$MSZ;jLp7M5gczem)%i*Qv?c?zFmbbsd+eco;;q5E$V28J#yu%#c{_>7+cn8Qk z+TqQYcbvn^$UDK|9VqW)hj);?oWna<-U5erh`h5L-l6i&ad?NxTj=l(mv^DVYn6Ag z!#hIWWe)F1c?E}el)S4Q-qG@|b$G|fyWZg)EAK{!cbvRi9G?BIB>(r^=J1Y}cc;TU zL0-w>oha{Khj)^^`yJlNcy`?4L5Ft=-jbY7#k1FiCmqYn$$P=!ohI)!hj+TXcOBjW zd3_G=40)eByffu}=kU&wS3jZly?C~~kq)m7Z%Iz)ETMPq5_;$1+4eHdv3?8Xg&p4c z@@6``3-IjUXV!9f7vkCWw~oWh%iGA|U4*wJr;C@+yJQKyOPA2QYze)~m(aTc&+fmi ze&v3dTDddqqhbGbifWXt@E7w-nyN zKWsZooa}jQaq~<1KHAT47B|0W4@yq`WO4JW-&3{{2c;G_zxp|smAU*>Pu(xqU!Rk> z`q!4PfBy*l%Iz!a53|*;-2eT0{TmUk&$O5Wht6fMTH-*S!1v+cips(SP66|J&h1mc?XbV^NN#s^dG>fH zpQ_8-VnO4=Vdpno;In7a%5vAk&p%zcfAsiR?CstUFY-*q)8k~Z-a@=id3wD3!n5_X z?*L47RhDOuoARl;o?HL-dYW(FS(JLV;@jiszx?Dc{juEkj^``BJ+A)CU(E71#?QV` z@$GTu@{h)ky;$+>ara;T&(_DbFZ;}G?A3~Ix2Jrn-rkKC`0O>%di!iuT%J81%crWh znDw@Q3ogmG$EVA;W7qk=RMx{Dum9!$Y`txLY+t+ddd0WLZ~0VXeeAtKuBYPL@QgJYakqhT-QSk7o+}Q0(D(WNF5aLY{J)e-DF< z?}YqT?W`N%yFSmXb739hEcD?WF75$C^z-0Sa7}2-nWWy{SB|HD3QlP7%(eI5!x-EC z&POcQjz^4R{4Gxm#{0#!MEiG?v0UyoXqS5w+H!h%{gVSc-{_rng~s;Z zk=pXNfg|Ww*LV^f#rP-wJNuFF8))7o(9if|zJJNCzX0v;a0;~hFD-5dZM`;!<}Cx4 zgFWbKC_dy!q9niKj`yCZq&SlWY_ylO)_R!X2w)iarTR;2# zBI|GGj8$wt3EK5;3GI4Uh5WzydlqW`7tqEf$f`7-2F*`G^Z&r}mpz{LfadK4xyt6X zpn1*Ey!UvYW4HSm$VHoP6)%D29R|%yLtD-^B9GDX<+#n|%kfw#^A%{9yA#^wiqI~1 zfoQ*PZr3*t+VxEnmxgw^PkHXJ%k@IL+>4^Uy4n41uMmP;>GY*M<^#cn%o`>lB;e)Ujn%@mO7(dK=$G8XboDk@Mcfb<7 z9TuT^d3YP+HZiL{18=2Ii%Ioy*iIi4BkDu&7W$y*QQv>A$8$4%pV$NKdb{9F^qpc! zeG%SBUl7~WXW?(@Tg9~cB)ow>A;#24;Pv!jF{s`Hd2S30oKs;RwDswM*U@*2o$5>Q zTKaaepuP?MhCU~@s!zjf=u=`seGFbr9~HyugYYVPzc|oVS)V?5C4H~ht-cc$=sU!A z^#ynZeO}C|Z-tlBXT+5H1iXwsE=JXd;idE;(XW2sY>(#>`hKw&+WpoIFQ)GjJJh$s zi|C7DUVRSc>9b-+eF|PkpA_Tjqmb9IKtv3w_rvq)Jz_sksJ1@6a3Ot<*rmP$o=0C2 zi|X_6T>3UKt3CtIp-+oR^>Nrn9}^?$L-1_+AUq3t)c2psZ%#1ogJ-}VSl<5O0>+*2 zbXbI^!2-;|HfUZJp31lto&wYAlkjB533w8WsgJ-D8HeEsFsR-Gk7qn^2K#2P58Cp3 z;Bkz*;jyq&eF+}JxE&r13+mh8QH*n9tNJuNl0GFS)W_fv^ieUaJ_tEh6!41!3o7f= z2M?$36}#1U!o%o0#CG)scqn~d%&BjMhtOxll==ibm_9B>)ra9h^dZr&e&BSE=Ro>? zu@~C?)(tcCU1Ep&b~vBDDCX7Y-~semF{3^O_oq*aarIHSAALj&srSQu={;iqX_fWq zh5OL=h+XPC;NJ8lv8X-|)AVg(R(%HUMV}Uv>f>-v`j{9|AA)<(2Stzi{v7+e^nGFv zEN}O4H~LPoq`nAur7wtW>a%bc`c^TmJ_%Fw2{EQV0(Yhli$V1sxD)*VZ@7$ou)O`l z7RKFhN7$*p1b1NE4!4H|^=)uF#yOaTt?JWoTgEB44UEC9VN?u5yS^aYirx>mgafBk z`aZY?<6gKq>{j0i6O23HX0Tm-0dC4T4>y51^{sGY#u>N~OsP-6d5q(5Ll{*bhH=Ir zxB>L5A2`|LS)Xyg*bB?sJ)BG5C3dK9hwIT7#k~3)T$es8X4I$PI`l~~u09IarjLjr z^?n$m_lW%`Ro15$&Y|xSyVQ5UwdhM?QGFh+N#7=B)o0)u^l34vJ`Pu>kBJfWA-EcS zQ1qzpKaua&rSB7aV0pWTQTk4?q`nAe(-*`x^;x(IeXE#OpMPv7seLIZ6g8DYN662iMsy+=@q))*WU_yNiPGcN}%fqnx zAY6{IA5Mh>$5+;;4~7}{!YQy@eJ5O&aR+RM?dl6~GUGg42Ikba!byxXa3V~pPrwl4 zIGg}`+2Ja0&u~2BE;tV6)#u>#7-SrQqhUzB9|jnE;3(LC zT;+Ou;Yh|ka0Kj9-vNg+F2N?4hkn=w8({_xgK5|R_66HJF0;` z_@8>N2mS;*;g7Hc?S3f29~c+l_pnWU7JkRL6@ClT>XUGQaRPn=W9lRDYsO*tZx~eX zfnPBmIL71o686FJb_l;<+zmg6o$5=lpK&|<3>MV4!GAH%L5^7jTGglFCyZ0@V;F<~ zgi-hp7=(S$4?ltfM^~=D4}QqF7ycb~tM7y#Fz$eVgYD`I@O{R4_#VuuZ-pE?31q~S z`UHHJJ}ySphv7T)A(dKgqwf*B)OWzY(3ixb`aFD-k&%i&^r^TfD zIDCaZCPvhU;LG$u(WAcq2#!HXrs;g$92gMXy&6}#1U!YAlE#CG)s_&9xD%&BjMo%9(or9J^4 zqmPSG^{8zWe@|Z$i|X_6KKeE>t3CtorB91V^>KI) zeN2p~55c?XgQ7=${~;U)qVE%Xpxtj>@GkmJv828Te@9;s+tg>_o%F3@T744UL7xy~ z>Lc)W`mh*O?}4|`4;)-!A1rVG@K*Y6u~U5sw$rzZ1@&$47W$mnsy+>Grca3p^)Yx8 zeN+sq55gPi{o=qumG$X^zoqXLyVZBX8|XX4cJ&2#J$+uxsc(fv`iz)TpMclV$Hl1n zFuayNB>L449LRAc`hKw&mbZU+4Sko`p}rknOT~ca`YgN>X4I!(fpHRE0pseU zkk7sZBJeU8QtyYCGWI||lN0FARMw{#@>!lh59G5yfiCqOFweLI`L}~WQGFg>z_<;b z53}ksa3SL~rr=R929JbMcmxc>R_KR^!@m7FE&_Yup|BGk z0z2TrumBH&d3YeqLAzgCVTN%A&W9=W33veGINTpb)raAJj6-l=IIthb8(=@&8+OAq z?1Fp24rtfY4)Hls*l4R>0@vQ7*QXB+cOTr?Vv|}|2`ZqVB80{ zg*~vmeZp-RcfzeOF8X`hmSG z?1Q#GJ#bU{Zn0B+32s8)E*8|c!Hwy2VypTz+=xB}=fQ;f7~GI?R1B*R!Z^JjZU6_; zmG$X^>oe{ZyVZBXx%3@kyZQoLk3KKv)VIQQ=`&(VeFCmS9~YzQ!*Ff-kmy%GuouT6 z==;T9X!lz;oI~FwcBpTMYta|Qy!sqmlRhhE)TiJY^hq(UJ_=W-kBA}lez+RFN9^CT zvOc|VRr(&WOMM57(wE?DSX7^ft1xa8v+6T&7JXVws*l5!>0@F+kgAv#R%iBL(iE*b`QeT8C(ig-w^;x(AeXE#OpM=xs6Jkt#1TIe>7K7?Na5?&c z-7D;avuN$C5< zURd7#;aK`Eu|s`397A6e^XhYOY5J^~QJ*r>C&jq>C=Aj^#E^PF98K>L`**3VPcID6 z_lRBUJK!k#l2}xqha>6R#H{)Z96_HJlj`GeIDJfvs1Ly=`k?4h-=E?*4t<~41Iyb# zY^3iLOX`bo7=1x(Q=f$m^sQoAeG>ZU6Jkt#1lH4s#h`i*tfL>;xxzkJ-u|JNzFX{6 zUxFU`cCnzo4f0(kft=W?J`MRUlt4;MsE z!t(YHzoPFFJJh$sFX@Y7UVRSoT|j}Xm{FgCe3wulDaO@DA>Tz5h=?Kee#mzj1w3N^ zj+OQ4g?txMphxUd-vRk9r9eq6s?Wnu=-b4s`V9P-J}oBI$06SZ6^Mxu^&!Z2NdnztM-q zpn4DFyTAei+gI2J%iBNXvq^z&u~U5s_R_bD1@&!^?=lPI#8&lb$akRyQer}V4DwxS zfv6Z(AB1nw`^ACnD(lk+-=yyqyVZBXztVSz?dl7V?~)7T#hm(9$am2NGGa=70`gsU zfw&k|ABKDvULYj;)ej^&zDM6L_QIv?{SSPVz6<^tcBpTMeCJ=FDCX7YAm14n$ch>D zDadyY29oe47*`*Ke79jB0{Je)KuEnGKF`<#{{*|Xt*lQ6CBBz-6RBP^*eLcWtT zP!QYHXCdF|8E6&L>XWdOJ|V``N8n@hVKJ!Q10SUy*t)_#XzSAh|3Kd@cB(JIN9fzd zg8DZ2FnvyJRiB1@b}x_;6Y68|LHei|Rv&~N^nP(*tIGQH!3XGj#cuVT@P7IZv0Z%u z@>#(^Ud*X)h4;~C#FY93yq7*MM%9PmJ@g^buYO=lj7+m)N1c9o|J> z6!YqH@OSiCF{3^O@1#$ParIGn2Yo~gsrSR%={;iq7M1nsg}2f7h+XPC;H~r}v8X-| z+v(fHtojVRg+47N)yLt@^f57_J_K)~4~ic3{hOCRpC9NGdtiC{hrh+|6ie!h@CN#V z*rq-UucvPn)9RD3NS_d6>Lc(v`mh*O?}69S4{MTZ*U-0%1@&$4 zYWkemsy+>`qECql^)YxQeN+sq55fYyUmV!1vOazA3i@7nIqX*72`^*ZA-1b8z)R`# z@Di9)-wH2goDoy%6YwJXxENI*hI#ss=vP0mDaY^V`^8>Z-u~eQ^j%_y`gV9eeNoJ- z&%uTCSuvwN1<#{TigEQ(crJZJ45|0SbLc%{|0b37>4k0dJz|&o4#;PQ10}JjJ`c~L zZxgfXGw@9Mw3t*MhiA~o#EAM3TtFWbJ?i^6=C~q#pV$M-+dn*wzEdozFTxysL2Of> zg{RWDifQ#pcnW<&jH!>nlj*}^P`wA9L_e@mg?+HR{lgRKyTwlRC3pgTJ3Jm1)VIMb z;~YE=wyICVV;QI5F)*P%29IVOg-5}#`XD@#u^%1*2j*4Qrw_I=?uCcLZuOn;FvcD5 zP}r`%01siDhX=!)`c`-l;|x3yrqm~3hH)Iuhf(!mcmU%N+#mYY4{XTsPR9LkU)T%F z+dtfgaTnYhcBpTMX~spk7tE{A!95vg;T|xfJ_UDYoP@iNkFvZv- z_Qxyh(+hW|?-9Gycfg(KOJY%d9=6c8iCOg-xFda9OsbE=9q40XM12TuPahOL>iaj~ zxF>y|*aOSkKTOhhiY4_$xGjA_Y*U|w+t9a)Y4u6CHGKkZ1tV}>7#4%juFnIvq#szH z=y^-R@SEv#_4ZeH5hln)nSMFcDNejqL^2ogR9bKVH9T6r{HYHNw^A( ztB=B2j3aPm7*g+tGZ}l}4A{SJWqo?#bjCd}0=v|Az?B%6;EJ%QJ`Y!5+y%48w@}5S+p|2$zK(_5JH`Jdbgo*aPi;>w=T%JH?XvB3y>P04KpV z^;tNPajTeCpM)X$gcwsFffMM%a6AmE_rP(C2iE3z9PEST?H-O{+zpq8o$5##M>VvR}u^;;3K&-MpeXx;nFB}HD)px=M z#vRZH+tn9fJ>$HXQ{M{f=rdwUeFA#v<6=~O7<%YKqF?>M9FAjo+0MjXSl<5OPxM`4 zhx&H-BYjcKtIxq7=(A!*eF}b0pA_TjqwqWWh!|4uhu_kB#QwD^>(dJd=zGMX`aJxG zzD>-k&%m$g(_&J69R8a=CPvhU;8*lP(WAb9O^##H_lZ5Qyq&`@=sU%d`Xcj?}UG+?-1M77vKlKH z75{j0ipQ7&&+tnA~lk|Bpr@j^b zkv;>TfGPC}_&DP@?1WMEVfYy15PTH+)ep?#xEJGo_z3KUcE5GQhZ%Q?9qQZRL-a*4 zuRaGKq|b^O^(ojvpA_TjqwoRxh!|4uhxgNa#Qv2l>(dK=Pv0YUsqcXI(U-)c`aHas zz75_3v+6VOZpLXbsXh)%^f57_J_PTg4~ic3{WCd^Mc*g(!1DGF@1*Y(OX`d84*G)F zralXAr*9S0>XYy``h*x$AAz^hhsB_J4{WC&m{DOLEN}nt7W!_nQ+)~EOy4dR)VIN# z=yPJL`ZT-k z&p^JvCXg1B>f`W2`j{9|AA%Rq2Stzi{uMdCMc*g(!1DGF7t(i%CG|yk9(_SkH9wiuozVDfoIbXtWaSeEN}ntEc$M-Q+)}ZN#8CO)VIMi=yPJL z`ZQcXpAr-5WAJqPs2Elsgs0K_#er#+_348-`d+bHeJ4DXzC&zRUx263=f#}*R(LXf zMog(sz?10XVpM$?o=6`O{ptsn=lB+Vzt{`Q+dn*>zDw*--ww0%MKP~F2aluAiW&7O zcr1NVjH{2rW9TDdNWC8(P45x=m#eH#FFcCAN9hsB_J51daw5U#KfmbZU+0DZUEslEjFr*9Vv>f7Lc^f|FreH!jdpAr-5 zV{jk(s2ElsgnQHb#epf6_349Y`d+bHeJ9+DzC&zRUx0hk=f#}*R=5X!Mog(sz}@NN zVpM$??nWOH{ptsn<@h3fzt{_xviCo57y2%-Lw!3;(HF(M`W)PuJ}YL_r{GTXNinWI z3R~zSVo1Fo?nv(u`5wXf?LxEMUVRa$sBK_?}J;y9%%Pl7u_ri@$RCNK#% zh6%V4j6qv&1kPg|h8x15dixT#IOBn3I9>?*p!q#;ea78lr}`3{OWzLHg9Y_%a9zeZ zu~mHMx-zk>V z7vV(ug4m|sz85S+-zuinC*cJ81RM`z>LYL*WBWeTu`sCK1II8P7|-!bXx|@J-tLWz zyI~M^s<-b49?iHN2B3Z4viWUr6l44T>XEQjeHxBnoPxt)LVXN2F^)n%466^qM#g?P z3=WK|EWZynFz$suXumsP*V_r}8F#=s*sk7w*TKs;4?Qraz7_t5%VpqCFr_{Le`Fko zKftK^F#Miz2!03s>IcSh9FcK99Du#h)~6eO1H0hYutR-2{5NC!9?Gv^UVRRJ$v6wY zfcAS!wwx6F9428ujH{2r&lpGGzhFqcAAZW%BleG}ET@kRe4B9rz6I0jlkiQ(3HVnSQy+nEFb=~W7*y|puQMLt%3gy#@Gr0%z6v`b z{|}Tn`!j5ZuR!~qcI(?Xdl}}$H0)-af-k`sd=WpM^IvZiT;vY4u5X1LFj|9>&y1V3BbcUI&Bf zJ@8t_10y-U0Q;b=PY=8XcEhV-r}`4SigCNx2CrnCg9X?M?eb}O1x&%qVM2WjUdA{I zFNIN-V$G|^E8>D}C*wOIM zq|Kmz3TzSl_cyogc33ITCfHH1)wE^wm+w4|g#TjNh4h~bI|BYQX{XS?5Oz5HhtURM z3&Gj21+ba0l3xbw^{{EM`LO$&+5X#MuLEy`y%x3%_8Qowuvfz_hL!yn!VZI-4|^5t zO!`lOy%IbYHV-xiI}|ntb_i@H>=m%>VK0Z>-xT*pur;uQV7I|a`qi+P!B)Wzgk20f z0Co{hm&4nEcEBg(Djlm9v?FX9;+ZVPwY!nvX;Y0=)V*;2fPIK64*ubpAUO6crNTku+!;37WP7LA?;xL=fGY7{~&F5`nQKY zAO0D%DfF*N#eEO_x6^KdmE){}4Z@buE}{P-*Z}+&($1y-bXY(9r_dJCe=w{M{xRAh z{ky|@;h#yHLH`t35B&EZhx;Vh?XXgwO|S-RHEcF)8U2^Qo(EnGdoJuk`p<>!1)d3e z4(t^A7sB=g4}(1$Hb(y-Y!7fYY; zuw7sm(|;lC8Q}S_S+FzdKLs`uJQlVy>@fPrU^{_xU^~KQ(?1io1Gqix>9A?^-=Bi} z7H|#iHdv{*YS>d@t6nfDqCDnvfOuz3kyqM!T2#@^qGav*x^?Qqc4;7-{SDiF^iYXvbl&X z--i)5Nf_x}#`JC?4mX;@|TMfagQ?5b5ElPR&l3S6lA)ibxBzGcDCd>EtW&fMW+2q^FA@W`1-sF49{mBoK zhms#7%XhIQ{in&J$uE#6lb4dGlgr6>kXMuMCa)*oPyU4b2>C1WQ{;b<|A)Mf{2KWP zS+2jNyv;Glh+9QYCx1Y0N8Up2O#YJGjr<+?Jn~+0fP92}0a>mOCI3svZOHw|r;)EC zcOlDjZ*k|4r;&Z+JIEK4?;-ai|A9Q1{3r6&vb?7d_dfY1@u2CHEm`kq45`B40)B zNghu2lE;%TC6|z|Am2{TC!6FV^8MtS$&ZrnB0o)jl>8$3N%EWI7s>CC%gJlW?~*r@ zx01gg?;w9iK1kk2ZkcISUy7@ReLlL7Tata`lgWe0oyqy+9^|QH4|yi}BJzXee&nag zmy^rL*OFJ0i^yBZlga-i-$G8yO0nE5avO3f`84u_9LHOY&3X9po3t|02Im z-bbz=r*^UPe~)}Tc_X$SNM1(1nY@yG2f3OYCx1+Sfcz!-G4j92&ye?% zUnU>d)vo`y$TIIlTqQY+ypG(9yoKy1e?`88yo-D(`6u#~&bJ-Tgdm4w~`+s z?*N>78^~{xx02r>A0V$KH|b`Ve>3@X@)zW@ z$={LBC+{QoCcEU}3yvp`+>$(+d@}hqa%b{A)Rk<-bkJ?!H@l`QjG#dRT{MearJLk^HH zBZtXXllzlLk@LvY$pz%Q$m7V5kc-LBl4p?1$aj(7Bi~2Pb8T;8kvxZdEBPVv9P*3gd&%#S zA0q#g`~ZRh_cxhwe{^2Ow}kL1V6Ka-y&r@HOqdzIXR{5Cm*yo%h8yq?^N z{3-cN@;Bu3$-Bve$Op-z$W7&?8qUux?0SG!{iy{!Q{Kh*OTufPb5D~{tfvlvPph{{0H*u)lP@6W zk)z}Z7V@9TUy=Vt-bG$Z{)zk@IaOXx<9r;C$pzw0Aa^FWBcD&sA`c?> zB#$8b$dk#JknbetlK)5^LS9VHC%-`+L#`&@NdAg^D|sJz4!IR3QHZ;j+?o6k*++hY zd@1>P^7Z7`$WzJXAg*~k`}{Nw+T4bG zI{9>RkbEY&KlwcJ_2dwFD!C6?zK0-gAo&sURph^shm+-d3*yF;zb2QE50h^vx5OkE zaVEJP`F`@b`6F^?@(ywja_af^@p#BB$rq7NCHEtDBVSIwfP5|aQgRWwfIOKz ziF^xr7I_xgB$tx!AwNi#?~RCiocsj&S@QGbSIKXX-zKjjuOjatuP1*;{*=6%{0;d> z@^11^;jz50YOXFCxEAeu7*?$ayj{P z@=Eef@>cSX1&qs^XINp#?B6lWtB=;nDBVR-|$nrfPaTk!~J3->2?asl}(@(pB}ha<;VLjH+7lbm|G9WLL45_bYwz7r*`9r;;u7Wp-D zPjUs>M_x<5guI2EOa6vDguI8GPd-8(LvDGoU7j1s?Z`53M~<%xc@FtJ^1b8>$TCky z;`bvzK^{Vuc{>tbKz@xpo?K48nY@NPi~JG!Uh-D*!{i<0r^zx;NAi1_e2Dxuxp@aW zd=0q`c`NyJ@{i;*$t^Ci>+3vnXL5)fBKIL*Ngha^K)#ARn>?IslE;%v$tC3b$TIIo zj_*OTN&YMOe)8MoN6FP>ndc+>e?oqd{4M!SaeBl%f!H}b3GbI5O#z2sHoe&qG! zJo2aHBJwxnY2@AHIpl-nhsaGk+4c1VIi0+Od@8w|+=X0C?nT~24v@bihsk@%{mDnj zdE^$o?fNSqpG+P{K8svT_K|0h`;qS==aKItk0(D&o=JX+yny@y`5E%-& zkvEYylD{B-PTou2Np980KHeY6XONGOz2p|1?emjEK8f6y+>tEb0~ObeJdtdWZz5kn zzMUK;-$x!qew=(Yc`11$c^!Eo`75%_OA`IAnzfMBp)JABR9{okM}OJ z%+r$g_%Qi&@(biM$z|m8$RChH^j4)|B2+5a@?8_283-;vjon_OzA zFZ0@@KIHrG;=UpGAnzt$Kt4zwKyKQ_-oJ>PPQHVDD*2D(F66(Gdy(HF%RDtH&l+-= z`~|r``3G_y`MCae`3uMyr=yUCxEn+&k?+eto!{3F>QA0b~%Zqd~~zRSobk;juel4p>+ zk>`;O@*?sD?ZmM}B~uM}CYv zhWrfqH)NUjCg*z|`7QFF$d%+*$?M3KWSQqC`)?(GMgE?=i=29yeLO#rJCak+wD<2x zK7o8bxgB{BIg4CC?nxd?_K|NSUqb#JIhQ<-JcRsvaz6Rb+TvdpWK`n;6<8u==6Ie8R$4f#g$N95bcTgh?q4)Q|s9`aM< zL*$pp&CjyS^ESB+`CanqvH?}_mNK^ySmxsmA`8wt|eLi?vc2Y$rq42lZTLdkgq3u$TyKMBHuyoM}CNW zIe8KJTJqE6BJ%%`CzD?#-$GtSo<*)8my%bLA0)3MKTh63ewMtK{3`hX`EBxXSJ?Hl zirk63o_rShQ}VgwZ^(Y~ZgQA>kUW6gw7Y$Nt|F(CN03h?Pb7CCPbc>x&msrN_mIQn zhsgcOPm=S2&cakq7|41H2K0+QrZqdU|Zvy!w@=fH9(zX@}J02@?!EJ@=Iiyw<*W7j69OOl01=IO}?4@G5HSim*hD4U*reK`^k@yj~i;A zk7vlO$S;#mA-_e=Bv+EpCa)uV$y>-5lfNRz$h*h|!Xx>0{KaDJMx=k znKvr+_W`*lc?a1?mXAk>yM!!%Z%|w=S^gfOxFO^iIiGw5c?@|J`9^Xv`Bw7XPr z$@h|9B|k*2AU{D~O@5xdiToOQE4iFpLtaC6U1=ZBN8}U9TghF>JIG%09&(g?h#H#AIWa=v*e4&%g8bEdt{k6D(Ckz^7Z6hrC3z(I6!JuJ7WoeHIphW80Qt}4-sCsQ1Ih1`<$LQ^eUe9#caSHM zn_OcT_ZD&o@@#TX^1bBq$$up0lAj_Ml9!N6$ZwMGBCjMrL|#XJmi!6%E%Ge^Qwgxlg}bABOBy(jDxAXfexhMHm@-T84c@B9E`G3e8$ZN=-lWWM| zl20zM^V>&0pL|@lU7rQy6UcXw+ml})cOh>ipG)3L4v{+++WAGu5%M7Nc=9#m2gpU_ zx5-n;>&Ul~zb5~Vyq|m@`GnyqmV1PpNq(9fCci|!l>8QX1i6Ylk-VOK7x^>tbL1W5 zE#x1_$BnSdbA;?6A8*+8e>wSN@^8qQ(3ld&p;yA0lUypCtDuzd*j0{04ap`5p2d;OA%9K& zJ9#&`nk@71rM|u*H+S27h?(c@^8o`rofkUt_nPToO&j(m{(8ab`VKHlZz_T=}-=a4s%bI4zi zW8{C4hmmETztmSgxrxW-5oDS7FX2fZP(ZRko%C|CJ!R7CSObbh&+b8 zja*FLNxq%DmwZ3j<+bbUX>u#_o8)%nwPaamAocq-xfgjSS^gfEgx8S!kPnhCBR3sm z*U#1DHsn#{j^xSY9^~JUedIah-sJh@LF9+YMdZJbZzaD-zK^_&{4}|e{1*8G@_O>8 z56B@cuen zS%+V$!*A5#59;vzIy|J#@!V5~7uVrAbr^pGxYqICSchG8ct)N4@eTZ1`}eEExLv6g z9<0NU*5Mg-ctst4v`%^U)(OWq^K0ezXdO-|7&*3R6H-S9BA~Kd{jI{yUYc}<9_2Dv=qlVl2Pt)wfB*fiznH+$@YY#Z7BwFO(`fSD4sSP zwLfy~_<}Jd!>6K(dgt|p=hO)!r`(caZ4{yGy)Uz>?dHi=jLW1#EzjbjX$9&zp?K`L z(MS}Li%Ui%{6|c3k19fC_RbxI5>1&pZql^TRxJB$C6{6J@Nqb`PNnE68&O;|eCo)t z1$K}_Mbqgqa%$1=X+^AxVmqTTMbofV5Gfixykx?(D@rC64VXM~_ykm4LBYh~#p9>K z$4<`PyLLNr{LtJ`7h{JPkFC{C&n*H=DcMw&+0c{|ZB4y!P;$0waq*;DI3a;@rm%+w zv#luGXIRlb$%;JB%CdKIYEDgR1jhqatA4d>w~n`kILacl99D)=Fd!Bl5-W%d3J(~d zzU~HnJ+*yRr&fwqXJDr#38qLBEV8uAz4{CqI5=fM!MQj^DWY%L0Vf^*bE|j~Hzshy zj%;uzH?4=(OY4K8ZyG+Kq^Ou4e%b(SkTyhXWIG#9(uR|^;UsQ2sT)2gvXiXgq-!_{ z8&1k@CuO&jvfD}7?WF8>Qg%BjyPcHXPRed4Ww(>E$4S}aq>NibyM8=Q${r_WkCU>; zN!jD1>~T`|I4OIbl)X;MUMFR*ld{)I+3Te2byD^^DSMriy-vzLCuN_Lvd>8w>#gm= z`<#@0PRc$fWvmHh94BR;ld|7Q8P6l^IDRK(zmu}xN!jnD>~~W3J1P5}l>JW10Vm~v zlXAdGIpCy>#n5)9SVhbYC*^>Xa==MB;G`UMQVu#P2c49IPRh9bu@l7KOXh}?a?nW` zOG_E#q>P7Pwok}OIpm}qa#9XCDTkbtLr%&eC*_cnGFE%q2^!f>(nhwEwvp{5Zs2a& ziRUD5WIO2_*-i#Vwv&T_zuWEXp?M_9QS(R$GNH(XBomr6G>?QT6S7oY8Y)afm1(Fn z4b`Th;xts9hRV}WeHtoILltVML=Dxbp&~U@rH0DXP@NhoR6~_&s8kKrs-a>vRIP@} z)lj_}Dp*4mYp7%m)vTeSHB_~R%GOZb8Y)~vm20SU4b`rp;x$yghELDA>eo;K8>(PK zC2XjM4HdDWDmGNchU(Z*Aseb>L#1q}mJJoNp=vf%&W7sQ2xz-fMH?zYTHn88$s2F%G*$V8!B)^6>g}+4b`}zA~#g!hRWPfox4@% zZq>P4b?#Q3yR#jgyH)3I)wx@B?pB?fEh5cdO3bs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%j zI(Mti-Kul9>fEh5cdO3bs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%jI(Mti-Kul9 z>fEh5cdO3bs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%jI(Mti-Kul9>fEh5cdO3b zs&lvM+^srytIpl3bGPc;tvYwB&fThWx9Z%jI(Mti-Kul9>fEh5cdO3bs&lvM+^sry ztIpl3bGPc;tvYwB&fThWkLui`I`^o~J*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rW zqdNDf&ONGgkLui`I`^o~J*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGg zkLui`I`^o~J*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~ zJ*sn$>fEC`_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~J*sn$>fEC` z_o&W2s&kL(+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~J*sn$>fEC`_o&W2s&kL( z+@m`8sLnmAbC2rWqdNDf&ONGgkLui`I`^o~J*soB>fEb3_o~jls&lXE+^ahGs?NQt zbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p z&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^Z zI`^v1y{dDs>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs z>fEb3_o~jls&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jl zs&lXE+^ahGs?NQtbFb>$t2+0p&b_L0uj<^ZI`^v1y{dDs>fEb3_o~jls&k*}+^0JC zsm^_>bD!$mr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$m zr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zL zpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zLpX%JFI`^s0 zeX4Vx>fEO~_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~ z_o>c(s&k*}+^0JCsm^_>bD!$mr#knk&V8zLpX%JFI`^s0eX4Vx>fEO~_o>c(s&k*} z+^0JCsm^_>bHD1`uR8au&i$%$zv|qtI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZ zbHD1`uR8au&i$%$zv|qtI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au z&i$%$zv|qtI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au&i$%$zv|qt zI`^y2{i<`n>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au&i$%$zv|qtI`^y2{i<`n z>fEn7_p8qRs&l{U+^;(KtIqwZbHD1`uR8au&i$%$zv|qtI`^y2{i<`n>fEn7_p8qR zs&l{U+^;(KtIqwZbHD1`uR8au&i$(Mfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!c zsLlhb^ML9+pgIqz&I79Rfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+ zpgIqz&I79Rfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79R zfa*M;IuEGM1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79Rfa*M;IuEGM z1FG|Y>O7!252(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79Rfa*M;IuEGM1FG|Y>O7!2 z52(%qs`G&AJfJ!csLlhb^ML9+pgIqz&I79Rfa*M;IuEGM1FG|&>O81A530_Cs`H@g zJg7Pks?LL|^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL| z^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d- z&V#D+pz1uRIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d-&V#D+pz1uR zIuEMOgR1kO>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO z>O81A530_Cs`H@gJg7Pks?LL|^PuWHs5%d-&V#D+pz1uRIuEMOgR1kO>O81A530_C zs`HTQJfu1gsm?>H^N{L1q&g3&&O@s6km@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1g zsm?>H^N{L1q&g3&&O@s6km@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1 zq&g3&&O@s6km@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1q&g3&&O@s6 zkm@|7IuEJNL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1q&g3&&O@s6km@|7IuEJN zL#p$T>O7=652?;Ws`HTQJfu1gsm?>H^N{L1q&g3&&O@s6km@|7IuEJNL#p$T>O7=6 z52?;Ws`HTQJfu1gsm?>HbIg-TOq5Zj!#6QiMzs!K=OsEe6SHMh?(j{_mr=pP*LjnU zxj2d3RP*pn;;G4)z z`vCYRa?@S_bBYqVX+HqpL~hy>z&DYb_66`wfan5z625wD$WDC|eTk9iON>Nc zVkG(!Bhi-_iN3^0^d&~3FEJ8*iIM0_k|yFM&BRNZikCDOFKIGf(rmn>>3B)=@scLw zCC$i7nv$0^CogGIUec_*q-l9c^YW4=<|WO{OPZROG&e74a$eHxyrk)QN%QlPCg>&2 z&`X-4mo!H&X_8*jEWM;@dP(#2k|ydU&D2Yps+TlZFKMz~(rmq?>3T+@FG-rPmo#H9 zY06&GoV}z;dr7nQlBVq?&D%?wxR*3@FKOyt(%ikI$$Lq&_mZaXCC%SUn!sly`jVt6 zd`WZok|yyb&EiX%#+NjYFKHrQ(oDXjseDGFFG-rrmo%HtNc1I1^ZAk{^d-&cOPbP` zG^a0VQeV=nzNBe=iFtjHoAxD%nSJopz9ccX55C%$Bxd))SNoF0{66?Ful8JtsebU)o+~lg5B-PslZokm@J-~FxGqV|_(O!m zu_dlcWYS+WhV@9pC*tz}4X%^0)=_W)MXjY0$pN)iOC(laSPLE!>m(Wskfjn5kkZ9C z&z+r_aOhZY`H1O@q0CIY@bXotM}etno_8#1HON{N@TD#Vx`5F>x8R4$E>w`Egk!mhDU{!iptz1qDN+!-gvA z#vbM+>B+uj_|IAz+9YMBM#4rx!AL9{88>MRJ?p0Dq{C&CDXC6D7@x(}B$3|aiBpD; zoK{dW>E>~hMimqch-jc}aEBavW*|MOt0`F5$)H+E78DeXwOfq6L*4S_F!mItH<;-W zQ?Q&BXFK5}dVBn4BEJ)02RFl-QCL~_Iv7835=VY=s0g;|ALbXiyqNh__^R-g;k@wB zA%kP)!Kkq}HfKxvY+0zfw@;=keRfl9ZI?uI&6NY^>`kBj6Sm{GwvClyZE;G<8?uCw z;gtjD97&)3GdyDP;`XsQd#AOEjU3W;fO*7>B0t58rMKdQoXUbr&dB|#rtH=syYEh&D=RW*Zgefb+J-89Vu_8;lIBZ z;lDS8!%O9)SQ+i~*N+mmqD*z7pq8eggm$G2F!x#eq2dRaHL+PM(yk3(7tRk~A1=tR zXf&xmk@{-oE`0edu@tfM`%ev&09?Q+@{0gUA7%5(k ztHw!QH%v}-Z72TXy4a>(IG1UsxPEg*ifej?E2CBOwE2jI&q}3qz;Dr^BbIa0NeQ>k z_}y`RPH1-NtmgBYl{USn$-N@0l&<&}|EyXB5`y!0}@q=(a<(jEUs`tG|w4BvH4^f3Z1b(~gsV-x^yDdx%i7yK#x9Zho^g-Ik4_-$WtNgM%IY=~o){5pmnRWqZP_dJGiBj;$<(5hl1bwyO}=?jCRPKdh^!L}ur1`e zZV8btM(kzbfl=!N0k~)@nr?YvXE#>tOQ>vOeA8_#>aXpnA2y*x*wMzZu81Pz*s#O) zz~typ$1x_64V#YszB?=u@0dkC%?|G?wSXfkC>tV2n z(>ewVUAGRxqUp8n4vVJPTG}L^8vePfTPL^?2TseO7ogYV+l8lUd zj?2MDI>HyxuN^okIOW_rY=7`!!sOwjtcCvey#f}O%OEqlWYS3cI}q}90J(>-ysgN! zBG%nqM;pYlQkjMnrI`uiBL>BjCl&KCnsYzx+;BQ~($0;obD!zl(mHp~&QrLgAuQ#1 zxL-PsVKR9zc^sQQwPluZ2KWE|@*d=!@{4Gzw^-*ea*$E-03;m10T z9bjIP9@=$EHN=o58PprcMxv6ZNr>g@-d9 zeVdVMZpbzFnKP;f#LtwZa^n|vjg{tGw>}+W=4ac*b57ax3<)q-T8N>vq#K9M0i{;G zy&_Eay4;a9i^rOT&Ggr$CUBn%&PfZK&CDv?lV!*~nRQ2&-gzd% zQ>^k`DP_ydH4n#1quXL;bdy=~rJ1)q7Vjugc>9?ZD=pdPl&>v3o#G*WtaRX}ojq%p zF;+TblU>dw@X|Z^Vc#E*v8imWeHhg`4#b|Norgxq#dE4dF z`}(l?L)bh#z`oANopnh{N#|Ipb9e21{>K`3CgPfTAMz01 zma2W@Dg4KBS6InznRZ>o^hC^&P2$lH%|0l*bv9!0VB*wGGjijX00)={t$pW|4TxLU zK+`gFkBj)xxx6PyH+t*di<2Vbgd%E%~Y)+4do5bR$^z7ZF zq**+i*0XmS>MdRVHk^dx`A4lYcM^}vK9)*L7PVuvsud)+?#b!dS8Iv%WAT5Vf4q6m zX89F3G&t#3B}0*C8h+9T$@ba!_270GHiz52VZ~p1%D(vJ;MWJgLj2^OPWBy(pQIz7 zZo3h`9Q-7{++)hN_}`3Q34RiP9;(@epKLFJ&4FDA`^a%%{KQ|rC-peD{{;JIZa)V5 z1h?DCfxyYW?US}o#kRx|fB8-6i+__LV)KhwTKo5u2%k=v5LB%ebL(ne?p)5=32>l$Gscc6I) zwoS_>jFkvm#7(&_%t|?~UU&|DxEBY_@&t2WwlB> zA?N=xhT}3qT)q9P8%e*Wk^S4+=^pht*WjP*`va*z%Q?@j`p;@MPoHuno^zEkzSL)} z`2A)zxd-j@9C%9G4j!=6m3pwwzMV7{#X2Gf%^xc?aPoq%{w`Hq&}N}MlTTl88Ci~F-) z55wYEE-Hn^Am2-#m!S{scnd79Z7-5*TZ!KuHWN03wi&|@AE zqqPk#D^V%<*K8X+#Fo)6qMb=wNSi~ONeg4`C-=E>f9zcB8p8NF{XniTPMC8)a1Fzq zex#V}^lP`12TPi8rZ5^pp>?H$F^Az!KlMjpG$`l#`$=-P4E%5}lZTPZ$cxGEk*mq_ zTwK!IPac6Z8awkj3K*B+%NpNxnU2@8Eopuiow>Zb_st z-A+OtB*^nFD}5`WhMt-uqbViwJwt31Po9eJHP(AjZWqx0I-^9NJcZxVltNnH+?1^9 z9E(2NNb+YPHAqXRK8dU>FW_X`%y=s}po^vc_dW*Q%Qluvr91BrCcB!lZJ3?d6IbwLO zA+E+YDZ}uv)Q!v$ZPr@( z)ST9JSnjM9jD=&iV(mP^*^0UlVW||l?gM}ZpM%8ae2_kS44O~OoG~}vuT^|dS|pwx ziT7)QoAlXIW`yJ|jbCiecsG7!6Fk=lo9~B>mC>w~^1ti-uqbe-z5x7;$ZiU)kNvdn9W9i2S0)JK?N%@V{$a#I+-SoS*zuLS9KJ7$BVPgl7;4K$=6sO$y#nK54-l7D9r|hdCii=5p%g@ zX{?T9eQ&IG)r8IOt^I;#$$T6XGSuVR9X5Y-t;2p7nk9>@>>|eZS*!7182e!_WP;?P z=8CM<;TG?PvsQ##d>BbBdADEblir7Jx$~NE`HIx2`E|tn2hLuk#d7T1;``L-iqZwg zNpSh{reSk~Ssl&#I?`fWB&#gaq9)>6RXQ)t3N6Q@wfD`caMp$v)sd`i2t=LsEqx`$ zPI~1DQL`pu)`YXFT2y6KM_QCcQj0$9Tl!>XBI|7tb6Yg42D@feAwp_ib?Jf(&AM8$ zM!LuvQOY8&pOUk#lB}zlby?K40a<4sHS2iZlBnz7=kEIW-(()2@d&bi#Xjf ztHL7j8H>WEopwW_L!QByiQLwr*Q zuCUru3$!OR#nO4lTX9pP3kR5=Nh2(8iIx;GRwMP}BnVX;F;^k=bfY|Cl=nti#M`wW zZLGXJ6)}y~j9OmSB9c0Afr++=wEHq`E6LR8d`q#$+TNuLno9!Z%hOW_ei$*=8kNSz z(s}8YUwLY3^hs#VSZk~;oo&an60JtOjYcI3Wkp1BTBhbLwv((ZUC@pxLW>by%kf$hOLaGwx1a*o$iXwIue?C#sJrm zzsntPtcU$*-%0_Ge=&4eBZ6@xx3tM6f0tn?)&rwSrR9q`W@ewkm~dwH8CrLb%0AXu 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 z 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Ðf6^8&c5vg6>ySmOX#%E(ZP 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�r8A}kN;5d1B(Az@en_> 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%0DV;G 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

FqrXg3wR(hiP=FxN#-+)?R|8W;0~# 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 UN1fEZ%C_m>90C9U000VETCGJ2r~m)} literal 0 HcmV?d00001 From 66401d4633c55ee17a11c4d9e599a578e137b4ab Mon Sep 17 00:00:00 2001 From: Pablo Date: Sun, 2 Feb 2014 12:11:29 +0100 Subject: [PATCH 236/465] Update README for Fedora instructions --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e65eac7..e2cd59f 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ On gentoo: $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua +On Fedora: + + $ sudo yum install lua-devel, openssl-devel, libconfig-devel, readline-devel + Default Makefile uses liblua5.2 from ubuntu. If you use different version of liblua or linux you have to run ./configure script or you will get some strange compilation error. Then From 47446009f91444cea45f12507162e4a3b6d78117 Mon Sep 17 00:00:00 2001 From: antma Date: Mon, 3 Feb 2014 16:25:09 +0400 Subject: [PATCH 237/465] remove printf from signal handlers use AC_SEARCH_LIB in configure.ac (shorter code) replace '-lm -lcrypto -lz' by @LIBS@ in Makefile.in and AC_CHECK_LIB macros in configure.ac replace NO_BACKTRACE by HAVE_EXECINFO_H --- Makefile.in | 4 +- config.h | 6 + config.h.in | 6 + configure | 391 +++++++++++++++++++++++++++++---------------------- configure.ac | 29 +--- main.c | 23 +-- 6 files changed, 258 insertions(+), 201 deletions(-) diff --git a/Makefile.in b/Makefile.in index 9f8947d..5ee1b03 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,8 +6,8 @@ CPPFLAGS=@CPPFLAGS@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -EXTRA_LIBS=@EXTRA_LIBS@ -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} +EXTRA_LIBS=-lssl @LIBS@ @EXTRA_LIBS@ +LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/lua-tg.h diff --git a/config.h b/config.h index c3e95d2..ee1ba04 100644 --- a/config.h +++ b/config.h @@ -13,6 +13,9 @@ /* Define to 1 if you have the `endpwent' function. */ #define HAVE_ENDPWENT 1 +/* Define to 1 if you have the header file. */ +#define HAVE_EXECINFO_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 @@ -31,6 +34,9 @@ /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + /* Define to 1 if you have the header file. */ #define HAVE_LUACONF_H 1 diff --git a/config.h.in b/config.h.in index b77cede..dfb83e9 100644 --- a/config.h.in +++ b/config.h.in @@ -12,6 +12,9 @@ /* Define to 1 if you have the `endpwent' function. */ #undef HAVE_ENDPWENT +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H + /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H @@ -30,6 +33,9 @@ /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM +/* Define to 1 if you have the `z' library (-lz). */ +#undef HAVE_LIBZ + /* Define to 1 if you have the header file. */ #undef HAVE_LUACONF_H diff --git a/configure b/configure index f40b39a..2361488 100755 --- a/configure +++ b/configure @@ -1489,73 +1489,6 @@ fi } # ac_fn_c_try_link -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. @@ -1806,6 +1739,73 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -3211,6 +3211,163 @@ _ACEOF fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 +$as_echo_n "checking for library containing clock_gettime... " >&6; } +if ${ac_cv_search_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_clock_gettime=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_clock_gettime+:} false; then : + break +fi +done +if ${ac_cv_search_clock_gettime+:} false; then : + +else + ac_cv_search_clock_gettime=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 +$as_echo "$ac_cv_search_clock_gettime" >&6; } +ac_res=$ac_cv_search_clock_gettime +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5 +$as_echo_n "checking for library containing backtrace... " >&6; } +if ${ac_cv_search_backtrace+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char backtrace (); +int +main () +{ +return backtrace (); + ; + return 0; +} +_ACEOF +for ac_lib in '' execinfo; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_backtrace=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_backtrace+:} false; then : + break +fi +done +if ${ac_cv_search_backtrace+:} false; then : + +else + ac_cv_search_backtrace=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5 +$as_echo "$ac_cv_search_backtrace" >&6; } +ac_res=$ac_cv_search_backtrace +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflate in -lz" >&5 +$as_echo_n "checking for inflate in -lz... " >&6; } +if ${ac_cv_lib_z_inflate+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char inflate (); +int +main () +{ +return inflate (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_z_inflate=yes +else + ac_cv_lib_z_inflate=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflate" >&5 +$as_echo "$ac_cv_lib_z_inflate" >&6; } +if test "x$ac_cv_lib_z_inflate" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBZ 1 +_ACEOF + + LIBS="-lz $LIBS" + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AES_set_encrypt_key in -lcrypto" >&5 $as_echo_n "checking for AES_set_encrypt_key in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_AES_set_encrypt_key+:} false; then : @@ -3256,63 +3413,8 @@ _ACEOF fi - EXTRA_LIBS="" -BT= -ac_fn_c_check_func "$LINENO" "backtrace" "ac_cv_func_backtrace" -if test "x$ac_cv_func_backtrace" = xyes; then : - - BT=1 - -fi - - -if test "x$BT" = "x" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace in -lexecinfo" >&5 -$as_echo_n "checking for backtrace in -lexecinfo... " >&6; } -if ${ac_cv_lib_execinfo_backtrace+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lexecinfo $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char backtrace (); -int -main () -{ -return backtrace (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_execinfo_backtrace=yes -else - ac_cv_lib_execinfo_backtrace=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_execinfo_backtrace" >&5 -$as_echo "$ac_cv_lib_execinfo_backtrace" >&6; } -if test "x$ac_cv_lib_execinfo_backtrace" = xyes; then : - EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; -else - CFLAGS="${CFLAGS} -DNO_BACKTRACE" ; -fi - -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_save_prompt in -lreadline" >&5 $as_echo_n "checking for rl_save_prompt in -lreadline... " >&6; } if ${ac_cv_lib_readline_rl_save_prompt+:} false; then : @@ -3412,49 +3514,6 @@ $as_echo "#define READLINE_EDIT 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lrt $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char clock_gettime (); -int -main () -{ -return clock_gettime (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_rt_clock_gettime=yes -else - ac_cv_lib_rt_clock_gettime=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : - - EXTRA_LIBS="${EXTRA_LIBS} -lrt" ; - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libconfig" >&5 $as_echo_n "checking for libconfig... " >&6; } # Check whether --enable-libconfig was given. @@ -5301,7 +5360,7 @@ fi # Checks for header files. -for ac_header in fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h +for ac_header in execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/configure.ac b/configure.ac index 82b8117..357b911 100644 --- a/configure.ac +++ b/configure.ac @@ -10,25 +10,12 @@ AC_PROG_CC # Checks for libraries. AC_CHECK_LIB([m], [sqrt]) +AC_SEARCH_LIBS([clock_gettime], [rt]) +AC_SEARCH_LIBS([backtrace], [execinfo]) +AC_CHECK_LIB([z], [inflate]) AC_CHECK_LIB([crypto], [AES_set_encrypt_key]) - EXTRA_LIBS="" -BT= -AC_CHECK_FUNC([backtrace], - [ - BT=1 - ], - [ - ] -) - -if test "x$BT" = "x" ; then - AC_CHECK_LIB([execinfo], [backtrace], - [ EXTRA_LIBS="${EXTRA_LIBS} -lexecinfo" ; ], - [ CFLAGS="${CFLAGS} -DNO_BACKTRACE" ; ]) -fi - AC_CHECK_LIB([readline], [rl_save_prompt], [ AC_DEFINE([READLINE_GNU], [1], [Use gnu libreadline]) @@ -41,14 +28,6 @@ AC_CHECK_LIB([readline], [rl_save_prompt], ] ) -AC_CHECK_LIB([rt], [clock_gettime], - [ - [ EXTRA_LIBS="${EXTRA_LIBS} -lrt" ; ] - ], - [ - ] -) - AC_MSG_CHECKING([for libconfig]) AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], [ @@ -100,7 +79,7 @@ AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], ]) # Checks for header files. -AC_CHECK_HEADERS([fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h]) +AC_CHECK_HEADERS([execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T diff --git a/main.c b/main.c index 01b571e..d6b5842 100644 --- a/main.c +++ b/main.c @@ -38,7 +38,8 @@ #include #include #include -#ifndef NO_BACKTRACE + +#ifdef HAVE_EXECINFO_H #include #endif #include @@ -420,7 +421,7 @@ void args_parse (int argc, char **argv) { } } -#ifndef NO_BACKTRACE +#ifdef HAVE_EXECINFO_H void print_backtrace (void) { void *buffer[255]; const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); @@ -428,21 +429,27 @@ void print_backtrace (void) { } #else void print_backtrace (void) { - printf ("No libexec. Backtrace disabled\n"); + write (1, "No libexec. Backtrace disabled\n", 32); } #endif -void sig_handler (int signum) { +void sig_segv_handler (int signum __attribute__ ((unused))) { set_terminal_attributes (); - printf ("Signal %d received\n", signum); + write (1, "SIGSEGV received\n", 18); print_backtrace (); - exit(EXIT_FAILURE); + exit (EXIT_FAILURE); } +void sig_abrt_handler (int signum __attribute__ ((unused))) { + set_terminal_attributes (); + write (1, "SIGABRT received\n", 18); + print_backtrace (); + exit (EXIT_FAILURE); +} int main (int argc, char **argv) { - signal (SIGSEGV, sig_handler); - signal (SIGABRT, sig_handler); + signal (SIGSEGV, sig_segv_handler); + signal (SIGABRT, sig_abrt_handler); log_level = 10; From ca7ff6d7e3db3ca2fe2f6aeac7c157eae6a36ac9 Mon Sep 17 00:00:00 2001 From: vysheng Date: Mon, 3 Feb 2014 16:19:41 +0300 Subject: [PATCH 238/465] Update main.c --- main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index d6b5842..ff5859d 100644 --- a/main.c +++ b/main.c @@ -435,14 +435,14 @@ void print_backtrace (void) { void sig_segv_handler (int signum __attribute__ ((unused))) { set_terminal_attributes (); - write (1, "SIGSEGV received\n", 18); + (void) write (1, "SIGSEGV received\n", 18); print_backtrace (); exit (EXIT_FAILURE); } void sig_abrt_handler (int signum __attribute__ ((unused))) { set_terminal_attributes (); - write (1, "SIGABRT received\n", 18); + (void) write (1, "SIGABRT received\n", 18); print_backtrace (); exit (EXIT_FAILURE); } From 4c0736a646404a30648e4b59b5a59227dc6bea8d Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 3 Feb 2014 19:26:43 +0400 Subject: [PATCH 239/465] main.c: fixed gcc warning. --- main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index ff5859d..562e351 100644 --- a/main.c +++ b/main.c @@ -435,14 +435,18 @@ void print_backtrace (void) { void sig_segv_handler (int signum __attribute__ ((unused))) { set_terminal_attributes (); - (void) write (1, "SIGSEGV received\n", 18); + if (write (1, "SIGSEGV received\n", 18) < 0) { + // Sad thing + } print_backtrace (); exit (EXIT_FAILURE); } void sig_abrt_handler (int signum __attribute__ ((unused))) { set_terminal_attributes (); - (void) write (1, "SIGABRT received\n", 18); + if (write (1, "SIGABRT received\n", 18) < 0) { + // Sad thing + } print_backtrace (); exit (EXIT_FAILURE); } From badd283794aea90ca3d33e632ede4252f32406e8 Mon Sep 17 00:00:00 2001 From: Pablo Date: Mon, 3 Feb 2014 16:27:34 +0100 Subject: [PATCH 240/465] Fix binary permissions once installed --- telegram.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram.spec b/telegram.spec index 748a562..afe56bd 100644 --- a/telegram.spec +++ b/telegram.spec @@ -31,7 +31,7 @@ make %{?_smp_mflags} %install cd %{name} cd tg-master -%{__install} -D -m0550 telegram %{buildroot}/usr/bin/telegram +%{__install} -D -m0755 telegram %{buildroot}/usr/bin/telegram %files /usr/bin/telegram From 3b680a4a999592b00ade39b1a82c89c7f8aeabb8 Mon Sep 17 00:00:00 2001 From: Pablo Date: Mon, 3 Feb 2014 16:28:46 +0100 Subject: [PATCH 241/465] Updated rpm with fixed binary permissions --- rpm/Telegram-Beta-1.fc20.x86_64.rpm | Bin 354764 -> 146852 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rpm/Telegram-Beta-1.fc20.x86_64.rpm b/rpm/Telegram-Beta-1.fc20.x86_64.rpm index 49453245a5dede1bd828e494bac91962d0517c61..b80e259977c6df86fec470889632d71ecea1abd3 100644 GIT binary patch literal 146852 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