From ed7aa7de5b9b4d63e7b89ef9f0cd20fdb131eb61 Mon Sep 17 00:00:00 2001 From: mjentsch Date: Sat, 26 Jul 2014 11:55:45 +0200 Subject: [PATCH 01/27] 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 02/27] 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 03/27] 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 04/27] 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 05/27] 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 06/27] 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 07/27] 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 08/27] 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 09/27] 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 10/27] 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 11/27] 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 12/27] 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 13/27] 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 14/27] 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 15/27] 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 16/27] 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 17/27] 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 18/27] 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 19/27] 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 20/27] 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 21/27] 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 22/27] 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 23/27] 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 24/27] 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 25/27] 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 26/27] 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 27/27] 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);