diff --git a/.gitignore b/.gitignore
index 7cee62d..f9f3975 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
telegram
*.o
Makefile
+aclocal.m4
autom4te.cache
config.h
config.log
@@ -16,4 +17,5 @@ debian/telegram-cli.[a-z]
debian/files
debian/telegram-cli/*
debian/telegram-cli.debhelper.log
-debian/telegram-cli.substvars
\ No newline at end of file
+debian/telegram-cli.substvars
+__pycache__
diff --git a/.travis.yml b/.travis.yml
index a299f36..51df285 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,7 @@ install:
- sudo apt-get install libreadline6-dev
- sudo apt-get install libssl-dev
- sudo apt-get install liblua5.2-dev lua5.2
+ - sudo apt-get install python-dev python
- sudo apt-get install libevent-dev
- sudo apt-get install libjansson-dev
diff --git a/Makefile.in b/Makefile.in
index e1989ab..c032397 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -4,10 +4,9 @@ CFLAGS=@CFLAGS@
LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@
CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@
DEFS=@DEFS@
-COMPILE_FLAGS=${CFLAGS} ${CPFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter -fPIC
-
+COMPILE_FLAGS=${CFLAGS} ${CPFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Werror -Wextra -Wno-missing-field-initializers -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter -fPIC
EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ @OPENSSL_LIBS@
-LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS}
+LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil
LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS}
DEP=dep
@@ -19,7 +18,7 @@ DIR_LIST=${DEP} ${AUTO} ${EXE} ${OBJ} ${LIB} ${DEP}/auto ${OBJ}/auto
EXE_LIST=${EXE}/telegram-cli
-TG_OBJECTS=${OBJ}/main.o ${OBJ}/loop.o ${OBJ}/interface.o ${OBJ}/lua-tg.o ${OBJ}/json-tg.o
+TG_OBJECTS=${OBJ}/main.o ${OBJ}/loop.o ${OBJ}/interface.o ${OBJ}/lua-tg.o ${OBJ}/json-tg.o ${OBJ}/python-tg.o ${OBJ}/python-types.o
INCLUDE=-I. -I${srcdir} -I${srcdir}/tgl
CC=@CC@
diff --git a/README-PY b/README-PY
new file mode 100644
index 0000000..ae4467b
--- /dev/null
+++ b/README-PY
@@ -0,0 +1,95 @@
+To use python with client you should write python script. You can specify it from config ("python_script" option) or from command_line [-Z].
+
+You should set the following callbacks in your script:
+ tgl.on_binlog_replay_end() - it is called when replay of old events end. Any updates prior this call were already received by this client
+ some time ago.
+
+ tgl.on_get_difference_end() - it is called after first get_difference call. So we received all updates after last client execute.
+
+ tgl.on_our_id(our_id) - Informs about id of currently logged in user.
+
+ tgl.on_msg_receive(msg) - it is called when we receive new msg (!! may be called before on_binlog_replay_end, than it is old msg).
+
+ tgl.on_user_update(peer, what_changed) - updated info about user. what_changed is array of strings.
+ tgl.on_chat_update(peer, what_changed) - updated info about user. what_changed is array of strings.
+ tgl.on_secret_chat_update(peer, what_changed) - updated info about user. what_changed is array of strings.
+
+
+
+Also, you can call several functions. Each this function last two arguments, are callback, which is a python function implementing the callback from the function.
+These functions may return false immidiately if something is bad with args, or return true and call cb_function in future.
+The callback function should have one arguments: first success (True or False), and the rest depends on the call.
+Functions that require a peer type other than what is passed will raise tgl.PeerError.
+
+
+Function_list (arguments are listed aside from callback, import tgl for access) :
+ tgl.get_contact_list ()
+ tgl.get_dialog_list ()
+
+ tgl.rename_chat (peer, new_name)
+ tgl.chat_set_photo (peer, file)
+
+ tgl.send_typing (peer)
+ tgl.send_typing_abort (peer)
+
+ tgl.send_msg (peer, text)
+ tgl.fwd_msg (peer, msg)
+
+ tgl.send_photo (peer, file)
+ tgl.send_video (peer, file)
+ tgl.send_audio (peer, file)
+ tgl.send_document (peer, file)
+ tgl.send_text (peer, file)
+
+ tgl.load_photo(msg)
+ tgl.load_video(msg)
+ tgl.load_video_thumb(msg)
+ tgl.load_audio(msg)
+ tgl.load_document(msg)
+ tgl.load_document_thumb(msg)
+
+ tgl.info (peer)
+
+ tgl.get_history (peer, limit)
+
+ tgl.chat_add_user (peer, user)
+ tgl.chat_del_user (peer, user)
+
+ tgl.add_contact (phone, first_name, last_name)
+ tgl.rename_contact (phone, first_name, last_name)
+
+ tgl.msg_search (peer, text)
+ tgl.msg_global_search (text)
+
+ tgl.mark_read (peer)
+
+ tgl.set_profile_photo (file)
+
+ tgl.create_secret_chat (user)
+ tgl.create_group_chat (peer, name)
+
+ tgl.delete_msg (msg)
+ tgl.restore_msg (msg_id)
+
+ tgl.status_online ()
+ tgl.status_offline ()
+
+ tgl.send_location (peer, latitude, longitude)
+
+Additionally, the tgl.Peer object has the following direct methods:
+ peer.rename_chat(new_name)
+ peer.chat_set_photo(file)
+ peer.send_typing()
+ peer.send_typing_abort()
+ peer.send_msg(text)
+ peer.send_photo(file)
+ peer.send_video(file)
+ peer.send_document(file)
+ peer.send_text(file)
+ peer.info()
+ peer.history(limit, offset)
+ peer.add_user(peer)
+ peer.del_user(peer)
+ peer.search(text)
+ peer.mark_read()
+ peer.send_location(latitude, longitude)
diff --git a/README.md b/README.md
index f0f8c63..31e7179 100644
--- a/README.md
+++ b/README.md
@@ -24,30 +24,35 @@ Clone GitHub Repository
git clone --recursive https://github.com/vysheng/tg.git && cd tg
+### Python Support
+
+Python support is currently limited to Python 2.7 or Python 3.1+. Other versions may work but are not tested.
+
#### Linux and BSDs
-Install libs: readline, openssl and (if you want to use config) libconfig, liblua and libjansson.
-If you do not want to use them pass options --disable-libconfig, --disable-liblua and --disable-json respectively.
+Install libs: readline, openssl and (if you want to use config) libconfig, liblua, python and libjansson.
+If you do not want to use them pass options --disable-libconfig, --disable-liblua, --disable-python and --disable-json respectively.
On Ubuntu/Debian use:
- sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev make
+ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make
On gentoo:
- sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua dev-libs/libevent dev-libs/jansson
+ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua dev-libs/libevent dev-libs/jansson dev-lang/python
On Fedora:
sudo yum install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel libjansson-devel
+ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel python-devel
On FreeBSD:
- pkg install libconfig libexecinfo lua52
+ pkg install libconfig libexecinfo lua52 python
On OpenBSD:
- pkg_add libconfig libexecinfo lua
+ pkg_add libconfig libexecinfo lua python
Then,
@@ -69,6 +74,7 @@ If using [Homebrew](http://brew.sh/):
brew install libconfig
brew install readline
brew install lua
+ brew install python
brew install libevent
export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.3.8/include"
export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.3.8/lib"
@@ -81,6 +87,7 @@ If using [MacPorts](https://www.macports.org):
sudo port install libconfig-hr
sudo port install readline
sudo port install lua51
+ sudo port install python34
sudo port install libevent
export CFLAGS="-I/usr/local/include -I/opt/local/include -I/opt/local/include/lua-5.1"
export LDFLAGS="-L/usr/local/lib -L/opt/local/lib -L/opt/local/lib/lua-5.1"
diff --git a/ax_python.m4 b/ax_python.m4
new file mode 100644
index 0000000..9702193
--- /dev/null
+++ b/ax_python.m4
@@ -0,0 +1,109 @@
+# ===========================================================================
+# 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.4 python3.3 python3.2 python3.1 python3 python2.7 python2.6 python2 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
+unset ac_cv_prog_PYTHON_BIN
+unset PYTHON_BIN
+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])
+
+
+PYTHON_FOUND=yes
+if test x$ax_python_header != xno; then
+ PYTHON_INCLUDE_DIR=$ax_python_header
+ AC_SUBST(PYTHON_INCLUDE_DIR)
+else
+ PYTHON_FOUND=no
+fi
+
+if test x$ax_python_lib != xno; then
+ PYTHON_LIB=$ax_python_lib
+ AC_SUBST(PYTHON_LIB)
+else
+ PYTHON_FOUND=no
+fi
+AC_SUBST(PYTHON_FOUND)
+
+])dnl
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000..67cea4f
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+aclocal
+autoheader
+automake --gnu --add-missing
+autoconf
diff --git a/config.h.in b/config.h.in
index 38bec97..bb5f2d6 100644
--- a/config.h.in
+++ b/config.h.in
@@ -164,6 +164,9 @@
/* use lua */
#undef USE_LUA
+/* use python */
+#undef USE_PYTHON
+
/* fixed for correct valgrind work */
#undef VALGRIND_FIXES
diff --git a/configure b/configure
index ea6dc0f..93723f5 100755
--- a/configure
+++ b/configure
@@ -622,6 +622,12 @@ ac_includes_default="\
ac_subst_vars='LTLIBOBJS
EXTRA_LIBS
LIBOBJS
+PYTHON_CFLAGS
+PYTHON_LIBS
+PYTHON_FOUND
+PYTHON_LIB
+PYTHON_INCLUDE_DIR
+PYTHON_BIN
LUA_LIB
LUA_INCLUDE
pkgluaexecdir
@@ -694,6 +700,7 @@ with_zlib
enable_libconfig
enable_extf
enable_liblua
+enable_python
enable_json
with_progname
enable_valgrind
@@ -1322,6 +1329,7 @@ Optional Features:
--enable-libconfig/--disable-libconfig
--enable-extf/--disable-extf
--enable-liblua/--disable-liblua
+--enable-python/--disable-python
--enable-json/--disable-json
--enable-valgrind/--disable-valgrind
@@ -2393,6 +2401,62 @@ ac_config_headers="$ac_config_headers config.h"
+
+
+# ===========================================================================
+# 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
# ===========================================================================
@@ -5867,6 +5931,403 @@ fi
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for python" >&5
+$as_echo_n "checking for python... " >&6; }
+# Check whether --enable-python was given.
+if test "${enable_python+set}" = set; then :
+ enableval=$enable_python;
+ if test "x$enableval" = "xno" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+$as_echo "disabled" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
+$as_echo "enabled" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for python build information" >&5
+$as_echo_n "checking for python build information... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5
+$as_echo "" >&6; }
+for python in python3.4 python3.3 python3.2 python3.1 python3 python2.7 python2.6 python2 python; do
+for ac_prog in $python
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PYTHON_BIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PYTHON_BIN"; then
+ ac_cv_prog_PYTHON_BIN="$PYTHON_BIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PYTHON_BIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PYTHON_BIN=$ac_cv_prog_PYTHON_BIN
+if test -n "$PYTHON_BIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_BIN" >&5
+$as_echo "$PYTHON_BIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$PYTHON_BIN" && break
+done
+
+ax_python_bin=$PYTHON_BIN
+if test x$ax_python_bin != x; then
+ as_ac_Lib=`$as_echo "ac_cv_lib_$ax_python_bin''_main" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -l$ax_python_bin" >&5
+$as_echo_n "checking for main in -l$ax_python_bin... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$ax_python_bin $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+ ax_python_lib=$ax_python_bin
+else
+ ax_python_lib=no
+fi
+
+ if test x$ax_python_lib == xno; then
+ as_ac_Lib=`$as_echo "ac_cv_lib_${ax_python_bin}m''_main" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -l${ax_python_bin}m" >&5
+$as_echo_n "checking for main in -l${ax_python_bin}m... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l${ax_python_bin}m $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+ ax_python_lib=${ax_python_bin}m
+else
+ ax_python_lib=no
+fi
+
+ 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
+unset ac_cv_prog_PYTHON_BIN
+unset PYTHON_BIN
+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
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: results of the Python check:" >&5
+$as_echo " results of the Python check:" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Binary: $ax_python_bin" >&5
+$as_echo " Binary: $ax_python_bin" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Library: $ax_python_lib" >&5
+$as_echo " Library: $ax_python_lib" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Include Dir: $ax_python_header" >&5
+$as_echo " Include Dir: $ax_python_header" >&6; }
+
+
+PYTHON_FOUND=yes
+if test x$ax_python_header != xno; then
+ PYTHON_INCLUDE_DIR=$ax_python_header
+
+else
+ PYTHON_FOUND=no
+fi
+
+if test x$ax_python_lib != xno; then
+ PYTHON_LIB=$ax_python_lib
+
+else
+ PYTHON_FOUND=no
+fi
+
+
+
+
+ if test $PYTHON_FOUND = no ; then
+ as_fn_error $? "No supported python lib version found. Try --disable-python" "$LINENO" 5
+ else
+
+
+ EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}"
+ CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}"
+
+$as_echo "#define USE_PYTHON 1" >>confdefs.h
+
+ fi
+ fi
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
+$as_echo "enabled" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for python build information" >&5
+$as_echo_n "checking for python build information... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5
+$as_echo "" >&6; }
+for python in python3.4 python3.3 python3.2 python3.1 python3 python2.7 python2.6 python2 python; do
+for ac_prog in $python
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PYTHON_BIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PYTHON_BIN"; then
+ ac_cv_prog_PYTHON_BIN="$PYTHON_BIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PYTHON_BIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PYTHON_BIN=$ac_cv_prog_PYTHON_BIN
+if test -n "$PYTHON_BIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_BIN" >&5
+$as_echo "$PYTHON_BIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$PYTHON_BIN" && break
+done
+
+ax_python_bin=$PYTHON_BIN
+if test x$ax_python_bin != x; then
+ as_ac_Lib=`$as_echo "ac_cv_lib_$ax_python_bin''_main" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -l$ax_python_bin" >&5
+$as_echo_n "checking for main in -l$ax_python_bin... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$ax_python_bin $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+ ax_python_lib=$ax_python_bin
+else
+ ax_python_lib=no
+fi
+
+ if test x$ax_python_lib == xno; then
+ as_ac_Lib=`$as_echo "ac_cv_lib_${ax_python_bin}m''_main" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -l${ax_python_bin}m" >&5
+$as_echo_n "checking for main in -l${ax_python_bin}m... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l${ax_python_bin}m $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+ ax_python_lib=${ax_python_bin}m
+else
+ ax_python_lib=no
+fi
+
+ 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
+unset ac_cv_prog_PYTHON_BIN
+unset PYTHON_BIN
+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
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: results of the Python check:" >&5
+$as_echo " results of the Python check:" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Binary: $ax_python_bin" >&5
+$as_echo " Binary: $ax_python_bin" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Library: $ax_python_lib" >&5
+$as_echo " Library: $ax_python_lib" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Include Dir: $ax_python_header" >&5
+$as_echo " Include Dir: $ax_python_header" >&6; }
+
+
+PYTHON_FOUND=yes
+if test x$ax_python_header != xno; then
+ PYTHON_INCLUDE_DIR=$ax_python_header
+
+else
+ PYTHON_FOUND=no
+fi
+
+if test x$ax_python_lib != xno; then
+ PYTHON_LIB=$ax_python_lib
+
+else
+ PYTHON_FOUND=no
+fi
+
+
+
+
+ if test $PYTHON_FOUND = no ; then
+ as_fn_error $? "No supported python lib version found. Try --disable-python" "$LINENO" 5
+ else
+
+
+ EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}"
+ CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}"
+
+$as_echo "#define USE_PYTHON 1" >>confdefs.h
+
+ fi
+
+fi
+
+
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libjansson" >&5
$as_echo_n "checking for libjansson... " >&6; }
# Check whether --enable-json was given.
diff --git a/configure.ac b/configure.ac
index 3e33cc2..a2c09e5 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,44 @@ AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua],
])
])
+AC_MSG_CHECKING([for python])
+AC_ARG_ENABLE(python,[--enable-python/--disable-python],
+ [
+ if test "x$enableval" = "xno" ; then
+ AC_MSG_RESULT([disabled])
+ else
+ AC_MSG_RESULT([enabled])
+
+ AX_PYTHON()
+ AC_SUBST([PYTHON_FOUND])
+ if test $PYTHON_FOUND = no ; then
+ AC_MSG_ERROR([No supported python lib version found. Try --disable-python])
+ else
+ AC_SUBST([PYTHON_LIBS])
+ AC_SUBST([PYTHON_CFLAGS])
+ EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}"
+ CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}"
+ AC_DEFINE(USE_PYTHON,1,[use python])
+ fi
+ fi
+ ],[
+ AC_MSG_RESULT([enabled])
+
+ AX_PYTHON()
+ AC_SUBST([PYTHON_FOUND])
+ if test $PYTHON_FOUND = no ; then
+ AC_MSG_ERROR([No supported python lib version found. Try --disable-python])
+ else
+ AC_SUBST([PYTHON_LIBS])
+ AC_SUBST([PYTHON_CFLAGS])
+ EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}"
+ CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}"
+ AC_DEFINE(USE_PYTHON,1,[use python])
+ fi
+ ])
+
+
+
AC_MSG_CHECKING([for libjansson])
AC_ARG_ENABLE(json,[--enable-json/--disable-json],
[
diff --git a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild
index c6ec5b3..de50269 100644
--- a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild
+++ b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild
@@ -20,7 +20,9 @@ DEPEND="sys-libs/zlib
dev-libs/libconfig
dev-libs/openssl
dev-libs/libevent
- lua? ( dev-lang/lua )"
+ lua? ( dev-lang/lua )
+ json? ( dev-lib/jansson )
+ python? ( dev-lang/python )"
src_unpack() {
git-2_src_unpack
@@ -30,6 +32,8 @@ src_unpack() {
src_configure() {
econf $(use_enable lua liblua )
+ econf $(use_enable python python )
+ econf $(use_enable json json )
}
src_install() {
diff --git a/interface.c b/interface.c
index 5256acf..6de300d 100644
--- a/interface.c
+++ b/interface.c
@@ -21,7 +21,13 @@
#include "config.h"
#endif
-#define _GNU_SOURCE
+#ifdef USE_PYTHON
+# include "python-tg.h"
+#endif
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
#include
#include
@@ -59,6 +65,7 @@
# include "lua-tg.h"
#endif
+
//#include "mtproto-common.h"
#include
@@ -1288,6 +1295,7 @@ extern char *downloads_directory;
extern char *config_directory;
extern char *binlog_file_name;
extern char *lua_file;
+extern char *python_file;
extern struct event *term_ev;
void do_clear (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
@@ -1302,6 +1310,7 @@ void do_clear (struct command *command, int arg_num, struct arg args[], struct i
free (config_directory);
free (binlog_file_name);
free (lua_file);
+ free (python_file);
clear_history ();
event_free (term_ev);
struct event_base *ev_base = TLS->ev_base;
@@ -2332,6 +2341,9 @@ void print_message_gw (struct tgl_state *TLSR, struct tgl_message *M) {
#ifdef USE_LUA
lua_new_msg (M);
#endif
+ #ifdef USE_PYTHON
+ py_new_msg (M);
+ #endif
if (!binlog_read) { return; }
if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) {
write_secret_chat_file ();
@@ -2361,6 +2373,9 @@ void our_id_gw (struct tgl_state *TLSR, int id) {
#ifdef USE_LUA
lua_our_id (id);
#endif
+ #ifdef USE_PYTHON
+ py_our_id (id);
+ #endif
}
void print_peer_updates (struct in_ev *ev, int flags) {
@@ -2426,7 +2441,10 @@ void user_update_gw (struct tgl_state *TLSR, struct tgl_user *U, unsigned flags)
#ifdef USE_LUA
lua_user_update (U, flags);
#endif
-
+ #ifdef USE_PYTHON
+ py_user_update (U, flags);
+ #endif
+
if (disable_output && !notify_ev) { return; }
if (!binlog_read) { return; }
struct in_ev *ev = notify_ev;
@@ -2457,7 +2475,10 @@ void chat_update_gw (struct tgl_state *TLSR, struct tgl_chat *U, unsigned flags)
#ifdef USE_LUA
lua_chat_update (U, flags);
#endif
-
+ #ifdef USE_PYTHON
+ py_chat_update (U, flags);
+ #endif
+
if (disable_output && !notify_ev) { return; }
if (!binlog_read) { return; }
struct in_ev *ev = notify_ev;
@@ -2488,7 +2509,12 @@ void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, u
#ifdef USE_LUA
lua_secret_chat_update (U, flags);
#endif
+ #ifdef USE_PYTHON
+ py_secret_chat_update (U, flags);
+ #endif
+
+
if ((flags & TGL_UPDATE_WORKING) || (flags & TGL_UPDATE_DELETED)) {
write_secret_chat_file ();
}
diff --git a/loop.c b/loop.c
index 1bbe620..050537b 100644
--- a/loop.c
+++ b/loop.c
@@ -21,7 +21,13 @@
#include "config.h"
#endif
+#if USE_PYTHON
+#include "python-tg.h"
+#endif
+
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#define READLINE_CALLBACKS
#include
@@ -56,7 +62,10 @@
#include "interface.h"
#include "telegram.h"
#include "loop.h"
+#if USE_LUA
#include "lua-tg.h"
+#endif
+
#include
#include
#include
@@ -215,6 +224,10 @@ void net_loop (void) {
lua_do_all ();
#endif
+ #ifdef USE_PYTHON
+ py_do_all ();
+ #endif
+
if (safe_quit && !TLS->active_queries) {
printf ("All done. Exit\n");
do_halt (0);
@@ -655,6 +668,10 @@ void on_started (struct tgl_state *TLS) {
lua_diff_end ();
#endif
+ #ifdef USE_PYTHON
+ py_diff_end ();
+ #endif
+
if (start_command) {
safe_quit = 1;
while (*start_command) {
@@ -710,6 +727,10 @@ int loop (void) {
lua_binlog_end ();
#endif
+ #ifdef USE_PYTHON
+ py_binlog_end ();
+ #endif
+
if (sfd >= 0) {
struct event *ev = event_new (TLS->ev_base, sfd, EV_READ | EV_PERSIST, accept_incoming, 0);
event_add (ev, 0);
diff --git a/main.c b/main.c
index 888eece..9452d27 100644
--- a/main.c
+++ b/main.c
@@ -21,6 +21,10 @@
#include "config.h"
#endif
+#ifdef USE_PYTHON
+# include "python-tg.h"
+#endif
+
#include
#include
#include
@@ -75,6 +79,7 @@
# include "lua-tg.h"
#endif
+
#include
#define PROGNAME "telegram-cli"
@@ -107,6 +112,7 @@ char *downloads_directory;
char *config_directory;
char *binlog_file_name;
char *lua_file;
+char *python_file;
int binlog_enabled;
extern int log_level;
int sync_from_start;
@@ -381,6 +387,10 @@ void parse_config (void) {
parse_config_val (&conf, &lua_file, "lua_script", 0, config_directory);
}
+ if (!python_file) {
+ parse_config_val (&conf, &python_file, "python_script", 0, config_directory);
+ }
+
strcpy (buf + l, "binlog_enabled");
config_lookup_bool (&conf, buf, &binlog_enabled);
@@ -484,6 +494,26 @@ void usage (void) {
#ifdef USE_JSON
printf (" --json prints answers and values in json format\n");
#endif
+ #ifdef USE_PYTHON
+ printf (" -Z python script file\n");
+ #endif
+ #ifdef USE_PYTHON
+ printf (" -Z python script file\n");
+ #endif
+ printf (" -W send dialog_list query and wait for answer before reading input\n");
+ printf (" -C disable color output\n");
+ printf (" -R disable readline\n");
+ printf (" -d daemon mode\n");
+ printf (" -L log file name\n");
+ printf (" -U change uid after start\n");
+ printf (" -G change gid after start\n");
+ printf (" -D disable output\n");
+ printf (" -P port to listen for input commands\n");
+ printf (" -S unix socket to create\n");
+ printf (" -e make commands end exit\n");
+ printf (" -I use user and chat IDs in updates instead of names\n");
+ printf (" -6 use ipv6 (may be unstable)\n");
+
exit (1);
}
@@ -643,8 +673,12 @@ void args_parse (int argc, char **argv) {
#endif
#ifdef USE_LUA
"s:"
+#endif
+#ifdef USE_PYTHON
+ "Z:"
#endif
, long_options, NULL
+
)) != -1) {
switch (opt) {
case 1000:
@@ -700,6 +734,11 @@ void args_parse (int argc, char **argv) {
case 'W':
wait_dialog_list = 1;
break;
+#ifdef USE_PYTHON
+ case 'Z':
+ python_file = strdup (optarg);
+ break;
+#endif
case 'C':
disable_colors ++;
break;
@@ -922,6 +961,9 @@ int main (int argc, char **argv) {
"This is free software, and you are welcome to redistribute it\n"
"under certain conditions; type `show_license' for details.\n"
"Telegram-cli uses libtgl version " TGL_VERSION "\n"
+#ifdef USE_PYTHON
+ "Telegram-cli uses libpython version " PY_VERSION "\n"
+#endif
);
}
running_for_first_time ();
@@ -942,6 +984,12 @@ int main (int argc, char **argv) {
lua_init (lua_file);
}
#endif
+ #ifdef USE_PYTHON
+ if (python_file) {
+ py_init (python_file);
+ }
+ #endif
+
inner_main ();
diff --git a/python-tg.c b/python-tg.c
new file mode 100644
index 0000000..a045bda
--- /dev/null
+++ b/python-tg.c
@@ -0,0 +1,1253 @@
+/*
+ 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
+
+#include
+#include "bytesobject.h"
+
+// Python 2/3 compat macros
+#if PY_MAJOR_VERSION >= 3
+ #define MOD_ERROR_VAL NULL
+ #define MOD_SUCCESS_VAL(val) val
+ #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+ #define MOD_DEF(ob, name, doc, methods) \
+ static struct PyModuleDef moduledef = { \
+ PyModuleDef_HEAD_INIT, name, doc, -1, methods, NULL, NULL, NULL, NULL,}; \
+ ob = PyModule_Create(&moduledef);
+ #define PyInt_FromLong PyLong_FromLong
+#else
+ #define MOD_ERROR_VAL
+ #define MOD_SUCCESS_VAL(val)
+ #define MOD_INIT(name) void init##name(void)
+ #define MOD_DEF(ob, name, doc, methods) \
+ ob = Py_InitModule3(name, methods, doc);
+#endif
+
+#define TGL_PYTHON_CALLBACK(name, func) \
+ PyObject *set##func(PyObject *dummy, PyObject *args) { \
+ PyObject *result = NULL; \
+ PyObject *temp; \
+ if (PyArg_ParseTuple(args, "O:set_##name", &temp)) { \
+ if (!PyCallable_Check(temp)) { \
+ PyErr_SetString(PyExc_TypeError, "parameter must be callable");\
+ return NULL;\
+ }\
+ Py_XINCREF(temp);\
+ Py_XDECREF(func);\
+ func = temp;\
+ Py_INCREF(Py_None);\
+ result = Py_None;\
+ }\
+ return result;\
+ }
+
+
+// Python Imports
+#include "datetime.h"
+
+// Custom Types
+#include "python-types.h"
+
+
+extern PyTypeObject tgl_PeerType;
+extern PyTypeObject tgl_MsgType;
+
+//#include "interface.h"
+//#include "auto/constants.h"
+#include
+#include "interface.h"
+
+#include
+extern int verbosity;
+extern struct tgl_state *TLS;
+
+
+static int python_loaded;
+
+// TGL Python Exceptions
+PyObject *TglError;
+PyObject *PeerError;
+PyObject *MsgError;
+
+
+// Python update function callables
+PyObject *_py_binlog_end;
+PyObject *_py_diff_end;
+PyObject *_py_our_id;
+PyObject *_py_new_msg;
+PyObject *_py_secret_chat_update;
+PyObject *_py_user_update;
+PyObject *_py_chat_update;
+
+PyObject* get_peer (tgl_peer_id_t id, tgl_peer_t *P);
+
+void py_add_string_field (PyObject* dict, char *name, const char *value) {
+ assert (PyDict_Check(dict));
+ assert (name && strlen (name));
+ if (!value || !strlen (value)) { return; }
+ PyObject *str = PyUnicode_FromString(value);
+
+ if(PyUnicode_Check(str))
+ PyDict_SetItemString (dict, name, str);
+}
+
+void py_add_string_field_arr (PyObject* list, int num, const char *value) {
+ assert(PyList_Check(list));
+ if (!value || !strlen (value)) { return; }
+ if(num >= 0)
+ PyList_SetItem (list, num, PyUnicode_FromString (value));
+ else // Append
+ PyList_Append (list, PyUnicode_FromString (value));
+}
+
+void py_add_num_field (PyObject* dict, const char *name, double value) {
+ assert (PyDict_Check(dict));
+ assert (name && strlen (name));
+ PyDict_SetItemString (dict, name, PyFloat_FromDouble(value));
+}
+
+PyObject* get_tgl_peer_type (int x) {
+ PyObject *type;
+
+ switch (x) {
+ case TGL_PEER_USER:
+ type = PyUnicode_FromString("user");
+ break;
+ case TGL_PEER_CHAT:
+ type = PyUnicode_FromString("chat");
+ break;
+ case TGL_PEER_ENCR_CHAT:
+ type = PyUnicode_FromString("encr_chat");
+ break;
+ default:
+ assert (0);
+ }
+
+ return type;
+}
+
+PyObject* get_update_types (unsigned flags) {
+ PyObject* types;
+ types = PyList_New(0);
+ if(types == NULL)
+ assert(0); // TODO handle python exception
+
+ if (flags & TGL_UPDATE_CREATED) {
+ py_add_string_field_arr(types, -1, "created");
+ }
+ if (flags & TGL_UPDATE_DELETED) {
+ py_add_string_field_arr(types, -1, "deleted");
+ }
+ if (flags & TGL_UPDATE_PHONE) {
+ py_add_string_field_arr(types, -1, "phone");
+ }
+ if (flags & TGL_UPDATE_CONTACT) {
+ py_add_string_field_arr(types, -1, "contact");
+ }
+ if (flags & TGL_UPDATE_PHOTO) {
+ py_add_string_field_arr(types, -1, "photo");
+ }
+ if (flags & TGL_UPDATE_BLOCKED) {
+ py_add_string_field_arr(types, -1, "blocked");
+ }
+ if (flags & TGL_UPDATE_REAL_NAME) {
+ py_add_string_field_arr(types, -1, "real_name");
+ }
+ if (flags & TGL_UPDATE_NAME) {
+ py_add_string_field_arr(types, -1, "name");
+ }
+ if (flags & TGL_UPDATE_REQUESTED) {
+ py_add_string_field_arr(types, -1, "requested");
+ }
+ if (flags & TGL_UPDATE_WORKING) {
+ py_add_string_field_arr(types, -1, "working");
+ }
+ if (flags & TGL_UPDATE_FLAGS) {
+ py_add_string_field_arr(types, -1, "flags");
+ }
+ if (flags & TGL_UPDATE_TITLE) {
+ py_add_string_field_arr(types, -1, "title");
+ }
+ if (flags & TGL_UPDATE_ADMIN) {
+ py_add_string_field_arr(types, -1, "admin");
+ }
+ if (flags & TGL_UPDATE_MEMBERS) {
+ py_add_string_field_arr(types, -1, "members");
+ }
+ if (flags & TGL_UPDATE_ACCESS_HASH) {
+ py_add_string_field_arr(types, -1, "access_hash");
+ }
+ if (flags & TGL_UPDATE_USERNAME) {
+ py_add_string_field_arr(types, -1, "username");
+ }
+ return types;
+}
+
+PyObject* get_peer (tgl_peer_id_t id, tgl_peer_t *P) {
+ PyObject *peer;
+
+ peer = tgl_Peer_FromTglPeer(P);
+ return peer;
+}
+
+PyObject* get_message (struct tgl_message *M) {
+ assert (M);
+ PyObject *msg;
+
+ msg = tgl_Msg_FromTglMsg(M);
+ return msg;
+}
+
+void py_binlog_end (void) {
+ if (!python_loaded) { return; }
+
+ PyObject *arglist, *result;
+
+ if(_py_binlog_end == NULL) {
+ logprintf("Callback not set for on_binlog_end");
+ return;
+ }
+
+ arglist = Py_BuildValue("()");
+ result = PyEval_CallObject(_py_binlog_end, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+ else if(PyUnicode_Check(result))
+ logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
+
+ Py_XDECREF(result);
+}
+
+void py_diff_end (void) {
+ if (!python_loaded) { return; }
+
+ PyObject *arglist, *result;
+
+ if(_py_diff_end == NULL) {
+ logprintf("Callback not set for on_diff_end");
+ return;
+ }
+
+ arglist = Py_BuildValue("()");
+ result = PyEval_CallObject(_py_diff_end, arglist);
+ Py_DECREF(arglist);
+ if(result == NULL)
+ PyErr_Print();
+ else if(PyUnicode_Check(result))
+ logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
+
+ Py_XDECREF(result);
+}
+
+void py_our_id (int id) {
+ if (!python_loaded) { return; }
+
+ PyObject *arglist, *result;
+
+ if(_py_our_id == NULL) {
+ logprintf("Callback not set for on_our_id");
+ return;
+ }
+
+ arglist = Py_BuildValue("(i)", id);
+ result = PyEval_CallObject(_py_our_id, arglist);
+ Py_DECREF(arglist);
+ if(result == NULL)
+ PyErr_Print();
+ else if(PyUnicode_Check(result))
+ logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
+
+ Py_XDECREF(result);
+}
+
+void py_new_msg (struct tgl_message *M) {
+ if (!python_loaded) { return; }
+ PyObject *msg;
+ PyObject *arglist, *result;
+
+ if(_py_new_msg == NULL) {
+ logprintf("Callback not set for on_new_msg");
+ return;
+ }
+
+ msg = get_message (M);
+
+ arglist = Py_BuildValue("(O)", msg);
+ result = PyEval_CallObject(_py_new_msg, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+ else if(PyUnicode_Check(result))
+ logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
+
+ Py_XDECREF(result);
+}
+
+void py_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) {
+ if (!python_loaded) { return; }
+ PyObject *peer, *types;
+ PyObject *arglist, *result;
+
+ if(_py_secret_chat_update == NULL) {
+ logprintf("Callback not set for on_secret_chat_update");
+ return;
+ }
+
+ peer = get_peer (C->id, (void *)C);
+ types = get_update_types (flags);
+
+ arglist = Py_BuildValue("(OO)", peer, types);
+ result = PyEval_CallObject(_py_secret_chat_update, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+ else if(PyUnicode_Check(result))
+ logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
+
+ Py_XDECREF(result);
+}
+
+
+void py_user_update (struct tgl_user *U, unsigned flags) {
+ if (!python_loaded) { return; }
+ PyObject *peer, *types;
+ PyObject *arglist, *result;
+
+ if(_py_user_update == NULL) {
+ logprintf("Callback not set for on_user_update");
+ return;
+ }
+
+ peer = get_peer (U->id, (void *)U);
+ types = get_update_types (flags);
+
+ arglist = Py_BuildValue("(OO)", peer, types);
+ result = PyEval_CallObject(_py_user_update, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+ else if(PyUnicode_Check(result))
+ logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
+
+ Py_XDECREF(result);
+}
+
+void py_chat_update (struct tgl_chat *C, unsigned flags) {
+ if (!python_loaded) { return; }
+
+ PyObject *peer, *types;
+ PyObject *arglist, *result;
+
+ if(_py_chat_update == NULL) {
+ logprintf("Callback not set for on_chat_update");
+ return;
+ }
+
+ peer = get_peer (C->id, (void *)C);
+ types = get_update_types (flags);
+
+ arglist = Py_BuildValue("(OO)", peer, types);
+ result = PyEval_CallObject(_py_chat_update, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+ else if(PyUnicode_Check(result))
+ logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
+
+ Py_XDECREF(result);
+}
+
+////extern tgl_peer_t *Peers[];
+////extern int peer_num;
+//
+#define MAX_PY_COMMANDS 1000
+void *py_ptr[MAX_PY_COMMANDS];
+static int pos;
+//
+//static inline tgl_peer_t *get_peer (const char *s) {
+// return tgl_peer_get_by_name (TLS, s);
+//}
+
+enum py_query_type {
+ pq_contact_list,
+ pq_dialog_list,
+ pq_msg,
+ pq_send_typing,
+ pq_send_typing_abort,
+ pq_rename_chat,
+ pq_send_photo,
+ pq_chat_set_photo,
+ pq_set_profile_photo,
+ pq_set_profile_name,
+ pq_send_video,
+ pq_send_text,
+ pq_fwd,
+ pq_fwd_media,
+ pq_load_photo,
+ pq_load_video_thumb,
+ pq_load_video,
+ pq_chat_info,
+ pq_user_info,
+ pq_history,
+ pq_chat_add_user,
+ pq_chat_del_user,
+ pq_add_contact,
+ pq_del_contact,
+ pq_rename_contact,
+ pq_search,
+ pq_global_search,
+ pq_mark_read,
+ pq_create_secret_chat,
+ pq_create_group_chat,
+ pq_send_audio,
+ pq_send_document,
+ pq_send_file,
+ pq_load_audio,
+ pq_load_document,
+ pq_load_document_thumb,
+ pq_delete_msg,
+ pq_restore_msg,
+ pq_accept_secret_chat,
+ pq_send_contact,
+ pq_status_online,
+ pq_status_offline,
+ pq_send_location,
+ pq_extf
+};
+
+void py_empty_cb (struct tgl_state *TLSR, void *cb_extra, int success) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ arglist = Py_BuildValue("(O)", success ? Py_True : Py_False);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_user **UL) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *peers = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ peers = PyList_New(0);
+ if (success) {
+ int i;
+ for (i = 0; i < num; i++) {
+ PyList_Append(peers, get_peer (UL[i]->id, (void *)UL[i]));
+ }
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peers);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_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);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *dialog_list = NULL;
+ PyObject *dialog = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ dialog_list = PyList_New(0);
+ if (success) {
+ int i;
+ for (i = 0; i < num; i++) {
+ dialog = PyDict_New();
+ PyDict_SetItemString(dialog, "peer", get_peer(peers[i], tgl_peer_get (TLS, peers[i])));
+
+ struct tgl_message *M = tgl_message_get (TLS, msgs[i]);
+ if (M && (M->flags & TGLMF_CREATED)) {
+ PyDict_SetItemString(dialog, "message", get_message(M));
+ }
+ PyDict_SetItemString(dialog, "unread", unread[i] ? Py_True : Py_False);
+
+ PyList_Append(dialog_list, dialog);
+ }
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, dialog_list);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_message *M) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *msg = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ if (success && M && (M->flags & TGLMF_CREATED)) {
+ msg = get_message(M);
+ } else {
+ Py_INCREF(Py_None);
+ msg = Py_None;
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, msg);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_msg_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_message *M[]) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *msgs = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ msgs = PyList_New(0);
+ if (success) {
+ int i;
+ for (i = 0; i < num; i++) {
+ PyList_Append(msgs, get_message (M[i]));
+ }
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, msgs);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_file_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *file_name) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *filename = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ if(success)
+ filename = PyUnicode_FromString(file_name);
+ else {
+ Py_INCREF(Py_None);
+ filename = Py_None;
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, filename);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_chat *C) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *peer = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ if (success) {
+ peer = get_peer(C->id, (void *)C);
+ } else {
+ Py_INCREF(Py_None);
+ peer = Py_None;
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peer);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_secret_chat *C) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *peer = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ if (success) {
+ peer = get_peer(C->id, (void *)C);
+ } else {
+ Py_INCREF(Py_None);
+ peer = Py_None;
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peer);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_user_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_user *C) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *peer = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ if (success) {
+ peer = get_peer(C->id, (void *)C);
+ } else {
+ Py_INCREF(Py_None);
+ peer = Py_None;
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peer);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+void py_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *data) {
+ assert (TLSR == TLS);
+ PyObject *callable = cb_extra;
+ PyObject *arglist = NULL;
+ PyObject *str = NULL;
+ PyObject *result = NULL;
+
+ if(PyCallable_Check(callable)) {
+ if(success)
+ str = PyUnicode_FromString(data);
+ else {
+ Py_INCREF(Py_None);
+ str = Py_None;
+ }
+
+ arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, str);
+ result = PyEval_CallObject(callable, arglist);
+ Py_DECREF(arglist);
+
+ if(result == NULL)
+ PyErr_Print();
+
+ Py_XDECREF(result);
+ }
+
+ Py_XDECREF(callable);
+}
+
+#define PY_PEER_ID(x) (tgl_peer_id_t)((tgl_Peer*)x)->peer->id
+
+void py_do_all (void) {
+ int p = 0;
+ while (p < pos) {
+ assert (p + 2 <= pos);
+
+ enum py_query_type f = (long)py_ptr[p ++];
+ PyObject *args = (PyObject *)py_ptr[p ++];
+
+ const char *str, *str1, *str2, *str3;
+
+ Py_ssize_t i;
+ tgl_user_id_t *ids;
+
+ int len, len1, len2, len3;
+ int limit, offset;
+ long msg_id = 0;
+ PyObject *pyObj1 = NULL;
+ PyObject *pyObj2 = NULL;
+ PyObject *cb_extra = NULL;
+
+ PyObject *peer = NULL;
+ PyObject *peer1 = NULL;
+
+ switch (f) {
+ case pq_contact_list:
+ if(PyArg_ParseTuple(args, "|O", &cb_extra))
+ tgl_do_update_contact_list (TLS, py_contact_list_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_dialog_list:
+ if(PyArg_ParseTuple(args, "|O", &cb_extra))
+ tgl_do_get_dialog_list (TLS, 100, 0, py_dialog_list_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_msg:
+ if(PyArg_ParseTuple(args, "O!s#|O", &tgl_PeerType, &peer, &str, &len, &cb_extra))
+ tgl_do_send_message (TLS, PY_PEER_ID(peer), str, len, 0, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_typing:
+ if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
+ tgl_do_send_typing (TLS, PY_PEER_ID(peer), tgl_typing_typing, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_typing_abort:
+ if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
+ tgl_do_send_typing (TLS, PY_PEER_ID(peer), tgl_typing_cancel, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_rename_chat:
+ if(PyArg_ParseTuple(args, "O!s#|O", &tgl_PeerType, &peer, &str, &len, &cb_extra))
+ tgl_do_rename_chat (TLS, PY_PEER_ID(peer), str, len, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_photo:
+ if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
+ tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_video:
+ if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
+ tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_audio:
+ if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
+ tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_document:
+ if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
+ tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, 0, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_file:
+ if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
+ tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_text:
+ if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
+ tgl_do_send_text (TLS, PY_PEER_ID(peer), str, 0, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_chat_set_photo:
+ if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
+ tgl_do_set_chat_photo (TLS, PY_PEER_ID(peer), str, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+/* case pq_load_photo:
+ case pq_load_video:
+ case pq_load_audio:
+ case pq_load_document:
+ M = py_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)) {
+ py_file_cb (TLS, py_ptr[p], 0, 0);
+ } else {
+ , limit, offse, limit, offsettif (M->media.type == tgl_message_media_photo) {
+ tgl_do_load_photo (TLS, &M->media.photo, py_file_cb, py_ptr[p]);
+ } else if (M->media.type == tgl_message_media_document) {
+ tgl_do_load_document (TLS, &M->media.document, py_file_cb, py_ptr[p]);
+ } else {
+ tgl_do_load_encr_document (TLS, &M->media.encr_document, py_file_cb, py_ptr[p]);
+ }
+ }
+ break;
+ case pq_load_video_thumb:
+ case pq_load_document_thumb:
+ M = py_ptr[p + 1];
+ if (!M || (M->media.type != tgl_message_media_document)) {
+ py_file_cb (TLS, py_ptr[p], 0, 0);
+ } else {
+ tgl_do_load_document_thumb (TLS, &M->media.document, py_file_cb, py_ptr[p]);
+ }
+ break;
+*/
+ case pq_fwd:
+ if(PyArg_ParseTuple(args, "O!l|O", &tgl_PeerType, &peer, &msg_id, &cb_extra))
+ tgl_do_forward_message (TLS, PY_PEER_ID(peer), msg_id, 0, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_fwd_media:
+ if(PyArg_ParseTuple(args, "O!l|O", &tgl_PeerType, &peer, &msg_id, &cb_extra))
+ tgl_do_forward_media (TLS, PY_PEER_ID(peer), msg_id, 0, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_chat_info:
+ if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
+ tgl_do_get_chat_info (TLS, PY_PEER_ID(peer), 0, py_chat_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_user_info:
+ if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
+ tgl_do_get_user_info (TLS, PY_PEER_ID(peer), 0, py_user_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_history:
+ if(PyArg_ParseTuple(args, "O!ii|O", &tgl_PeerType, &peer, &offset, &limit, &cb_extra))
+ tgl_do_get_history (TLS, PY_PEER_ID(peer), offset, limit, 0, py_msg_list_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_chat_add_user:
+ if(PyArg_ParseTuple(args, "O!O!|O", &tgl_PeerType, &peer, &tgl_PeerType, &peer1, &cb_extra))
+ tgl_do_add_user_to_chat (TLS, PY_PEER_ID(peer), PY_PEER_ID(peer1), 100, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_chat_del_user:
+ if(PyArg_ParseTuple(args, "O!O!|O", &tgl_PeerType, &peer, &tgl_PeerType, &peer1, &cb_extra))
+ tgl_do_del_user_from_chat (TLS, PY_PEER_ID(peer), PY_PEER_ID(peer1), py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_add_contact:
+ if(PyArg_ParseTuple(args, "s#s#s#|O", &str1, &len1, &str2, &len2, &str3, &len3, &cb_extra))
+ tgl_do_add_contact (TLS, str1, len1, str2, len2, str3, len3, 0, py_contact_list_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_del_contact:
+ if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
+ tgl_do_del_contact (TLS, PY_PEER_ID(peer), py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_rename_contact:
+ if(PyArg_ParseTuple(args, "s#s#s#|O", &str1, &len1, &str2, &len2, &str3, &len3, &cb_extra))
+ tgl_do_add_contact (TLS, str1, len1, str2, len2, str3, len3, 1, py_contact_list_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_search:
+ if(PyArg_ParseTuple(args, "O!s#|O", &tgl_PeerType, &peer, &str, &len, &cb_extra))
+ tgl_do_msg_search (TLS, PY_PEER_ID(peer), 0, 0, 40, 0, str, len, py_msg_list_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_global_search:
+ if(PyArg_ParseTuple(args, "s#|O", &str, &len, &cb_extra))
+ tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, str, len, py_msg_list_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_mark_read:
+ if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
+ tgl_do_mark_read (TLS, PY_PEER_ID(peer), py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_set_profile_photo:
+ if(PyArg_ParseTuple(args, "s|O", &str, &cb_extra))
+ tgl_do_set_profile_photo (TLS, str, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_set_profile_name:
+ if(PyArg_ParseTuple(args, "s#s#|O", &str1, &len1, &str2, &len2, &cb_extra))
+ tgl_do_set_profile_name (TLS, str1, len1, str2, len2, py_user_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_create_secret_chat:
+ if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
+ tgl_do_create_secret_chat (TLS, PY_PEER_ID(peer), py_secret_chat_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_create_group_chat:
+ if(PyArg_ParseTuple(args, "O!s#|O", &PyList_Type, &pyObj1, &str, &len, &cb_extra)) {
+ if(PyList_GET_SIZE(pyObj1) > 2) {
+ ids = (tgl_user_id_t *)malloc(PyList_GET_SIZE(pyObj1) * sizeof(tgl_user_id_t));
+ for(i = 0; i < PyList_GET_SIZE(pyObj1); i++) {
+ peer = PyList_GetItem(pyObj1, i);
+ *(ids+i) = PY_PEER_ID(peer);
+ }
+ tgl_do_create_group_chat (TLS, PyList_GET_SIZE(pyObj1), ids, str, len, py_empty_cb, cb_extra);
+
+ tfree(ids, PyList_GET_SIZE(pyObj1) * sizeof(tgl_user_id_t));
+ } else {
+ logprintf("create_group_chat: Argument 1 must be a list of at least 3 peers");
+ }
+ }
+ Py_XDECREF(pyObj1);
+ break;
+ case pq_delete_msg:
+ case pq_restore_msg:
+ if(PyArg_ParseTuple(args, "l|O", &msg_id, &cb_extra))
+ tgl_do_delete_msg (TLS, msg_id, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+/*
+ case pq_accept_secret_chat:
+ tgl_do_accept_encr_chat_request (TLS, py_ptr[p + 1], py_secret_chat_cb, py_ptr[p]);
+ break;
+*/
+ case pq_send_contact:
+ if(PyArg_ParseTuple(args, "O!s#s#s#|O", &tgl_PeerType, &peer, &str1, &len1, &str2, &len2,
+ &str3, &len3, &cb_extra))
+ tgl_do_send_contact (TLS, PY_PEER_ID(peer), str1, len1, str2, len2, str3, len3, 0, py_msg_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_status_online:
+ if(PyArg_ParseTuple(args, "|O", &cb_extra))
+ tgl_do_update_status (TLS, 1, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_status_offline:
+ if(PyArg_ParseTuple(args, "|O", &cb_extra))
+ tgl_do_update_status (TLS, 0, py_empty_cb, cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_extf:
+ if(PyArg_ParseTuple(args, "s#|O", &str, &len, &cb_extra))
+ tgl_do_send_extf (TLS, str, len, py_str_cb, &cb_extra);
+ else
+ PyErr_Print();
+ break;
+ case pq_send_location:
+ if(PyArg_ParseTuple(args, "O!O!O!|O", &tgl_PeerType, &peer, &PyFloat_Type, &pyObj1, &PyFloat_Type, &pyObj2, &cb_extra)){
+ tgl_do_send_location (TLS, PY_PEER_ID(peer),
+ PyFloat_AsDouble(pyObj1), PyFloat_AsDouble(pyObj2), 0, py_msg_cb, cb_extra);
+ Py_XDECREF(pyObj1);
+ Py_XDECREF(pyObj2);
+ } else
+ PyErr_Print();
+ break;
+ default:
+ assert (0);
+ }
+
+ // Increment reference on cb_extra as it is passed on to the callback to use
+ Py_XINCREF(cb_extra);
+
+ // Clean up any arg variables we could have used.
+ //Py_XDECREF(args); // TODO: this is going negative ref and causing segfaults
+ Py_XDECREF(peer);
+ Py_XDECREF(peer1);
+
+ }
+ pos = 0;
+}
+
+PyObject* push_py_func(enum py_query_type type, PyObject *args) {
+ assert(pos + 2 < MAX_PY_COMMANDS);
+
+ py_ptr[pos ++] = (void *)(long)type;
+ py_ptr[pos ++] = (void *)args;
+
+ Py_INCREF(args);
+ Py_RETURN_TRUE;
+}
+
+// Register functions to push commands on the queue
+PyObject* py_contact_list(PyObject *self, PyObject *args) { return push_py_func(pq_contact_list, args); }
+PyObject* py_dialog_list(PyObject *self, PyObject *args) { return push_py_func(pq_dialog_list, args); }
+PyObject* py_rename_chat(PyObject *self, PyObject *args) { return push_py_func(pq_rename_chat, args); }
+PyObject* py_send_msg(PyObject *self, PyObject *args) { return push_py_func(pq_msg, args); }
+PyObject* py_send_typing(PyObject *self, PyObject *args) { return push_py_func(pq_send_typing, args); }
+PyObject* py_send_typing_abort(PyObject *self, PyObject *args) { return push_py_func(pq_send_typing_abort, args); }
+PyObject* py_send_photo(PyObject *self, PyObject *args) { return push_py_func(pq_send_photo, args); }
+PyObject* py_send_video(PyObject *self, PyObject *args) { return push_py_func(pq_send_video, args); }
+PyObject* py_send_audio(PyObject *self, PyObject *args) { return push_py_func(pq_send_audio, args); }
+PyObject* py_send_document(PyObject *self, PyObject *args) { return push_py_func(pq_send_document, args); }
+PyObject* py_send_file(PyObject *self, PyObject *args) { return push_py_func(pq_send_file, args); }
+PyObject* py_send_text(PyObject *self, PyObject *args) { return push_py_func(pq_send_text, args); }
+PyObject* py_chat_set_photo(PyObject *self, PyObject *args) { return push_py_func(pq_chat_set_photo, args); }
+PyObject* py_load_photo(PyObject *self, PyObject *args) { return push_py_func(pq_load_photo, args); }
+PyObject* py_load_video(PyObject *self, PyObject *args) { return push_py_func(pq_load_video, args); }
+PyObject* py_load_video_thumb(PyObject *self, PyObject *args) { return push_py_func(pq_load_video_thumb, args); }
+PyObject* py_load_audio(PyObject *self, PyObject *args) { return push_py_func(pq_load_audio, args); }
+PyObject* py_load_document(PyObject *self, PyObject *args) { return push_py_func(pq_load_document, args); }
+PyObject* py_load_document_thumb(PyObject *self, PyObject *args) { return push_py_func(pq_load_document_thumb, args); }
+PyObject* py_fwd(PyObject *self, PyObject *args) { return push_py_func(pq_fwd, args); }
+PyObject* py_fwd_media(PyObject *self, PyObject *args) { return push_py_func(pq_fwd_media, args); }
+PyObject* py_chat_info(PyObject *self, PyObject *args) { return push_py_func(pq_chat_info, args); }
+PyObject* py_user_info(PyObject *self, PyObject *args) { return push_py_func(pq_chat_info, args); }
+PyObject* py_history(PyObject *self, PyObject *args) { return push_py_func(pq_history, args); }
+PyObject* py_chat_add_user(PyObject *self, PyObject *args) { return push_py_func(pq_chat_add_user, args); }
+PyObject* py_chat_del_user(PyObject *self, PyObject *args) { return push_py_func(pq_chat_del_user, args); }
+PyObject* py_add_contact(PyObject *self, PyObject *args) { return push_py_func(pq_add_contact, args); }
+PyObject* py_del_contact(PyObject *self, PyObject *args) { return push_py_func(pq_del_contact, args); }
+PyObject* py_rename_contact(PyObject *self, PyObject *args) { return push_py_func(pq_rename_contact, args); }
+PyObject* py_search(PyObject *self, PyObject *args) { return push_py_func(pq_search, args); }
+PyObject* py_global_search(PyObject *self, PyObject *args) { return push_py_func(pq_global_search, args); }
+PyObject* py_mark_read(PyObject *self, PyObject *args) { return push_py_func(pq_mark_read, args); }
+PyObject* py_set_profile_photo(PyObject *self, PyObject *args) { return push_py_func(pq_set_profile_photo, args); }
+PyObject* py_set_profile_name(PyObject *self, PyObject *args) { return push_py_func(pq_set_profile_name, args); }
+PyObject* py_create_secret_chat(PyObject *self, PyObject *args) { return push_py_func(pq_create_secret_chat, args); }
+PyObject* py_create_group_chat(PyObject *self, PyObject *args) { return push_py_func(pq_create_group_chat, args); }
+PyObject* py_delete_msg(PyObject *self, PyObject *args) { return push_py_func(pq_delete_msg, args); }
+PyObject* py_restore_msg(PyObject *self, PyObject *args) { return push_py_func(pq_restore_msg, args); }
+PyObject* py_accept_secret_chat(PyObject *self, PyObject *args) { return push_py_func(pq_accept_secret_chat, args); }
+PyObject* py_send_contact(PyObject *self, PyObject *args) { return push_py_func(pq_send_contact, args); }
+PyObject* py_status_online(PyObject *self, PyObject *args) { return push_py_func(pq_status_online, args); }
+PyObject* py_status_offline(PyObject *self, PyObject *args) { return push_py_func(pq_status_offline, args); }
+PyObject* py_send_location(PyObject *self, PyObject *args) { return push_py_func(pq_send_location, args); }
+PyObject* py_extf(PyObject *self, PyObject *args) { return push_py_func(pq_extf, args); }
+
+
+// Store callables for python functions
+TGL_PYTHON_CALLBACK("on_binlog_replay_end", _py_binlog_end);
+TGL_PYTHON_CALLBACK("on_get_difference_end", _py_diff_end);
+TGL_PYTHON_CALLBACK("on_our_id", _py_our_id);
+TGL_PYTHON_CALLBACK("on_msg_receive", _py_new_msg);
+TGL_PYTHON_CALLBACK("on_secret_chat_update", _py_secret_chat_update);
+TGL_PYTHON_CALLBACK("on_user_update", _py_user_update);
+TGL_PYTHON_CALLBACK("on_chat_update", _py_chat_update);
+
+static PyMethodDef py_tgl_methods[] = {
+ {"get_contact_list", py_contact_list, METH_VARARGS, "retrieve contact list"},
+ {"get_dialog_list", py_dialog_list, METH_VARARGS, ""},
+ {"rename_chat", py_rename_chat, METH_VARARGS, ""},
+ {"send_msg", py_send_msg, METH_VARARGS, "send message to user or chat"},
+ {"send_typing", py_send_typing, METH_VARARGS, ""},
+ {"send_typing_abort", py_send_typing_abort, METH_VARARGS, ""},
+ {"send_photo", py_send_photo, METH_VARARGS, ""},
+ {"send_video", py_send_video, METH_VARARGS, ""},
+ {"send_audio", py_send_audio, METH_VARARGS, ""},
+ {"send_document", py_send_document, METH_VARARGS, ""},
+ {"send_file", py_send_file, METH_VARARGS, ""},
+ {"send_text", py_send_text, METH_VARARGS, ""},
+ {"chat_set_photo", py_chat_set_photo, METH_VARARGS, ""},
+ {"load_photo", py_load_photo, METH_VARARGS, ""},
+ {"load_video", py_load_video, METH_VARARGS, ""},
+ {"load_video_thumb", py_load_video_thumb, METH_VARARGS, ""},
+ {"load_audio", py_load_audio, METH_VARARGS, ""},
+ {"load_document", py_load_document, METH_VARARGS, ""},
+ {"load_document_thumb", py_load_document_thumb, METH_VARARGS, ""},
+ {"fwd_msg", py_fwd, METH_VARARGS, ""},
+ {"fwd_media", py_fwd_media, METH_VARARGS, ""},
+ {"chat_info", py_chat_info, METH_VARARGS, ""},
+ {"user_info", py_user_info, METH_VARARGS, ""},
+ {"get_history", py_history, METH_VARARGS, ""},
+ {"chat_add_user", py_chat_add_user, METH_VARARGS, ""},
+ {"chat_del_user", py_chat_del_user, METH_VARARGS, ""},
+ {"add_contact", py_add_contact, METH_VARARGS, ""},
+ {"del_contact", py_del_contact, METH_VARARGS, ""},
+ {"rename_contact", py_rename_contact, METH_VARARGS, ""},
+ {"msg_search", py_search, METH_VARARGS, ""},
+ {"msg_global_search", py_global_search, METH_VARARGS, ""},
+ {"mark_read", py_mark_read, METH_VARARGS, ""},
+ {"set_profile_photo", py_set_profile_photo, METH_VARARGS, ""},
+ {"set_profile_name", py_set_profile_name, METH_VARARGS, ""},
+ {"create_secret_chat", py_create_secret_chat, METH_VARARGS, ""},
+ {"create_group_chat", py_create_group_chat, METH_VARARGS, ""},
+ {"delete_msg", py_delete_msg, METH_VARARGS, ""},
+ {"restore_msg", py_restore_msg, METH_VARARGS, ""},
+ {"accept_secret_chat", py_accept_secret_chat, METH_VARARGS, ""},
+ {"send_contact", py_send_contact, METH_VARARGS, ""},
+ {"status_online", py_status_online, METH_VARARGS, ""},
+ {"status_offline", py_status_offline, METH_VARARGS, ""},
+ {"send_location", py_send_location, METH_VARARGS, ""},
+ {"ext_function", py_extf, METH_VARARGS, ""},
+ {"set_on_binlog_replay_end", set_py_binlog_end, METH_VARARGS, ""},
+ {"set_on_get_difference_end", set_py_diff_end, METH_VARARGS, ""},
+ {"set_on_our_id", set_py_our_id, METH_VARARGS, ""},
+ {"set_on_msg_receive", set_py_new_msg, METH_VARARGS, ""},
+ {"set_on_secret_chat_update", set_py_secret_chat_update, METH_VARARGS, ""},
+ {"set_on_user_update", set_py_user_update, METH_VARARGS, ""},
+ {"set_on_chat_update", set_py_chat_update, METH_VARARGS, ""},
+ { NULL, NULL, 0, NULL }
+};
+
+MOD_INIT(tgl)
+{
+ PyObject *m;
+
+ MOD_DEF(m, "tgl", NULL, py_tgl_methods)
+
+ if (m == NULL)
+ return MOD_ERROR_VAL;
+
+ if (PyType_Ready(&tgl_PeerType) < 0)
+ return MOD_ERROR_VAL;
+
+ Py_INCREF(&tgl_PeerType);
+ PyModule_AddObject(m, "Peer", (PyObject *)&tgl_PeerType);
+
+ if (PyType_Ready(&tgl_MsgType) < 0)
+ return MOD_ERROR_VAL;
+
+ Py_INCREF(&tgl_MsgType);
+ PyModule_AddObject(m, "Msg", (PyObject *)&tgl_MsgType);
+
+ TglError = PyErr_NewException("tgl.Error", NULL, NULL);
+ Py_INCREF(TglError);
+ PyModule_AddObject(m, "TglError", TglError);
+
+ PeerError = PyErr_NewException("tgl.PeerError", NULL, NULL);
+ Py_INCREF(PeerError);
+ PyModule_AddObject(m, "PeerError", PeerError);
+
+ MsgError = PyErr_NewException("tgl.MsgError", NULL, NULL);
+ Py_INCREF(MsgError);
+ PyModule_AddObject(m, "MsgError", MsgError);
+
+ return MOD_SUCCESS_VAL(m);
+}
+
+/*
+extern int safe_quit;
+static int safe_quit_from_py() {
+ Py_Finalize();
+ safe_quit = 1;
+ return 1;
+}
+*/
+
+void py_init (const char *file) {
+ if (!file) { return; }
+ python_loaded = 0;
+
+ PyObject *pModule;
+
+ // Get a copy of the filename for dirname/basename, which may modify the string, and break const correctness
+ char filename[1024];
+ strncpy(filename, file, 1024);
+
+
+
+#if PY_MAJOR_VERSION >= 3
+ PyImport_AppendInittab("tgl", &PyInit_tgl);
+ Py_Initialize();
+#else
+ Py_Initialize();
+ inittgl();
+#endif
+
+
+ PyObject* sysPath = PySys_GetObject((char*)"path");
+ PyList_Append(sysPath, PyUnicode_FromString(dirname(filename)));
+
+ // Recopy the string in, since dirname modified it.
+ strncpy(filename, file, 1024);
+
+ // remove .py extension from file, if any
+ char* dot = strrchr(filename, '.');
+ if (dot && strcmp(dot, ".py") == 0)
+ *dot = 0;
+ pModule = PyImport_Import(PyUnicode_FromString(basename(filename)));
+
+ if(pModule == NULL || PyErr_Occurred()) { // Error loading script
+ logprintf("Failed to load python script\n");
+ PyErr_Print();
+ exit(1);
+ }
+
+
+ python_loaded = 1;
+ PyDateTime_IMPORT;
+ logprintf("Python Initialized\n");
+}
+
+#endif
diff --git a/python-tg.h b/python-tg.h
new file mode 100644
index 0000000..bc724ea
--- /dev/null
+++ b/python-tg.h
@@ -0,0 +1,89 @@
+/*
+ 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
+#include
+
+// Python functions
+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);
+
+// Binding functions
+PyObject* py_contact_list(PyObject *self, PyObject *args);
+PyObject* py_dialog_list(PyObject *self, PyObject *args);
+PyObject* py_rename_chat(PyObject *self, PyObject *args);
+PyObject* py_send_msg(PyObject *self, PyObject *args);
+PyObject* py_send_typing(PyObject *self, PyObject *args);
+PyObject* py_send_typing_abort(PyObject *self, PyObject *args);
+PyObject* py_send_photo(PyObject *self, PyObject *args);
+PyObject* py_send_video(PyObject *self, PyObject *args);
+PyObject* py_send_audio(PyObject *self, PyObject *args);
+PyObject* py_send_document(PyObject *self, PyObject *args);
+PyObject* py_send_file(PyObject *self, PyObject *args);
+PyObject* py_send_text(PyObject *self, PyObject *args);
+PyObject* py_chat_set_photo(PyObject *self, PyObject *args);
+PyObject* py_load_photo(PyObject *self, PyObject *args);
+PyObject* py_load_video(PyObject *self, PyObject *args);
+PyObject* py_load_video_thumb(PyObject *self, PyObject *args);
+PyObject* py_load_audio(PyObject *self, PyObject *args);
+PyObject* py_load_document(PyObject *self, PyObject *args);
+PyObject* py_load_document_thumb(PyObject *self, PyObject *args);
+PyObject* py_fwd(PyObject *self, PyObject *args);
+PyObject* py_fwd_media(PyObject *self, PyObject *args);
+PyObject* py_chat_info(PyObject *self, PyObject *args);
+PyObject* py_user_info(PyObject *self, PyObject *args);
+PyObject* py_history(PyObject *self, PyObject *args);
+PyObject* py_chat_add_user(PyObject *self, PyObject *args);
+PyObject* py_chat_del_user(PyObject *self, PyObject *args);
+PyObject* py_add_contact(PyObject *self, PyObject *args);
+PyObject* py_del_contact(PyObject *self, PyObject *args);
+PyObject* py_rename_contact(PyObject *self, PyObject *args);
+PyObject* py_search(PyObject *self, PyObject *args);
+PyObject* py_global_search(PyObject *self, PyObject *args);
+PyObject* py_mark_read(PyObject *self, PyObject *args);
+PyObject* py_set_profile_photo(PyObject *self, PyObject *args);
+PyObject* py_set_profile_name(PyObject *self, PyObject *args);
+PyObject* py_create_secret_chat(PyObject *self, PyObject *args);
+PyObject* py_create_group_chat(PyObject *self, PyObject *args);
+PyObject* py_delete_msg(PyObject *self, PyObject *args);
+PyObject* py_restore_msg(PyObject *self, PyObject *args);
+PyObject* py_accept_secret_chat(PyObject *self, PyObject *args);
+PyObject* py_send_contact(PyObject *self, PyObject *args);
+PyObject* py_status_online(PyObject *self, PyObject *args);
+PyObject* py_status_offline(PyObject *self, PyObject *args);
+PyObject* py_send_location(PyObject *self, PyObject *args);
+PyObject* py_extf(PyObject *self, PyObject *args);
+
+
+// Util Functions
+void py_add_string_field (PyObject* dict, char *name, const char *value);
+void py_add_string_field_arr (PyObject* list, int num, const char *value);
+void py_add_num_field (PyObject* dict, const char *name, double value);
+#endif
diff --git a/python-types.c b/python-types.c
new file mode 100644
index 0000000..c073cdb
--- /dev/null
+++ b/python-types.c
@@ -0,0 +1,1422 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_PYTHON
+#include
+#include
+#include
+#include
+#include
+#include
+#include "structmember.h"
+
+// Python Imports
+#include "datetime.h"
+
+#include "python-types.h"
+#include "python-tg.h"
+
+extern struct tgl_state *TLS;
+
+// TGL Python Exceptions
+extern PyObject *TglError;
+extern PyObject *PeerError;
+extern PyObject *MsgError;
+
+// Forward type declarations
+PyTypeObject tgl_PeerType;
+
+// Utility functions
+PyObject* get_datetime(long datetime)
+{
+ return PyDateTime_FromTimestamp(Py_BuildValue("(O)", PyLong_FromLong(datetime)));
+}
+
+
+//
+// tgl_peer_t wrapper
+//
+static void
+tgl_Peer_dealloc(tgl_Peer* self)
+{
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject *
+tgl_Peer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ tgl_Peer *self;
+
+ PyDateTime_IMPORT;
+ self = (tgl_Peer *)type->tp_alloc(type, 0);
+ return (PyObject *)self;
+}
+
+static int
+tgl_Peer_init(tgl_Peer *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"type", "id", NULL};
+ tgl_peer_id_t peer_id;
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist,
+ &peer_id.type,
+ &peer_id.id))
+ {
+ PyErr_Format(PeerError, "Peer must specify type and id");
+ return -1;
+ }
+ self->peer = tgl_peer_get(TLS, peer_id);
+ if(self->peer == NULL)
+ return -1;
+
+ return 0;
+}
+
+static PyObject *
+tgl_Peer_getname (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ ret = PyUnicode_FromString(self->peer->user.print_name);
+ break;
+ case TGL_PEER_CHAT:
+ ret = PyUnicode_FromString(self->peer->chat.print_title);
+ break;
+ case TGL_PEER_ENCR_CHAT:
+ ret = PyUnicode_FromString(self->peer->encr_chat.print_name);
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+
+static PyObject *
+tgl_Peer_getuser_id (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ ret = PyLong_FromLong(self->peer->id.id);
+ break;
+ case TGL_PEER_CHAT:
+ PyErr_SetString(PeerError, "peer.type_name == 'chat' has no user_id");
+ Py_RETURN_NONE;
+
+ break;
+ case TGL_PEER_ENCR_CHAT:
+ ret = PyLong_FromLong(self->peer->encr_chat.user_id);
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_getuser_list (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+ int i;
+ struct tgl_chat_user *user_list;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_CHAT:
+ ret = PyList_New(0);
+ for(i = 0; i < self->peer->chat.user_list_size; i++) {
+ // TODO: Sort tgl_user objects, maybe offline mode is enoug?
+ user_list = self->peer->chat.user_list + i;
+ PyList_Append(ret, PyLong_FromLong(user_list->user_id));
+ }
+ break;
+ case TGL_PEER_ENCR_CHAT:
+ case TGL_PEER_USER:
+ PyErr_SetString(PeerError, "Only peer.type_name == 'chat' has user_list");
+ Py_RETURN_NONE;
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_getuser_status(tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ ret = PyDict_New();
+ PyDict_SetItemString(ret, "online", self->peer->user.status.online? Py_True : Py_False);
+ PyDict_SetItemString(ret, "when", get_datetime(self->peer->user.status.when));
+
+ break;
+ case TGL_PEER_CHAT:
+ case TGL_PEER_ENCR_CHAT:
+ PyErr_SetString(PeerError, "Only peer.type_name == 'user' has user_status");
+ Py_RETURN_NONE;
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_getphone (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ if(self->peer->user.phone)
+ ret = PyUnicode_FromString(self->peer->user.phone);
+ else
+ Py_RETURN_NONE;
+ break;
+ case TGL_PEER_CHAT:
+ case TGL_PEER_ENCR_CHAT:
+ PyErr_SetString(PeerError, "Only peer.type_name == 'user' has phone");
+ Py_RETURN_NONE;
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_getusername (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ if(self->peer->user.username)
+ ret = PyUnicode_FromString(self->peer->user.username);
+ else
+ Py_RETURN_NONE;
+ break;
+ case TGL_PEER_CHAT:
+ case TGL_PEER_ENCR_CHAT:
+ PyErr_SetString(PeerError, "Only peer.type_name == 'user' has username");
+ Py_RETURN_NONE;
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_getfirst_name (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ if(self->peer->user.first_name)
+ ret = PyUnicode_FromString(self->peer->user.first_name);
+ else
+ Py_RETURN_NONE;
+ break;
+ case TGL_PEER_CHAT:
+ case TGL_PEER_ENCR_CHAT:
+ PyErr_SetString(PeerError, "Only peer.type_name == 'user' has first_name");
+ Py_RETURN_NONE;
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_getlast_name (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ if(self->peer->user.last_name)
+ ret = PyUnicode_FromString(self->peer->user.last_name);
+ else
+ Py_RETURN_NONE;
+ break;
+ case TGL_PEER_CHAT:
+ case TGL_PEER_ENCR_CHAT:
+ PyErr_SetString(PeerError, "Only peer.type_name == 'user' has last_name");
+ Py_RETURN_NONE;
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_getuser (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_ENCR_CHAT:
+ ret = tgl_Peer_FromTglPeer(tgl_peer_get(TLS, TGL_MK_USER (self->peer->encr_chat.user_id)));
+ break;
+ case TGL_PEER_USER:
+ ret = (PyObject*)self;
+ break;
+ case TGL_PEER_CHAT:
+ PyErr_SetString(PeerError, "Only peer.type_name == 'chat' does not have user");
+ Py_RETURN_NONE;
+ break;
+ default:
+ PyErr_SetString(PeerError, "peer.type_name not supported!");
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_gettype_name(tgl_Peer* self)
+{
+ PyObject *name;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ name = PyUnicode_FromString("user");
+ break;
+ case TGL_PEER_CHAT:
+ name = PyUnicode_FromString("chat");
+ break;
+ case TGL_PEER_ENCR_CHAT:
+ name = PyUnicode_FromString("secret_chat");
+ break;
+ default:
+ name = PyUnicode_FromString("unknown");
+ }
+ return name;
+}
+
+static PyObject *
+tgl_Peer_getid (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = PyLong_FromLong(self->peer->id.id);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Peer_gettype (tgl_Peer *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = PyLong_FromLong(self->peer->id.type);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyGetSetDef tgl_Peer_getseters[] = {
+ {"id", (getter)tgl_Peer_getid, NULL, "", NULL},
+ {"type", (getter)tgl_Peer_gettype, NULL, "", NULL},
+ {"type_name", (getter)tgl_Peer_gettype_name, NULL, "", NULL},
+ {"name", (getter)tgl_Peer_getname, NULL, "", NULL},
+ {"user_id", (getter)tgl_Peer_getuser_id, NULL, "", NULL},
+ {"user", (getter)tgl_Peer_getuser, NULL, "", NULL},
+ {"user_list", (getter)tgl_Peer_getuser_list, NULL, "", NULL},
+ {"user_status", (getter)tgl_Peer_getuser_status, NULL, "", NULL},
+ {"phone", (getter)tgl_Peer_getphone, NULL, "", NULL},
+ {"username", (getter)tgl_Peer_getusername, NULL, "", NULL},
+ {"first_name", (getter)tgl_Peer_getfirst_name, NULL, "", NULL},
+ {"last_name", (getter)tgl_Peer_getlast_name, NULL, "", NULL},
+ {NULL} /* Sentinel */
+};
+
+static PyMemberDef tgl_Peer_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyObject *
+tgl_Peer_send_msg (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"message", "callback", NULL};
+
+ char *message;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &message, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, message, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, message);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_msg(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_typing (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"callback", NULL};
+
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OO", (PyObject*) self, callback);
+ else
+ api_call = Py_BuildValue("O", (PyObject*) self);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_typing(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_typing_abort (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"callback", NULL};
+
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OO", (PyObject*) self, callback);
+ else
+ api_call = Py_BuildValue("O", (PyObject*) self);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_typing_abort(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_rename_chat (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"title", "callback", NULL};
+
+ char * title;
+ PyObject *callback = NULL;
+
+ if(self->peer->id.type != TGL_PEER_CHAT) {
+ PyErr_SetString(PeerError, "Only a chat peer can be renamed");
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &title, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, title, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, title);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_rename_chat(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_photo (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"filename", "callback", NULL};
+
+ char *filename;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &filename, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, filename, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, filename);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_photo(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_video (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"filename", "callback", NULL};
+
+ char *filename;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &filename, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, filename, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, filename);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_video(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_audio (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"filename", "callback", NULL};
+
+ char *filename;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &filename, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, filename, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, filename);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_audio(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_document (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"filename", "callback", NULL};
+
+ char *filename;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &filename, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, filename, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, filename);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_document(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_file (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"filename", "callback", NULL};
+
+ char *filename;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &filename, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, filename, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, filename);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_file(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_text (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"filename", "callback", NULL};
+
+ char *filename;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &filename, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, filename, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, filename);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_text(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_chat_set_photo (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"filename", "callback", NULL};
+
+ char * filename;
+ PyObject *callback = NULL;
+
+ if(self->peer->id.type != TGL_PEER_CHAT) {
+ PyErr_SetString(PeerError, "Only a chat peer can have a chat photo set.");
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "s|O", kwlist, &filename, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OsO", (PyObject*) self, filename, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, filename);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_chat_set_photo(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_chat_add_user (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"peer", "callback", NULL};
+
+ PyObject *peer;
+ PyObject *callback = NULL;
+
+ if(self->peer->id.type != TGL_PEER_CHAT) {
+ PyErr_SetString(PeerError, "Only a chat peer can have a user added.");
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &tgl_PeerType, &peer, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OOO", (PyObject*) self, peer, callback);
+ else
+ api_call = Py_BuildValue("OO", (PyObject*) self, peer);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_chat_add_user(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_chat_del_user (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"peer", "callback", NULL};
+
+ PyObject *peer;
+ PyObject *callback = NULL;
+
+ if(self->peer->id.type != TGL_PEER_CHAT) {
+ PyErr_SetString(PeerError, "Only a chat peer can have a user deleted.");
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &tgl_PeerType, &peer, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OOO", (PyObject*) self, peer, callback);
+ else
+ api_call = Py_BuildValue("OO", (PyObject*) self, peer);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_chat_del_user(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_history (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"offset", "limit", "callback", NULL};
+
+ int offset, limit;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "ii|O", kwlist, &offset, &limit, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OiiO", (PyObject*) self, offset, limit, callback);
+ else
+ api_call = Py_BuildValue("Oii", (PyObject*) self, offset, limit);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_history(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_info (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"callback", NULL};
+
+ PyObject *callback = NULL;
+
+ if(self->peer->id.type == TGL_PEER_ENCR_CHAT) {
+ PyErr_SetString(PeerError, "Secret chats currently have no info.");
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OO", (PyObject*) self, callback);
+ else
+ api_call = Py_None;
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+ if(self->peer->id.type == TGL_PEER_USER)
+ return py_user_info(Py_None, api_call);
+ else
+ return py_chat_info(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_send_contact (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"phone", "first_name", "last_name", "callback", NULL};
+
+ char *phone, *first_name, *last_name;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "sss|O", kwlist, &phone, &first_name, &last_name, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("Osss", (PyObject*) self, phone, first_name, last_name, callback);
+ else
+ api_call = Py_BuildValue("Os", (PyObject*) self, phone, first_name, last_name);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_contact(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+
+static PyObject *
+tgl_Peer_send_location (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"latitude", "longitude", "callback", NULL};
+
+ PyObject *latitude, *longitude;
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!|O", kwlist, &PyFloat_Type,
+ &latitude, &PyFloat_Type, &longitude, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OOOO", (PyObject*) self, latitude, longitude, callback);
+ else
+ api_call = Py_BuildValue("OOO", (PyObject*) self, latitude, longitude);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_send_location(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyObject *
+tgl_Peer_mark_read (tgl_Peer *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"callback", NULL};
+
+ PyObject *callback = NULL;
+
+ if(PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &callback)) {
+ PyObject *api_call;
+
+ if(callback)
+ api_call = Py_BuildValue("OO", (PyObject*) self, callback);
+ else
+ api_call = Py_BuildValue("O", (PyObject*) self);
+
+ Py_INCREF(Py_None);
+ Py_XINCREF(api_call);
+
+ return py_mark_read(Py_None, api_call);
+ } else {
+ PyErr_Print();
+ Py_XINCREF(Py_False);
+ return Py_False;
+ }
+
+}
+
+static PyMethodDef tgl_Peer_methods[] = {
+ {"send_msg", (PyCFunction)tgl_Peer_send_msg, METH_VARARGS | METH_KEYWORDS,
+ "Send a message to peer object"},
+ {"send_typing", (PyCFunction)tgl_Peer_send_typing, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_typing_abort", (PyCFunction)tgl_Peer_send_typing_abort, METH_VARARGS | METH_KEYWORDS, ""},
+ {"rename_chat", (PyCFunction)tgl_Peer_rename_chat, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_photo", (PyCFunction)tgl_Peer_send_photo, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_video", (PyCFunction)tgl_Peer_send_video, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_audio", (PyCFunction)tgl_Peer_send_audio, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_file", (PyCFunction)tgl_Peer_send_file, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_document", (PyCFunction)tgl_Peer_send_document, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_text", (PyCFunction)tgl_Peer_send_text, METH_VARARGS | METH_KEYWORDS, ""},
+ {"chat_set_photo", (PyCFunction)tgl_Peer_chat_set_photo, METH_VARARGS | METH_KEYWORDS, ""},
+ {"info", (PyCFunction)tgl_Peer_info, METH_VARARGS | METH_KEYWORDS, ""},
+ {"history", (PyCFunction)tgl_Peer_history, METH_VARARGS | METH_KEYWORDS, ""},
+ {"chat_add_user", (PyCFunction)tgl_Peer_chat_add_user, METH_VARARGS | METH_KEYWORDS, ""},
+ {"chat_del_user", (PyCFunction)tgl_Peer_chat_del_user, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_contact", (PyCFunction)tgl_Peer_send_contact, METH_VARARGS | METH_KEYWORDS, ""},
+ {"send_location", (PyCFunction)tgl_Peer_send_location, METH_VARARGS | METH_KEYWORDS, ""},
+ {"mark_read", (PyCFunction)tgl_Peer_mark_read, METH_VARARGS | METH_KEYWORDS, ""},
+ {NULL} /* Sentinel */
+};
+
+
+static PyObject *
+tgl_Peer_repr(tgl_Peer *self)
+{
+ PyObject *ret;
+
+ switch(self->peer->id.type) {
+ case TGL_PEER_USER:
+ ret = PyUnicode_FromFormat("",
+ self->peer->id.id,
+ PyObject_GetAttrString((PyObject*)self, "username"),
+ PyObject_GetAttrString((PyObject*)self, "name"),
+ PyObject_GetAttrString((PyObject*)self, "first_name"),
+ PyObject_GetAttrString((PyObject*)self, "last_name"),
+ PyObject_GetAttrString((PyObject*)self, "phone")
+ );
+ break;
+ case TGL_PEER_CHAT:
+ ret = PyUnicode_FromFormat("",
+ self->peer->id.id, self->peer->chat.print_title);
+ break;
+ case TGL_PEER_ENCR_CHAT:
+ ret = PyUnicode_FromFormat("",
+ self->peer->id.id, self->peer->encr_chat.print_name,
+ PyObject_GetAttrString((PyObject*)self, "user"));
+ break;
+ default:
+ ret = PyUnicode_FromFormat("");
+ }
+
+ return ret;
+}
+
+
+PyTypeObject tgl_PeerType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "tgl.Peer", /* tp_name */
+ sizeof(tgl_Peer), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)tgl_Peer_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)tgl_Peer_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "tgl Peer", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ tgl_Peer_methods, /* tp_methods */
+ tgl_Peer_members, /* tp_members */
+ tgl_Peer_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)tgl_Peer_init, /* tp_init */
+ 0, /* tp_alloc */
+ tgl_Peer_new, /* tp_new */
+};
+
+
+PyObject *
+tgl_Peer_FromTglPeer(tgl_peer_t *peer) {
+ tgl_Peer *self = (tgl_Peer *) tgl_Peer_new((PyTypeObject *)&tgl_PeerType, Py_None, Py_None);
+
+ self->peer = peer;
+ return (PyObject *) self;
+}
+
+//
+// struct tgl_message wrapper
+//
+
+static void
+tgl_Msg_dealloc(tgl_Msg* self)
+{
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject *
+tgl_Msg_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ tgl_Msg *self;
+
+ PyDateTime_IMPORT;
+ self = (tgl_Msg *)type->tp_alloc(type, 0);
+ return (PyObject *)self;
+}
+
+static int
+tgl_Msg_init(tgl_Msg *self, PyObject *args, PyObject *kwds)
+{
+ PyErr_SetString(MsgError, "You cannot instantiate a tgl.Msg object, only the API can send them.");
+ return -1;
+}
+
+static PyObject *
+tgl_Msg_getid (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = PyLong_FromLong(self->msg->id);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getflags (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = PyLong_FromLong(self->msg->flags);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getmention (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = ((self->msg->flags & TGLMF_MENTION) ? Py_True : Py_False);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getout (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = ((self->msg->flags & TGLMF_OUT) ? Py_True : Py_False);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getunread (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = ((self->msg->flags & TGLMF_UNREAD) ? Py_True : Py_False);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getservice (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ ret = ((self->msg->flags & TGLMF_SERVICE) ? Py_True : Py_False);
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+
+static PyObject *
+tgl_Msg_getsrc (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(tgl_get_peer_type (self->msg->from_id)) {
+ tgl_peer_t *peer = tgl_peer_get (TLS, self->msg->from_id);
+ if(peer)
+ ret = tgl_Peer_FromTglPeer(peer);
+ else {
+ PyErr_SetString(PeerError, "Cannot Retrieve Peer. Internal tgl error");
+ Py_RETURN_NONE;
+ }
+
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getdest (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(tgl_get_peer_type (self->msg->to_id)) {
+ tgl_peer_t *peer = tgl_peer_get (TLS, self->msg->to_id);
+ if(peer)
+ ret = tgl_Peer_FromTglPeer(peer);
+ else {
+ PyErr_SetString(PeerError, "Cannot Retrieve Peer. Internal tgl error");
+ Py_RETURN_NONE;
+ }
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_gettext (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(self->msg->message_len && self->msg->message && !(self->msg->flags & TGLMF_SERVICE)) {
+ ret = PyUnicode_FromStringAndSize(self->msg->message, self->msg->message_len);
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getmedia (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ // TODO probably want a custom class for media, but it's not too important right now.
+ if(self->msg->media.type && self->msg->media.type != tgl_message_media_none && !(self->msg->flags & TGLMF_SERVICE)) {
+
+ ret = PyDict_New();
+ switch (self->msg->media.type) {
+ case tgl_message_media_photo:
+ py_add_string_field (ret, "type", "photo");
+ py_add_string_field (ret, "caption", self->msg->media.caption);
+ break;
+ case tgl_message_media_document:
+ case tgl_message_media_document_encr:
+ py_add_string_field (ret, "type", "document");
+ break;
+ case tgl_message_media_unsupported:
+ py_add_string_field (ret, "type", "unsupported");
+ break;
+ case tgl_message_media_geo:
+ py_add_string_field (ret, "type", "geo");
+ py_add_num_field (ret, "longitude", self->msg->media.geo.longitude);
+ py_add_num_field (ret, "latitude", self->msg->media.geo.latitude);
+ break;
+ case tgl_message_media_contact:
+ py_add_string_field (ret, "type", "contact");
+ py_add_string_field (ret, "phone", self->msg->media.phone);
+ py_add_string_field (ret, "first_name", self->msg->media.first_name);
+ py_add_string_field (ret, "last_name", self->msg->media.last_name);
+ py_add_num_field (ret, "user_id", self->msg->media.user_id);
+ break;
+ case tgl_message_media_webpage:
+ py_add_string_field (ret, "type", "webpage");
+ py_add_string_field (ret, "type", "webpage");
+ py_add_string_field (ret, "url", self->msg->media.webpage->url);
+ py_add_string_field (ret, "title", self->msg->media.webpage->title);
+ py_add_string_field (ret, "description", self->msg->media.webpage->description);
+ py_add_string_field (ret, "author", self->msg->media.webpage->author);
+ break;
+ case tgl_message_media_venue:
+ py_add_string_field (ret, "type", "venue");
+ py_add_num_field (ret, "longitude", self->msg->media.venue.geo.longitude);
+ py_add_num_field (ret, "latitude", self->msg->media.venue.geo.latitude);
+ py_add_string_field (ret, "title", self->msg->media.venue.title);
+ py_add_string_field (ret, "address", self->msg->media.venue.address);
+ py_add_string_field (ret, "provider", self->msg->media.venue.provider);
+ py_add_string_field (ret, "venue_id", self->msg->media.venue.venue_id);
+ break;
+ default:
+ py_add_string_field (ret, "type", "unknown");
+ }
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getdate (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(self->msg->date) {
+ ret = get_datetime(self->msg->date);
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getfwd_src (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(tgl_get_peer_type (self->msg->fwd_from_id)) {
+ tgl_peer_t *peer = tgl_peer_get (TLS, self->msg->fwd_from_id);
+ if(peer)
+ ret = tgl_Peer_FromTglPeer(peer);
+ else {
+ PyErr_SetString(PeerError, "Cannot Retrieve Peer. Internal tgl error");
+ Py_RETURN_NONE;
+ }
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getfwd_date (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(tgl_get_peer_type (self->msg->fwd_from_id)) {
+ ret = get_datetime(self->msg->fwd_date);
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getreply (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(self->msg->reply_id) {
+ struct tgl_message *MR = tgl_message_get (TLS, self->msg->reply_id);
+ if(MR) {
+ ret = tgl_Msg_FromTglMsg(MR);
+ } else {
+ Py_RETURN_NONE;
+ }
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_getreply_id (tgl_Msg *self, void *closure)
+{
+ PyObject *ret;
+
+ if(self->msg->reply_id) {
+ ret = PyLong_FromLong(self->msg->reply_id);
+ } else {
+ Py_RETURN_NONE;
+ }
+
+ Py_XINCREF(ret);
+ return ret;
+}
+
+static PyObject *
+tgl_Msg_repr(tgl_Msg *self)
+{
+ PyObject *ret;
+
+ ret = PyUnicode_FromFormat("",
+ self->msg->id, self->msg->flags,
+ PyObject_GetAttrString((PyObject*)self, "mention"),
+ PyObject_GetAttrString((PyObject*)self, "out"),
+ PyObject_GetAttrString((PyObject*)self, "unread"),
+ PyObject_GetAttrString((PyObject*)self, "service"),
+ PyObject_GetAttrString((PyObject*)self, "src"),
+ PyObject_GetAttrString((PyObject*)self, "dest"),
+ PyObject_GetAttrString((PyObject*)self, "text"),
+ PyObject_GetAttrString((PyObject*)self, "media"),
+ PyObject_GetAttrString((PyObject*)self, "date"),
+ PyObject_GetAttrString((PyObject*)self, "fwd_src"),
+ PyObject_GetAttrString((PyObject*)self, "fwd_date"),
+ PyObject_GetAttrString((PyObject*)self, "reply_id"),
+ PyObject_GetAttrString((PyObject*)self, "reply")
+ );
+
+ return ret;
+}
+
+
+static PyGetSetDef tgl_Msg_getseters[] = {
+ {"id", (getter)tgl_Msg_getid, NULL, "", NULL},
+ {"flags", (getter)tgl_Msg_getflags, NULL, "", NULL},
+ {"mention", (getter)tgl_Msg_getmention, NULL, "", NULL},
+ {"out", (getter)tgl_Msg_getout, NULL, "", NULL},
+ {"unread", (getter)tgl_Msg_getunread, NULL, "", NULL},
+ {"service", (getter)tgl_Msg_getservice, NULL, "", NULL},
+ {"src", (getter)tgl_Msg_getsrc, NULL, "", NULL},
+ {"dest", (getter)tgl_Msg_getdest, NULL, "", NULL},
+ {"text", (getter)tgl_Msg_gettext, NULL, "", NULL},
+ {"media", (getter)tgl_Msg_getmedia, NULL, "", NULL},
+ {"date", (getter)tgl_Msg_getdate, NULL, "", NULL},
+ {"fwd_src", (getter)tgl_Msg_getfwd_src, NULL, "", NULL},
+ {"fwd_date", (getter)tgl_Msg_getfwd_date, NULL, "", NULL},
+ {"reply", (getter)tgl_Msg_getreply, NULL, "", NULL},
+ {"reply_id", (getter)tgl_Msg_getreply_id, NULL, "", NULL},
+ {NULL} /* Sentinel */
+};
+
+static PyMemberDef tgl_Msg_members[] = {
+ {NULL} /* Sentinel */
+};
+
+
+
+static PyMethodDef tgl_Msg_methods[] = {
+ {NULL} /* Sentinel */
+};
+
+
+PyTypeObject tgl_MsgType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "tgl.Msg", /* tp_name */
+ sizeof(tgl_Msg), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)tgl_Msg_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)tgl_Msg_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "tgl Message", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ tgl_Msg_methods, /* tp_methods */
+ tgl_Msg_members, /* tp_members */
+ tgl_Msg_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)tgl_Msg_init, /* tp_init */
+ 0, /* tp_alloc */
+ tgl_Msg_new, /* tp_new */
+};
+
+
+PyObject *
+tgl_Msg_FromTglMsg(struct tgl_message *msg) {
+ tgl_Msg *self = (tgl_Msg *) tgl_Msg_new((PyTypeObject *)&tgl_MsgType, Py_None, Py_None);
+
+ self->msg = msg;
+ return (PyObject *) self;
+}
+
+#endif
diff --git a/python-types.h b/python-types.h
new file mode 100644
index 0000000..448516a
--- /dev/null
+++ b/python-types.h
@@ -0,0 +1,21 @@
+#ifndef __PYTHON_TYPES_H__
+#define __PYTHON_TYPES_H__
+
+#include
+#include
+
+typedef struct {
+ PyObject_HEAD
+ tgl_peer_t *peer;
+} tgl_Peer;
+
+typedef struct {
+ PyObject_HEAD
+ struct tgl_message *msg;
+} tgl_Msg;
+
+
+PyObject * tgl_Peer_FromTglPeer(tgl_peer_t *peer);
+PyObject * tgl_Msg_FromTglMsg(struct tgl_message *peer);
+
+#endif
diff --git a/test.lua b/test.lua
index 00d2a6b..321f345 100644
--- a/test.lua
+++ b/test.lua
@@ -57,17 +57,6 @@ function get_title (P, Q)
end
end
-local lgi = require ('lgi')
-local notify = lgi.require('Notify')
-notify.init ("Telegram updates")
-local icon = os.getenv("HOME") .. "/.telegram-cli/telegram-pics/telegram_64.png"
-
-function do_notify (user, msg)
- local n = notify.Notification.new(user, msg, icon)
- n:show ()
-end
-
--- }}}
function on_msg_receive (msg)
if started == 0 then
@@ -76,7 +65,6 @@ function on_msg_receive (msg)
if msg.out then
return
end
- do_notify (get_title (msg.from, msg.to), msg.text)
if (msg.text == 'ping') then
if (msg.to.id == our_id) then
diff --git a/tg-test.py b/tg-test.py
new file mode 100644
index 0000000..fddd387
--- /dev/null
+++ b/tg-test.py
@@ -0,0 +1,71 @@
+import tgl
+import pprint
+from functools import partial
+
+
+our_id = 0
+pp = pprint.PrettyPrinter(indent=4)
+
+binlog_done = False;
+
+def on_binlog_replay_end():
+ binlog_done = True;
+
+def on_get_difference_end():
+ pass
+
+def on_our_id(id):
+ our_id = id
+ return "Set ID: " + str(our_id)
+
+def msg_cb(success, msg):
+ pp.pprint(success)
+ pp.pprint(msg)
+
+HISTORY_QUERY_SIZE = 100
+
+def history_cb(msg_list, peer, success, msgs):
+ print(len(msgs))
+ msg_list.extend(msgs)
+ print(len(msg_list))
+ if len(msgs) == HISTORY_QUERY_SIZE:
+ tgl.get_history(peer, len(msg_list), HISTORY_QUERY_SIZE, partial(history_cb, msg_list, peer));
+
+
+def cb(success):
+ print(success)
+
+def on_msg_receive(msg):
+ if msg.out and not binlog_done:
+ return;
+
+ if msg.dest.id == our_id: # direct message
+ peer = msg.src
+ else: # chatroom
+ peer = msg.dest
+
+ pp.pprint(msg)
+ if msg.text.startswith("!ping"):
+ print("SENDING PONG")
+ peer.send_msg("PONG!", msg_cb)
+ peer.send_contact(msg.src.phone, msg.src.first_name, msg.src.last_name , cb)
+
+
+def on_secret_chat_update(peer, types):
+ return "on_secret_chat_update"
+
+def on_user_update():
+ pass
+
+def on_chat_update():
+ pass
+
+# Set callbacks
+tgl.set_on_binlog_replay_end(on_binlog_replay_end)
+tgl.set_on_get_difference_end(on_get_difference_end)
+tgl.set_on_our_id(on_our_id)
+tgl.set_on_msg_receive(on_msg_receive)
+tgl.set_on_secret_chat_update(on_secret_chat_update)
+tgl.set_on_user_update(on_user_update)
+tgl.set_on_chat_update(on_chat_update)
+