Merge branch 'refactor-telegram-cli'
This commit is contained in:
commit
386abe2ab9
51 changed files with 5393 additions and 10592 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -13,3 +13,5 @@ tags
|
|||
.DS_Store
|
||||
.ycm_extra_conf.py
|
||||
*.pyc
|
||||
app-hash.png
|
||||
.gdbinit
|
||||
|
|
16
Makefile.in
16
Makefile.in
|
@ -8,16 +8,17 @@ 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}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h
|
||||
|
||||
INCLUDE=-I. -I${srcdir}
|
||||
CC=@CC@
|
||||
OBJECTS=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
|
||||
|
@ -53,6 +54,7 @@ PRPL_CFLAGS = \
|
|||
-fPIC \
|
||||
-DPURPLE_PLUGINS \
|
||||
-DPIC \
|
||||
-DDEBUG \
|
||||
-g \
|
||||
$(CFLAGS_PURPLE)
|
||||
|
||||
|
@ -84,10 +86,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 +106,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"
|
||||
|
||||
|
|
142
README.es
142
README.es
|
@ -1,142 +0,0 @@
|
|||
## Telegram messenger CLI [](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 <clave-servidor-público>
|
||||
|
||||
|
||||
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 <guión bajo> 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 <marca de exclamación> <guión bajo> Nombre <guión bajo> 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** \<peer\> texto - envía el mensaje a este usuario.
|
||||
* **fwd** \<usuario\> \<numero-mensaje\> - reenviar un mensaje al usuario. Puedes ver los número de mensajes iniciando el Cliente con -N.
|
||||
* **chat_with_peer** \<peer\> - inicia un chat con este usuario. /exit o /quit para salir de este modo.
|
||||
* **add_contact** \<numero-teléfono\> \<nombre\> \<apellido\> - intenta añadir este contacto a la lista de contactos.
|
||||
* **rename_contact** \<usuario\> \<nombre\> \<apellido\> - intenta renombrar el contacto. Si tienes otro dispositivo será una pelea.
|
||||
* **mark_read** \<peer\> - marca todos los mensajes como recibidos de ese usuario.
|
||||
|
||||
#### Multimedia
|
||||
|
||||
* **send_photo** \<peer\> \<nombre-archivo-foto\> - manda una foto al usuario.
|
||||
* **send_video** \<peer\> \<nombre-archivo-video\> - envia un video al usuario.
|
||||
* **send_text** \<peer\> \<nombre-archivo-texto> - envia un archivo de texto como un mensaje en plano.
|
||||
* **load_photo**/load_video/load_video_thumb \<numero-mensaje\> - carga foto/video indicado del directorio de descarga.
|
||||
* **view_photo**/view_video/view_video_thumb \<numero-mensaje\> - 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** \<chat\> - imprime información del chat.
|
||||
* **chat_add_user** \<chat\> \<usuario\> - agrega un usuario al chat.
|
||||
* **chat_del_user** \<chat\> \<usuario\> - elimina un usuario del chat.
|
||||
* **rename_chat** \<chat\> \<nuevo-nombre\> - cambia el nombre al chat.
|
||||
|
||||
#### Search
|
||||
|
||||
* **search** \<peer\> 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** \<user\> - crea un chat secreto con el usuario indicado.
|
||||
* **visualize_key** \<secret_chat\> - Muestra la clave de cifrado. Debes compararla con la del otro usuario.
|
||||
|
||||
#### Estadísticas e información varia.
|
||||
|
||||
* **user_info** \<user\> - muestra información sobre el usuario.
|
||||
* **history** \<peer\> [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.
|
363
README.md
363
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
|
||||
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
|
||||
|
||||
|
||||
|
|
614
ax_lua.m4
614
ax_lua.m4
|
@ -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 <tprk77@gmail.com>
|
||||
# Copyright (c) 2013 Reuben Thomas <rrt@sc3d.org>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 <lua.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
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])
|
||||
])
|
115
binlog.h
115
binlog.h
|
@ -20,6 +20,7 @@
|
|||
#define __BINLOG_H__
|
||||
|
||||
#include "structures.h"
|
||||
#include "telegram.h"
|
||||
|
||||
#define LOG_START 0x8948329a
|
||||
#define LOG_AUTH_KEY 0x984932aa
|
||||
|
@ -83,68 +84,68 @@
|
|||
#define CODE_binlog_create_message_service_encr 0x8b4b9395
|
||||
#define CODE_binlog_delete_msg 0xa1d6ab6d
|
||||
|
||||
void *alloc_log_event (int l);
|
||||
void replay_log (void);
|
||||
void add_log_event (const int *data, int l);
|
||||
void write_binlog (void);
|
||||
void bl_do_set_auth_key_id (int num, unsigned char *buf);
|
||||
void *alloc_log_event (struct binlog *bl, int l);
|
||||
void replay_log (struct telegram *instance);
|
||||
void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int l);
|
||||
void write_binlog (struct binlog *bl);
|
||||
void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf);
|
||||
|
||||
void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port);
|
||||
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 (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 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 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 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 (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 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 (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 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 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 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 (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 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
|
||||
|
|
177
config.h.in
177
config.h.in
|
@ -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 <arpa/inet.h> 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 <execinfo.h> header file. */
|
||||
#undef HAVE_EXECINFO_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <lauxlib.h> 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 <luaconf.h> header file. */
|
||||
#undef HAVE_LUACONF_H
|
||||
|
||||
/* Define to 1 if you have the <lualib.h> header file. */
|
||||
#undef HAVE_LUALIB_H
|
||||
|
||||
/* Define to 1 if you have the <lua.h> header file. */
|
||||
#undef HAVE_LUA_H
|
||||
|
||||
/* Define to 1 if you have the <mach/mach.h> 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 <malloc.h> 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 <memory.h> 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 <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> 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 <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> 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 <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> 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 <sys/file.h> header file. */
|
||||
#undef HAVE_SYS_FILE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <termios.h> 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 <unistd.h> 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 <sys/types.h> 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 <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
|
@ -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;
|
||||
};
|
||||
|
54
configure.ac
54
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=<name>],
|
||||
[
|
||||
|
|
5
debian/changelog
vendored
5
debian/changelog
vendored
|
@ -1,5 +0,0 @@
|
|||
telegram-cli (0.1-1) unstable; urgency=low
|
||||
|
||||
* Initial release (Closes #737563)
|
||||
|
||||
-- Cleto Martín <cleto@debian.org> Mon, 03 Feb 2014 20:00:03 +0000
|
1
debian/clean
vendored
1
debian/clean
vendored
|
@ -1 +0,0 @@
|
|||
Makefile
|
1
debian/compat
vendored
1
debian/compat
vendored
|
@ -1 +0,0 @@
|
|||
9
|
36
debian/control
vendored
36
debian/control
vendored
|
@ -1,36 +0,0 @@
|
|||
Source: telegram-cli
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Cleto Martín <cleto@debian.org>
|
||||
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.
|
28
debian/copyright
vendored
28
debian/copyright
vendored
|
@ -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 <cleto@debian.org>
|
||||
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 <http://www.gnu.org/licenses/>
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
|
1
debian/docs
vendored
1
debian/docs
vendored
|
@ -1 +0,0 @@
|
|||
README.md
|
1
debian/install
vendored
1
debian/install
vendored
|
@ -1 +0,0 @@
|
|||
telegram usr/bin
|
17
debian/rules
vendored
17
debian/rules
vendored
|
@ -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
|
1
debian/source/format
vendored
1
debian/source/format
vendored
|
@ -1 +0,0 @@
|
|||
3.0 (quilt)
|
4
debian/watch
vendored
4
debian/watch
vendored
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
EBUILD telegram-cli-9999.ebuild 641 SHA256 4597e2f84c36b1ee02ecc415c399408bb8536b456e94370e996d57477db621be SHA512 287da263c9a4ba2058bf2f5844599432619053abc9249fd5725ed7b5e920c5c02e2493ad7b07f89177933b2c15394d939e7dc7dbf05d5873c32e55c9ec614d4c WHIRLPOOL 73dee37f91f1d4b747afc35c0a0cb2efb141d37702c71a7a9d188d2e1d727375c0ee3e7a1192e6c4c34f17ba1303f3a0be47b24272b5378ff255bce1a4a281be
|
|
@ -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
|
||||
}
|
1586
interface.c
1586
interface.c
File diff suppressed because it is too large
Load diff
63
interface.h
63
interface.h
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
514
loop.c
514
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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef READLINE_GNU
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#else
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
|
@ -43,15 +34,12 @@
|
|||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "interface.h"
|
||||
#include "net.h"
|
||||
#include "mtproto-client.h"
|
||||
#include "mtproto-common.h"
|
||||
#include "queries.h"
|
||||
#include "telegram.h"
|
||||
#include "loop.h"
|
||||
#include "binlog.h"
|
||||
#include "lua-tg.h"
|
||||
|
||||
//
|
||||
|
||||
|
@ -59,10 +47,9 @@
|
|||
//
|
||||
|
||||
|
||||
extern char *default_username;
|
||||
|
||||
extern char *auth_token;
|
||||
extern int test_dc;
|
||||
void set_default_username (const char *s);
|
||||
int test_dc = 0;
|
||||
int default_dc_num;
|
||||
extern int binlog_enabled;
|
||||
|
||||
|
@ -70,67 +57,9 @@ 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);
|
||||
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;
|
||||
|
@ -148,36 +77,15 @@ 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);
|
||||
char *get_secret_chat_filename (void);
|
||||
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);
|
||||
|
@ -195,36 +103,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) {
|
||||
if (binlog_enabled) { return; }
|
||||
int auth_file_fd = open (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, &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,13 +137,10 @@ 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);
|
||||
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;
|
||||
}
|
||||
|
@ -250,20 +151,38 @@ 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 (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);
|
||||
}
|
||||
|
||||
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);
|
||||
/**
|
||||
* 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) {
|
||||
logprintf("read_auth_file()\n");
|
||||
|
||||
struct authorization_state state;
|
||||
memset(state.DC_list, 0, 11 * sizeof(void *));
|
||||
|
||||
int auth_file_fd = open (filename, O_RDWR, 0600);
|
||||
logprintf("fd: %d\n", auth_file_fd);
|
||||
if (auth_file_fd < 0) {
|
||||
empty_auth_file ();
|
||||
logprintf("auth_file does not exist, creating empty...\n");
|
||||
empty_auth_file (filename);
|
||||
}
|
||||
auth_file_fd = open (filename, O_RDWR, 0600);
|
||||
assert (auth_file_fd >= 0);
|
||||
|
||||
// amount of data centers
|
||||
|
@ -271,82 +190,96 @@ void read_auth_file (void) {
|
|||
// 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 ();
|
||||
return;
|
||||
empty_auth_file (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);
|
||||
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, &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;
|
||||
}
|
||||
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;
|
||||
|
||||
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) {
|
||||
logprintf("read_state_file()\n");
|
||||
struct protocol_state state = {0, 0, 0, 0};
|
||||
|
||||
int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600);
|
||||
if (state_file_fd < 0) {
|
||||
return;
|
||||
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);
|
||||
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 (void) {
|
||||
if (binlog_enabled) { return; }
|
||||
void write_state_file (struct protocol_state *state, const char* filename) {
|
||||
/*
|
||||
static int wseq;
|
||||
static int wpts;
|
||||
static int wqts;
|
||||
static int wdate;
|
||||
if (wseq >= seq && wpts >= pts && wqts >= qts && wdate >= last_date) { return; }
|
||||
int state_file_fd = open (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 +290,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 +349,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,273 +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 (void) {
|
||||
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");
|
||||
|
||||
assert (DC_list[dc_working_num]);
|
||||
if (!DC_working || !DC_working->auth_key_id) {
|
||||
// if (auth_state == 0) {
|
||||
logprintf("No working DC or not start_loopd.\n");
|
||||
DC_working = DC_list[dc_working_num];
|
||||
assert (!DC_working->auth_key_id);
|
||||
dc_authorize (DC_working);
|
||||
assert (DC_working->auth_key_id);
|
||||
auth_state = 100;
|
||||
write_auth_file ();
|
||||
logprintf("Authorized DataCentre: auth_key_id: %lld \n", DC_working->auth_key_id);
|
||||
}
|
||||
|
||||
if (verbosity) {
|
||||
logprintf ("Requesting info about DC...\n");
|
||||
}
|
||||
do_help_get_config ();
|
||||
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);
|
||||
}
|
||||
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_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.
|
||||
*/
|
||||
int network_client_is_registered() {
|
||||
return !(auth_state == 100 || !(DC_working->has_auth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a verification for the given client, by sending
|
||||
* a code to the current phone number
|
||||
*/
|
||||
char* network_request_registration ()
|
||||
{
|
||||
return do_send_code (default_username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
|
40
loop.h
40
loop.h
|
@ -16,11 +16,41 @@
|
|||
|
||||
Copyright Vitaly Valtman 2013
|
||||
*/
|
||||
|
||||
#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);
|
||||
// forward declarations
|
||||
|
||||
struct dc;
|
||||
|
||||
#ifndef __TELEGRAM_H__
|
||||
struct authorization_state;
|
||||
struct protocol_state;
|
||||
#endif
|
||||
|
||||
int loop();
|
||||
void write_secret_chat_file (const char *filename);
|
||||
|
||||
struct protocol_state {
|
||||
int pts;
|
||||
int qts;
|
||||
int seq;
|
||||
int last_date;
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
#endif
|
||||
|
|
549
lua-tg.c
549
lua-tg.c
|
@ -1,549 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_LUA
|
||||
#include "lua-tg.h"
|
||||
|
||||
#include "include.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
lua_State *luaState;
|
||||
|
||||
#include "structures.h"
|
||||
#include "interface.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
|
16
lua-tg.h
16
lua-tg.h
|
@ -1,16 +0,0 @@
|
|||
#ifndef __LUA_TG_H__
|
||||
#define __LUA_TG_H__
|
||||
|
||||
#include <string.h>
|
||||
#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
|
493
main.c
493
main.c
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright Vitaly Valtman 2013
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#if (READLINE == GNU)
|
||||
#include <readline/readline.h>
|
||||
#else
|
||||
#include <editline/readline.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_LIBCONFIG
|
||||
#include <libconfig.h>
|
||||
#endif
|
||||
|
||||
#include "telegram.h"
|
||||
#include "loop.h"
|
||||
#include "mtproto-client.h"
|
||||
#include "interface.h"
|
||||
#include "tools.h"
|
||||
|
||||
#ifdef USE_LUA
|
||||
# include "lua-tg.h"
|
||||
#endif
|
||||
|
||||
// TODO: Delete this shit
|
||||
#include <signal.h>
|
||||
#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;
|
||||
int binlog_enabled;
|
||||
extern int log_level;
|
||||
int sync_from_start;
|
||||
int allow_weak_random;
|
||||
|
||||
void set_default_username (const char *s) {
|
||||
if (default_username) {
|
||||
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;
|
||||
}
|
6
msglog.c
6
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
|
||||
|
||||
|
|
2
msglog.h
2
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, ...);
|
||||
|
|
1410
mtproto-client.c
1410
mtproto-client.c
File diff suppressed because it is too large
Load diff
487
mtproto-client.h
487
mtproto-client.h
|
@ -14,20 +14,491 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this telegram-client. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
void on_start (void);
|
||||
long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful);
|
||||
void dc_authorize (struct dc *DC);
|
||||
void work_update (struct connection *c, long long msg_id);
|
||||
void work_update_binlog (void);
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "include.h"
|
||||
#include "tools.h"
|
||||
#include "constants.h"
|
||||
#include "msglog.h"
|
||||
#include "net.h"
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#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;
|
||||
struct mtproto_connection;
|
||||
void mtproto_destroy (struct mtproto_connection *self);
|
||||
|
||||
#define DECRYPT_BUFFER_INTS 16384
|
||||
#define ENCRYPT_BUFFER_INTS 16384
|
||||
#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix
|
||||
|
||||
struct mtproto_connection {
|
||||
struct connection *connection;
|
||||
|
||||
int auth_success;
|
||||
enum dc_state c_state;
|
||||
char nonce[256];
|
||||
char new_nonce[256];
|
||||
char server_nonce[256];
|
||||
|
||||
int total_packets_sent;
|
||||
long long total_data_sent;
|
||||
|
||||
unsigned long long what;
|
||||
unsigned p1, p2;
|
||||
|
||||
int *in_ptr, *in_end;
|
||||
|
||||
// common
|
||||
|
||||
int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr;
|
||||
int *packet_buffer;
|
||||
|
||||
long long rsa_encrypted_chunks, rsa_decrypted_chunks;
|
||||
|
||||
BN_CTX *BN_ctx;
|
||||
|
||||
|
||||
// DH
|
||||
|
||||
int encrypt_buffer[ENCRYPT_BUFFER_INTS];
|
||||
int decrypt_buffer[ENCRYPT_BUFFER_INTS];
|
||||
char s_power [256];
|
||||
BIGNUM dh_prime, dh_g, g_a, dh_power, auth_key_num;
|
||||
|
||||
struct {
|
||||
long long auth_key_id;
|
||||
long long out_msg_id;
|
||||
int msg_len;
|
||||
} unenc_msg_header;
|
||||
|
||||
|
||||
// AES IGE
|
||||
|
||||
unsigned char aes_key_raw[32], aes_iv[32];
|
||||
AES_KEY aes_key;
|
||||
|
||||
// authorized
|
||||
|
||||
struct encrypted_message enc_msg;
|
||||
long long client_last_msg_id;
|
||||
long long server_last_msg_id;
|
||||
|
||||
int longpoll_count, good_messages;
|
||||
|
||||
int unread_messages;
|
||||
int our_id;
|
||||
int pts;
|
||||
int qts;
|
||||
int last_date;
|
||||
int seq;
|
||||
|
||||
// extra (queries.c)
|
||||
|
||||
int *encr_extra;
|
||||
int *encr_ptr;
|
||||
int *encr_end;
|
||||
|
||||
// callbacks
|
||||
|
||||
void (*on_ready)(struct mtproto_connection *self, void* data);
|
||||
void *on_ready_data;
|
||||
|
||||
void (*on_error)(struct mtproto_connection *self, void *data);
|
||||
|
||||
// the amount of currently outgoing messages that
|
||||
// have not yet received a response
|
||||
int queries_num;
|
||||
|
||||
// binlog that consumes all updates and events of this connection
|
||||
struct binlog *bl;
|
||||
|
||||
// marks this connection for destruction, so it
|
||||
// will be freed once all queries received a response or timed out
|
||||
int destroy;
|
||||
};
|
||||
|
||||
void mtproto_connection_init (struct mtproto_connection *c);
|
||||
struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg);
|
||||
void mtproto_close(struct mtproto_connection *c);
|
||||
void mtproto_connect(struct mtproto_connection *c);
|
||||
|
||||
void on_start (struct mtproto_connection *self);
|
||||
long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful);
|
||||
void work_update (struct mtproto_connection *self, long long msg_id);
|
||||
void work_update_binlog (struct mtproto_connection *self);
|
||||
int check_g (unsigned char p[256], BIGNUM *g);
|
||||
int check_g_bn (BIGNUM *p, BIGNUM *g);
|
||||
int check_DH_params (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
|
||||
*/
|
||||
|
||||
void prng_seed (struct mtproto_connection *self, const char *password_filename, int password_length);
|
||||
int serialize_bignum (BIGNUM *b, char *buffer, int maxlen);
|
||||
long long compute_rsa_key_fingerprint (RSA *key);
|
||||
|
||||
static inline void out_ints (struct mtproto_connection *self, const int *what, int len) {
|
||||
assert (self->packet_ptr + len <= self->packet_buffer + PACKET_BUFFER_SIZE);
|
||||
memcpy (self->packet_ptr, what, len * 4);
|
||||
self->packet_ptr += len;
|
||||
}
|
||||
|
||||
|
||||
static inline void out_int (struct mtproto_connection *self, int x) {
|
||||
assert (self->packet_ptr + 1 <= self->packet_buffer + PACKET_BUFFER_SIZE);
|
||||
*self->packet_ptr++ = x;
|
||||
}
|
||||
|
||||
|
||||
static inline void out_long (struct mtproto_connection *self, long long x) {
|
||||
assert (self->packet_ptr + 2 <= self->packet_buffer + PACKET_BUFFER_SIZE);
|
||||
*(long long *)self->packet_ptr = x;
|
||||
self->packet_ptr += 2;
|
||||
}
|
||||
|
||||
static inline void clear_packet (struct mtproto_connection *self) {
|
||||
self->packet_ptr = self->packet_buffer;
|
||||
}
|
||||
|
||||
void out_cstring (struct mtproto_connection *self, const char *str, long len);
|
||||
void out_cstring_careful (struct mtproto_connection *self, const char *str, long len);
|
||||
void out_data (struct mtproto_connection *self, const void *data, long len);
|
||||
|
||||
static inline void out_string (struct mtproto_connection *self, const char *str) {
|
||||
out_cstring (self, str, strlen (str));
|
||||
}
|
||||
|
||||
static inline void out_bignum (struct mtproto_connection *self, BIGNUM *n) {
|
||||
int l = serialize_bignum (n, (char *)self->packet_ptr, (PACKET_BUFFER_SIZE - (self->packet_ptr - self->packet_buffer)) * 4);
|
||||
assert (l > 0);
|
||||
self->packet_ptr += l >> 2;
|
||||
}
|
||||
|
||||
|
||||
void fetch_pts (struct mtproto_connection *self);
|
||||
void fetch_qts (struct mtproto_connection *self);
|
||||
void fetch_date (struct mtproto_connection *self);
|
||||
void fetch_seq (struct mtproto_connection *self);
|
||||
static inline int prefetch_strlen (struct mtproto_connection *self) {
|
||||
if (self->in_ptr >= self->in_end) {
|
||||
return -1;
|
||||
}
|
||||
unsigned l = *self->in_ptr;
|
||||
if ((l & 0xff) < 0xfe) {
|
||||
l &= 0xff;
|
||||
return (self->in_end >= self->in_ptr + (l >> 2) + 1) ? (int)l : -1;
|
||||
} else if ((l & 0xff) == 0xfe) {
|
||||
l >>= 8;
|
||||
return (l >= 254 && self->in_end >= self->in_ptr + ((l + 7) >> 2)) ? (int)l : -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
extern int verbosity;
|
||||
static inline char *fetch_str (struct mtproto_connection *self, int len) {
|
||||
assert (len >= 0);
|
||||
if (verbosity > 6) {
|
||||
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);
|
||||
|
||||
void mtproto_free_closed ();
|
||||
|
||||
#endif
|
||||
|
||||
|
|
172
mtproto-common.c
172
mtproto-common.c
|
@ -1,61 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "mtproto-common.h"
|
||||
#include "interface.h"
|
||||
#include "include.h"
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#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) {
|
||||
|
@ -122,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);
|
||||
|
@ -150,17 +103,15 @@ void prng_seed (const char *password_filename, int password_length) {
|
|||
if (l < 0) {
|
||||
logprintf ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename);
|
||||
} else {
|
||||
if (verbosity > 0) {
|
||||
logprintf ( "read %d bytes from password file.\n", l);
|
||||
}
|
||||
logprintf ( "read %d bytes from password file.\n", l);
|
||||
RAND_add (a, l, l);
|
||||
}
|
||||
close (fd);
|
||||
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) {
|
||||
|
@ -205,14 +156,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);
|
||||
|
@ -220,13 +171,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) {
|
||||
|
@ -238,36 +189,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);
|
||||
|
@ -279,10 +229,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);
|
||||
|
@ -294,7 +244,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;
|
||||
}
|
||||
|
@ -307,9 +257,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);
|
||||
|
@ -326,31 +276,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));
|
||||
|
@ -361,51 +308,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
|
||||
|
|
355
mtproto-common.h
355
mtproto-common.h
|
@ -1,355 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright Nikolay Durov, Andrey Lopatin 2012-2013
|
||||
Copyright Vitaly Valtman 2013
|
||||
*/
|
||||
#ifndef __MTPROTO_COMMON_H__
|
||||
#define __MTPROTO_COMMON_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "interface.h"
|
||||
#include "tools.h"
|
||||
#include "constants.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
|
134
net.c
134
net.c
|
@ -17,10 +17,6 @@
|
|||
Copyright Vitaly Valtman 2013
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -41,9 +37,7 @@
|
|||
#include "net.h"
|
||||
#include "include.h"
|
||||
#include "mtproto-client.h"
|
||||
#include "mtproto-common.h"
|
||||
#include "tree.h"
|
||||
#include "interface.h"
|
||||
|
||||
#ifndef POLLRDHUP
|
||||
#define POLLRDHUP 0
|
||||
|
@ -55,7 +49,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 = 0;
|
||||
|
||||
void fail_connection (struct connection *c);
|
||||
|
||||
|
@ -105,16 +100,14 @@ 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) {
|
||||
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);
|
||||
|
@ -330,9 +323,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);
|
||||
}
|
||||
|
@ -417,10 +408,8 @@ void fail_connection (struct connection *c) {
|
|||
}
|
||||
|
||||
extern FILE *log_net_f;
|
||||
void try_write (struct connection *c) {
|
||||
if (verbosity) {
|
||||
logprintf ( "try write: fd = %d\n", c->fd);
|
||||
}
|
||||
int try_write (struct connection *c) {
|
||||
logprintf ( "try write: fd = %d\n", c->fd);
|
||||
int x = 0;
|
||||
while (c->out_head) {
|
||||
int r = netwrite (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr);
|
||||
|
@ -454,20 +443,17 @@ void try_write (struct connection *c) {
|
|||
delete_connection_buffer (b);
|
||||
} else {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
if (verbosity) {
|
||||
logprintf ("fail_connection: write_error %m\n");
|
||||
}
|
||||
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) {
|
||||
|
@ -533,9 +519,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);
|
||||
}
|
||||
|
@ -546,7 +530,6 @@ void try_read (struct connection *c) {
|
|||
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");
|
||||
|
@ -554,17 +537,14 @@ void try_read (struct connection *c) {
|
|||
}
|
||||
if (r > 0) {
|
||||
c->last_receive_time = get_double_time ();
|
||||
// reset ping timer
|
||||
stop_ping_timer (c);
|
||||
start_ping_timer (c);
|
||||
// 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);
|
||||
|
@ -572,9 +552,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 {
|
||||
|
@ -582,9 +560,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);
|
||||
|
@ -627,9 +603,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) {
|
||||
|
@ -645,16 +619,18 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -672,7 +648,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;
|
||||
|
@ -696,3 +672,59 @@ void dc_create_session (struct dc *DC) {
|
|||
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 session
|
||||
c->session = DC->sessions[0];
|
||||
|
||||
// add backreference to used mtproto-connection
|
||||
c->mtconnection = mtp;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection by freeing all attached buffers and setting
|
||||
* the state to conn_stopped, but does NOT close the attached file descriptor
|
||||
*/
|
||||
void fd_close_connection(struct connection *c) {
|
||||
struct connection_buffer *b = c->out_head;
|
||||
while (b) {
|
||||
struct connection_buffer *d = b;
|
||||
b = b->next;
|
||||
delete_connection_buffer (d);
|
||||
}
|
||||
while (b) {
|
||||
struct connection_buffer *d = b;
|
||||
b = b->next;
|
||||
delete_connection_buffer (d);
|
||||
}
|
||||
c->out_head = c->out_tail = c->in_head = c->in_tail = 0;
|
||||
c->state = conn_stopped;
|
||||
c->out_bytes = c->in_bytes = 0;
|
||||
}
|
||||
|
||||
|
|
35
net.h
35
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,14 @@
|
|||
#ifndef __NET_H__
|
||||
#define __NET_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <poll.h>
|
||||
struct dc;
|
||||
#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,14 +38,8 @@ struct dc;
|
|||
#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 {
|
||||
|
@ -130,6 +129,8 @@ struct connection {
|
|||
void *extra;
|
||||
struct event_timer ev;
|
||||
double last_receive_time;
|
||||
struct telegram *instance;
|
||||
struct mtproto_connection *mtconnection;
|
||||
};
|
||||
|
||||
extern struct connection *Connections[];
|
||||
|
@ -145,7 +146,17 @@ 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);
|
||||
|
||||
#define GET_DC(c) (telegram_get_working_dc(c->instance))
|
||||
|
||||
// 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);
|
||||
|
||||
#define GET_DC(c) (c->session->dc)
|
||||
#endif
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
// test
|
||||
#include <assert.h>
|
||||
|
||||
// Libpurple Plugin Includes
|
||||
#include "notify.h"
|
||||
|
@ -42,33 +41,26 @@
|
|||
#include "prpl.h"
|
||||
#include "prefs.h"
|
||||
#include "util.h"
|
||||
|
||||
// Telegram Includes
|
||||
#include "telegram.h"
|
||||
#include "msglog.h"
|
||||
#include "mtproto-client.h"
|
||||
#include "mtproto-common.h"
|
||||
#include "structures.h"
|
||||
#include "eventloop.h"
|
||||
#include "request.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
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -77,8 +69,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(peer_t *user);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Returns the base icon name for the given buddy and account.
|
||||
|
@ -103,26 +97,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 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)
|
||||
{
|
||||
|
@ -130,9 +105,222 @@ 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");
|
||||
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");
|
||||
|
||||
// TODO: remove input handler when no more input
|
||||
telegram_read_input(tg);
|
||||
if (telegram_has_output(tg)) {
|
||||
tgprpl_has_output(tg);
|
||||
}
|
||||
}
|
||||
|
||||
static void tgprpl_has_input(struct telegram *tg)
|
||||
{
|
||||
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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void telegram_on_proxy_request(struct telegram *instance, const char *ip, int port)
|
||||
{
|
||||
telegram_conn *conn = instance->extra;
|
||||
purple_proxy_connect (conn->gc, conn->pa, ip, port, tgprpl_login_on_connected, conn->tg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
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 ("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
|
||||
*
|
||||
* Set the proxy to the current telegram-instance, and add callbacks to monitor
|
||||
*/
|
||||
void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message)
|
||||
{
|
||||
purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n");
|
||||
struct telegram *tg = (struct telegram*) data;
|
||||
telegram_conn *conn = tg->extra;
|
||||
if (fd == -1) {
|
||||
logprintf("purple_proxy_connect failed: %s\n", error_message);
|
||||
telegram_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);
|
||||
|
||||
telegram_set_proxy(tg, fd);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
message_allocated_handler,
|
||||
peer_allocated_handler
|
||||
};
|
||||
|
||||
/**
|
||||
* This must be implemented.
|
||||
*/
|
||||
|
@ -140,125 +328,48 @@ static void tgprpl_login(PurpleAccount * acct)
|
|||
{
|
||||
purple_debug_info(PLUGIN_ID, "tgprpl_login()\n");
|
||||
PurpleConnection *gc = purple_account_get_connection(acct);
|
||||
_gc = gc;
|
||||
_pa = acct;
|
||||
char const *username = purple_account_get_username(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);
|
||||
|
||||
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);
|
||||
// TODO: fetch current home directory
|
||||
// use this as root
|
||||
struct telegram *tg = telegram_new (&DC, username, &tgconf);
|
||||
telegram_restore_session(tg);
|
||||
|
||||
// ensure config-file exists an
|
||||
purple_debug_info(PLUGIN_ID, "running_for_first_time()\n");
|
||||
running_for_first_time();
|
||||
|
||||
// load all settings: the known network topology, secret keys, logs and configuration file paths
|
||||
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) {
|
||||
store_config();
|
||||
} else {
|
||||
login_verification_fail(acct);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
login_request_verification(acct);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Assure client registration
|
||||
if (!network_client_is_registered()) {
|
||||
purple_debug_info(PLUGIN_ID, "Client is not registered\n");
|
||||
|
||||
if (code && strlen(code) > 0 && hash && strlen(hash) > 0) {
|
||||
purple_debug_info(PLUGIN_ID, "SMS code provided, trying to verify \n");
|
||||
purple_debug_info(PLUGIN_ID, "strlen - code: %lu hash: %lu\n", strlen(code), strlen(hash));
|
||||
purple_debug_info(PLUGIN_ID, "pointer - code: %p hash: %p\n", code, hash);
|
||||
purple_debug_info(PLUGIN_ID, "string - code: %s hash: %s\n", code, hash);
|
||||
int verified = network_verify_registration(code, hash);
|
||||
if (verified) {
|
||||
store_config();
|
||||
} else {
|
||||
login_verification_fail(acct);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
login_request_verification(acct);
|
||||
return;
|
||||
}
|
||||
}
|
||||
purple_debug_info(PLUGIN_ID, "Logged in...\n");
|
||||
purple_connection_set_display_name(gc, username);
|
||||
purple_connection_set_state(gc, PURPLE_CONNECTED);
|
||||
purple_blist_add_account(acct);
|
||||
|
||||
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;
|
||||
|
||||
conn->tg = tg;
|
||||
conn->gc = gc;
|
||||
conn->pa = acct;
|
||||
purple_connection_set_protocol_data(gc, conn);
|
||||
gc->proto_data = conn;
|
||||
tg->extra = conn;
|
||||
|
||||
purple_connection_set_state (conn->gc, PURPLE_CONNECTING);
|
||||
telegram_network_connect(tg);
|
||||
}
|
||||
|
||||
void on_new_message(struct message *M)
|
||||
void message_allocated_handler(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
|
||||
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);
|
||||
logprintf ("message_allocated_handler\n");
|
||||
telegram_conn *conn = tg->extra;
|
||||
PurpleConnection *gc = conn->gc;
|
||||
|
||||
// TODO: this should probably be freed again somwhere
|
||||
int id = get_peer_id(M->from_id);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -295,8 +406,13 @@ static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id)
|
|||
}
|
||||
|
||||
|
||||
void peer_allocated_handler(peer_t *user)
|
||||
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);
|
||||
|
||||
|
@ -310,10 +426,10 @@ void peer_allocated_handler(peer_t *user)
|
|||
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);
|
||||
|
@ -322,7 +438,7 @@ void peer_allocated_handler(peer_t *user)
|
|||
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);
|
||||
|
@ -330,7 +446,7 @@ void peer_allocated_handler(peer_t *user)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -338,7 +454,7 @@ void peer_allocated_handler(peer_t *user)
|
|||
//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) {
|
||||
|
@ -389,11 +505,13 @@ 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(*peer, message, strlen(message));
|
||||
flush_queries();
|
||||
do_send_message(conn->tg, *peer, message, strlen(message));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -751,14 +869,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 +881,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 +897,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);
|
||||
|
||||
|
@ -813,8 +928,8 @@ static PurplePluginInfo info = {
|
|||
PLUGIN_ID,
|
||||
"Telegram",
|
||||
"0.1",
|
||||
"Telegram integration.",
|
||||
"Includes support for the Telegram protocol into libpurple.",
|
||||
"Telegram protocol",
|
||||
"Adds support for the telegram protocol to libpurple.",
|
||||
"Christopher Althaus <althaus.christopher@gmail.com>, Markus Endres <endresma45241@th-nuernberg.de>, Matthias Jentsch <mtthsjntsch@gmail.com>",
|
||||
"https://bitbucket.org/telegrampurple/telegram-purple",
|
||||
NULL, // on load
|
||||
|
@ -832,3 +947,4 @@ static PurplePluginInfo info = {
|
|||
|
||||
|
||||
PURPLE_INIT_PLUGIN(telegram, tgprpl_init, info)
|
||||
|
||||
|
|
|
@ -14,14 +14,8 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "notify.h"
|
||||
#include "plugin.h"
|
||||
#include "version.h"
|
||||
#include "account.h"
|
||||
#include "connection.h"
|
||||
|
||||
#ifndef __TG_PURPLE_H__
|
||||
#define __TG_PURPLE_H__
|
||||
#define PLUGIN_ID "prpl-telegram"
|
||||
|
||||
#define TELEGRAM_APP_API_ID 16944
|
||||
|
@ -34,8 +28,27 @@
|
|||
#define TELEGRAM_AUTH_MODE_PHONE "phone"
|
||||
#define TELEGRAM_AUTH_MODE_SMS "sms"
|
||||
|
||||
#include <glib.h>
|
||||
#include "notify.h"
|
||||
#include "plugin.h"
|
||||
#include "version.h"
|
||||
#include "account.h"
|
||||
#include "connection.h"
|
||||
|
||||
typedef struct {
|
||||
PurpleAccount *account;
|
||||
struct telegram *tg;
|
||||
PurpleAccount *pa;
|
||||
PurpleConnection *gc;
|
||||
PurpleSslConnection *gsc;
|
||||
|
||||
/**
|
||||
* Write handler returned by purple_input_add
|
||||
*/
|
||||
guint wh;
|
||||
|
||||
/**
|
||||
* Read handler returned by purple_input_add
|
||||
*/
|
||||
guint rh;
|
||||
} telegram_conn;
|
||||
|
||||
#endif
|
||||
|
|
105
queries.h
105
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.
|
||||
|
@ -16,11 +16,18 @@
|
|||
|
||||
Copyright Vitaly Valtman 2013
|
||||
*/
|
||||
#include "net.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
|
||||
|
||||
struct query;
|
||||
|
@ -63,63 +70,65 @@ 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);
|
||||
void do_send_code_result (struct telegram *instance, const char *code);
|
||||
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);
|
||||
void do_auth_check_phone (struct telegram *instance, const char *user);
|
||||
void do_get_nearest_dc (struct telegram*);
|
||||
void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name);
|
||||
void do_import_auth (struct telegram *instance, int num);
|
||||
void do_export_auth (struct telegram *instance, int num);
|
||||
void do_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();
|
||||
|
||||
int all_queries_done();
|
||||
|
|
Binary file not shown.
1229
structures.c
1229
structures.c
File diff suppressed because it is too large
Load diff
52
structures.h
52
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 <assert.h>
|
||||
typedef struct { int type; int id; } peer_id_t;
|
||||
|
||||
//#define FLAG_EMPTY 1
|
||||
#define FLAG_MESSAGE_EMPTY 1
|
||||
|
@ -318,6 +322,7 @@ struct message {
|
|||
int unread;
|
||||
int date;
|
||||
int service;
|
||||
struct telegram *instance;
|
||||
union {
|
||||
struct message_action action;
|
||||
struct {
|
||||
|
@ -328,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 (void);
|
||||
struct message *fetch_alloc_geo_message (void);
|
||||
struct message *fetch_alloc_message_short (void);
|
||||
struct message *fetch_alloc_message_short_chat (void);
|
||||
struct message *fetch_alloc_encrypted_message (void);
|
||||
void fetch_encrypted_message_file (struct message_media *M);
|
||||
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);
|
||||
|
@ -362,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);
|
||||
|
|
|
@ -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
|
349
telegram.c
349
telegram.c
|
@ -1,60 +1,321 @@
|
|||
#include <sys/types.h>
|
||||
#include "mtproto-common.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "telegram.h"
|
||||
#include "msglog.h"
|
||||
#include "glib.h"
|
||||
#include "tools.h"
|
||||
#include "mtproto-client.h"
|
||||
#include "binlog.h"
|
||||
|
||||
|
||||
/*
|
||||
* Events
|
||||
*/
|
||||
|
||||
/*
|
||||
* New message received
|
||||
*/
|
||||
void (*on_msg_handler)(struct message *M);
|
||||
void on_update_new_message(void (*on_msg)(struct message *M)) {
|
||||
on_msg_handler = on_msg;
|
||||
}
|
||||
void event_update_new_message(struct message *M) {
|
||||
if (on_msg_handler) {
|
||||
on_msg_handler(M);
|
||||
}
|
||||
void event_update_new_message(struct telegram *instance, struct message *M)
|
||||
{
|
||||
if (instance->config->on_msg_handler) {
|
||||
instance->config->on_msg_handler(instance, M);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Peer allocated
|
||||
*/
|
||||
void (*on_peer_allocated_handler)(peer_t *peer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback to create proxy connections
|
||||
*/
|
||||
void (*proxy_connection_source)(const char *host, int port, void (*on_connection_created)(int fd)) = NULL;
|
||||
void *proxy_connection_data = NULL;
|
||||
void set_proxy_connection_source (void (*connection_source)(const char *host, int port,
|
||||
void (*on_connection_created)(int fd)), void* data)
|
||||
void event_peer_allocated(struct telegram *instance, void *peer)
|
||||
{
|
||||
proxy_connection_source = connection_source;
|
||||
proxy_connection_data = data;
|
||||
if (instance->config->on_peer_allocated_handler) {
|
||||
instance->config->on_peer_allocated_handler(instance, peer);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
// }
|
||||
//}
|
||||
/**
|
||||
* 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->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
|
||||
*
|
||||
* Execute all actions necessary when a certain state is reached. The state machine executes
|
||||
* the authorization and registration steps needed to connect the client to the telegram network,
|
||||
* and will either trigger RPC queries or callbacks to the GUI to request input from the user.
|
||||
*/
|
||||
void telegram_change_state (struct telegram *instance, int state, void *data)
|
||||
{
|
||||
instance->session_state = state;
|
||||
logprintf("on_state_change: %d\n", state);
|
||||
switch (state) {
|
||||
case STATE_ERROR: {
|
||||
const char* err = data;
|
||||
if (err == NULL) {
|
||||
err = "<no description>";
|
||||
}
|
||||
logprintf("telegram errored: %s\n", err);
|
||||
|
||||
// close the connection
|
||||
mtproto_close (instance->connection);
|
||||
}
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case STATE_CONFIG_RECEIVED:
|
||||
logprintf("received network configuration, checking whether phone is registered.\n");
|
||||
telegram_store_session(instance);
|
||||
do_auth_check_phone(instance, instance->login);
|
||||
break;
|
||||
|
||||
case STATE_PHONE_NOT_REGISTERED:
|
||||
logprintf("phone is not registered, need to register phone number.\n");
|
||||
do_send_code(instance, instance->login);
|
||||
break;
|
||||
|
||||
case STATE_PHONE_CODE_NOT_ENTERED:
|
||||
logprintf("phone authenticion, user needs to enter code, first and last name.\n");
|
||||
assert (instance->config->on_phone_registration_required);
|
||||
instance->config->on_phone_registration_required (instance);
|
||||
// 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.\n");
|
||||
assert (instance->config->on_client_registration_required);
|
||||
instance->config->on_client_registration_required (instance);
|
||||
// wait for user input ...
|
||||
break;
|
||||
|
||||
case STATE_READY:
|
||||
logprintf("telegram is registered and ready.\n");
|
||||
telegram_store_session (instance);
|
||||
instance->config->on_ready (instance);
|
||||
break;
|
||||
|
||||
case STATE_DISCONNECTED_SWITCH_DC: {
|
||||
// telegram demands that we use a different data center, which caused
|
||||
// the current mtproto_connection to be disconnected
|
||||
|
||||
int target_dc = *(int*) data;
|
||||
logprintf ("Disconnected: Migrate to data center %d\n", target_dc);
|
||||
|
||||
// close old connection and mark it for destruction
|
||||
mtproto_close (instance->connection);
|
||||
assert (instance->config->proxy_request_cb);
|
||||
// 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
|
||||
// on_error function of the query
|
||||
telegram_network_connect (instance);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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->bl = talloc0 (sizeof(struct binlog));
|
||||
this->config = config;
|
||||
|
||||
this->login = g_strdup(login);
|
||||
this->config_path = g_strdup_printf("%s/%s", config->base_config_path, login);
|
||||
this->download_path = telegram_get_config(this, "downloads");
|
||||
this->auth_path = telegram_get_config(this, "auth");
|
||||
this->state_path = telegram_get_config(this, "state");
|
||||
this->secret_path = telegram_get_config(this, "secret");
|
||||
|
||||
logprintf("%s\n", this->login);
|
||||
logprintf("%s\n", this->config_path);
|
||||
logprintf("%s\n", this->download_path);
|
||||
logprintf("%s\n", this->auth_path);
|
||||
logprintf("%s\n", this->state_path);
|
||||
logprintf("%s\n", this->secret_path);
|
||||
|
||||
telegram_change_state(this, STATE_INITIALISED, NULL);
|
||||
return this;
|
||||
}
|
||||
|
||||
void telegram_free(struct telegram *this)
|
||||
{
|
||||
g_free(this->login);
|
||||
g_free(this->config_path);
|
||||
g_free(this->download_path);
|
||||
g_free(this->auth_path);
|
||||
g_free(this->state_path);
|
||||
g_free(this->secret_path);
|
||||
tfree(this->bl, sizeof(struct binlog));
|
||||
tfree(this, sizeof(struct telegram));
|
||||
}
|
||||
|
||||
void assert_file_usable(const char *file)
|
||||
{
|
||||
logprintf ("assert_file_usable (%s)\n", file);
|
||||
assert(access(file, W_OK | R_OK | F_OK) != -1);
|
||||
}
|
||||
|
||||
void assure_file_exists(const char *dir, const char *file)
|
||||
{
|
||||
g_mkdir_with_parents(dir, 0700);
|
||||
char *f = g_strdup_printf("%s/%s", dir, file);
|
||||
close(open(f, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
|
||||
assert_file_usable(f);
|
||||
g_free(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently used connection
|
||||
*
|
||||
* Will only work after telegram_connect has been called and the connection has
|
||||
* not errored.
|
||||
*/
|
||||
struct connection *telegram_get_connection(struct telegram *instance)
|
||||
{
|
||||
assert(instance->session_state != STATE_ERROR);
|
||||
|
||||
struct dc *DC = telegram_get_working_dc(instance);
|
||||
assert(DC);
|
||||
assert(DC->sessions[0]);
|
||||
assert(DC->sessions[0]->c);
|
||||
return DC->sessions[0]->c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently used DC
|
||||
*
|
||||
* Will only work after restore_session has been called and the data center configuration
|
||||
* was properly loaded
|
||||
*/
|
||||
struct dc *telegram_get_working_dc(struct telegram *instance)
|
||||
{
|
||||
assert(instance->session_state != STATE_ERROR);
|
||||
|
||||
assert(instance->auth.DC_list);
|
||||
assert(instance->auth.dc_working_num > 0);
|
||||
struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num];
|
||||
return DC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the current session state to a file
|
||||
*/
|
||||
void telegram_restore_session(struct telegram *instance)
|
||||
{
|
||||
g_mkdir_with_parents(instance->config_path, 0700);
|
||||
instance->auth = read_auth_file(instance->auth_path);
|
||||
instance->proto = read_state_file(instance->state_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the current session state
|
||||
*/
|
||||
void telegram_store_session(struct telegram *instance)
|
||||
{
|
||||
assure_file_exists(instance->config_path, "auth");
|
||||
assure_file_exists(instance->config_path, "state");
|
||||
write_auth_file(&instance->auth, instance->auth_path);
|
||||
write_state_file(&instance->proto, instance->state_path);
|
||||
}
|
||||
|
||||
void on_authorized(struct mtproto_connection *c, void* data);
|
||||
|
||||
/**
|
||||
* Connect to the currently active data center
|
||||
*/
|
||||
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);
|
||||
assert (instance->config->proxy_request_cb);
|
||||
instance->config->proxy_request_cb (instance, DC_working->ip, DC_working->port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login, and perform a registration when needed
|
||||
*/
|
||||
int telegram_login(struct telegram *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_authorized(struct mtproto_connection *c, void *data)
|
||||
{
|
||||
struct telegram *instance = data;
|
||||
logprintf("Authorized... storing current session %d.\n", c->connection->session[0]);
|
||||
telegram_store_session(instance);
|
||||
telegram_change_state(instance, STATE_AUTHORIZED, NULL);
|
||||
}
|
||||
|
||||
void telegram_read_input (struct telegram *instance)
|
||||
{
|
||||
try_read(instance->connection->connection);
|
||||
mtproto_free_closed();
|
||||
// free all mtproto_connections that may have errored through
|
||||
// a received query
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return try_write(instance->connection->connection);
|
||||
}
|
||||
|
||||
int telegram_has_output (struct telegram *instance)
|
||||
{
|
||||
return instance->connection->queries_num > 0;
|
||||
}
|
||||
|
|
333
telegram.h
333
telegram.h
|
@ -2,9 +2,12 @@
|
|||
* 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)
|
||||
*/
|
||||
|
||||
#ifndef __TELEGRAM_H__
|
||||
#define __TELEGRAM_H__
|
||||
|
||||
#define MAX_DC_NUM 9
|
||||
#define MAX_PEER_NUM 100000
|
||||
|
||||
|
@ -13,75 +16,269 @@
|
|||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#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;
|
||||
|
||||
/*
|
||||
* telegram states
|
||||
*/
|
||||
|
||||
#define STATE_INITIALISED 0
|
||||
#define STATE_DISCONNECTED 1
|
||||
|
||||
// Error
|
||||
#define STATE_ERROR 2
|
||||
|
||||
// intermediate authorization states already present and handled in mtproto-client.c
|
||||
//#define STATE_PQ_REQUESTED 3
|
||||
//#define STATE_DH_REQUESTED 4
|
||||
//#define STATE_CDH_REQUESTED 5
|
||||
#define STATE_AUTHORIZED 6
|
||||
|
||||
// dc discovery
|
||||
#define STATE_CONFIG_REQUESTED 7
|
||||
#define STATE_EXPORTING_CONFIG 8
|
||||
#define STATE_DISCONNECTED_SWITCH_DC 9
|
||||
#define STATE_CONFIG_RECEIVED 11
|
||||
|
||||
// login
|
||||
|
||||
// - Phone Registration
|
||||
#define STATE_PHONE_NOT_REGISTERED 13
|
||||
#define STATE_PHONE_CODE_REQUESTED 14
|
||||
#define STATE_PHONE_CODE_NOT_ENTERED 15
|
||||
#define STATE_PHONE_CODE_ENTERED 16
|
||||
|
||||
// - Client Registration
|
||||
#define STATE_CLIENT_IS_REGISTERED_SENT 17
|
||||
#define STATE_CLIENT_NOT_REGISTERED 18
|
||||
#define STATE_CLIENT_CODE_REQUESTED 19
|
||||
#define STATE_CLIENT_CODE_NOT_ENTERED 20
|
||||
#define STATE_CLIENT_CODE_ENTERED 21
|
||||
|
||||
// Ready for sending and receiving messages
|
||||
#define STATE_READY 22
|
||||
|
||||
/**
|
||||
* 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];
|
||||
};
|
||||
|
||||
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
|
||||
*
|
||||
* 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;
|
||||
char *config_path;
|
||||
char *download_path;
|
||||
char *auth_path;
|
||||
char *state_path;
|
||||
char *secret_path;
|
||||
|
||||
int session_state;
|
||||
struct telegram_config *config;
|
||||
|
||||
/*
|
||||
* Events and Callbacks
|
||||
* protocol state
|
||||
*/
|
||||
// TODO: Insert definitions for all function pointers for event and logging
|
||||
struct protocol_state proto;
|
||||
struct authorization_state auth;
|
||||
|
||||
/*
|
||||
* Internal protocol state
|
||||
/*
|
||||
* connection
|
||||
*/
|
||||
// TODO: Insert *all* global variables from the telegram-implementation
|
||||
struct mtproto_connection *connection;
|
||||
|
||||
/*
|
||||
* binlog
|
||||
*/
|
||||
struct binlog *bl;
|
||||
|
||||
// TODO: Bind this to the current data center, since the code hash is only
|
||||
// valid in its context
|
||||
char *phone_code_hash;
|
||||
|
||||
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 Contains all callbacks used for the telegram instance
|
||||
*/
|
||||
void telegram_create( /* struct telegram, struct configuration config */ );
|
||||
// TODO: Initiate a new telegram instance
|
||||
struct telegram *telegram_new(struct dc *DC, const char* login, struct telegram_config *config);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Resume the session to
|
||||
*/
|
||||
void telegram_restore_session(struct telegram *instance);
|
||||
|
||||
/**
|
||||
* Store
|
||||
*/
|
||||
void telegram_store_session(struct telegram *instance);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
void telegram_destroy(struct telegram instance);
|
||||
// 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 telegram_login (struct telegram *instance);
|
||||
|
||||
/**
|
||||
* Read the authorization_state stored in the given file
|
||||
*/
|
||||
|
||||
// Export functions for plugins
|
||||
void running_for_first_time ();
|
||||
|
||||
/**
|
||||
* Read and process all available input from the network
|
||||
*/
|
||||
void telegram_read_input (struct telegram *instance);
|
||||
|
||||
/**
|
||||
* Write all available output to the network
|
||||
*/
|
||||
int telegram_write_output (struct telegram *instance);
|
||||
|
||||
/**
|
||||
* Return whether there is pending output.
|
||||
*/
|
||||
int telegram_has_output (struct telegram *instance);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -127,62 +324,30 @@ void session_update_contact_list();
|
|||
/*
|
||||
* Events
|
||||
*/
|
||||
void on_update_new_message(void (*on_msg)(struct message *M));
|
||||
void event_update_new_message(struct message *M);
|
||||
|
||||
void on_update_user_typing();
|
||||
void on_update_chat_user_typing();
|
||||
void on_update_user_status();
|
||||
void on_update_user_name();
|
||||
void on_update_user_photo();
|
||||
void on_update_chat_participants();
|
||||
void event_update_new_message(struct telegram *instance, 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 event_peer_allocated(struct telegram *instance, void *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));
|
||||
void set_net_write_cb(ssize_t (*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.
|
||||
* Set the proxy-connection to use
|
||||
*
|
||||
* @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.
|
||||
* NOTE: you may only call this function from the
|
||||
*/
|
||||
void set_proxy_connection_source (void (*connection_source)(const char *host, int port, void (*on_connection_created)(int fd)), void* data);
|
||||
void telegram_set_proxy(struct telegram *instance, int fd);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void set_default_username ();
|
||||
#endif
|
||||
|
|
95
test.lua
95
test.lua
|
@ -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
|
8
tools.c
8
tools.c
|
@ -17,10 +17,6 @@
|
|||
Copyright Vitaly Valtman 2013
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -30,8 +26,8 @@
|
|||
#include <openssl/err.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "interface.h"
|
||||
#include "tools.h"
|
||||
#include "msglog.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define RES_PRE 8
|
||||
|
@ -213,7 +209,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);
|
||||
}
|
||||
|
|
5
tools.h
5
tools.h
|
@ -17,14 +17,14 @@
|
|||
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);
|
||||
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);
|
||||
|
@ -41,4 +41,3 @@ int tasprintf (char **res, const char *format, ...) __attribute__ ((format (prin
|
|||
void tcheck (void);
|
||||
void texists (void *ptr, int size);
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue