diff --git a/ax_python.m4 b/ax_python.m4 new file mode 100644 index 0000000..ebfb8d6 --- /dev/null +++ b/ax_python.m4 @@ -0,0 +1,98 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_python.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PYTHON +# +# DESCRIPTION +# +# This macro does a complete Python development environment check. +# +# It recurses through several python versions (from 2.1 to 2.6 in this +# version), looking for an executable. When it finds an executable, it +# looks to find the header files and library. +# +# It sets PYTHON_BIN to the name of the python executable, +# PYTHON_INCLUDE_DIR to the directory holding the header files, and +# PYTHON_LIB to the name of the Python library. +# +# This macro calls AC_SUBST on PYTHON_BIN (via AC_CHECK_PROG), +# PYTHON_INCLUDE_DIR and PYTHON_LIB. +# +# LICENSE +# +# Copyright (c) 2008 Michael Tindal +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 14 + +AC_DEFUN([AX_PYTHON], +[AC_MSG_CHECKING(for python build information) +AC_MSG_RESULT([]) +for python in python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python; do +AC_CHECK_PROGS(PYTHON_BIN, [$python]) +ax_python_bin=$PYTHON_BIN +if test x$ax_python_bin != x; then + AC_CHECK_LIB($ax_python_bin, main, ax_python_lib=$ax_python_bin, ax_python_lib=no) + if test x$ax_python_lib == xno; then + AC_CHECK_LIB(${ax_python_bin}m, main, ax_python_lib=${ax_python_bin}m, ax_python_lib=no) + fi + if test x$ax_python_lib != xno; then + ax_python_header=`$ax_python_bin -c "from distutils.sysconfig import *; print(get_config_var('CONFINCLUDEPY'))"` + if test x$ax_python_header != x; then + break; + fi + fi +fi +done +if test x$ax_python_bin = x; then + ax_python_bin=no +fi +if test x$ax_python_header = x; then + ax_python_header=no +fi +if test x$ax_python_lib = x; then + ax_python_lib=no +fi + +AC_MSG_RESULT([ results of the Python check:]) +AC_MSG_RESULT([ Binary: $ax_python_bin]) +AC_MSG_RESULT([ Library: $ax_python_lib]) +AC_MSG_RESULT([ Include Dir: $ax_python_header]) + +if test x$ax_python_header != xno; then + PYTHON_INCLUDE_DIR=$ax_python_header + AC_SUBST(PYTHON_INCLUDE_DIR) +fi +if test x$ax_python_lib != xno; then + PYTHON_LIB=$ax_python_lib + AC_SUBST(PYTHON_LIB) +fi +])dnl diff --git a/configure.ac b/configure.ac index 27393e8..e6f1b95 100644 --- a/configure.ac +++ b/configure.ac @@ -4,6 +4,7 @@ AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) m4_include([ax_lua.m4]) +m4_include([ax_python.m4]) m4_include([m4_ax_check_openssl.m4]) m4_include([m4_ax_check_zlib.m4]) m4_include([m4-ax_gcc_builtin.m4]) @@ -94,6 +95,17 @@ AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], ]) ]) +AC_ARG_ENABLE(python,[--enable-python/--disable-python], + [ + dnl python checks (you can change the required python version bellow) + AM_PATH_PYTHON(2.7.0) + PY_PREFIX=`$PYTHON -c 'import sys ; print sys.prefix'` + PYTHON_LIBS="-lpython$PYTHON_VERSION" + PYTHON_CFLAGS="-I$PY_PREFIX/include/python$PYTHON_VERSION" + AC_SUBST([PYTHON_LIBS]) + AC_SUBST([PYTHON_CFLAGS]) + ]) + #check for custom prog name AC_ARG_WITH(progname,[--with-progname=], [ diff --git a/python-tg.c b/python-tg.c new file mode 100644 index 0000000..bb55972 --- /dev/null +++ b/python-tg.c @@ -0,0 +1,1497 @@ +/* + This file is part of telegram-cli. + + Telegram-cli 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-cli 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-cli. If not, see . + + Copyright Vitaly Valtman 2013-2015 + Copyright Vincent Castellano 2015 +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef USE_PYTHON +#include "python-tg.h" + +#include +#include + + +#include +#ifdef EVENT_V2 +#include +#else +#include +#include "event-old.h" +#endif + +//#include "interface.h" +//#include "auto/constants.h" +#include +#include "interface.h" + +#include +extern int verbosity; +extern struct tgl_state *TLS; + +static int have_file; + +#define my_lua_checkstack(L,x) assert (lua_checkstack (L, x)) +void push_user (tgl_peer_t *P); +void push_peer (tgl_peer_id_t id, tgl_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_string_field_arr (int num, const char *value) { + if (!value || !strlen (value)) { return; } + my_lua_checkstack (luaState, 3); + lua_pushnumber (luaState, num); + 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_tgl_peer_type (int x) { + switch (x) { + case TGL_PEER_USER: + lua_pushstring (luaState, "user"); + break; + case TGL_PEER_CHAT: + lua_pushstring (luaState, "chat"); + break; + case TGL_PEER_ENCR_CHAT: + lua_pushstring (luaState, "encr_chat"); + break; + default: + assert (0); + } +} + +void push_user (tgl_peer_t *P) { + 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); + if (P->user.access_hash) { + lua_add_num_field ("access_hash", 1); + } +} + +void push_chat (tgl_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); + if (P->chat.user_list) { + lua_pushstring (luaState, "members"); + lua_newtable (luaState); + int i; + for (i = 0; i < P->chat.users_num; i++) { + lua_pushnumber (luaState, i); + tgl_peer_id_t id = TGL_MK_USER (P->chat.user_list[i].user_id); + push_peer (id, tgl_peer_get (TLS, id)); + lua_settable (luaState, -3); + } + lua_settable (luaState, -3); + } +} + +void push_encr_chat (tgl_peer_t *P) { + my_lua_checkstack (luaState, 4); + lua_pushstring (luaState, "user"); + push_peer (TGL_MK_USER (P->encr_chat.user_id), tgl_peer_get (TLS, TGL_MK_USER (P->encr_chat.user_id))); + lua_settable (luaState, -3); +} + +void push_update_types (unsigned flags) { + my_lua_checkstack (luaState, 4); + lua_newtable (luaState); + int cc = 0; + + + if (flags & TGL_UPDATE_CREATED) { + lua_add_string_field_arr (cc++, "created"); + } + if (flags & TGL_UPDATE_DELETED) { + lua_add_string_field_arr (cc++, "deleted"); + } + if (flags & TGL_UPDATE_PHONE) { + lua_add_string_field_arr (cc++, "phone"); + } + if (flags & TGL_UPDATE_CONTACT) { + lua_add_string_field_arr (cc++, "contact"); + } + if (flags & TGL_UPDATE_PHOTO) { + lua_add_string_field_arr (cc++, "photo"); + } + if (flags & TGL_UPDATE_BLOCKED) { + lua_add_string_field_arr (cc++, "blocked"); + } + if (flags & TGL_UPDATE_REAL_NAME) { + lua_add_string_field_arr (cc++, "real_name"); + } + if (flags & TGL_UPDATE_NAME) { + lua_add_string_field_arr (cc++, "name"); + } + if (flags & TGL_UPDATE_REQUESTED) { + lua_add_string_field_arr (cc++, "requested"); + } + if (flags & TGL_UPDATE_WORKING) { + lua_add_string_field_arr (cc++, "working"); + } + if (flags & TGL_UPDATE_FLAGS) { + lua_add_string_field_arr (cc++, "flags"); + } + if (flags & TGL_UPDATE_TITLE) { + lua_add_string_field_arr (cc++, "title"); + } + if (flags & TGL_UPDATE_ADMIN) { + lua_add_string_field_arr (cc++, "admin"); + } + if (flags & TGL_UPDATE_MEMBERS) { + lua_add_string_field_arr (cc++, "members"); + } + if (flags & TGL_UPDATE_ACCESS_HASH) { + lua_add_string_field_arr (cc++, "access_hash"); + } + if (flags & TGL_UPDATE_USERNAME) { + lua_add_string_field_arr (cc++, "username"); + } + +} + +void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { + lua_newtable (luaState); + + lua_add_num_field ("id", tgl_get_peer_id (id)); + lua_pushstring (luaState, "type"); + push_tgl_peer_type (tgl_get_peer_type (id)); + lua_settable (luaState, -3); + + + if (!P || !(P->flags & FLAG_CREATED)) { + lua_pushstring (luaState, "print_name"); + static char s[100]; + switch (tgl_get_peer_type (id)) { + case TGL_PEER_USER: + sprintf (s, "user#%d", tgl_get_peer_id (id)); + break; + case TGL_PEER_CHAT: + sprintf (s, "chat#%d", tgl_get_peer_id (id)); + break; + case TGL_PEER_ENCR_CHAT: + sprintf (s, "encr_chat#%d", tgl_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 (tgl_get_peer_type (id)) { + case TGL_PEER_USER: + push_user (P); + break; + case TGL_PEER_CHAT: + push_chat (P); + break; + case TGL_PEER_ENCR_CHAT: + push_encr_chat (P); + break; + default: + assert (0); + } +} + +void push_media (struct tgl_message_media *M) { + my_lua_checkstack (luaState, 4); + + switch (M->type) { + case tgl_message_media_photo: + case tgl_message_media_photo_encr: + lua_newtable (luaState); + lua_add_string_field ("type", "photo"); + break; + /*case tgl_message_media_video: + case tgl_message_media_video_encr: + lua_newtable (luaState); + lua_add_string_field ("type", "video"); + break; + case tgl_message_media_audio: + case tgl_message_media_audio_encr: + lua_newtable (luaState); + lua_add_string_field ("type", "audio"); + break;*/ + case tgl_message_media_document: + case tgl_message_media_document_encr: + lua_newtable (luaState); + lua_add_string_field ("type", "document"); + break; + case tgl_message_media_unsupported: + lua_newtable (luaState); + lua_add_string_field ("type", "unsupported"); + break; + case tgl_message_media_geo: + lua_newtable (luaState); + lua_add_string_field ("type", "geo"); + lua_add_num_field ("longitude", M->geo.longitude); + lua_add_num_field ("latitude", M->geo.latitude); + break; + case tgl_message_media_contact: + lua_newtable (luaState); + lua_add_string_field ("type", "contact"); + 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 tgl_message *M) { + assert (M); + my_lua_checkstack (luaState, 10); + lua_newtable (luaState); + + static char s[30]; + snprintf (s, 30, "%lld", M->id); + lua_add_string_field ("id", s); + if (!(M->flags & FLAG_CREATED)) { return; } + lua_add_num_field ("flags", M->flags); + + if (tgl_get_peer_type (M->fwd_from_id)) { + lua_pushstring (luaState, "fwd_from"); + push_peer (M->fwd_from_id, tgl_peer_get (TLS, 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, tgl_peer_get (TLS, M->from_id)); + lua_settable (luaState, -3); + + lua_pushstring (luaState, "to"); + push_peer (M->to_id, tgl_peer_get (TLS, 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 != tgl_message_media_none) { + 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 tgl_message *M) { + 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_update (struct tgl_secret_chat *C, unsigned flags) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_secret_chat_update"); + push_peer (C->id, (void *)C); + push_update_types (flags); + assert (lua_gettop (luaState) == 3); + + int r = lua_pcall (luaState, 2, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_user_update (struct tgl_user *U, unsigned flags) { + 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); + push_update_types (flags); + assert (lua_gettop (luaState) == 3); + + int r = lua_pcall (luaState, 2, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +void lua_chat_update (struct tgl_chat *C, unsigned flags) { + 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); + push_update_types (flags); + assert (lua_gettop (luaState) == 3); + + int r = lua_pcall (luaState, 2, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + +//extern tgl_peer_t *Peers[]; +//extern int peer_num; + +#define MAX_LUA_COMMANDS 1000 +void *lua_ptr[MAX_LUA_COMMANDS]; +static int pos; + +static inline tgl_peer_t *get_peer (const char *s) { + return tgl_peer_get_by_name (TLS, s); +} + +enum lua_query_type { + lq_contact_list, + lq_dialog_list, + lq_msg, + lq_send_typing, + lq_send_typing_abort, + lq_rename_chat, + lq_send_photo, + lq_chat_set_photo, + lq_set_profile_photo, + lq_set_profile_name, + lq_send_video, + lq_send_text, + lq_fwd, + lq_fwd_media, + lq_load_photo, + lq_load_video_thumb, + lq_load_video, + lq_chat_info, + lq_user_info, + lq_history, + lq_chat_add_user, + lq_chat_del_user, + lq_add_contact, + lq_del_contact, + lq_rename_contact, + lq_search, + lq_global_search, + lq_mark_read, + lq_create_secret_chat, + lq_create_group_chat, + lq_send_audio, + lq_send_document, + lq_send_file, + lq_load_audio, + lq_load_document, + lq_load_document_thumb, + lq_delete_msg, + lq_restore_msg, + lq_accept_secret_chat, + lq_send_contact, + lq_status_online, + lq_status_offline, + lq_send_location, + lq_extf +}; + +struct lua_query_extra { + int func; + int param; +}; + +void lua_empty_cb (struct tgl_state *TLSR, void *cb_extra, int success) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + assert (lua_gettop (luaState) == 3); + + int r = lua_pcall (luaState, 2, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_user **UL) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + lua_newtable (luaState); + int i; + for (i = 0; i < num; i++) { + lua_pushnumber (luaState, i); + push_peer (UL[i]->id, (void *)UL[i]); + lua_settable (luaState, -3); + } + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], int msgs[], int unread[]) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + if (success) { + lua_newtable (luaState); + int i; + for (i = 0; i < num; i++) { + lua_pushnumber (luaState, i); + + lua_newtable (luaState); + + lua_pushstring (luaState, "peer"); + push_peer (peers[i], tgl_peer_get (TLS, peers[i])); + lua_settable (luaState, -3); + + struct tgl_message *M = tgl_message_get (TLS, msgs[i]); + if (M && (M->flags & FLAG_CREATED)) { + lua_pushstring (luaState, "message"); + push_message (M); + lua_settable (luaState, -3); + } + + lua_pushstring (luaState, "unread"); + lua_pushnumber (luaState, unread[i]); + lua_settable (luaState, -3); + + lua_settable (luaState, -3); + } + } else { + lua_pushboolean (luaState, 0); + } + assert (lua_gettop (luaState) == 4); + + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_message *M) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + push_message (M); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_msg_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_message *M[]) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + lua_newtable (luaState); + int i; + for (i = 0; i < num; i++) { + lua_pushnumber (luaState, i); + push_message (M[i]); + lua_settable (luaState, -3); + } + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_file_cb (struct tgl_state *TLSR, void *cb_extra, int success, char *file_name) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + lua_pushstring (luaState, file_name); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_chat *C) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + push_peer (C->id, (void *)C); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_secret_chat *C) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + push_peer (C->id, (void *)C); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_user_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_user *C) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + push_peer (C->id, (void *)C); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, char *data) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + lua_pushstring (luaState, data); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + +void lua_do_all (void) { + int p = 0; + while (p < pos) { + int l = (long)lua_ptr[p ++]; + assert (p + l + 1 <= pos); + enum lua_query_type f = (long)lua_ptr[p ++]; + struct tgl_message *M; + char *s, *s1, *s2, *s3; + switch (f) { + case lq_contact_list: + tgl_do_update_contact_list (TLS, lua_contact_list_cb, lua_ptr[p ++]); + break; + case lq_dialog_list: + tgl_do_get_dialog_list (TLS, lua_dialog_list_cb, lua_ptr[p ++]); + break; + case lq_msg: + tgl_do_send_message (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], strlen (lua_ptr[p + 2]), lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_send_typing: + tgl_do_send_typing (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, tgl_typing_typing, lua_empty_cb, lua_ptr[p]); + p += 2; + break; + case lq_send_typing_abort: + tgl_do_send_typing (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, tgl_typing_cancel, lua_empty_cb, lua_ptr[p]); + p += 2; + break; + case lq_rename_chat: + tgl_do_rename_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_send_photo: + tgl_do_send_document (TLS, -1, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_send_video: + tgl_do_send_document (TLS, FLAG_DOCUMENT_VIDEO, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_send_audio: + tgl_do_send_document (TLS, FLAG_DOCUMENT_AUDIO, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_send_document: + tgl_do_send_document (TLS, 0, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_send_file: + tgl_do_send_document (TLS, -2, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_send_text: + tgl_do_send_text (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_chat_set_photo: + tgl_do_set_chat_photo (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; + case lq_load_photo: + case lq_load_video: + case lq_load_audio: + case lq_load_document: + M = lua_ptr[p + 1]; + if (!M || (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_photo_encr && M->media.type != tgl_message_media_document && M->media.type != tgl_message_media_document_encr)) { + lua_file_cb (TLS, lua_ptr[p], 0, 0); + } else { + if (M->media.type == tgl_message_media_photo) { + tgl_do_load_photo (TLS, &M->media.photo, lua_file_cb, lua_ptr[p]); + } else if (M->media.type == tgl_message_media_document) { + tgl_do_load_document (TLS, &M->media.document, lua_file_cb, lua_ptr[p]); + } else { + tgl_do_load_encr_document (TLS, &M->media.encr_document, lua_file_cb, lua_ptr[p]); + } + } + p += 2; + break; + case lq_load_video_thumb: + case lq_load_document_thumb: + M = lua_ptr[p + 1]; + if (!M || (M->media.type != tgl_message_media_document)) { + lua_file_cb (TLS, lua_ptr[p], 0, 0); + } else { + tgl_do_load_document_thumb (TLS, &M->media.document, lua_file_cb, lua_ptr[p]); + } + p += 2; + break; + case lq_fwd: + tgl_do_forward_message (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((struct tgl_message *)lua_ptr[p + 2])->id, lua_msg_cb, lua_ptr[p]); + p += 3; + break; + case lq_fwd_media: + tgl_do_forward_media (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((struct tgl_message *)lua_ptr[p + 2])->id, lua_msg_cb, lua_ptr[p]); + p += 3; + break; + case lq_chat_info: + tgl_do_get_chat_info (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, lua_chat_cb, lua_ptr[p]); + p += 2; + break; + case lq_user_info: + tgl_do_get_user_info (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, lua_user_cb, lua_ptr[p]); + p += 2; + break; + case lq_history: + tgl_do_get_history (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, (long)lua_ptr[p + 2], 0, lua_msg_list_cb, lua_ptr[p]); + p += 3; + break; + case lq_chat_add_user: + tgl_do_add_user_to_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((tgl_peer_t *)lua_ptr[p + 2])->id, 10, lua_msg_cb, lua_ptr[p]); + p += 3; + break; + case lq_chat_del_user: + tgl_do_del_user_from_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((tgl_peer_t *)lua_ptr[p + 2])->id, lua_msg_cb, lua_ptr[p]); + p += 3; + break; + case lq_add_contact: + s1 = lua_ptr[p + 1]; + s2 = lua_ptr[p + 2]; + s3 = lua_ptr[p + 3]; + tgl_do_add_contact (TLS, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 0, lua_contact_list_cb, lua_ptr[p]); + free (s1); + free (s2); + free (s3); + p += 4; + break; + case lq_del_contact: + tgl_do_del_contact (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); + p += 2; + break; + case lq_rename_contact: + s1 = lua_ptr[p + 1]; + s2 = lua_ptr[p + 2]; + s3 = lua_ptr[p + 3]; + tgl_do_add_contact (TLS, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 1, lua_contact_list_cb, lua_ptr[p]); + free (s1); + free (s2); + free (s3); + p += 4; + break; + case lq_search: + s = lua_ptr[p + 2]; + tgl_do_msg_search (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, 0, 40, 0, s, lua_msg_list_cb, lua_ptr[p]); + free (s); + p += 3; + break; + case lq_global_search: + s = lua_ptr[p + 1]; + tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, s, lua_msg_list_cb, lua_ptr[p]); + free (s); + p += 2; + break; + case lq_mark_read: + tgl_do_mark_read (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); + p += 2; + break; + case lq_set_profile_photo: + s = lua_ptr[p + 1]; + tgl_do_set_profile_photo (TLS, s, lua_empty_cb, lua_ptr[p]); + free (s); + p += 2; + break; + case lq_set_profile_name: + s1 = lua_ptr[p + 1]; + s2 = lua_ptr[p + 1]; + tgl_do_set_profile_name (TLS, s1, s2, lua_user_cb, lua_ptr[p]); + free (s1); + free (s2); + p += 3; + break; + case lq_create_secret_chat: + tgl_do_create_secret_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_secret_chat_cb, lua_ptr[p]); + p += 2; + break; + case lq_create_group_chat: + s = lua_ptr[p + 2]; + tgl_do_create_group_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, s, lua_msg_cb, lua_ptr[p]); + free (s); + p += 3; + break; + case lq_delete_msg: + tgl_do_delete_msg (TLS, ((struct tgl_message *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); + p += 2; + break; + case lq_restore_msg: + tgl_do_delete_msg (TLS, (long)lua_ptr[p + 1], lua_empty_cb, lua_ptr[p]); + p += 2; + break; + case lq_accept_secret_chat: + tgl_do_accept_encr_chat_request (TLS, lua_ptr[p + 1], lua_secret_chat_cb, lua_ptr[p]); + p += 2; + break; + case lq_send_contact: + s1 = lua_ptr[p + 2]; + s2 = lua_ptr[p + 3]; + s3 = lua_ptr[p + 4]; + tgl_do_send_contact (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), lua_msg_cb, lua_ptr[p]); + free (s1); + free (s2); + free (s3); + p += 5; + break; + case lq_status_online: + tgl_do_update_status (TLS, 1, lua_empty_cb, lua_ptr[p]); + p ++; + break; + case lq_status_offline: + tgl_do_update_status (TLS, 0, lua_empty_cb, lua_ptr[p]); + p ++; + break; + case lq_extf: + s = lua_ptr[p + 1]; + tgl_do_send_extf (TLS, s, strlen (s), lua_str_cb, lua_ptr[p]); + free (s); + p += 2; + break; + case lq_send_location: + if (sizeof (void *) == 4) { + tgl_do_send_location (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id , *(float *)(lua_ptr + p + 2), *(float *)(lua_ptr + p + 3), lua_msg_cb, lua_ptr[p]); + } else { + tgl_do_send_location (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id , *(double *)(lua_ptr + p + 2), *(double *)(lua_ptr + p + 3), lua_msg_cb, lua_ptr[p]); + } + p += 4; + break; + /* + lq_delete_msg, + lq_restore_msg, + case 0: + tgl_do_send_message (((tgl_peer_t *)lua_ptr[p])->id, lua_ptr[p + 1], strlen (lua_ptr[p + 1]), 0, 0); + free (lua_ptr[p + 1]); + p += 2; + break; + case 1: + tgl_do_forward_message (((tgl_peer_t *)lua_ptr[p])->id, (long)lua_ptr[p + 1], 0, 0); + p += 2; + break; + case 2: + tgl_do_mark_read (((tgl_peer_t *)lua_ptr[p])->id, 0, 0); + p += 1; + break;*/ + default: + assert (0); + } + } + pos = 0; +} + + +enum lua_function_param { + lfp_none, + lfp_peer, + lfp_chat, + lfp_user, + lfp_secret_chat, + lfp_string, + lfp_number, + lfp_positive_number, + lfp_nonnegative_number, + lfp_msg, + lfp_double +}; + +struct lua_function { + char *name; + enum lua_query_type type; + enum lua_function_param params[10]; +}; + +struct lua_function functions[] = { + {"get_contact_list", lq_contact_list, { lfp_none }}, + {"get_dialog_list", lq_dialog_list, { lfp_none }}, + {"rename_chat", lq_rename_chat, { lfp_chat, lfp_string, lfp_none }}, + {"send_msg", lq_msg, { lfp_peer, lfp_string, lfp_none }}, + {"send_typing", lq_send_typing, { lfp_peer, lfp_none }}, + {"send_typing_abort", lq_send_typing_abort, { lfp_peer, lfp_none }}, + {"send_photo", lq_send_photo, { lfp_peer, lfp_string, lfp_none }}, + {"send_video", lq_send_video, { lfp_peer, lfp_string, lfp_none }}, + {"send_audio", lq_send_audio, { lfp_peer, lfp_string, lfp_none }}, + {"send_document", lq_send_document, { lfp_peer, lfp_string, lfp_none }}, + {"send_file", lq_send_file, { lfp_peer, lfp_string, lfp_none }}, + {"send_text", lq_send_text, { lfp_peer, lfp_string, lfp_none }}, + {"chat_set_photo", lq_chat_set_photo, { lfp_chat, lfp_string, lfp_none }}, + {"load_photo", lq_load_photo, { lfp_msg, lfp_none }}, + {"load_video", lq_load_video, { lfp_msg, lfp_none }}, + {"load_video_thumb", lq_load_video_thumb, { lfp_msg, lfp_none }}, + {"load_audio", lq_load_audio, { lfp_msg, lfp_none }}, + {"load_document", lq_load_document, { lfp_msg, lfp_none }}, + {"load_document_thumb", lq_load_document_thumb, { lfp_msg, lfp_none }}, + {"fwd_msg", lq_fwd, { lfp_peer, lfp_msg, lfp_none }}, + {"fwd_media", lq_fwd_media, { lfp_peer, lfp_msg, lfp_none }}, + {"chat_info", lq_chat_info, { lfp_chat, lfp_none }}, + {"user_info", lq_user_info, { lfp_user, lfp_none }}, + {"get_history", lq_history, { lfp_peer, lfp_nonnegative_number, lfp_none }}, + {"chat_add_user", lq_chat_add_user, { lfp_chat, lfp_user, lfp_none }}, + {"chat_del_user", lq_chat_del_user, { lfp_chat, lfp_user, lfp_none }}, + {"add_contact", lq_add_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, + {"del_contact", lq_del_contact, { lfp_user, lfp_none }}, + {"rename_contact", lq_rename_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, + {"msg_search", lq_search, { lfp_peer, lfp_string, lfp_none }}, + {"msg_global_search", lq_global_search, { lfp_string, lfp_none }}, + {"mark_read", lq_mark_read, { lfp_peer, lfp_none }}, + {"set_profile_photo", lq_set_profile_photo, { lfp_string, lfp_none }}, + {"set_profile_name", lq_set_profile_name, { lfp_string, lfp_none }}, + {"create_secret_chat", lq_create_secret_chat, { lfp_user, lfp_none }}, + {"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }}, + {"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }}, + {"restore_msg", lq_restore_msg, { lfp_positive_number, lfp_none }}, + {"accept_secret_chat", lq_accept_secret_chat, { lfp_secret_chat, lfp_none }}, + {"send_contact", lq_send_contact, { lfp_peer, lfp_string, lfp_string, lfp_string, lfp_none }}, + {"status_online", lq_status_online, { lfp_none }}, + {"status_offline", lq_status_offline, { lfp_none }}, + {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, + {"ext_function", lq_extf, { lfp_string, lfp_none }}, + { 0, 0, { lfp_none}} +}; + +static int parse_lua_function (lua_State *L, struct lua_function *F) { + int p = 0; + while (F->params[p] != lfp_none) { p ++; } + if (lua_gettop (L) != p + 2) { + lua_pushboolean (L, 0); + return 1; + } + + int a1 = luaL_ref (L, LUA_REGISTRYINDEX); + int a2 = luaL_ref (L, LUA_REGISTRYINDEX); + + struct lua_query_extra *e = malloc (sizeof (*e)); + assert (e); + e->func = a2; + e->param = a1; + + assert (pos + 3 + p < MAX_LUA_COMMANDS); + + lua_ptr[pos ++] = (void *)(long)(p + 1); + lua_ptr[pos ++] = (void *)(long)F->type; + lua_ptr[pos ++] = e; + + int sp = p; + int ok = 1; + int cc = 0; + while (p > 0) { + p --; + cc ++; + const char *s; + tgl_peer_t *P; + long long num; + double dval; + struct tgl_message *M; + switch (F->params[p]) { + case lfp_none: + assert (0); + break; + case lfp_peer: + case lfp_user: + case lfp_chat: + case lfp_secret_chat: + s = lua_tostring (L, -cc); + if (!s) { + ok = 0; + break; + } + if (sscanf (s, "user#id%lld", &num) == 1 && num > 0) { + tgl_insert_empty_user (TLS, num); + P = tgl_peer_get (TLS, TGL_MK_USER (num)); + } else if (sscanf (s, "chat#id%lld", &num) == 1 && num > 0) { + tgl_insert_empty_chat (TLS, num); + P = tgl_peer_get (TLS, TGL_MK_CHAT (num)); + } else { + P = get_peer (s); + } + if (!P/* || !(P->flags & FLAG_CREATED)*/) { + ok = 0; + break; + } + if (F->params[p] != lfp_peer) { + if ((tgl_get_peer_type (P->id) == TGL_PEER_USER && F->params[p] != lfp_user) || + (tgl_get_peer_type (P->id) == TGL_PEER_CHAT && F->params[p] != lfp_chat) || + (tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT && F->params[p] != lfp_secret_chat)) { + ok = 0; + break; + } + } + lua_ptr[pos + p] = P; + break; + + case lfp_string: + s = lua_tostring (L, -cc); + if (!s) { + ok = 0; + break; + } + lua_ptr[pos + p] = (void *)s; + break; + + case lfp_number: + num = lua_tonumber (L, -cc); + + lua_ptr[pos + p] = (void *)(long)num; + break; + + case lfp_double: + dval = lua_tonumber (L, -cc); + + if (sizeof (void *) == 4) { + *(float *)(lua_ptr + pos + p) = dval; + } else { + assert (sizeof (void *) >= 8); + *(double *)(lua_ptr + pos + p) = dval; + } + break; + + case lfp_positive_number: + num = lua_tonumber (L, -cc); + if (num <= 0) { + ok = 0; + break; + } + + lua_ptr[pos + p] = (void *)(long)num; + break; + + case lfp_nonnegative_number: + num = lua_tonumber (L, -cc); + if (num < 0) { + ok = 0; + break; + } + + lua_ptr[pos + p] = (void *)(long)num; + break; + + case lfp_msg: + s = lua_tostring (L, -cc); + if (!s || !strlen (s)) { + ok = 0; + break; + } + + num = atoll (s); + + M = tgl_message_get (TLS, num); + + if (!M || !(M->flags & FLAG_CREATED)) { + ok = 0; + break; + } + + lua_ptr[pos + p] = M; + break; + + default: + assert (0); + } + } + if (!ok) { + luaL_unref (luaState, LUA_REGISTRYINDEX, a1); + luaL_unref (luaState, LUA_REGISTRYINDEX, a2); + free (e); + pos -= 3; + lua_pushboolean (L, 0); + return 1; + } + + for (p = 0; p < sp; p++) { + if (F->params[p] == lfp_string) { + lua_ptr[pos + p] = strdup (lua_ptr[pos + p]); + } + } + pos += p; + + lua_pushboolean (L, 1); + return 1; +} + + +static void lua_postpone_alarm (evutil_socket_t fd, short what, void *arg) { + int *t = arg; + + 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)); + } + +} + +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); + + + int *t = malloc (16); + assert (t); + struct event *ev = evtimer_new (TLS->ev_base, lua_postpone_alarm, t); + t[0] = a1; + t[1] = a2; + *(void **)(t + 2) = ev; + + struct timeval ts= { + .tv_sec = (long)timeout, + .tv_usec = (timeout - ((long)timeout)) * 1000000 + }; + event_add (ev, &ts); + + lua_pushboolean (L, 1); + return 1; +} + +extern int safe_quit; +static int safe_quit_from_lua (lua_State *L) { + int n = lua_gettop (L); + if (n != 0) { + lua_pushboolean (L, 0); + return 1; + } + safe_quit = 1; + + lua_pushboolean (L, 1); + return 1; +} + +static int universal_from_lua (lua_State *L) { + const char *s = lua_tostring(L, lua_upvalueindex(1)); + if (!s) { + lua_pushboolean (L, 0); + return 1; + } + int i = 0; + while (functions[i].name) { + if (!strcmp (functions[i].name, s)) { + return parse_lua_function (L, &functions[i]); + } + i ++; + } + lua_pushboolean (L, 0); + return 1; +} + + +static void my_python_register (const char *name, lua_CFunction f) { + lua_pushstring(L, name); + lua_pushcclosure(L, f, 1); + lua_setglobal(L, name); +} + + +void py_init (const char *file) { + if (!file) { return; } + have_file = 1; + + PyObject *pName, *pModule; + + Py_Initialize() + + pName = PyFile_FromFile(file, "telegram.py", 'r', null); + + err = PyErr_Occurred(); + if (err != NULL) { + logprintf("python error occurred"); // TODO: implement the backtrace + exit(1); + } + + int i = 0; + while (functions[i].name) { + my_lua_register (luaState, functions[i].name, universal_from_lua); + i ++; + } + //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); + lua_register (luaState, "safe_quit", safe_quit_from_lua); + //lua_register (luaState, "get_contact_list", get_contacts_from_lua); + /*lua_register (luaState, "get_dialog_list", get_dialog_list_from_lua); + lua_register (luaState, "send_msg", send_msg_from_lua); + lua_register (luaState, "rename_chat", rename_chat_from_lua); + lua_register (luaState, "send_photo", send_photo_from_lua); + lua_register (luaState, "send_video", send_video_from_lua); + lua_register (luaState, "send_audio", send_audio_from_lua); + lua_register (luaState, "send_document", send_document_from_lua); + lua_register (luaState, "send_text", send_text_from_lua); + lua_register (luaState, "chat_set_photo", chat_set_photo_from_lua); + lua_register (luaState, "load_photo", load_photo_from_lua); + lua_register (luaState, "load_video", load_video_from_lua); + lua_register (luaState, "load_video_thumb", load_video_thumb_from_lua); + lua_register (luaState, "load_audio", load_audio_from_lua); + lua_register (luaState, "load_document", load_document_from_lua); + lua_register (luaState, "load_document_thumb", load_document_thumb_from_lua); + lua_register (luaState, "fwd_msg", message_forward_from_lua); + lua_register (luaState, "chat_info", chat_info_from_lua); + lua_register (luaState, "user_info", user_info_from_lua); + lua_register (luaState, "get_history", get_history_from_lua); + lua_register (luaState, "chat_add_user", chat_add_user_from_lua); + lua_register (luaState, "chat_del_user", chat_del_user_from_lua); + lua_register (luaState, "add_contact", add_contact_from_lua); + lua_register (luaState, "rename_contact", rename_contact_from_lua);*/ + + int ret = luaL_dofile (luaState, file); + if (ret) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + exit (1); + } +} + +#endif diff --git a/python-tg.h b/python-tg.h new file mode 100644 index 0000000..2fb84ab --- /dev/null +++ b/python-tg.h @@ -0,0 +1,35 @@ +/* + This file is part of telegram-cli. + + Telegram-cli 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-cli 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-cli. If not, see . + + Copyright Vitaly Valtman 2013-2015 + Copyright Vincent Castellano 2015 +*/ +#ifndef __PYTHON_TG_H__ +#define __PYTHON_TG_H__ + +#include +#include + +void py_init (const char *file); +void py_new_msg (struct tgl_message *M); +void py_our_id (int id); +void py_secret_chat_update (struct tgl_secret_chat *U, unsigned flags); +void py_user_update (struct tgl_user *U, unsigned flags); +void py_chat_update (struct tgl_chat *C, unsigned flags); +void py_binlog_end (void); +void py_diff_end (void); +void py_do_all (void); +#endif