From 648a063244b95dae26a00cdfcc85fdb7386e8d64 Mon Sep 17 00:00:00 2001 From: Dann Luciano Date: Sat, 30 Nov 2013 23:36:22 -0200 Subject: [PATCH 001/164] Added make rule install --- Makefile.in | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Makefile.in b/Makefile.in index 1bf9014a..7c30e0cb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -15,6 +15,10 @@ INCLUDE=-I. -I${srcdir} CC=@CC@ OBJECTS=main.o loop.o interface.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o +PREFIX?=/usr/local +INSTALL_BIN=$(PREFIX)/bin +INSTALL=install + .SUFFIXES: .SUFFIXES: .c .h .o @@ -33,3 +37,6 @@ telegram: ${OBJECTS} clean: rm -rf *.o telegram > /dev/null || echo "all clean" +install: all + @mkdir -p $(INSTALL_BIN) + $(INSTALL) telegram $(INSTALL_BIN) From d7b2026a3b4a4a8b44d477a7046832789e79b4f3 Mon Sep 17 00:00:00 2001 From: Kartik Mistry Date: Fri, 21 Feb 2014 16:59:40 +0530 Subject: [PATCH 002/164] Update debian/control * Sorted Build-Depends, Depends. * Updated to latest Standards-Version. --- debian/control | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/debian/control b/debian/control index 5e7e1f01..0b060d3b 100644 --- a/debian/control +++ b/debian/control @@ -2,22 +2,22 @@ Source: telegram-cli Section: net Priority: optional Maintainer: Cleto Martín -Build-Depends: debhelper (>= 8.0.0), +Build-Depends: autoconf-archive, autotools-dev, - autoconf-archive, - libreadline-dev, + debhelper (>= 8.0.0), libconfig-dev, + liblua5.2-dev, + libreadline-dev, libssl-dev, - lua5.2, - liblua5.2-dev -Standards-Version: 3.9.4 + lua5.2 +Standards-Version: 3.9.5 Homepage: https://github.com/vysheng/tg Vcs-Git: git://github.com/vysheng/tg.git Vcs-Browser: https://github.com/vysheng/tg Package: telegram-cli Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Command-line interface for Telegram messenger Telegram messenger is a cloud-based instant messaging designed for smart phones and similar to Whatsapp but more flexible, and From b341233e99b93be13ad7847816d7bac76eae576b Mon Sep 17 00:00:00 2001 From: Kartik Mistry Date: Fri, 21 Feb 2014 17:03:43 +0530 Subject: [PATCH 003/164] Updated changelog --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index c83e5f76..37950ef3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +telegram-cli (0.1-2) unstable; urgency=low + + * Updated Standards-Version to 3.9.5 + * Sorted Build/Depends fields. + + -- Kartik Mistry Fri, 21 Feb 2014 17:02:38 +0530 + telegram-cli (0.1-1) unstable; urgency=low * Initial release (Closes #737563) From 2780a716270c5c3ef38d4a134eab51a01039c0d6 Mon Sep 17 00:00:00 2001 From: venam Date: Tue, 10 Jun 2014 16:18:26 +0300 Subject: [PATCH 004/164] a man page for tg --- telegram.1 | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 telegram.1 diff --git a/telegram.1 b/telegram.1 new file mode 100644 index 00000000..7e970236 --- /dev/null +++ b/telegram.1 @@ -0,0 +1,197 @@ +.TH telegram 1 "Jun 10, 2014" "" "" +.SH NAME +telegram \- Command-line interface for http://telegram.org. Uses readline interface. +.SH SYNOPSIS +\fBtelegram\fR [\fB-hvNRfBEwW\fR] [\fB-k\fR \fIpublic-key\fR] [\fB-l\fR \fIlog-level\fR] [\fB-L\fR \fIlog-file\fR] [\fB-c\fR \fIconfig-file\fR] [\fB-p\fR \fIprefix\fR] [\fB-s\fR \fIlua-script\fR] + +.SH DESCRIPTION +.B telegram\fP is a CLI for telegram (http://telegram.org) with an embedded lua interpreter. +.PP +Documentation for Telegram API is available here: http://core.telegram.org/api +.PP +Documentation for MTproto protocol is available here: http://core.telegram.org/mtproto + +.SH OPTIONS +.TP +.B \-h +prints a help message. +.TP +.B \-u username +specify username. +.TP +.B \-k public-key +specify server public key. +By default public key is stored in the same folder named tg-server.pub or in /etc/telegram/server.pub, if it's not, specify where to find it: +.TP +.B \-v +verbose. +.TP +.B \-l [1-3] +log level. +.TP +.B \-L log-file +log net file. +.TP +.B \-N +message num mode. +.TP +.B \-c config-file +specify config file. +.TP +.B \-p prefix +specify prefix. +.TP +.B \-R +register mode. +.TP +.B \-f +sync from start. +.TP +.B \-B +enable binlog. +.TP +.B \-E +disable auto accept +.TP +.B \-w +allow weak random +.TP +.B \-s +specify lua script. Refer to the \fBSCRIPT\fR section for more information about scripting. +.TP +.B \-W +wait dialog list +.PP +All those options can be set automatically using the config file (\fI~/.telegram/config\fR). You can refer to the config.sample file that comes with the source. + +Example: + +log_level = 0; +.sp +msg_num = TRUE; + +.SH COMMANDS +Client support \fBTAB\fR completion and command history. + +Peer refers to the name of the contact or dialog and can be accessed by \fBTAB\fR completion. +For user contacts peer name is Name <\fIunderscore\fR> Lastname with all spaces changed to underscores. +For chats it is it's title with all spaces changed to underscores +For encrypted chats it is <\fIExсlamation mark\fR> <\fIunderscore\fR> Name <\fIunderscore\fR> Lastname with all spaces changed to underscores. + +If two or more peers have same name, <\fIsharp\fR>number is appended to the name. (for example \fBA_B\fR, \fBA_B#1\fR, \fBA_B#2\fR and so on) + +You can see message numbers (\fImsg-seqno\fR) starting client with \fB-N\fR + +The default download dir is \fB~/.telegram/downloads\fR. + +The download dir can be set in the main.c line 68 + +#define DOWNLOADS_DIRECTORY "downloads" + +.SS SUPPORTED COMMANDS +.PP +Messaging +.RS +.IP \(bu 2 +.B msg <\fIpeer\fR> Text - sends message to this peer +.IP \(bu 2 +.B fwd <\fIuser\fR> <\fImsg-seqno\fR> forward message to user. +.IP \(bu 2 +.B chat_with_peer <\fIpeer\fR> starts one on one chat session with this peer. /exit or /quit to end this mode. +.IP \(bu 2 +.B add_contact <\fIphone_number\fR> <\fIfirst_name\fR> <\fIlast_name\fR> tries to add contact to contact-list by phone +.IP \(bu 2 +.B rename_contact <\fIuser\fR> <\fIfirst-name\fR> <\fIlast-name\fR> tries to rename contact. If you have another device it will be a fight +.IP \(bu 2 +.B mark_read <\fIpeer\fR> mark read all received messages with peer +.RE +.PP +Multimedia +.RS +.IP \(bu 2 +.B send_photo <\fIpeer\fR> <\fIphoto-file-name\fR> sends photo to peer +.IP \(bu 2 +.B send_video <\fIpeer\fR> <\fIvideo-file-name\fR> sends video to peer +.IP \(bu 2 +.B send_text <\fIpeer\fR> <\fItext-file-name\fR> sends text file as plain messages +.IP \(bu 2 +.B load_photo/load_video/load_video_thumb <\fImsg-seqno\fR> loads photo/video to download dir +.IP \(bu 2 +.B view_photo/view_video/view_video_thumbnail <\fImsg-seqno\fR> loads photo/video to download dir and starts system default viewer (xdg-open on some system) +.RE +Group chat options +.RS +.IP \(bu 2 +.B chat_info <\fIchat\fR> prints info about chat +.IP \(bu 2 +.B chat_add_user <\fIchat\fR> <\fIuser\fR> add user to chat +.IP \(bu 2 +.B chat_del_user <\fIchat\fR> <\fIuser\fR> remove user from chat +.IP \(bu 2 +.B rename_chat <\fIchat\fR> <\fInew-name\fR> +.IP \(bu 2 +.B creacte_group_chat <\fIuser\fR> <\fIchat-topic\fR> creates a groupchat with user, use \fBchar_add_user\fR to add more users +.RE +Search +.RS +.IP \(bu 2 +.B search <\fIpeer\fR> pattern - searches pattern in messages with peer +.IP \(bu 2 +.B global_search\fR pattern - searches pattern in all messages +.RE +Secret chat +.RS +.IP \(bu 2 +.B create_secret_chat <\fIuser\fR> creates secret chat with this user +.IP \(bu 2 +.B visualize_key <\fIsecret_chat\fR> prints visualization of encryption key. You should compare it to your partner's one +.RE +Stats and various info +.RS +.IP \(bu 2 +.B user_info <\fIuser\fR> prints info about user +.IP \(bu 2 +.B history <\fIpeer\fR> [\fIlimit\fR] prints history (and marks it as read). Default limit = 40 +.IP \(bu 2 +.B dialog_list\fR prints info about your dialogs +.IP \(bu 2 +.B contact_list\fR prints info about users in your contact list +.IP \(bu 2 +.B suggested_contact\fR prints info about contacts, you have max common friends +.IP \(bu 2 +.B stats\fR just for debugging +.IP \(bu 2 +.B show_license\fR prints contents of GPLv2 +.IP \(bu 2 +.B help\fR prints a help page +.SH SCRIPTS +You can extend the program by writting a lua script. An example script come with the source (test.lua). + +The callbacks available are: +.IP \(bu 2 +on_msg_receive (msg) +.IP \(bu 2 +on_our_id (id) +.IP \(bu 2 +on_secret_chat_created (peer) +.IP \(bu 2 +on_user_update (user) +.IP \(bu 2 +on_chat_update (user) +.IP \(bu 2 +on_get_difference_end () +.IP \(bu 2 +on_binlog_replay_end () + +To get more info about the parameters of those functions you can use the \fBvardump()\fR function in the test.lua. + +.SH ERRORS AND TROUBLESHOOTING +Report or check the Github issues (https://github.com/vysheng/tg/issues) +.SH SEE ALSO +.B lua(1) +.B xdg-open(1) +.SH AUTHOR +vysheng (https://github.com/vysheng) +.PP +Big thanks for the help of all the people contributing on Github. +.PP From f9f2a90092de37261211cdc3c4b60f1ccc2d621b Mon Sep 17 00:00:00 2001 From: venam Date: Tue, 10 Jun 2014 21:39:02 +0300 Subject: [PATCH 005/164] man page --- telegram.1 | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/telegram.1 b/telegram.1 index 7e970236..f065b1a1 100644 --- a/telegram.1 +++ b/telegram.1 @@ -104,6 +104,12 @@ Messaging .B rename_contact <\fIuser\fR> <\fIfirst-name\fR> <\fIlast-name\fR> tries to rename contact. If you have another device it will be a fight .IP \(bu 2 .B mark_read <\fIpeer\fR> mark read all received messages with peer +.IP \(bu 2 +.B delete_msg <\fImsg-seqno\fR> remove a message +.IP \(bu 2 +.B status_online/status_offline \fR appear online to others or not +.IP \(bu 2 +.B fwd <\fIpeer\fR> <\fImsg-seqno\fR> forward a message to the peer specified .RE .PP Multimedia @@ -115,9 +121,9 @@ Multimedia .IP \(bu 2 .B send_text <\fIpeer\fR> <\fItext-file-name\fR> sends text file as plain messages .IP \(bu 2 -.B load_photo/load_video/load_video_thumb <\fImsg-seqno\fR> loads photo/video to download dir +.B load_photo/load_video/load_video_thumb/load_document/load_document_thumb/load_audio <\fImsg-seqno\fR> loads photo/video to download dir .IP \(bu 2 -.B view_photo/view_video/view_video_thumbnail <\fImsg-seqno\fR> loads photo/video to download dir and starts system default viewer (xdg-open on some system) +.B view_photo/view_video/view_video_thumbnail/view_document/view_document_thumb/view_audio <\fImsg-seqno\fR> loads photo/video to download dir and starts system default viewer (xdg-open on some system) .RE Group chat options .RS @@ -164,6 +170,39 @@ Stats and various info .B show_license\fR prints contents of GPLv2 .IP \(bu 2 .B help\fR prints a help page +.RE +Options +.RS +.IP \(bu 2 +.B set <\fIparam\fR> <\fIparam-value\fR> Possible <\fIparam\fR> values are: +.Ps +.RS +.IP \(bu 2 +\fIdebug_verbosity\fR - just as it sounds. Debug verbosity +.IP \(bu 2 +\fIlog_level\fR - level of logging of new events. Lower is less verbose: +.RS +.RS +.IP \(bu 2 +\fILevel 1\fR: prints info about read messages +.IP \(bu 2 +\fILevel 2\fR: prints line, when somebody is typing in chat +.IP \(bu 2 +\fILevel 3\fR: prints line, when somebody changes online status +.RE +.RE +.IP \(bu 2 +\fImsg_num\fR - enables/disables numeration of messages +.IP \(bu 2 +\fIalert\fR - enables/disables alert sound notifications +.RE +.RE + +.RS +.IP \(bu 2 +.B quit/safe_quit \fR exit the program +.RE + .SH SCRIPTS You can extend the program by writting a lua script. An example script come with the source (test.lua). From bfb4717704720d01d52424a55fb5ccec2b3025da Mon Sep 17 00:00:00 2001 From: venam Date: Fri, 18 Jul 2014 22:06:56 +0300 Subject: [PATCH 006/164] /read and /history --- telegram.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram.1 b/telegram.1 index f065b1a1..d62b0da2 100644 --- a/telegram.1 +++ b/telegram.1 @@ -97,7 +97,7 @@ Messaging .IP \(bu 2 .B fwd <\fIuser\fR> <\fImsg-seqno\fR> forward message to user. .IP \(bu 2 -.B chat_with_peer <\fIpeer\fR> starts one on one chat session with this peer. /exit or /quit to end this mode. +.B chat_with_peer <\fIpeer\fR> starts one on one chat session with this peer. /exit or /quit to end this mode. /history to show history and /read to mark as read the messages. .IP \(bu 2 .B add_contact <\fIphone_number\fR> <\fIfirst_name\fR> <\fIlast_name\fR> tries to add contact to contact-list by phone .IP \(bu 2 From 4daedd84276f8699d1800cfd70a460554e7e7a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20R=2E=20Ruiz?= Date: Thu, 31 Jul 2014 11:54:17 +0100 Subject: [PATCH 007/164] Add default server.pub to /etc/telegram --- debian/install | 1 + debian/rules | 2 ++ 2 files changed, 3 insertions(+) diff --git a/debian/install b/debian/install index f0f94de6..abdef872 100644 --- a/debian/install +++ b/debian/install @@ -1 +1,2 @@ telegram usr/bin +server.pub etc/telegram diff --git a/debian/rules b/debian/rules index 0f41aca7..e76bf03d 100755 --- a/debian/rules +++ b/debian/rules @@ -5,7 +5,9 @@ VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') %: + cp tg-server.pub server.pub dh $@ --with autotools-dev + rm server.pub build-orig: mkdir -p $(PACKAGE_NAME)-$(VERSION) From 2c4f07ed2045ec81e2f31c26e2639315d484ec0b Mon Sep 17 00:00:00 2001 From: Andrea D'Amore Date: Wed, 20 Aug 2014 10:21:17 +0200 Subject: [PATCH 008/164] Remove unneeded Mac OS X instructions Remove stray FreeBSD instructions left in Mac OS X section due to partial revert of c373008, see comments of 1cc2ffe and 1f505031. --- README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/README.md b/README.md index 263a24e1..7cc998ad 100644 --- a/README.md +++ b/README.md @@ -62,18 +62,6 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. - -Install these ports: - -* devel/libconfig -* devel/libexecinfo -* lang/lua52 - -Then build: - - env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure - make - #### Other UNIX If you manage to launch it on other UNIX, please let me know. From 898c1947c26290fcfa690fc3ab8d11b6bc2cf055 Mon Sep 17 00:00:00 2001 From: danielberlin Date: Sun, 7 Dec 2014 20:31:48 +0100 Subject: [PATCH 009/164] Update config.sample Setting default profile to one without binlog as activated binlog has different storage and thus confuses people. Default sample config should be working out of the box which is the case now. :-) --- config.sample | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.sample b/config.sample index dffcc44f..93a3c686 100644 --- a/config.sample +++ b/config.sample @@ -1,13 +1,12 @@ # This is an empty config file # Feel free to put something here -default_profile = "binlog"; +default_profile = "dc1"; test_dc1 = { config_directory = ".telegram/test_dc1"; test = true; msg_num = true; - binlog_enabled = true; }; binlog = { From d446f4b9b9bcb15473aadd78aca7d6994e47c960 Mon Sep 17 00:00:00 2001 From: danielberlin Date: Tue, 9 Dec 2014 01:33:33 +0100 Subject: [PATCH 010/164] Update config.sample production on top and set as default. This is avoids confusion and makes it clearer. --- config.sample | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config.sample b/config.sample index 93a3c686..1c25f0d5 100644 --- a/config.sample +++ b/config.sample @@ -1,7 +1,13 @@ # This is an empty config file # Feel free to put something here -default_profile = "dc1"; +default_profile = "production"; + +production = { + config_directory = ".telegram/production"; + test = false; + msg_num = true; +}; test_dc1 = { config_directory = ".telegram/test_dc1"; @@ -39,12 +45,6 @@ new = { msg_num = true; }; -production = { - config_directory = ".telegram/production"; - test = false; - msg_num = true; -}; - test = { config_directory = ".telegram/test"; test = true; From 053a7724cb35f2aedc738da4b4a66df7839e3e7f Mon Sep 17 00:00:00 2001 From: Tincan Date: Sun, 18 Jan 2015 21:49:50 +0100 Subject: [PATCH 011/164] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 185e3672..c5b1664c 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ If two or more peers have same name, number is appended to the name. (for * **send_photo** \ \ - sends photo to peer * **send_video** \ \ - sends video to peer * **send_text** \ \ - sends text file as plain messages +* **send_document** \ \ - sends document to peer * **load_photo**/load_video/load_video_thumb/load_audio/load_document/load_document_thumb \ - loads photo/video/audio/document to download dir * **view_photo**/view_video/view_video_thumb/view_audio/view_document/view_document_thumb \ - loads photo/video to download dir and starts system default viewer * **fwd_media** \ send media in your message. Use this to prevent sharing info about author of media (though, it is possible to determine user_id from media itself, it is not possible get access_hash of this user) From 10ba89be3680bf5f05a36ca71c9c9a416203f69d Mon Sep 17 00:00:00 2001 From: Yuval Langer Date: Wed, 4 Mar 2015 15:48:17 +0200 Subject: [PATCH 012/164] Minor typo correction --- debian/telegram-cli.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/telegram-cli.8 b/debian/telegram-cli.8 index d0c29a0e..59e0f97d 100644 --- a/debian/telegram-cli.8 +++ b/debian/telegram-cli.8 @@ -29,7 +29,7 @@ Telegram-cli Usage -p use specified profile -l log level -f during authorization fetch all messages since registration - -E diable auto accept of encrypted chats + -E disable auto accept of encrypted chats -s lua script file -W send dialog_list query and wait for answer before reading input -C disable color output @@ -45,4 +45,4 @@ Telegram-cli Usage .SH BUGS No known bugs. .SH AUTHOR -Vitaliy Vatman (-@-) \ No newline at end of file +Vitaliy Vatman (-@-) From 6bba88aae1e1648ed7d1357119699fc462c4e965 Mon Sep 17 00:00:00 2001 From: Abilio Henrique Date: Sun, 5 Apr 2015 22:31:38 +0000 Subject: [PATCH 013/164] Added username variable to lua c library --- lua-tg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua-tg.c b/lua-tg.c index 08cbef49..9db40656 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -102,6 +102,9 @@ void push_user (tgl_peer_t *P) { lua_add_string_field ("real_first_name", P->user.real_first_name); lua_add_string_field ("real_last_name", P->user.real_last_name); lua_add_string_field ("phone", P->user.phone); + if (P->user.username) { + lua_add_string_field ("username", P->user.username); + } if (P->user.access_hash) { lua_add_num_field ("access_hash", 1); } From 79934840cbf143a5d771ffea040e770f846e87aa Mon Sep 17 00:00:00 2001 From: Julio Gonzalez Gil Date: Wed, 13 May 2015 16:06:44 +0200 Subject: [PATCH 014/164] Fix RPM SPEC file, remove existing RPMs, and add a helper script to build RPMs --- .gitignore | 7 +++- rpm/README.md | 34 ++++++++++++++++++ rpm/SPECS/telegram-cli.spec | 43 ++++++++++++++++++++++ rpm/clean | 9 +++++ rpm/telegram-cli-Beta-2.fc20.x86_64.rpm | Bin 147652 -> 0 bytes rpm/telegram-cli-build-rpm | 16 +++++++++ telegram-cli.spec | 46 ------------------------ 7 files changed, 108 insertions(+), 47 deletions(-) create mode 100644 rpm/README.md create mode 100644 rpm/SPECS/telegram-cli.spec create mode 100755 rpm/clean delete mode 100644 rpm/telegram-cli-Beta-2.fc20.x86_64.rpm create mode 100755 rpm/telegram-cli-build-rpm delete mode 100644 telegram-cli.spec diff --git a/.gitignore b/.gitignore index 7cee62db..ec7ca68a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,9 @@ 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 +rpm/BUILD +rpm/BUILDROOT +rpm/RPMS +rpm/SRPMS +rpm/SOURCES diff --git a/rpm/README.md b/rpm/README.md new file mode 100644 index 00000000..f869543a --- /dev/null +++ b/rpm/README.md @@ -0,0 +1,34 @@ +Build requirements +------------------ + +* lua-devel +* openssl-devel +* libconfig-devel +* readline-devel +* libevent-devel +* gcc +* git +* rpm-build + + +Building fresh RPMs +------------------- + +Install build dependencies: +``` +yum install git lua-devel openssl-devel libconfig-devel readline-devel libevent-devel gcc rpm-build +``` +Clone the repo: +``` +git clone --recursive https://github.com/vysheng/tg.git +``` +Build telegram-cli RPM: +``` +cd tg/rpm +./telegram-cli-build-rpm +``` +And install: +``` +rpm -Uvh RPMS/$HOSTTYPE/telegram-cli-Beta-*.$HOSTTYPE.rpm +``` +A SRPM will be generated at SRPMS/ diff --git a/rpm/SPECS/telegram-cli.spec b/rpm/SPECS/telegram-cli.spec new file mode 100644 index 00000000..76b5fe22 --- /dev/null +++ b/rpm/SPECS/telegram-cli.spec @@ -0,0 +1,43 @@ +Name: telegram-cli +Version: Beta +Release: 3%{?dist} +Summary: Private fast and open platform for instant messaging + +Packager: Julio González Gil +Group: Internet/Messaging +License: GPL +URL: https://github.com/vysheng/tg +Source: telegram-cli.zip + +BuildRequires: lua-devel, openssl-devel, libconfig-devel, readline-devel, libevent-devel, gcc, git + +%description +Telegram is an Open Source messaging platform for mobile, desktop focused on privacy. + +%prep +[ -d %{name} ] && rm -Rfv %{name} +git clone --recursive --depth=1 https://github.com/vysheng/tg.git telegram-cli +zip -r telegram-cli.zip telegram-cli +mv telegram-cli.zip %{_sourcedir} +cd %{name} +./configure +make %{?_smp_mflags} + +%install +cd %{name} +%{__install} -D -m0755 bin/telegram-cli %{buildroot}/usr/bin/telegram-cli +%{__install} -D -m0644 server.pub %{buildroot}/etc/telegram/server.pub + +%files +/usr/bin/telegram-cli +/etc/telegram/server.pub + +%changelog +* Wed May 13 2015 Julio González Gil (git@juliogonzalez.com) +- Build was not working: Fix it to use latest available code from GitHub + +* Tue Feb 4 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) +- Add server key to /etc/telegram/ + +* Sat Feb 1 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) +- Initial SPEC file diff --git a/rpm/clean b/rpm/clean new file mode 100755 index 00000000..614ca085 --- /dev/null +++ b/rpm/clean @@ -0,0 +1,9 @@ +#!/bin/bash +rm -rf BUILD BUILDROOT RPMS SRPMS SOURCES +if [ $? -eq 0 ]; then + echo "Directory cleaned up." + exit 0 +else + echo "There are errors. Check log!" + exit 1 +fi diff --git a/rpm/telegram-cli-Beta-2.fc20.x86_64.rpm b/rpm/telegram-cli-Beta-2.fc20.x86_64.rpm deleted file mode 100644 index 0deaace0e3bfbd1184e064b665486bb52dc9ac2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147652 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

_Vt8K7?mvk= zCTlv&$`Q>bbgCDD-l_zA&}tWH+4v`DL;$1e3LtxWmCaliGJl)n?HnzqLby3ZWU!YiD?zQQWy{?KEzo# zPsW;hL0}@KdFOAGm8BxX*0g6v4Hp?Hvgghy1lG60tkV0TE^dFSAV$__toI|`K~qD5 z6fqma?dt~mQj`1(*ehuT2p*U|@q~o3DxH`np|_M|-p7RfNLT6Gwp>q4g%k6Ny2Sfd zf&-SNt%7n;r2mk*u8vkWdRILA_k~F!Hev?e!Ew`0dz9tfwG^No=aL2i1O4k(_H1eZ zNN-#-ELGghvX?092)ldMO1d8d$;L`n?8*+0w*3)pX8M%st=F0Ce?e95LU)8UAC)c@fyz$6 z>kJ#?Tbc@-#;cInbNs-fIU9!ZBgQ!AspM6||6yJ!@Uo zgnjqCEX-VA)VJ@lRSecO7lQbjE86f+dD*uj9s3ee@e9 zIH`kQ0u7L|rG4(D0hDdxz9rp{k)oftNx!gj`EVTDTPd=d55L{bSm{1mA>Hu~ObXXc zaSPCSV#|HV>u8`!n3X1aPmk;k(c1B1Lrx%6zRwa-q&H1e%TAOklHi|NI?3Id2s3ft zLw!6lv*<hxn9^XZ!&@ce!--*(P;fJ4$25=5kG(hFdz{|0Xdm0;w1Uz5%4kD+OW? z%8OK%O_$`AA6u6O!gnWH`v=5c>$1<{jriiC_&CzZrDs!JmFti4m zEF2VAf%fn&!}k2v+~lXplJOvnImB@w6IgLSOikc|r=#7n{{><^(i(> zAxOlQJztm~x%jASL$3A)WL2FgojXJFD4MYBSkb&#e>Ak}?&@0+4-;)Q4(<8eYbIOzfU#2yrxo6nHJ)zj(( zF9J`t*o834*ojaR--?=%W>?7ihynH(GZ~OP=VWN?U`KLo-E7Wiu2Wv{`IQ|3GH~Q5 zhmU<3dIDy+W0dk2{JCdLvrz|n9`z#a*SnjRl2R~>-@9Bj1ab`N{rB7UU^NxOW3qLj zJPHW3?N&^5IFW)9m} z(S1L!J+IXhncvFYZVP39jSx6P*(Y0x1e8}@JMB$~@mqYAe+d z)VFx;y=R#eDbrc1TzoGU4ema7JAY1 zhs(^if6d09UT*k*CAsMb443aW;&NJsD`B3}_Inf$bg+}SMg1>GePI}cI+>h9tf}vQ z{zROA*}1ba3A@}s0j7`!lWn;3p9Dmtj;Oy7rYv9w5~urm*)BNAaimyp&bphJgx(1+ zYB&i!aY-ujm50AnYzpaK%6eJMb}$5G{A;vZ8)|`><{ddJZxT*hF*Z|fkha+5U^ALg z7o9MOKprZn+Mk8=$VZwAea32aM4&PP?!+#etP(#tiugl?Rbe<(7c_F zMWH{iw+ijrpPSmS=mnhcKoTH787^Jjs(Y>agiYr20>dttDA6?qiMq{oud-QDyFkOI zvzK#Hg4|{g{TI2@0`C0d`2#yNJX4$^GZ7kBTa%x~0H6GTifOWNGl_>bq`7AQ!!^gL z2Qg;7bqTlYT?d{n6A5LFVHnT21ahJo{Mkjy&RJ~qhWd_I1|V;eDoBf#i5*y^BiJvt zv=8}quMRj|N4VW|j7_@Qa_Qsk)iK{xp~6nZ7`jGEA@n6+DY~DntnJ_vb@7Ls-d-CD z$J;}g^+vLPg%WqO?VNv~eU>!FjEWb3aUDeWOX}(&8c{y{5Cftc-|i&}&3Z$SX;!u^ zCA>Ek4E+hm&PEyE7&zT?2+ap7>r_>n>X(8lwk)^`zxHZH6AKoE_VsN|?)R8Z=UW>C z$Y6%e>e%GG1w<;ifg7yI0HCyDrj&d2OG7ZxZc(Z7215yRu6*z=L}V%mgeTsg0Q#NY zA&0!mXw-mD3KP?3g%Mu;F-2Muk=$KyG_?F$+1zFDu%8R1dCIn^{G`&X$ObF}GRlt1 z>T!Dtno&7wD^4b5o>v(g0k66BXI6Klh2j*8v*7dxn~98HwE?)~*N7A};3*pP2>b ztpGPJK`n>|6Yu+V`cqeTtGXNE{6hi+7U|i$u=m!a>(l1751Q6#ds{e6#xmL!wG@MX z-JptyEU-gc-wei8n`<`&;&|DF_&m zP<1|6B5hJ>-PFQ(hMGWu13hWnLpZwWc2oDcnCy2$?R(SanpF7e|IQReqckusfk6KK zjSL)!aPsgbN$2z)^?Ydu6XRzFh}x#Sn*>;)WBNl{bi>El|KF7?_zQN7LhC_-$^WYh zT6K!_Qa@p(dvLR_d8Gf3PsUxs*m#-WS|YIh*-TqN`3P-7FdZl!@dsXIarKvT(1`P) zl`T_~tvbErZ#99KWnN4yh}T(#5el=we;h6;X4#1yKkszm2o; z$4)u52HS<;O4FI(x^HKAYt3&HtVYs8I)1YMABH5+_ci6;L~eu*RueRmuC$9?jvx)U zE}@9ueeZ%zs!H_jzUS92S!1YkDr-AP|K5ci;SoMkx>z=Tf035ul}?#Kd4^9yn6u{M z+3h{W zmc&#FHqr;2lemB+BzJ@xv^(Cp%dp*{g^x1^8a`<|Ct_0$ffj@Cze7Jr`3v>PilhaS zZa-c?^2bCZhRU@v$i+94*fGsG_;rbT^*Fgjyzk$QRr8{B-8$!@$Rt+?a{Cf12)4if z#qNZ6m%o>Ym}ssVdk^^>tn=)wIM$T1=9~K{m&d8=BjWo~%7*$#8RJkg+h-Z97sT?5`+2 z)~O}9MZBxn^=nN?YQqFt9uNdpV9fG5hU7r|9*-b8&TJ;F!1OI4m0X|!WbBCK?mx8f z*db&jxxEB+K;NFTmS?AzndS0hLSqh`WW}I;Ob%*f(v?!-zjkZ79|#SbqR%+Vm1U?_YIHq-Rkca z*6G$+R>5&Z^y#d`idPSyMCE;;U%@-c$<ViEx!1ng; z(zG%T;a8yCT%NoGKy2p};evF06NTX!6BlKXLW+ReYRr>vb#g7_(RFDu=5G8@kb*&K4iIalRi_`$44=Hx z6}24d$ze`8{6SSoc%X=Pf-%=Y>>;uS4~+tcr^ZQTr&|hvHs5^U92>5{^h!825!ZrNVFHs)YGnh?ER(vp2?6tal;gDG0eq!cNW z!GnJ9u2N!2G&GSWwk8Mt>trPlvt6=@w9aMGaebtu$y>?Ae*b1`=vD^ixM^)5 z&8Xl7Z{U+2l#vKL9KHh9@O)-aMaN|}zL5HD&t|XusCxt1qb2Zvxp;$m+=8Xsof- z6ZHLz|Ls=i$)zhRlm16~&$}QJ1HT0zaQfn?va~2b`GkIh7r}O)u|Hj4xZLKK=qI9% zJU$KBFTMnW8Mv`cu7Tn`w4-}vaXO6x?2ZzP4H9q$$=7>ckx)l=3FllflCUfeyv z07XE$zgEtjO!o6?$ltC~1mvuK8IuGMX*S==M}0@x{Q3ATZ7eRb*-jb4o~+jnPRzw(=27rnBYfX7`qPGV?B zLjGTZEvzAm_Ku>B6s%wn=7)S$T?)7%c}~dgKi#Z|tnnP)J?BOKy^frKB5T zL@L`uYu?`H%Xu(RD+b>EJQ?bFR;iiK)Cpx0AN#X9C?#>g-wiK(tcpCN1Wa^}xKzNm za;18S(Ph@+t!C^P&sG#L&74u`kCNZY&kjueKRD;h&%ZT z>;2kp)YnDs^G&C5!yR}IKP^w_n>gYpV=|uECfM)(8|*r0QB2+~?w_zKOFkALP6jb& zyEC*NbIoAG;#nnnB%E1iAxgJZunC=>ku+phN8AUcGlk>wEpBso8tv#GvdEMUVP0?% zLJbJgm2T5#gS!Pu^3ngMj-C^aK#b&s-5|P8(i%G#ma>sb62@qjXcRgGBwb>nJ7>Zr z6|O};?R#bK?3+?!jy=Ib2&0VWDdmAr(% zb>fIWA)Tn~3C8u{Qz?FblJ^TJE5^C>>I)fi8FlyeQ2-3)2@l^O(}#)glv1%i!j6%E z+p_I<6)^`M)$P^Uq3~6v@$WW)Z=U_NcZ>9wkFvdbA27shr4#fjAIIIzsH&@mqm%qU zKVuF=AeL4IWD}e*1561z)7oYfSjK4&xj3Pxdxkh>Q{J3jP5`A=a^QdCKtQP&BBR53 zn{&u~&W-P5@&vhgsZ5VmAfDXAuTM-1m>ZT&^$z%V&l9Mxp{@c2xj@7LzA4Xz54 zAr^pzAqV}j3b%rW{QyNqURfkp={J^aRlzW@`{SBgKR*s3R==aCBiWwaiV`O&`3?zn z*xleqp)ZITDdwc(rV(YgP_XY!?L2_!*vNMiu7`ARhShQ;ILrMRs<6g(4R-2 zEV4nT!ag&_+y9ILkXxlO_}4})BRNGN(~f_Kfw$34mZFSO=nlXdEe)J$O08%HE;8aH zWV`2eb*@Wg&x(-af?RWT+@~f?aV&y-j;2q8%`d%d1wo^&XU*G9YnY%D)fFac-^2JDrrrlk*2nH7av|{$;a`6Vji(^w_m$`E2Gfsq zGpmEDI;w%qvQ4sII*|W#v{oHOm5+!LDa=L_e><@&b$)Ev@f5d!NhH+BK544a%e(gp z9TB`-<>wfrzf6<5Z{-;0dp;X*7H=v8N~V8Mf9BZCvlKL8XI@AB;=4q@WJ%Oh55r?` z2R9ox4pT3kDs)2R$j~Q9#Bb?I-li)A_8PQwN?ZpRY}>N8FUIx|Njdj7VkJdSN$!VQ z{<+GMuGadY+H!g`4YhpRY4Z%B+4rHfUjb$S#m-cHAX+Nsv&^ zsBYIRh8y?T?q$SH*|3pNSewvyZ%gb@nRW`?FHVKBiz>;AzvCL@h+sMYpfa%1JT}Su zGl!sP`CVt*L0**LHY?jc-DV6cLxs?JoXSXm7s!Og~wmFK!%2X^7I?P!c&(a(dTHO*#-+TYs@3;npFruGB_C#CC zv?fa?f}CTlw)KbSt<-jfuAT)%@$C^VTyX$ZfaV1)RP<5Io9oIgtsI+Lh~=kDqR$ zHIHR~S(7SDvy4^_jkrW{MtKrWVdXiRm2VvvSf*owp{3E~h_NIC_B)9o7U$YhEZE|% zpVKU|?{nC~3F9QcuToZG@Ux5`W?9^+p!Y4eH7FMfl5C}fD0obgV(^l<~ zAw(S)6lM$2umtndHTqDn80c7bP$x2W@bvRlVil#^vaKY&k7*#jO5$}8p=lRG(Bg?D zpJ3O{7#%rq$LKdmkI)4x z)5S|OAMx~gH#7gohG`j<*J{4Vt;jY@gJ$$2*9Vb18H^7N=qakh2v4;WGX&dxMQV~T zV9~pR5zELL^2S~ZZUE;lUHPZ1UZYdi`%mZEhW%u}hBxuQ`c=pbnv1hJ(p6yh+Jw7& zEhM;RTStUnp=@bUV_-wN$X0+|_n9D@(3J~coK;<0pSHG%sNY5b@qwn2P0xc;8-ZhL zv;R3$zh%^}vE6s`kh6Ps{g4C(AWit+uca5`b6Kb%t0nd~8ZzLnWcqg|e`GVFfsx`J z+^af`!UnPZIc{u%_=XR$Kq1~mc3#_*r*69uan-k!7Ht3-iGv4@W_ zZAf>4ctVZGH=2j1MuDN)Q@oaH6ctuJ?!|Nq<0zRs?p4|Txcq%zZ&xRN{}a3#8=?jE zt2zANNpK?ppDWda2_C%2vvR}ZlmS*jyE-n*3Bg(c{=7mI-GCTmIVs+-CV8HcVbcC~ zx2E}X#9e!jQAuRa-e>+=+bxq}2EVVhCSPs7RVs^d!J#=*`m(pFz>7oCu&jPFMBQN7 zXL-9aoMkQ7I@Er#q2t`P7i4D72hyCNpp9^DVmF77x~Z%mc|Hc9NuYz;#kOYc z)L+L2YOFpP3-NzX3C&Ut=)-Sh=}AW7nJ66}D>`YNUS~~GH+z7e#)z83*TXNW%jbD` z{F(CA6z*&f%8S$#(?En^e^9PK+4*KSIL`#JP_G(gv-Dffnt%}K) z$*2{i!evtBWhVp>EB5Gd@W)=&&4H1v;pDs6b&+0W2tDNt%nG6H&4nBpV|x9)M+ZGO zTw#QJ2S$eInx=43aMk|WK(kLp%u<9D{q486pirf(-)~a`ZY`QR$u&A!;pIQCd2(=| zHj;ih91U|_3vMA%95579xszcwU}Do9{Vd(^cfS4>o`Ht=gp|t}nl!3{rQ4|UiQY><{W0Hj z%`4!TDMNzvpyq+1!^0%iTqJa1oy8EC7f|v(RL#Ok&ant990A35wp*jB@Mms4VChb$ zdg^KUY@3xAS5H`&J>&KkwtEra@2ZL-e~lSCVYg&82kFlK=1?~Ek9CdEV4O>~R3Vx0 zZtBEjJKRNvwdh;N$fh}U8^*`nthBBU27a{B+SIf;&RyOJW1PjyOJjkm!~P8QXg+Fp zx}Ku|jrLN0!Hw4@_wtMO2U@)8$bOU#!v{~_(PO=DEdyvK@eMTSos?MX`D(r~JVb!4WYmg#N_QwMa8Wn{>AT?`tqfTBt zLDnsG?3v0G~5Tfr!($FQkc33H+Ltcf44 z3jPM>azB)~vz}r^LZIgHNi;l1T*99hdxlz(Aa3yvGmGQl?nuJ}(OSe}&$0Uw1o)!1 zuX|LzQG=;!}XN)`-?6;O(7S0|l)3{&!k_@>`9-+g&{#a&tIaaHTVmEy)?+q8tDAbiY zmqxICK3?2noFwyrQmi@~7^6V=+{`nfYwJ`9LjJU!F1$0<(Z-0t{NAtWU+|u~zI1I_ z*x-~n6}M5T5QG6*{hun50tJ3|I9H~ND1Lyq3>Iq2#;8lfi0(SywEM>>B=bp&zb~+_ z8avebvv0NNlgQ<%7dE(q;ai#fTqqIMJDrk_?YXMQ5X(k$*v3Guauj_q>89-@^a=`q zv7J5mu%r&=s1oK?WbZulGDbp2PXzw{l`43K!zjcOsEh1&Xyv!-mSgGw5jXnucNDLR4Y_Q=CFP!!kJUos?iJqz~B!8~*vP>;m_ zX$HEf9wbGbD|09x&*A8MVIw;6HMEN`F@Y6Ifx_034uTk9BG&+%>9Xa)xLjcacScB= zN3voy+@j|Q3GVE3?Kl|#j>d5MHVN;$u&6A>PRFLL46UfEfWG^f?BQ0;XF`M7fmTxy zwI@|1`(+0Le|EZKQt60kH#&@n;-yUmW;!VePJ3yIEj-=o4X`i<{h6p*U@zzuBoss` zlQ^vBO0(cbf~Syo2ct0*I{`;1Eyfl={xU$N zfz_#&eY>m{P6Ms%+0FhwAiqMQ`~q2t#EAIl{!WL>d$^BnSJW+Bf<)d9UgqaEs^saK zYvVX(gA@NF{%FT)Zn!XO(mu|^dyw=topATTl`RfT5FRi`KEA0Lb_p}J`D5e4R!o_P0zhRJfd7RPw=kOcVhx zdpbTLj3PeF6dJsuc(&FoQDKPOXuWOIpr}A-yey>xKJyJJgwkW z3w`HR2wxB7Q3Pl$l851yXK&+SvXJmZl@=;S@z`Sf`HhEfgsK`tK)e_@>C!M|Y%xBz zROy#q?z6hETh4{%C(6?KwO86k_uhgXa z0wt|Qa#A7~jgnsKN~^ffcfvm|-cH$Kke(u-c5IDP$bOvygZ*(}L){;$aKZ#TsyW4i z|KkG0(`47_e83W`N+vk*ff^`r;GQX^T<>}NuH7jiIL!|q4SEu0P)7CK^*K1R!TzvY z<`2J-Qt(*RPcG9}fqWQ;o!G-ae1^V67bnCk(kg=ijmIYqhu3t6x1aX|>s3!4M~(}z zD`2V;MO?eYC(f!!+THUhU0K{lMrl-9cNDx~kKlYh^Kd?2lNI%)Se#03w9u|%6brB2n`=U;cgjF9K$``79}f1 zz#USiTjQmBYGkrzSsXeps8EQWdUv^nVZDiW$vZOFfhG!5rubhHI{(R(G1^ee>I#H} z@z%2aAQys_-Jf|r;LOg{skax&TQiv@cCO!^J`5Y314soRlTaAL{kP|uSnI2q$!P0o zh?+K{pE!N8=;;;ouZk|cV#CBFRV8TaO3q=TxEA!ISZh8@ zS_HoKVwOica^GFuJBtq2Tc|1W$=$ns{Aha?Vnz zCXj}dH}_D}!Bfvw8nn;|iX9$SGM!S9lH|e`;_;i*=1}hGU7~vp%ZXYcs*wWAGsC!( z>CA+MCIV)4olEVzjR$il&C$df+MahJJuL1LLGFXhPX9WuTbepVGW{R6i{lPs5rP8< z#*Aac-Vz%4!)Bit6C22$Lt|y5)V^anPAVO(b6c?PJ78Ig=kwi^o1rzBjpQWKYoUre zA`vCdbGQXzm?P~p6YnH@Z>TW{_Hk}!HI*2BSG-h;4fi%Up+bD~t#u-5B=zhPh*a0?Uq5@uaI#oq z5{Y>kCh~d%1N46o@5UUF<0eyhywT;JA^@0+M;!Y@x7Sm|yKw34^eSq+r&u^#*Aq(! zLYW+TbSkZ2U;C|28V_c~TDvm4ZawU92v!UX8{rBmTfufx1*j~@b#VbqmatY#O3$xK zG%U_FR0t7O1*GUC&T%^+`JL*IO-(58aZ3Y;D4t6JrJg}Fa!i}!@B&;?RqBfkRW@TH zY&TlsJt!Q8b+CQ(or&lMJ%b6pPjDDlcZdkFSE&wSNVvMn{hohzx%nLV>M3 z=O+(X=8iPW&hZ1wD`U}+Le9DEZ+>Yfb|u0J!v@_TUd23%TG=BF7-^v4e|7hTU3{2-(V{|M>->61l|hQBE_aRg_gsE4-8G=sf&u3 zjD4oK#SmmzSqws!fJ$%z9~!~Rlbz{V`0-mlH*ns=<6qVKJPaK{&zm;ahv$1OHWSh> zSoo!G`KRrn)dBQp$z5#z1;Ul+5GlEl)&TWC$AVm-%mkzf0a3`@m#ou%~6{_itN!IFhXq z>uT_c1Q=PC`ZKj;9hf7)ow4S+x6x`jwMUMr!Y9CJ*Dg!!aoMC7gt=uT;=#wTN9_qDue#BHLg=YyW;Agrm z@OLMKCZ4cNLXIsUuq_3~VXZVk_1R0vou52Dsb$Q2z?9rFJZ!bW#Uy|_Mp33E)tE1Y z&$YXya!g%> z5>gQbZmP)d)#+Z1sI+ezA%u_fD-ES#g$W}caf5LG16C{&^*qM@*{%YKE^V$08S`z4 zhl#fTx=WdjlwjICvA}Ti1)mvYmzVh82y`%@|!Lz<9&>YQUvZRdRQbHgFCS(bpcFOowMv3lN96;?V@IX(@Nip04s>X z#d#3-vUql5L*&*?-r!c{b@qSG*(}pdN+7Ak6KvJR5{ANk>UNz z;(D^?aQr(%`tiht!T2dbgoo;ugcCO9n<|B7rF1XSL4h<+{*c&&G_!_rSWp;_jcXF} zx39RR+da|5HK{NPE_jMVz743PkfMizwCTogKh<7CZZw>RfS_1KR%n9U2_RCFI(Puc zfBhBf7hOptbLp)c8;xM*Mu&@~>FG9t?b7I`21pI^##?e`6OXZ|M3D=blS=Y9PsWUB z4y6J6v=eN2dpDxE%lZ+yT3sB7)x@ZglrS%qw5G8FJu$YQ^;WTab+65o;E}>in^vZ- zm>6DbU7Vg@NJvmagYdHz`2nO@MeCV<8W#rUds}A#goKk+@pkzp1eQ zE>-bGZZRLH7HOC@7@!{Ti3UUP!rs)y{RJBYb|`{?r}Mc|&-zX+_1XBn)p$Av!jGKcd3lHd9@es1{V7f?>-OEdq*xWMg0`T@cJ<2nuR;CPlM38=#=3Z3R zevml3Pp>WH^-C+QdP(whviz4+HHO%Pg0^de;4fT+3j$}GenCy zDkk+!nizCQ_M2kOJ(H>+dI{*6=e2vk-afV9*q6~>9Q-uDL?~myGUwr{|P* zjwKKv{jEJ!w?Md|8>ll`jno;?jmKQxwoZc zuF}vdcz{!BwCiP7j{u@~xql5*Yv04neLEO`CLpCK=})alS%T|31rl&vaiN30s(aZ% zdSc~fW*<3pw~08(8Evs-8Qn67k&f=Bef03IB(ghee2Ju^EW3x+Gb!P_(J;vD=`4-4L88h$3*QNEe$G;qaD;xp zloSppoF>4hG{`?l!t5j8C@j`yVzNP&W2NP>kop|z(s3eh8IKYCy(Mz(R2 z#KTBJTg!c#>bA+1SBGHif+;&P^SEj?Yt}lUc#VwRC#=G!o!hlXOf&W^o(SEt$%N&N zbQ}ruzv4KHJ25w65mmV~*b^^8zP^g;>O5WrYSpFyQ`Xll87}55DGi~&wRC?nuYvc; zwT4(`9g+48?nMKE2*^^_Hi@1oB9O#}wjXBM;conYJBafXQ83^xRBRA21Y;utT1;7n zAX6O;nEA;)!{1;@;e)nx^oT>41V$BHC#{qLn$<~vPUuz4SvMQ9Hl4gD5Lhl!p0=QK z6$+cr$_{;H)JS+In0Y@gh^`FG=zkcHCbdrTBs}Ue6Uqd? zOvew({i!pscOp7ioMsa6@>EguHf@0<>n7NBj7|xn1>)t<6be&_UYBqiJ#`_Om*oU|SU8ee?pIAI|ht&bfS7 zZ>J`@mMrV7p-^CtJfah(m0G7v`$QCfO$;BBR=4SKFbA7{0vi0!P(eP`sce80(WoF? z{lm!rNcO9nxQqq<1ro|RP$wi+Xm8NjxSN+~=+%Guz%#dC{{cl+-2@>2*m<8fT~${h zng`st@Sk0E8)Ex0q5qfa_Sl`gBR2(h)imOu8*U3mdM1A-5*$;}4Y-kKrDFB9{#9`6 z?-#0trwVQv*U#B>RGaKOWp~3}(bxe8@l-1SL35pzYSCU8f6a0jVHP_FeI%ImBcU_G zwqo|($yu4D{H~RR*g&jcW_5hi1S=TLn;z&QYqzB2KFYZO=(z{6NWE|o;wZU^P}wr( zu#Ik^xv76r>%EnxIzo`e#7oYC1KX^;NA+xWK6hPfsZ_k9io@s%j_daUh_#6lTz{mw zv65f|-lBz*@w7chK(3CGyxkd*rwcMam@9>%iP_Y|{<1QYC5ShH$W}{ZQe3v%7Q&`- zuj+WSdXHR}d*BKnD?#6=io)S5*(tB%8M8iIupIN}39w;U%z*yMpqYPZQ05=DIqYS$ zLlfMiQ6krl@^7F0iCc%RTT(|`=L4%UH*+pMBQ^0Gf3bBoL8{9%b7k&0xEDX4TqRE^ z<8VmRS=cDu453y55c4!uE-=xwnS^fR z9}yui=V*r{q%CW2dXS=Yt8�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 O|(7c4`>_!C^ri z7MEV@e*>D((evSQX-q%dg12lV+&I;w^E(4b+_K&r1ird-Y66S-$CoMoCLDQcN_FM; z&@f{!tyQ>OITdBS61Ydx0IzfbqrIVp(y#>CiuVhFmayVPqLN;1Bgss}S!;>kh>l80 z(`@rg8TyhNqfX6hOo$#Vg1^@u(9H-K44xO3{OyYa&^LLNV5zq&psO8bj4%NyCP?xk zg{d3TM$2s8wT4Uh*xGkk#9}k+L{Ns23ncTk9tzLTZXfY~V?G-x#Rgl8W zF>^&o`FZ)~*OqO^eSL@$J4?*Jp`=QoIDKvmO%^cRF8_{Edn<6D)IhV)6LPtn7M~ZU zH$E|ude#Gn?gbqE#9Ksburqfu-#|fAo1naPbXY*b;8e`4QH2V{?a6ws=Uu?5g7F!H*~r`rFfl7V{zv*0v;X-CP7@5YdodXs|)8uXq9gHQ6KLRhb zw9|~>rQNuFT|?4V^iKVYe74KDu#=wITIrVSOtq_4wzCuE^N7??Djhyhb!5Fa5yIm{ zo4yt2rvjEn*hqALLEX&p=RxW=q{BeNu6FYNZQUwS?eUhj!jjJ0R!4WbGwHgzzJeg{ zC}pTQy8`u(@gaJ{vw}A2-EMHf;LY&9p&pc)3%}7m)kNHEZF_oh;Fr+qw`!jdB^DR@ zf#3M7D=-4!;SI_hy@jG~;yOZhW&lKE8XSe1)GANvr>4WU#!!o2K9xe8C#MaS)Woz} zU8nB9+;#YsNY*5K?>jF@2vhXM*-K=Hhq5O>}Hpi7=aY)ez3k!9L)$fvqMzBnzJq$Iwhl)vgo$uexGwBGXeei@HDbu z_FO9Wp=|;=p##bgoBHk3lpd+fT05v88mAZMdz(e%d&9^4x%o3)Ugi!=UsJGW?x*{v z3|nFq>vPUnc36i97QUu=&qA=j?n3c0tXWRPuwhM+PkHunRZKQ<8GA$f#iAn*Y+0&_ z)#o%)48rp_286zclbhfiT5v=3mK^(X;=BAAd)4ykkGAUo?Mc58Hm0k_U4&$rpoSn+ zG-a*We~wo5REaO=WHkmiLBuXq+MHjSc3kC|%+~t`n6#WI5zP=|n)VzNex>%Qzo z%mXW|D!da##F(E5c?BSQrXI!uQsv3%#KaX2kvMsrsyPM-A;=kNV!*UFmD+o#3-UGe z{zHr*>=%dm2%reqdjYk7&z&6L{GKOW_h*39BOT5X9hmTx za~@gVDie?c$aHm+%NyRRXCF;zx2jjrbsIUfyt1tT1|^;JY(|9?XDtqv!?afMw_7iA z@IgT*ll2irN%?4f`-1p$?A6{mj!%=sCP+duw-W>H%zZ9rwA$rWN&>ZMvZ18&JO68n zW{fK?5dd#YFjV~tw*GDhg5%f?Zf((*UwkN-y#JQK;%ab<;*Frl&?@fWV()-VjPsO z?2i)>Y@YoFzYc8^eZ=V+Q8dI`NO~D_b$sr&eElBG3hbjVq)IOT(X>nZdBfb8F;p0n z*fz1UQue_M_P@%p-HkZm?Q!#QjO`hKOHZX7G$&8vHgU5lfBQ9AE?$psL&_9;f^k|Xt%<XdEV(g^VEtmDUpUspirfxyIbqEVA{k*Y^JEqw1W-HT<{8&D=$<0)y z>s1tI6QPWJoE{bMrbrKh?;w+o>!2fM+Yx_S83?lb>H5dm*U-~WLIVF>L6Zq)-CH68 zi}vtYMy#w$?U*}XL((4Ldo;nDrgm8Vfc26vG}GOuu?p(LuL{aqWp3E0<6(kiXkyk_ zK3GQku0{xDVm<~1nLELm0kT@6lLC24XIHnh;y0hHG5U_8zj-7MVg&53@94bk1r&70 z2peE}Z|=8U)jetn0+U}k4|)7az1jm{+>*FXhVX@{PKJFFM<-xk<5oGx5{z)*v7g}q z*^#$?%D=X^R`SHd)XOw&5w~b6#c8^YpO?oMpvH_svfZ-LNPTw|<-uV~_WC%p&)*OX z|J2@b|M9uh%jyZ5IMz})z7f#v>QJ7`N?@DO{4{PfzD_^OGM4MS7|MHMKSlRnNe z0~GA&!PP-P{uaxs7uSfzY%FSEn2cFp8bf%o2HfNff?7wUqWn^hooc02eyF6;b{%B= zK}bzoq~uLJhX)n*jVUFmO3GwQivoc{Q`o`qXfkj+0D~;4j2t(xu9nbqYh*7cT(_N{ z?Rs_3APHF{YX!2jW4@NB#EL*#vykr;9?Uc@0!)81rdzfij%d^~Vl=vWwK?^RvjX?& zHCb6Um5(Eq#dH4ax5t%dlH_>26v62LLhoP>elxJM_jH5NcQwA*`%ixiyHrW$O}o01 za`MTK->G?|e(tN>enqPcjxLD^XUQ8s1q|>w0l0{9{nE6adAG|DvQ_%pB~c|oX7plx zGU3M9h)|Bm!klZYVHqk=1`#=s4^-xQG`BA7BD3bWR<82~j`EcVSc!C50KY&tg`pD~j@ z6N)W(jZjNmR%Ol#hKRuHVQ2emIQfYMa21XhfHP|vBSd zGW=$OuesYNoMl@_D%N{RVTK4`tV#41qgKxtIUo%`L(7UjM!-XjDYrP?n=hbPF(AP& z$iX|amsaD%y#q5zaTHr9x7B?5cP@w7L3pk~zO|B8r*qkd_s{&dU_DDEAdaJJ%ajo+ zlZ|E6lqRrY0y2X@v1#Jz>Th3aIy_up8ce)|uqL8>gVndm3Ya35k|{~mOClLWkS+x8 zZ-y&a<#q)?YEV2}^w%;aq6!7h2c}OwdCU#1Bp$ zRp$HgUkD%v=L6{1o`Qs>|6(OxzEcoCcNnn9orHH?BXF_=I*Pie%`kJ+g7B?|z@hf+jqE&xf2xdWy%mXjH zld+G!3Ep{9E-m#Y-#OnxEkiXiBxv?nMm({%XG68&e8pz1!$*KgK`xuuKZ82+ zXtijCg4+TzA@#h?^#up-*S%0#%yJ9K&dVSXQXJ$dLT*t9YCKqA)A+GB&yy{bW9{(* zWKkrTPThBzsza;Ch=CwI|Fu8ghN2vKv55^BBq>->WaD*(8!og|9|{*8;uX(~t6U!k zSxP`_D~oR0LTdb6tzzU0#pBr?rZ=AQG0a4Sn-`N$ic|R1pa#ak?3nZk z&VbSd|HCU>CRSgGggzFoUcoY711Z!CjRAu8741JbI5v66Tek7gtCiHiBJPiSTv_T6 zmD`x_6WouwcIrX(_k5hj65Vp(|XPWg%6i}N*-F_2@)g?TCNXK+p=T!EZM~twYxns>67v3y(`iU2h>*U0TVq@$u0xgRBSLiUjasE0U_^WZ&LJIwY^S@tqC z>rh556SgK*i~THL1iW-aV}%U0k!stZG}hxK}f_9D>)cB9c* z?Cvc($DcjPglOhz`8n1M8XN@zlP0Pbk5$H8x771tP`KGtD$^&j#jz8u04UbW-LfLhYfD>Gi-eKDP1cu; z?qF2ypfkbIm=IvmDZgoJ*>N&~%&|Mew>oR6+MIqD&s)kPHR|VfqkT+Tr=_%=j0A4E zP6f+JIdAFCKA?wh1IEzO>6<64kxqNmgsrFJ(VuL9+Qo2)q4 z^97n=e}GKH`Dd}>$MJDwOuDhGWkgLR3xTa^1R{uBe^3FOoK&`(X> zi4!aX0)g@O;OWDQA3nwL1rdF9H2OTRJ-C_E6^?pGc56YO56~g0SGu2GYFLz0WDwggmue)Tlf4%fzn<8uHpdpWeKW2I{ zmpWP5m|@uAh|vj>AjDnUlM;mtv9t_>Cp#X%&{8zc=7s>u(TsR6j+3nV!E-t#jJGrchaaA^3vXEO4OIT}#Id#Ynf1CL*XPwm&Tn zf`PXYuKPq%5lEa=6Xp6KGOOV23a3DXSpmRY0>^D>Juv-0?NQ0jZ;X!W_2Kz^Co%B@wDokG z( zPnzKfirMX-0OBZ&uM7^FwC5qXm z1Q`r39XAAb|2&C_G~i8?Sut8xhqBd?f#R`0%xM6e8R21JYMYDJdu^2U<8v&_E#69b z<)sSv6t8k$?gC6Q&OyG1;ZZwdZt}yE<=%KrkGOg~BJJW@h-W-Ob{SE?1XZFe%zn0AOS$o{O%JVW>i#>B$ znk|~~H^er)e|O2DzB=>8^Wxs-nOve(zJge4Z8vHOj*Xa2{fkyrV`n4-Mj^qGo@Xv` zJSxO}DJ8c118h#x@JSN<=C^Rwckm%inrkO74d^kD2l$NgJ&~>qW2Y< z1-~%d+Q7tDF1w(A6`f;@R9e|>5EC2A5S12OC^10=sz2|MLW6=dH8ePChI^%QD$Sq^ zw?>8RjC6Pdl2U~%w%^N1#+R+3Vtk#ff+K3c2bLCBmDLn-AY?73-$Tyo?$klog zu;0%OT~$dJ4Xkb1B0MU=FtSSCIVFtSKPZPNO)GPyW`5R$x`m)@&q@qr{N`Po5rFD* zSov3XwC$MsrL3{^+)#b&)Bm_YmDf0V{Xh#(VBS$mH zkRx#z|Dv1#ys!;qhx&HeT5^!=10H&&B_$yQO2Z4OExiyDiWQdLnOZtlk>&}*>wT+@ zKt69&H~lVl0>BBc2IJ^V440{-K%Hmm?(4YR6l>wH^3tT;n&J{pdyMCN?ZDX zGs+{)h+uNvE`Bc`LqJAmev!-{qL`SOj>#b;DeL8hqrz%t#V>B1#;#HNFa6DR32=HDDMJ4{)q zxpS+3?7sCqnZrQ`xInDH_JTD+is{EgP3z>m>>b{z2$&50YHsW5k8Sh&@CmS4JFYGi z605m3sFaM2#t+d_x3f_xB!X3=i+Bgf3$K%s*!kHr*tV+z4jSOq7};vL$yuYzU)w@q z0Y(zy_g#72k4r-6^(EPNCxd7Tb}!DAbv=GG&b{mxS-C4~cjd|3#~~X82Ogb~p=acm zHWrz_r@ta(ZiQ=jdkp+S0@`)CrA7YWfw?G; zexYm2EVu7gRj{1oA6HJ~uSzh!)p97EYM&XpYz2<#xvXp25q7$lCBf>DF{CrAfI?n1 zKY8W37mn`?Rj`4I@O=(@Qp-E@ z6*@XW$giNB5&lP$sQW^)!9ZuZ)q}|y%`gE++%U2u1Us-v%BqbA;f_7X0ce}y%XI#Q zdpm@>$8AQga&RZtd7pI@&$i4WBTsK}c%wmnm271ly{|$wCsVwCXWp_cYHh3m-8)U~ zBpIGMS22BK*yp~E6A(xxbsBu5iE0kp9dvM8b=BO^IEf?3PX`_9kRRxD~T4Vi$JpP+Hb7nB?a z@)$~poFKhvSP9zWNq>i{&X3p`ORR7}T~Gq}+W^wBI@?cSqX0dpN-iXgOw6gt2fXi9 z0PY<>R&O}0TrGoVD6bVC@@*v*;wlyGb1U?^i1ezO1FY7UYbPv)AII$(A)4ookxGg* zp|<26KGQJ4w<*>h*ej!10NM4(Rxos8RA$%UBw60rF%=k1 zQXZWyZj<_<&jq2`u)REQl)tOei%U&@JP+le&8+4M%K~Q%E|{4!K^O zVldOrP%M1{3&-}vO|xKy^K$itLg%tT-NBx%$V_*dL$T7Ed;)K5_WD$(*5%W_u}wlm z4~bU{$f`<@0k$|v$4m^H!zD200Sd=@-(6z*X_Tk1-6%D6oDfJ+0#m*vWI`9v%opgn z9WRtiEfS3HnX6gQBtL$XoJyd?VA!SnAx;_;E#A&1rZdH$Gzil{pvq|CjdJ<&7G64w zZ1;H2Z|3Qo9V|rWJ`kkfFpI(7*8zGLX-ikzhC$V2zH+s__u=S5KgRD53d>6Pxo__U zL1?aI!+di8=1^9~p(l3hd7knQ>VC|rAj(nySVuGuoqz8VnpJCufV0^7wcie7nBmGu z*ir6Otv!#y(Ynnz`Vn8woI92&ytBHPPAYz!++(_H<&$NA#z}F3`kU&01yAL}e5e zIZN>v@(~?IjEplf>b)c!q05~VSfYjXBgO+_fBtYy-{k{1izBe*!bSJ68P#6UrWi5$jaK-f_38ikM zxYG<<8$w>aSDY7gM~@t6*QXXKi%fjAx;y^PfaBl^n9@v7nD;Y+Lg-R5n(ngxA!q>M zVSjOFUP8erO_GTM;VpNESm!6P(rk>-Li(eKyWnC2EjNaQjspB&9Y(0yN(S)a!2y13 zxBmayG!k?(7#yIssR5M1rz{8O7~u^k*Hyfw2Y3pLEdsA@5ds~Bgf$8hp4o#@_7QI~ z=t!#x#HFZ1R+1x>57Ei(IVt9$$3mLUgMfa5t-F73o}e*k8ZTL!N2EIlghZKUs-GLH zJd5hX>PlE_CKnmd7-;{Qm2Y4Ns zNe1PkzDO95x?;Thl^?|+UTUWcqqRWe>|iK>m4uKSBVKk;^)35`WrJSX*3K5O+;ara z)e_J4Yxep{U@-|k9~5wkn$X+^zehxJwZZZnHgc2 z+5Ay{f7}uySQNF{Ok8y@vwBp7!{k@nGw@x`v1R3OkAq2s1cxygVvtqpg@8oJ5mb_J zP@n6JdDeXoUh0v&?cxw9Q5^_Lkj^9RDY-Uto?q94gT8oqD&%LljvQAgE-S?mQ|?%j z)lzyl){MXGK(B;n_EUkbsSo*dQqQ+I^UhUf_*&w(YAb``cZzuk)l@xg13z!h1iL6f`b{~pa z*JQ=)^1Au1H<1ZNd{T^69U6G7K`^8?HEc6+RvJzrI?OMsL*-zeFd{C8b`&E-2#$Zb zNgQzpfBE{--mEr~hqUbjHgnOMYg>maxfFy>5gy^u0oN}KI!mw}c_mt5uXt35Rb0IUx(g|RBD z$EIKoGiL`3o^6l=PD`Un%t+cQ%@%t=ze7lEc7u@&oZQJBk zNO@DNn>L_|PFDLM$T=3jnI%ePPikqx)}2!+i153!iiR9vK%jPhK*Tm%KC!|M0KJD5 z=t=9D?2-Jd0JKV#na5V&-w~`3^CiOZ_WWYkuRa(aZvCnrBSqShZHU3H#D>k1IV9Q+ znOO5XDK)&@E0-X79^REOHWpyO-u_s|UhQ^w&+67xxY|73ju^szH7p zdsg%El-Mkaw^%GpS*{99Ow_qSx|$of-YFl&Lh z-VNH<8M5-TfOB-U(=NoE8u;is%%cH>1`*CiKB04TLQlZRw}X-WOG}$@Qj->PBJm{$ z*1e1j{pA`2dj>__Ow++1C?k3CZM%Qcg(4jWw^)Z<9i24&uA0OBVt)XAj=)Lm8oJy?!U%}P*CWFI z6qQ6`Q~8?-Ov63HM+G;xOuy8E&va@S06pfS<);K>8sE(;4%ppQPcLb(a==8C+z!f+Dv`<&T3B@DoHXhgZH80gb~}O$;DnMN1J6^QFj>a7n!pcU8^Z7y*W@{Sm6{d+*es_G)ZMRrBbP;wVLrFZQ@KcvZGuvcB8MiWG!KS&GxAA>E_ z^IAUFGWsVJYL;Ap7MyzmTQV&b6PT+8ueQPL>Rg<3EM@(b(jd6WJICQWsvMH54%HxN zp9gwuMRe4+ETzX9WHDT*A+oGTZC>aQ3TteM`vjq4v|R_?a?;ZTB^KdVm6K&g%Vl9g z2PiYFb2=Z&v49$E)stVq8Q4Zw-h^8}eY9bXP)!VqA;dlUII=y^#2j!`;vTt8Z+bA* z)KxA+nH>_RaU7F&-1^uOrVnQAbG14a%0tHrMaqa>TmzN=K1RZ;Z`bH55|`9MO6meg z$dgI9gggb@y&Pg|zEJ!BE;Kbv_ar^Q#0ku@I=FdcKit30oE;&$13oTU?@e$01b~r z-Et2A`hMl(XLZ6NuhDfk_S5@-*gFDW%zQmNL9zuVcdbZ;1yFf9Riy7x?LxFyRCw(x zbS1kl7tQ5$=XJ5xA=DfAU}|{2OK|zzyl5fZj zYo^U_82+U&CocNmvg<{LChn z*n05XkJm;kjj3~^s5(%J$E3|sYS>Mg5|gd;`?T<#UL4!@C>~1@pNU(tj&kEKxRAC= z#ty8?ZW-S6+mrY;v?8a!NpIp2;&a3S!V4??5B_roq!XWn=;6O=N4?c|6SqY|Sqr-Mf95ee6v4f_a&9dbsVHJL<7wV{;;Wc!=0)d(=wU1K^sSu6b=kkt6fi z=v+NUsV;1{EUt@EbZR0R6&rj;Tqay()(1%g@d`kqe(*>BrFDmSYtC2Zhz zzMkm(LU8=~RNALSb{mw!4053QCnBU677Tk5QV(P|XwCdAh8HTyA-Axe5TQ)(hJlg} zhk2|PWA-&nz(Z>6SOL06k37E^GJCQJkfm-6FVY`GbA0^;DpmCq1R5shb?l&UBwep+ zX?Q()NWaV!Kj}H!J#yf1!jUowjBbQ%iq_gn$z7tw5DE!0ubK4Ertn^& zoVgq#tL6PnAcXfy|P%iIYcnK~@S$QQmw^ z!SfL+*ep*6+4YU6OC5yymJz?=X1&}ygqQ)~eVIXwLk5lLOZM+EkvdzAt5{x-5u?g) ze)-%qd1JM?XiW5ULsbw;UPvjsT7J7>t2Flgov$_BF(VIMq7=}Ujs~rGGQo)qr~_s3 zU%a|@4x1?2+#x-TBbFsqTE=pcufT6_k;z5?i$yM2$-z$R=%(g^qKkY?id@}m1C93a z=BfsOGURW;S_p-qc!6AMh2x!IQrRo56T zRwT^6P3Xx`a94^^OSSxRa9`^xlgj8?((J;+Vu_jPmRu-DVuMMo=}KTdS$|Jou!>n%KpdNsZpXm9 zcK9g9b*x`yKjLkBXXuT}c&=?+%0*BpPw9;Zk5rUiXPQEW;S zfmoI+Ub?eb?GaS$07}9)tN%EYh&inw&}^rQ`FqJEwuL2T-}&QrBp?rO@QD1P^H67V zGr_%;)OPSpIe+@5m;JjK(NoGzoaGsN$vs}O7M(~x#ihU= z-+6Ta^HQ_j_JV^VxrHJvx=T0bC9l1c=m0+8`uBK<%5B0F32_Gz5kK(OIu3ycAEx+% z1}p)0QMCku!DB;(NM&Lz#;gCDE?a4o06h~F)I19X`*^$yFUfy@GqwkH7scsKoGhvF zmfu5xsHmLNuu~g3iAVxqvrQy-AK6C}=1V{rLKNrM_8DUpn`bWt?Hy0=bY6G(4MES( z6!|n0^Mdw@tSCdI7JLQxIH8!&7GNqqLAkc2Ug}L+IfyJKAB0X9=wV`DbG4=YFDtjS&^2*GoEJLfK&;2Zg9tZUYP#&;bd9$qN9`?LXh=bD|#_@&%s z-b)WbEN`Z#zbi#mmv$INZ}^PXq>C}Rwi(y6xojs`i&tVZh>&v`*ywq781KxGv8th; z8?_WkCOh(Y9Ut}!^Zd}l(}%)yrpGhOi^sufoRltR?%6bO=w z<&)%^5Un((zU}1Xmv$4D3k55ft1tFUj!QAw8c33BewYpTsVuXX=`Y`gY*t53R;Qu? z$O$!)5+Z7}4kO=^Z?^%U>k`?$;*z@)t$Zb7XS$+`Qk6AT{5cbz6KO=+<%ko87_3)~ z^0fw5H!bGL$${vw5X0>Sqy!EIh>85!De{|PvtHCuI(>4uV8hVeQ22SmP@c5K4BoT)`9~lUXqKDRxsq?%c`4(*cvD&V# zrR}v&5yu~R$n*S`f8ZD5ar>0w19yn+cZ$9u>dn`J!RRAVg#kD__%b8dBo^-BYm8GU zT|pn=N6KIn1_~B!J$Iu-;NZuHxkuEC!GR1L8i%ktjkCZs38 zL$Y&Ar)tPE-6?DSe*zPngW!2UZs{YD&)JNZtt0P@{dxu^V3m3NhjZxqp|*#n{y%%o zsWlXFRb=Yxy2@Eu!TdtY8fa3$^MSzBwP%NhCbUFR@+Bk?u^!EUQ|;L)S|45x z#8snHV8knS->>+AbdN*58>JP0l%Y19^Vb#;SZtx*G7!@y``8Nx-|nXp%|;;x#0lJZ zD<+I@GNHa+XIsYOlLQmD`FD4F?~_lTEDk&_9>9rC`9hwaY&@jTp7IcbQ(3QKdX96G zG2@IOzQ*)}f54vczvuu#ORr`X8oy%Y6Zz;-;Oc-Qe*ped>5j7$-4+@8zwBpL)Ah{F zjsKfbM{+%2wz7?Rg+S^yF!d}8tWUVp8K4^@WAL>A_?{lzs;h?db{eCXBCd=5#g=U=;N9 zTrz4=VyshS9xZF&3~#El5;kLisQcu4LYe1p{4XP{*J=!7yAcePVZ&gfbO=I?Ej&5S z%35E!?47%Gp=l8fQ6gFGcyuJf5}~N$D5^0sacIV&HZ!|g;{jej1`I2JFY%cU^;E|% zT|2+7!;}W%&sD^C?}QziXo@n{JY@|&pF1>7DWaI@dohRMGy;QL7T5Y*$L7sKy!~bT zoR*1i+lt;A>Z9;AY*gLUf7DoojD$5Mjr1ezdJdHef#n{>@0sbWU0{knAF=Y}xm2C( z_oIs3Y)bu=oJ(I|xnl;6S%|hd5Y3iC8E;XqBCKqYrw?t59Aw%zsHCpBkFS>a`7TtM z&x#3aKY-Y{sEn@@ZBq?DALZbsYf!wzU#Cvj>08%dI^O8KhV?Ub(a1KQiS8Tbs}buK zMa>^>$5mN$F#6LZ4&|(VC~H}sUet5Ga$H3g|G`W%BIKi)b}u=&>;$c*7GP_Q@lPcg_J7=rBWRt4sG2S#Ay&5MExRjln+(;h#9{fhCI8+ zEKyY20o5ROE!m_|rvuQfXWcGtiXZqxkaEaC_aFa=@dU5KiusHOj4q!1CuZ2n7(bAg zYKo{)0zS;#YQ2_AJL3z|&x9ajGh|<{=tt>%DbxMXf-8rJ`gT zNTinE_{u#HCaOR8T8vi}Zu2-~ouOe2`C)u4FoejxzW4Eb6)Nyk6Kt+ih$65^w+r=W zapM7;o?@MO5@6YxA~B=BXQiZz6tt85*o7?*cP4-G+Q6Phr}&xf!x!9gIHXl}p7k7Q z)57au&WYd9%~-wCn%I+;i+t|H&Q6Gb;4ZK^HoY~njNRTn->|plZw}t9<%NL|bjad@ zj4JKoj&qa=7t(@)HbYk zFKbh)-)(FEGk!wfr5n) z4#KMy#;O+Jcs;>56tA=|I|!t-e0;ucEb=a|ac1+w@P)zw$-HrrE5@-wMyLh}W@maK zgVz+q^O>*rGIE-!JJzpH_!Xuk572V1348(RAQNFw2aHb?I|cmO$Z=KdhG3`y>+;T{WaySv6>?GTAhMkt zqn<(RIblwnim=P@p7Ik=4|4f)1#`Hen@+hnKJz>}pd;?< zDTH+~b8htq^h=yK7oTfC&W#4OjitUdjBo5(1i*PqNEs<+X2UgrhfmHkp?i;0n2kTW z4WBc%%Ig)02J^dL=uzHq{8O`m_AWTeHGb0$K_HRUN5sED%|d0OTZXhvTu1`%4Wdm3 ze;Z}5^x<0yz_j^cK22ltdDpg#`Q}0FuGz}9TPADu@h=9%Op8Xdiz0T>V|djuExjjf zw3BUJMnl4=au8|gY=e^&1L@H6m=R+F$&W6AGEE*}**O5#0OY4Qi}s-fBvabU942t>4~XXXpD zac!MKP1bYGFFx7_{^BH&1P@Y`dy8ky&;t*w17{bw+D53jdkvzPS!b{wEbE5iLOHqZ zGYkwB=J#yo!|?J9@AvZxOwQjBg|8Gx8}F(PEDk)HW_v>yc)#H;uP&#E!O|Gfj9^ez|Y<1Ni*o zoqu`r77R29eW-g)h+@s!ZV~hpH$*LdP3QDDM;n~6z!O+Nqp^H8#d%9? zYd`I9%zkIZE90heP?dV4hYbG=sw2203uqSsjE138G^Q3j+~{hH44ms|Su~w=Uk$9< z4r2mnh6pN&=qeYQ<=k9fK^nU{VH7Z-Dw2U<^O6pMkLsK|y88qe3?=_!o1>Y=*16wRNi?`%(x{$5}l4 zjh!|=*70EJ%)82a>(PKETR?}jCF%wxBsB!u5~Miifkowi8)C;?g-K10dclQi~dJSxZs9nR?}!P<(d|Q`7&G_k(fUj3GPAY&zbJ zt#)4T3VSXnmk`0yKkloq0*SPzHxuxis$VfdXHaw!wOQegYpe~6sZwx$n}9v6d8v17 zy#i?`u{@O09$b7&CV?X2IIF)ds-Ry?2NWRhKvVkf!Vknf)>+6s+iJy2{rZO57KbXE z<&zP}vLGshV*-v6EK#7#no>3IVt4llN3NRX9uR3z*)}CP?i|03KQ08|d@-2^PG@D! z+BzN6^xj7ucDl?!&)pJ3Cc|%6Qe2Bnd%}GNg`}mn&L!>%XT?uXU+EWYPPT%&$j#8g zK1Ixy$`ShYEk77KWdF;6Zm%SZ@%C@)+~0*`d)f`$@HcZbm}u=rd;p*vNaS5tcj^jP zXD3vRlVxZx{X_2hJW+&S*Ui2hmkSxu%TEQF2vujbSyZVAd!e zd211o3_$j!_b&arJeA&+3{+mL$fjsx@E-YwzpO3oJ{a;eqcKf+`iuOG?`#VG?x_s# zka|iKjEDzaa9NTEK!~is5##ihc7GP`veTjV4@FQy`o2wS%}HXL4m)-6q*_lDKLI>9 zm#hSx&AwacV4T;u0sf&~ymi9{tUfC-^~{_|z)@Zj>w{HnnW)nPHHocMK`b{Z4g~Rf z)eWjM6AlRl<2Q|Co{2E6p1<^PBQIvrfMsWK_1rX%vFg|!=&@+rA?zg)bgWb?m9$tq zmNUHW+4KAOc`l$}s?(EYr#r81NIOVO;ymYZF#F zZ1qDnSSmSc{%G>-8AQZeD!T5{KStn7{oE&T&MqAHw6fNmbJHY(UQv$he+2Y17QB_& z`MkCd*AH(fB2;~5w6 z2;r;;NYwW~I;=~%5a7F>M3-`B65a=|IOjZKUo?;Wi(k@xuPPOPcm(2b%sevo$#FJt zqy@SXRgw^;wIpiU1Rty5>+gN-a-&xlNQWhxdiG;i0<{uaKj>gu7P|pbUekv6&dDMe zEy3O9@qk$6GDja56_595E4p6l)?UuWQNt(|t!^ME%Vw_!6DqjIgB4RK81Be^2F<{K zz==lQ&rVZ5iguaa*n(z{d&2u_y&i!z7)UI)bWo8w%54-*qxv{&FVW5o92WMvOi`Ss zmote57G5SZcjs;0OdNZq4F$(Mr3NhKk{O20)g7({mKu zh`#KZ4ps|0HeP=hi@vU4*a$Rl)b(9d$4`4th?AHREYp9HiK%GrBAW0XEKui*Y@>6! zta7A}75Eq@D}e@GG02yKoxGN{QA@Y7s> zJ^RdY@7%h|3}!ydrOxiU-tWvKlaG@yJG0cGW-{D*<97m9hrNl=BNsIiNWzBQQm-K< zHXPLdeG}b06N1$Wc>QzOgvN|O2r4$HOe3?l~4hH~6y;XJ70wTi^BT&#=a6_M%DFds=!d%#q%6 z!x}Kem|QbzY06;UX4bb zh5LKTkF5*ug3Q{b!l!SF-La^<9AZUwXIJVE{1bIh=pygop)0?3ui(CJqj+GK)C*B9 zQ(;4ew1`C}3xbtEG_19+DWkbq>D{dKr_HynCH1{!FOfuXTOap#TlVCGLFvdnR?msb zu-h0LDGLo{6{j?gZp-56p&MQ{efFGF8Wzb@XEs{x?Dw%bt4i zj@PV2@3J>-l_QWzW6GHUk|Op@;Mm`H?4u=F3u@k3ftmD~1r2b&uuQCg;`~w9F4VN# z<%D!$dF1#Xs0a}@gRDh}4p$@_!VG{eEUxM#7wNqJHGZ^|9aMawUdXJLeTu#%2H3TIOgBi;7QP*a;4G*I865Ia&Ek zVk5~sHFp$gnsqQ7y~T*f7y*4jv-CyiJ47kkY~|hoF}b@t5X$^k6!22$`$^t*jkk4d z9~L2(ufH-@NN02Km8OQet_9Spzi&qjS!M?~*k*F6ViTZfCP}y`%nw2D(B3*ch`Ju* z!;;-C45yKS8eTCN$iYF$lVpOPhq0s56lEp+4D=Z2B0;?>swFz2YhlrA$@6wd{WH-~ z0|s1@n*q1-AMi;?kCD0}7EK8iJ^pgqFP|3q1(Cwu%>AKDM~)j$u8Ur-n8R#2UM^!u zt8C0uE*;I&=*x3T`C739blRZzX^u_SQ2wBZ9-xs{UW+CIiqzYxL@#5$v!N7S2DLUs z=^w3V&NN1n@*3MwRx>)Z9Mpl9K_T`BztUm6bwImsu1ZZ8qtfI^ELS%je~yYRYYs)^ zAzZI4E+?@J6;uP8f>A977GWi2#Fkj2=>xAFx>F$Icj z?OCQ7#U1Hf!z_=t;=z|6Z&vdU zZj+LGH-OoANWSlX$h2ts3*PQ1F49A%ZZVHkXY|j^y%k&*RBq=YBHzR4F!~`=GT<8Q za0N|i{d|1)%UI=&2303cHH-jZG!4F-k2u+gdA2UH^%IRF-!q<~( z!8gdX>C(jNHsT{z`)&mSuevw>>M|R0>@`G0>30@#T;hNkLmY22vyd8Qr6HJ&aMdfiG)J;5A*w8JYfw^f@QAH65?0Vikj&^0A=FBowAsntTz>H8w&WIL75v}e172cknjJY@e*()IIRpukZrQ{W8Vcr{%e}Gd+^~>M+b&Qj zR;IEHDK}M5*0qQD-OPbl6Kf>pT0-S<%w~QX z6q>i75xXhh!CxVIs;63T?U;bSWgVmBpEGstVKxwFqnWcI43B49R9Hf+NUhFQTUwpD zBryFGeDlY{&YRtFvb$17b_U3Mh;$8cC8D$Q5UP(mu-?ulmkR?{$K3H8WtS=l%xNvv z-<2rKnAsL;F4BIWs03iFf(6M=tJpm{QuTX~ZxsJ`FIFw`5S9FdegsU)&>Hbe0JM&l z6^nS;In=WOzhI_r@IMRyo@uMG?R&rkNJf2oom=>{|D`oA8B%@>n{S#{eS@wFqVFdd zqlm2Q74&U8ewmz>!wuYY#$(FkiDRDaf~Jual2XfJZ&!m%nT8wETrdhV>Ul-T=8AlI zb0=ZKDi!Sxo516GE>akN0=Aaqy@ zx};+dQp5LTX)RBSIQMSuJnjhjSBNfX`!RA(z^I-+`JH%lpJ-9>Q(>LLO#koh5K0L4ur<9xX!8bKF1>$n!0U z>jHxT>CQ#E4$>PZ!{%&^ed67|y!SXE*FWBX8#yU*xv{nu9ayky3LM7A01wmkgf>By ziK>m353}-@>jh1|F0D6bm1v6O2JL6QD=0!;^SOP7UQ(n_+$Jd!JUp+f57k(*1Kjh% zwTxjYZjbt}5ix>e@uQ`PQD9BVmR_V?}Vb>}gnGbb$)?liE^MRN@nP1(ed|#F&G1|R38*x8 zxtZY&s{Zyv_=P+isCjsVz+`Uq$^1wexm9Mx?}A(kw7S`b`1vR=4`Vh1=CW!!aEqv- zI@K-gkk!A-$8Q1%27PDbpksf{5qb0hEvQ9XJ5DNb@kqHz4AgD8k!t`9UmVUCOkV@1 znH?Dcp_cg|%%mq5AeY*ab)l1~pQN-H+B4*wOh~@hj!t0M!FiY%cZ!&0Rs3h<;hsGh@MSRtg0)S%;493g%RYG_-m1X9`6sHTO%^G!*uhn9`ddhJ>IL1*TOF zuDV&6+@_(JgeaF$_&>T1O}gTC4GP!(LnZFX$G(A0_eI3^EOj71oP~U7ygNa7Ol~%u zJdi*87YRUEGK)%9f%+rocL4fk8f$U2_=tYn6Kh;QARao$Cqv1+&d^TBRE2$y8hc$p$A z2U{GG)V((uY>{AxZ*_-J#8!`3k`la+*@qlM*_t72{I`)9gv`T@pL~p|OwIn^c5mp-r z%kWt9P!wdAe{k4cLUDOcIP0!LYLf;gPj^oII zBaZd__tnqaRzv7LHf>{sBOhACB8cpXf&tS~e4{pGh}fyc?sR!&9ihLuvL6RJOQkT! z^I_tRrX5flsy!)E=Gls`(p`+e_x?Nr5(YW`d3hY?NUsZv(6KIqdoCu0!oCl?iK(0U z6%<`!SL=HfXAx|+#%Y|b$H z2|5|@4Pr!%pw}o(dVA>M=m=E7HhLW9Ehx( zwKRmjLeFIa$F0DYbI;z$Y*^@|DmVtXdArD}CGZBwo4Nt^Bk^ypr-O-;)h7>Jeu(gZ|n8284C=6=2FO3`A8l=yM6w|DFvP zq^zRgPg|L&d8TnA&EQ!fH$$GauYcca9QXB(+|vNqV~@7db+CP=zH<);GY1X!B%muR zbFJU(@IF z&)O05o3sCksi5_cBU3=n%+<=}Q002`)$L9d&P#-cdrO8Ne<}y7Z7{8jUVRFiqs_AR zegI`xp{i}`zb*ksKw?Y)0001IGoxX&S!<8*pHZFzWi#bqo^WBMB4!32h5<;q#|3Zz a0mE9dz000003RzmU%@`8^ diff --git a/rpm/telegram-cli-build-rpm b/rpm/telegram-cli-build-rpm new file mode 100755 index 00000000..80fb13d8 --- /dev/null +++ b/rpm/telegram-cli-build-rpm @@ -0,0 +1,16 @@ +#!/bin/bash +VERSION='latest' +BASE_DIR=$(realpath $(dirname ${0})) +cd ${BASE_DIR} +./clean +if [ $? -ne 0 ]; then + echo 'Could not clean rpmbuild build directories. Check log!' +fi +rpmbuild --define "_topdir `pwd`" -ba 'SPECS/telegram-cli.spec' +if [ $? -eq 0 ]; then + echo "Your packages are available at $PWD/RPMS." + exit 0 +else + echo 'There are errors. Check log!' + exit 1 +fi diff --git a/telegram-cli.spec b/telegram-cli.spec deleted file mode 100644 index c187dc37..00000000 --- a/telegram-cli.spec +++ /dev/null @@ -1,46 +0,0 @@ -Name: telegram-cli -Version: Beta -Release: 2%{?dist} -Summary: Private fast and open platform for instant messaging - -Packager: Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) -Group: Internet/Messaging -License: GPL -URL: https://github.com/vysheng/tg -Source: master.zip - -BuildRequires: lua-devel, openssl-devel, libconfig-devel, readline-devel, wget -#Requires: wget - -%description -Telegram is an Open Source messaging platform for mobile, desktop focused on privacy. - - - - -%prep -[ -d %{name} ] && rm -Rfv %{name} -mkdir %{name} -cd %{name} -wget -O master.zip https://github.com/vysheng/tg/archive/master.zip -unzip master.zip -cd tg-master -./configure -make %{?_smp_mflags} - - -%install -cd %{name} -cd tg-master -%{__install} -D -m0755 telegram %{buildroot}/usr/bin/telegram -%{__install} -D -m0644 tg-server.pub %{buildroot}/etc/telegram/server.pub - -%files -/usr/bin/telegram -/etc/telegram/server.pub - -%changelog -* Tue Feb 4 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) -- Add server key to /etc/telegram/ -* Sat Feb 1 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) -- Initial SPEC file From 628abe1e77827eed5c9dfca7bb1e1f5f5c19fa0a Mon Sep 17 00:00:00 2001 From: gomayonqui Date: Mon, 25 May 2015 20:29:30 -0500 Subject: [PATCH 015/164] Fix overflow destination buffer error on yosemite --- Makefile.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index e1989abe..cf459cb7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ 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 -Wextra -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter -fPIC -Wno-builtin-memcpy-chk-size EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ @OPENSSL_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} @@ -53,4 +53,3 @@ ${EXE}/telegram-cli: ${TG_OBJECTS} ${LIB}/libtgl.a clean: rm -rf ${DIR_LIST} config.log config.status > /dev/null || echo "all clean" - From e4ff0b20724267cd79ccd5947fce092149f5fc40 Mon Sep 17 00:00:00 2001 From: "E. Bosch" Date: Thu, 13 Aug 2015 01:21:51 +0200 Subject: [PATCH 016/164] Added on_msg_history to lua --- README-LUA | 1 + interface.c | 6 ++++++ lua-tg.c | 15 +++++++++++++++ lua-tg.h | 1 + 4 files changed, 23 insertions(+) diff --git a/README-LUA b/README-LUA index 3ef81653..96e33d5b 100644 --- a/README-LUA +++ b/README-LUA @@ -9,6 +9,7 @@ It should have several functions: on_our_id(our_id) - Informs about id of currently logged in user. 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). + on_msg_history(msg) - it is called when a msg from history is printed. on_user_update(user,what_changed) - updated info about user. what_changed is array of strings. on_chat_update(user,what_changed) - updated info about user. what_changed is array of strings. diff --git a/interface.c b/interface.c index 9467dd14..f9bfbbf0 100644 --- a/interface.c +++ b/interface.c @@ -2003,6 +2003,9 @@ void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int nu if (!enable_json) { int i; for (i = num - 1; i >= 0; i--) { + #ifdef USE_LUA + lua_list_msg (ML[i]); + #endif print_message (ev, ML[i]); } } else { @@ -2010,6 +2013,9 @@ void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int nu json_t *res = json_array (); int i; for (i = num - 1; i >= 0; i--) { + #ifdef USE_LUA + lua_list_msg (ML[i]); + #endif json_t *a = json_pack_message (ML[i]); assert (json_array_append (res, a) >= 0); } diff --git a/lua-tg.c b/lua-tg.c index 592df608..d086dd5c 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -550,6 +550,21 @@ void lua_new_msg (struct tgl_message *M) { } } +void lua_list_msg (struct tgl_message *M) { + if (!have_file) { return; } + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + lua_getglobal (luaState, "on_msg_history"); + push_message (M); + assert (lua_gettop (luaState) == 2); + + int r = ps_lua_pcall (luaState, 1, 0, 0); + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } +} + void lua_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) { if (!have_file) { return; } lua_settop (luaState, 0); diff --git a/lua-tg.h b/lua-tg.h index d7bfc02f..94f0a13e 100644 --- a/lua-tg.h +++ b/lua-tg.h @@ -24,6 +24,7 @@ void lua_init (const char *file); void lua_new_msg (struct tgl_message *M); +void lua_list_msg (struct tgl_message *M); void lua_our_id (int id); void lua_secret_chat_update (struct tgl_secret_chat *U, unsigned flags); void lua_user_update (struct tgl_user *U, unsigned flags); From 4f4efe8bd1c501481a5e956c4abecfa53458634a Mon Sep 17 00:00:00 2001 From: "E. Bosch" Date: Fri, 14 Aug 2015 21:07:15 +0200 Subject: [PATCH 017/164] Fix typo in log print of callback --- python-tg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-tg.c b/python-tg.c index 09885f38..f8e9afd2 100644 --- a/python-tg.c +++ b/python-tg.c @@ -296,7 +296,7 @@ void py_new_msg (struct tgl_message *M) { PyObject *arglist, *result; if(_py_new_msg == NULL) { - logprintf("Callback not set for on_new_msg"); + logprintf("Callback not set for on_msg_receive"); return; } From bf1878ae3e538fdce4fde90ce01793287660608a Mon Sep 17 00:00:00 2001 From: "E. Bosch" Date: Sat, 15 Aug 2015 00:14:01 +0200 Subject: [PATCH 018/164] Added on_msg_history to python --- README-PY.md | 1 + interface.c | 6 ++++++ python-tg.c | 27 +++++++++++++++++++++++++++ python-tg.h | 1 + 4 files changed, 35 insertions(+) diff --git a/README-PY.md b/README-PY.md index 09ae1bb6..bf14ffed 100644 --- a/README-PY.md +++ b/README-PY.md @@ -20,6 +20,7 @@ Assign python fuctions to the following tgl attributes to set callbacks from TG. |`tgl.on_get_difference_end()`| This 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)`| This is called when we receive new `tgl.Msg` object (*may be called before on_binlog_replay_end, than it is old msg*).| +|`tgl.on_msg_history(msg)`| This is called when we receive a `tgl.Msg` object from a history printing.| |`tgl.on_user_update(peer, what_changed)`|updated info about user. peer is a `tgl.Peer` object representing the user, and what_changed is array of strings.| |`tgl.on_chat_update(peer, what_changed)`|updated info about chat. peer is a `tgl.Peer` object representing the chat, and what_changed is array of strings.| |`tgl.on_secret_chat_update(peer, what_changed)`|updated info about secret chat. peer is a `tgl.Peer` object representing the secret chat, and what_changed is array of strings.| diff --git a/interface.c b/interface.c index f9bfbbf0..16525478 100644 --- a/interface.c +++ b/interface.c @@ -2006,6 +2006,9 @@ void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int nu #ifdef USE_LUA lua_list_msg (ML[i]); #endif + #ifdef USE_PYTHON + py_list_msg (ML[i]); + #endif print_message (ev, ML[i]); } } else { @@ -2016,6 +2019,9 @@ void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int nu #ifdef USE_LUA lua_list_msg (ML[i]); #endif + #ifdef USE_PYTHON + py_list_msg (ML[i]); + #endif json_t *a = json_pack_message (ML[i]); assert (json_array_append (res, a) >= 0); } diff --git a/python-tg.c b/python-tg.c index f8e9afd2..3b5b8a2d 100644 --- a/python-tg.c +++ b/python-tg.c @@ -102,6 +102,7 @@ PyObject *_py_binlog_end; PyObject *_py_diff_end; PyObject *_py_our_id; PyObject *_py_new_msg; +PyObject *_py_list_msg; PyObject *_py_secret_chat_update; PyObject *_py_user_update; PyObject *_py_chat_update; @@ -314,6 +315,30 @@ void py_new_msg (struct tgl_message *M) { Py_XDECREF(result); } +void py_list_msg (struct tgl_message *M) { + if (!python_loaded) { return; } + PyObject *msg; + PyObject *arglist, *result; + + if(_py_list_msg == NULL) { + logprintf("Callback not set for on_msg_history"); + return; + } + + msg = get_message (M); + + arglist = Py_BuildValue("(O)", msg); + result = PyEval_CallObject(_py_list_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; @@ -1190,6 +1215,7 @@ 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_msg_history", _py_list_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); @@ -1245,6 +1271,7 @@ static PyMethodDef py_tgl_methods[] = { {"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_msg_history", set_py_list_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, ""}, diff --git a/python-tg.h b/python-tg.h index bc724eab..5fba58bf 100644 --- a/python-tg.h +++ b/python-tg.h @@ -27,6 +27,7 @@ // Python functions void py_init (const char *file); void py_new_msg (struct tgl_message *M); +void py_list_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); From e67856f409e9e3745a7a9a7b37915d1a1e04be4f Mon Sep 17 00:00:00 2001 From: javadib Date: Thu, 10 Sep 2015 15:11:02 +0430 Subject: [PATCH 019/164] Fix tgl_Peer_getname if user account deleted, raise exceptino when read name attribute --- python-types.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/python-types.c b/python-types.c index da3cd5a2..87e44d3f 100644 --- a/python-types.c +++ b/python-types.c @@ -76,22 +76,31 @@ 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); + if(self->peer->user.print_name) + ret = PyUnicode_FromString(self->peer->user.print_name); + else + Py_RETURN_NONE; break; case TGL_PEER_CHAT: - ret = PyUnicode_FromString(self->peer->chat.print_title); + if(self->peer->chat.print_title) + ret = PyUnicode_FromString(self->peer->chat.print_title); + else + Py_RETURN_NONE; break; case TGL_PEER_ENCR_CHAT: - ret = PyUnicode_FromString(self->peer->encr_chat.print_name); + if(self->peer->encr_chat.print_name) + ret = PyUnicode_FromString(self->peer->encr_chat.print_name); + else + Py_RETURN_NONE; break; default: PyErr_SetString(PeerError, "peer.type_name not supported!"); Py_RETURN_NONE; } - + Py_XINCREF(ret); return ret; } From b74be69c053e9464888ac32735138509b7edf817 Mon Sep 17 00:00:00 2001 From: javadib Date: Thu, 10 Sep 2015 15:45:57 +0430 Subject: [PATCH 020/164] Update README-PY.md --- README-PY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-PY.md b/README-PY.md index 09ae1bb6..42f2d67f 100644 --- a/README-PY.md +++ b/README-PY.md @@ -32,7 +32,7 @@ As mentioned, all methods and functions have callbacks. The following are the di |----- | ------------------ | ------------| |empty_cb|`(success)`|This just indicated the success of the call. All other callback types have this as well.| |contact_list_cb|`(success, peer_list)`|`peer_list` is a list of `tgl.Peer` objects| -|dialog_list_cb|`(success, dialog_list)`|`dialog_list` is a list of dicts, with keys: 'peer': `tgl.Peer`, 'message': `tgl.Msg`| +|dialog_list_cb|`(success, dialog_list)`|`dialog_list` is a list of dicts, with keys: 'peer': `tgl.Peer`, 'unread': `bool( Determine whether has unread message)`| |msg_cb|`(success, msg)`|`msg` is a `tgl.Msg`| |msg_list_cb|`(success, msg_list)`|`msg_list` is a list of `tgl.Msg` objects| |file_cb|`(success, file_path)`|`file_path` is a string with an absolute path| From 951f807837581975bfeb55e5027ff4d20acda715 Mon Sep 17 00:00:00 2001 From: javadib Date: Thu, 10 Sep 2015 19:45:48 +0430 Subject: [PATCH 021/164] Fix MarkRead. --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index 418f81be..e22b5c06 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 418f81be448fdebb04c3809795f8c160ee13280c +Subproject commit e22b5c061286e970f5a8501e19a66ac199317913 From 4c97ae95a9c72fc9558d574ec85a204197f3e309 Mon Sep 17 00:00:00 2001 From: Frank Dietrich Date: Thu, 3 Dec 2015 16:26:14 +0100 Subject: [PATCH 022/164] update dpkg build dependencies --- debian/control | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index ecc7fc58..3eff7ea0 100644 --- a/debian/control +++ b/debian/control @@ -8,10 +8,12 @@ Build-Depends: debhelper (>= 8.0.0), libreadline-dev, libconfig-dev, libssl-dev, - lua5.1, - liblua5.1-dev, + lua5.2, + liblua5.2-dev, lua-lgi, - libevent-dev + libevent-dev, + libjansson-dev, + libpython-dev Standards-Version: 3.9.5 Homepage: https://github.com/vysheng/tg Vcs-Git: git://github.com/vysheng/tg.git From 261a5e5f0df0dcce73c4a917d6855044abf1b0d2 Mon Sep 17 00:00:00 2001 From: Fabian Schlenz Date: Sat, 5 Dec 2015 12:22:24 +0100 Subject: [PATCH 023/164] Having on_loop not defined in a python scripts leads to an error message saying on_chat_update is not set. This one took me a looooooooong time to find. --- README-PY.md | 1 + python-tg.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README-PY.md b/README-PY.md index 09ae1bb6..722a10c5 100644 --- a/README-PY.md +++ b/README-PY.md @@ -23,6 +23,7 @@ Assign python fuctions to the following tgl attributes to set callbacks from TG. |`tgl.on_user_update(peer, what_changed)`|updated info about user. peer is a `tgl.Peer` object representing the user, and what_changed is array of strings.| |`tgl.on_chat_update(peer, what_changed)`|updated info about chat. peer is a `tgl.Peer` object representing the chat, and what_changed is array of strings.| |`tgl.on_secret_chat_update(peer, what_changed)`|updated info about secret chat. peer is a `tgl.Peer` object representing the secret chat, and what_changed is array of strings.| +|`tgl.on_loop()` | This is called every now and then.| Python Callback Signatures ========================= diff --git a/python-tg.c b/python-tg.c index 09885f38..d267bfb5 100644 --- a/python-tg.c +++ b/python-tg.c @@ -397,7 +397,7 @@ void py_on_loop () { PyObject *result; if(_py_on_loop == NULL) { - logprintf("Callback not set for on_chat_update"); + logprintf("Callback not set for on_loop"); return; } From 7ef685fd2a546d2dbf2e61750d84a845823fcb82 Mon Sep 17 00:00:00 2001 From: imandaneshi Date: Mon, 7 Dec 2015 22:56:30 +0330 Subject: [PATCH 024/164] Updated tg for teleseed --- lua-tg.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/lua-tg.c b/lua-tg.c index 592df608..0e739ad0 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -645,6 +645,7 @@ enum lua_query_type { lq_send_file, lq_load_audio, lq_load_document, + lq_res_user, lq_load_document_thumb, lq_delete_msg, lq_restore_msg, @@ -654,7 +655,10 @@ enum lua_query_type { lq_status_offline, lq_send_location, lq_extf, - lq_import_chat_link + lq_import_chat_link, + lq_export_chat_link, + lq_block_user, + lq_get_message }; struct lua_query_extra { @@ -914,6 +918,40 @@ void lua_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tg free (cb); } +void lua_link_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *link) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + lua_pushstring (luaState, link); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = ps_lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + + + void lua_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_secret_chat *C) { assert (TLSR == TLS); struct lua_query_extra *cb = cb_extra; @@ -1242,6 +1280,10 @@ void lua_do_all (void) { free (s); p += 2; break; + case lq_export_chat_link: + tgl_do_export_chat_link (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_str_cb, lua_ptr[p]); + p += 2; + break; case lq_send_location: if (sizeof (void *) == 4) { tgl_do_send_location (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id , *(float *)(lua_ptr + p + 2), *(float *)(lua_ptr + p + 3), 0, lua_msg_cb, lua_ptr[p]); @@ -1250,6 +1292,20 @@ void lua_do_all (void) { } p += 4; break; + case lq_res_user: + s = lua_ptr[p + 1]; + tgl_do_contact_search (TLS, s, strlen (s), lua_user_cb, lua_ptr[p]); + free (s); + p += 2; + break; + case lq_block_user: + tgl_do_block_user (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); + p += 2; + break; + case lq_get_message: + tgl_do_get_message (TLS, (long)lua_ptr[p + 1], lua_msg_cb, lua_ptr[p]); + p += 2; + break; /* lq_delete_msg, lq_restore_msg, @@ -1340,6 +1396,10 @@ struct lua_function functions[] = { {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, {"ext_function", lq_extf, { lfp_string, lfp_none }}, {"import_chat_link", lq_import_chat_link, { lfp_string, lfp_none }}, + {"res_user", lq_res_user, { lfp_string, lfp_none }}, + {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, + {"block_user", lq_block_user, { lfp_user, lfp_none }}, + {"get_message", lq_get_message, { lfp_positive_number, lfp_none }}, { 0, 0, { lfp_none}} }; From e039351082d5cc791566b0a01a475661b68e13db Mon Sep 17 00:00:00 2001 From: Yago Date: Tue, 8 Dec 2015 21:31:13 +0100 Subject: [PATCH 025/164] resolve_username in lua --- lua-tg.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/lua-tg.c b/lua-tg.c index 5f430a4e..835ce38d 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -715,7 +715,8 @@ enum lua_query_type { lq_channel_invite_user, lq_channel_kick_user, lq_channel_get_admins, - lq_channel_get_users + lq_channel_get_users, + lq_contact_search }; struct lua_query_extra { @@ -1135,6 +1136,38 @@ void lua_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char free (cb); } +void lua_contact_search_cb (struct tgl_state *TLSR, void *cb_extra, int success, tgl_peer_t *C) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + push_peer (C->id, (void *)C); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = ps_lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + #define LUA_STR_ARG(n) lua_ptr[n].str, strlen (lua_ptr[n].str) void lua_do_all (void) { @@ -1360,6 +1393,10 @@ void lua_do_all (void) { tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 100, 0, 0, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; + case lq_contact_search: + tgl_do_contact_search (TLS, LUA_STR_ARG (p + 1), lua_contact_search_cb, lua_ptr[p].ptr); + p += 2; + break; /* lq_delete_msg, lq_restore_msg, @@ -1465,6 +1502,7 @@ struct lua_function functions[] = { {"channel_kick_user", lq_channel_kick_user, { lfp_channel, lfp_user, lfp_none }}, {"channel_get_admins", lq_channel_get_admins, { lfp_channel, lfp_none }}, {"channel_get_users", lq_channel_get_users, { lfp_channel, lfp_none }}, + {"resolve_username", lq_contact_search, { lfp_string, lfp_none }}, { 0, 0, { lfp_none}} }; From 2284d7874859d121bfad9b66c67d29a2facebefd Mon Sep 17 00:00:00 2001 From: Yago Date: Wed, 6 Jan 2016 13:10:28 +0100 Subject: [PATCH 026/164] get_message Lua function :new_moon_with_face: --- lua-tg.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lua-tg.c b/lua-tg.c index 0529d1a6..6832a11d 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -719,7 +719,8 @@ enum lua_query_type { lq_channel_kick_user, lq_channel_get_admins, lq_channel_get_users, - lq_contact_search + lq_contact_search, + lq_get_message }; struct lua_query_extra { @@ -1400,6 +1401,10 @@ void lua_do_all (void) { tgl_do_contact_search (TLS, LUA_STR_ARG (p + 1), lua_contact_search_cb, lua_ptr[p].ptr); p += 2; break; + case lq_get_message: + tgl_do_get_message (TLS, &lua_ptr[p + 1].msg_id, lua_msg_cb, lua_ptr[p].ptr); + p += 2; + break; /* lq_delete_msg, lq_restore_msg, @@ -1506,6 +1511,7 @@ struct lua_function functions[] = { {"channel_get_admins", lq_channel_get_admins, { lfp_channel, lfp_none }}, {"channel_get_users", lq_channel_get_users, { lfp_channel, lfp_none }}, {"resolve_username", lq_contact_search, { lfp_string, lfp_none }}, + {"get_message", lq_get_message, { lfp_msg, lfp_none }}, { 0, 0, { lfp_none}} }; From 9e14543c8ac4f9dd72567e09889d3ebf223b4f66 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 8 Jan 2016 15:31:10 +0100 Subject: [PATCH 027/164] Fix crash on unsupported media received --- interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 47b9bcf8..644b4653 100644 --- a/interface.c +++ b/interface.c @@ -3443,7 +3443,8 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { default: mprintf (ev, "x = %d\n", M->type); - assert (0); + M->type = tgl_message_media_unsupported; + break; } } From 03ecdb610b97e382ce2b835937efc154f8da0e25 Mon Sep 17 00:00:00 2001 From: Yago Date: Fri, 8 Jan 2016 23:16:28 +0100 Subject: [PATCH 028/164] Add inviter in members table --- lua-tg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lua-tg.c b/lua-tg.c index 6832a11d..2324ab8b 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -144,6 +144,13 @@ void push_chat (tgl_peer_t *P) { lua_pushnumber (luaState, i); tgl_peer_id_t id = TGL_MK_USER (P->chat.user_list[i].user_id); push_peer (id, tgl_peer_get (TLS, id)); + int inviter_id = P->chat.user_list[i].inviter_id; + if (inviter_id) { + lua_pushstring (luaState, "inviter"); + tgl_peer_id_t id = TGL_MK_USER (inviter_id); + push_peer (id, tgl_peer_get (TLS, id)); + lua_settable (luaState, -3); + } lua_settable (luaState, -3); } lua_settable (luaState, -3); From c20d7575b7a8623b97c70315dab8c842e01eb5b4 Mon Sep 17 00:00:00 2001 From: Rondoozle Date: Tue, 12 Jan 2016 19:15:11 -0500 Subject: [PATCH 029/164] Added unblock_user function to lua-tg.c --- lua-tg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lua-tg.c b/lua-tg.c index 0e739ad0..dc382b9a 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -658,6 +658,7 @@ enum lua_query_type { lq_import_chat_link, lq_export_chat_link, lq_block_user, + lq_unblock_user, lq_get_message }; @@ -1302,6 +1303,10 @@ void lua_do_all (void) { tgl_do_block_user (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); p += 2; break; + case lq_unblock_user: + tgl_do_unblock_user (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); + p += 2; + break; case lq_get_message: tgl_do_get_message (TLS, (long)lua_ptr[p + 1], lua_msg_cb, lua_ptr[p]); p += 2; @@ -1399,6 +1404,7 @@ struct lua_function functions[] = { {"res_user", lq_res_user, { lfp_string, lfp_none }}, {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, {"block_user", lq_block_user, { lfp_user, lfp_none }}, + {"unblock_user", lq_unblock_user, { lfp_user, lfp_none }}, {"get_message", lq_get_message, { lfp_positive_number, lfp_none }}, { 0, 0, { lfp_none}} }; From a851d3fc33b522b39141b31d1322ef1b982d953d Mon Sep 17 00:00:00 2001 From: "E. Bosch" Date: Sun, 24 Jan 2016 21:18:21 +0100 Subject: [PATCH 030/164] README update --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..92928f48 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Command-line interface for [Telegram](http://telegram.org). Uses readline interface. +**[ This is a fork of [telegram-cli](https://github.com/vysheng/tg) with history callbacks to use in [ibotg](https://github.com/prsai/ibotg) ]** + ### API, Protocol documentation Documentation for Telegram API is available here: http://core.telegram.org/api @@ -22,7 +24,7 @@ Fourth, in peer_name '#' are substitued to '@'. (Not applied to appending of '#% Clone GitHub Repository - git clone --recursive https://github.com/vysheng/tg.git && cd tg + git clone --recursive https://github.com/prsai/tg.git && cd tg ### Python Support From 67bcc8620712a09b5b747119dc6e3cd51b03729f Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 17:07:56 +0800 Subject: [PATCH 031/164] Update README.md, update apt dependencies --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..f3d35a78 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ If you do not want to use them pass options --disable-libconfig, --disable-liblu On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make + sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev libpython3-dev make On gentoo: From bc4a112bb71d4d0df0448fc930115ed4994d2b4a Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 21:21:48 +0800 Subject: [PATCH 032/164] Update README.md Update FreeBSD pkg dependencies, add jansson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..76407c5d 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ On Archlinux: On FreeBSD: - pkg install libconfig libexecinfo lua52 python + pkg install libconfig libexecinfo lua52 python jansson On OpenBSD: From 74231b5cc5b184dac6154fba67d676eb0f0b2580 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 21:34:11 +0800 Subject: [PATCH 033/164] Fix compilation on FreeBSD libdl is part of libc on FreeBSD, force use -ldl will cause error on compilation. So detect the OS, and only add -ldl for non-FreeBSD. --- Makefile.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 8e7b2ae5..add3df73 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,14 +1,19 @@ srcdir=@srcdir@ +TARGET_OS=$(shell uname -s) CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@ CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@ DEFS=@DEFS@ 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} -ldl -lpthread -lutil +LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -lpthread -lutil LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} +ifneq (${TARGET_OS}, FreeBSD) + LOCAL_LDFLAGS += -ldl +endif + DEP=dep AUTO=auto EXE=bin From d3d2ab310d8a1dc387119206aad42b885fefd111 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 21:43:14 +0800 Subject: [PATCH 034/164] Update README.md, OpenBSD/FreeBSD should use gmake --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 76407c5d..e4ba309e 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Then, ./configure make +If you are going to build tg on OpenBSD or FreeBSD, please use `gmake` instead of `make`. + #### Other methods to install on linux On Gentoo: use ebuild provided. From 2d63e3a35f2d098e6889eeeac4a0fb4751a8f9a0 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 21:21:48 +0800 Subject: [PATCH 035/164] Update README.md Update FreeBSD pkg dependencies, add jansson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..76407c5d 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ On Archlinux: On FreeBSD: - pkg install libconfig libexecinfo lua52 python + pkg install libconfig libexecinfo lua52 python jansson On OpenBSD: From ca6c683e610e0f1019f17202afb3a52347b51112 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 21:34:11 +0800 Subject: [PATCH 036/164] Fix compilation on FreeBSD libdl is part of libc on FreeBSD, force use -ldl will cause error on compilation. So detect the OS, and only add -ldl for non-FreeBSD. --- Makefile.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 83424620..86f96189 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,14 +1,19 @@ srcdir=@srcdir@ +TARGET_OS=$(shell uname -s) CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@ CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@ DEFS=@DEFS@ 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} -ldl -lpthread -lutil +LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -lpthread -lutil LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} +ifneq (${TARGET_OS}, FreeBSD) + LOCAL_LDFLAGS += -ldl +endif + DEP=dep AUTO=auto EXE=bin From 297ac95196fbd368bdf3962e30ebd42b1e526d04 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 21:43:14 +0800 Subject: [PATCH 037/164] Update README.md, OpenBSD/FreeBSD should use gmake --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 76407c5d..e4ba309e 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Then, ./configure make +If you are going to build tg on OpenBSD or FreeBSD, please use `gmake` instead of `make`. + #### Other methods to install on linux On Gentoo: use ebuild provided. From 4a931a4b47125ae3bb6752bac7cfb1383607d123 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:10:36 +0800 Subject: [PATCH 038/164] use travis-ci's apt addon to install packages See: https://docs.travis-ci.com/user/installing-dependencies/#Installing-Packages-with-the-APT-Addon --- .travis.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51df2852..706821cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,14 +4,18 @@ compiler: - gcc - clang -install: - - sudo apt-get install libconfig8-dev - - sudo apt-get install libreadline6-dev - - sudo apt-get install libssl-dev - - sudo apt-get install liblua5.2-dev lua5.2 - - sudo apt-get install python-dev python - - sudo apt-get install libevent-dev - - sudo apt-get install libjansson-dev +addons: + apt: + packages: + - libconfig8-dev + - libreadline6-dev + - libssl-dev + - liblua5.2-dev + - lua5.2 + - python-dev + - python + - libevent-dev + - libjansson-dev script: - git submodule update --init --recursive From f94ea02bd54526bc9fb711e2583e45197f1e0d5b Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:11:47 +0800 Subject: [PATCH 039/164] Enable container-based infrastructure on travis-ci To make the build faster. Reference: https://docs.travis-ci.com/user/workers/container-based-infrastructure/ --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 706821cb..c729d83d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,8 @@ addons: - libevent-dev - libjansson-dev +sudo: false + script: - git submodule update --init --recursive - ./configure From 370b06be23de07f5085ddf67dd27c9822007a30a Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:13:05 +0800 Subject: [PATCH 040/164] Decrease git clone depth to speed up the build. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index c729d83d..e0babb79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,9 @@ addons: sudo: false +git: + depth: 10 + script: - git submodule update --init --recursive - ./configure From b059c2b292fb2eae9c2a11c164305ea65d47e586 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:22:18 +0800 Subject: [PATCH 041/164] add -Wno-unused-function to compile flags --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 83424620..4740603b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@ CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@ DEFS=@DEFS@ -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 +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 -Wno-unused-function EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ @OPENSSL_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} From f0410a555c07f3f3652812434fbcb664b1685828 Mon Sep 17 00:00:00 2001 From: janglapuk Date: Sun, 31 Jan 2016 11:51:22 +0800 Subject: [PATCH 042/164] Add new send_*_reply functions --- lua-tg.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lua-tg.c b/lua-tg.c index 592df608..afeaa248 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -613,15 +613,19 @@ enum lua_query_type { lq_contact_list, lq_dialog_list, lq_msg, + lq_msg_reply, lq_send_typing, lq_send_typing_abort, lq_rename_chat, lq_send_photo, + lq_send_photo_reply, lq_chat_set_photo, lq_set_profile_photo, lq_set_profile_name, lq_send_video, + lq_send_video_reply, lq_send_text, + lq_send_text_reply, lq_fwd, lq_fwd_media, lq_load_photo, @@ -641,8 +645,11 @@ enum lua_query_type { lq_create_secret_chat, lq_create_group_chat, lq_send_audio, + lq_send_audio_reply, lq_send_document, + lq_send_document_reply, lq_send_file, + lq_send_file_reply, lq_load_audio, lq_load_document, lq_load_document_thumb, @@ -1030,6 +1037,11 @@ void lua_do_all (void) { free (lua_ptr[p + 2]); p += 3; break; + case lq_msg_reply: //# + tgl_do_reply_message (TLS, (long)lua_ptr[p + 1], lua_ptr[p + 2], strlen (lua_ptr[p + 2]), 0, lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; case lq_send_typing: tgl_do_send_typing (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, tgl_typing_typing, lua_empty_cb, lua_ptr[p]); p += 2; @@ -1048,31 +1060,61 @@ void lua_do_all (void) { free (lua_ptr[p + 2]); p += 3; break; + case lq_send_photo_reply: //# + tgl_do_reply_document (TLS, (long)lua_ptr[p + 1], lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; case lq_send_video: tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, lua_msg_cb, lua_ptr[p]); free (lua_ptr[p + 2]); p += 3; break; + case lq_send_video_reply: //# + tgl_do_reply_document (TLS, (long)lua_ptr[p + 1], lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; case lq_send_audio: tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, lua_msg_cb, lua_ptr[p]); free (lua_ptr[p + 2]); p += 3; break; + case lq_send_audio_reply: //# + tgl_do_reply_document (TLS, (long)lua_ptr[p + 1], lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; case lq_send_document: tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, 0, lua_msg_cb, lua_ptr[p]); free (lua_ptr[p + 2]); p += 3; break; + case lq_send_document_reply: //# + tgl_do_reply_document (TLS, (long)lua_ptr[p + 1], lua_ptr[p + 2], NULL, 0, 0, lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; case lq_send_file: tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, lua_msg_cb, lua_ptr[p]); free (lua_ptr[p + 2]); p += 3; break; + case lq_send_file_reply: //# + tgl_do_reply_document (TLS, (long)lua_ptr[p + 1], lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; case lq_send_text: tgl_do_send_text (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], 0, lua_msg_cb, lua_ptr[p]); free (lua_ptr[p + 2]); p += 3; break; + case lq_send_text_reply: //# + tgl_do_reply_text (TLS, (long)lua_ptr[p + 1], lua_ptr[p + 2], 0, lua_msg_cb, lua_ptr[p]); + free (lua_ptr[p + 2]); + p += 3; + break; case lq_chat_set_photo: tgl_do_set_chat_photo (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_empty_cb, lua_ptr[p]); free (lua_ptr[p + 2]); @@ -1299,14 +1341,21 @@ struct lua_function functions[] = { {"get_dialog_list", lq_dialog_list, { lfp_none }}, {"rename_chat", lq_rename_chat, { lfp_chat, lfp_string, lfp_none }}, {"send_msg", lq_msg, { lfp_peer, lfp_string, lfp_none }}, + {"send_msg_reply", lq_msg_reply, { lfp_nonnegative_number, lfp_string, lfp_none }}, {"send_typing", lq_send_typing, { lfp_peer, lfp_none }}, {"send_typing_abort", lq_send_typing_abort, { lfp_peer, lfp_none }}, {"send_photo", lq_send_photo, { lfp_peer, lfp_string, lfp_none }}, + {"send_photo_reply", lq_send_photo_reply, { lfp_nonnegative_number, lfp_string, lfp_none }}, {"send_video", lq_send_video, { lfp_peer, lfp_string, lfp_none }}, + {"send_video_reply", lq_send_video_reply, { lfp_nonnegative_number, lfp_string, lfp_none }}, {"send_audio", lq_send_audio, { lfp_peer, lfp_string, lfp_none }}, + {"send_audio_reply", lq_send_audio_reply, { lfp_nonnegative_number, lfp_string, lfp_none }}, {"send_document", lq_send_document, { lfp_peer, lfp_string, lfp_none }}, + {"send_document_reply", lq_send_document_reply, { lfp_nonnegative_number, lfp_string, lfp_none }}, {"send_file", lq_send_file, { lfp_peer, lfp_string, lfp_none }}, + {"send_file_reply", lq_send_file_reply, { lfp_nonnegative_number, lfp_string, lfp_none }}, {"send_text", lq_send_text, { lfp_peer, lfp_string, lfp_none }}, + {"send_text_reply", lq_send_text_reply, { lfp_nonnegative_number, lfp_string, lfp_none }}, {"chat_set_photo", lq_chat_set_photo, { lfp_chat, lfp_string, lfp_none }}, {"load_photo", lq_load_photo, { lfp_msg, lfp_none }}, {"load_video", lq_load_video, { lfp_msg, lfp_none }}, From 64f1b1a6714d9408b35b3039e24a9e65a9083425 Mon Sep 17 00:00:00 2001 From: "E. Bosch" Date: Thu, 4 Feb 2016 00:40:15 +0100 Subject: [PATCH 043/164] README update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 92928f48..1aaa5213 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) +## Telegram messenger CLI Command-line interface for [Telegram](http://telegram.org). Uses readline interface. From 2c47452bef7c7fed4ef80bc2dca4a4c7668be8bd Mon Sep 17 00:00:00 2001 From: Ali Lotfi Date: Mon, 8 Feb 2016 01:23:55 +0330 Subject: [PATCH 044/164] Fix Fedora libjansson package name The package which contains Header files for jansson in fedora repo is named "jansson-devel" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..4cab341a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ On gentoo: On Fedora: - sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel + sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel On Archlinux: From 536880fedc07e9c647b8bad43f782f0b04e50d32 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Mon, 7 Mar 2016 21:39:26 +0000 Subject: [PATCH 045/164] SuperGroups --- Makefile.in | 7 +- Makefile.tgl | 8 +- Makefile.tl-parser | 2 +- README-LUA | 1 + config.h.in | 10 +- config.sample | 7 +- configure | 497 ++++++++--------- configure.ac | 31 +- interface.c | 1275 +++++++++++++++++++++++++++++++++----------- interface.h | 6 + json-tg.c | 50 +- loop.c | 61 ++- lua-tg.c | 458 ++++++++++------ lua-tg.h | 2 +- main.c | 67 +-- telegram.h | 2 +- 16 files changed, 1634 insertions(+), 850 deletions(-) diff --git a/Makefile.in b/Makefile.in index 8e7b2ae5..83424620 100644 --- a/Makefile.in +++ b/Makefile.in @@ -14,7 +14,7 @@ AUTO=auto EXE=bin OBJ=objs LIB=libs -DIR_LIST=${DEP} ${AUTO} ${EXE} ${OBJ} ${LIB} ${DEP}/auto ${OBJ}/auto +DIR_LIST=${DEP} ${AUTO} ${EXE} ${OBJ} ${LIB} ${DEP}/auto ${OBJ}/auto ${OBJ}/crypto ${DEP}/crypto EXE_LIST=${EXE}/telegram-cli @@ -51,5 +51,8 @@ ${EXE}/telegram-cli: ${TG_OBJECTS} ${LIB}/libtgl.a ${CC} $^ ${LINK_FLAGS} -o $@ clean: - rm -rf ${DIR_LIST} config.log config.status > /dev/null || echo "all clean" + rm -rf ${DIR_LIST} + +distclean: + rm -rf ${DIR_LIST} config.h config.log config.status diff --git a/Makefile.tgl b/Makefile.tgl index 88e0bf4c..28447e17 100644 --- a/Makefile.tgl +++ b/Makefile.tgl @@ -1,11 +1,11 @@ -TGL_OBJECTS=${OBJ}/mtproto-common.o ${OBJ}/mtproto-client.o ${OBJ}/queries.o ${OBJ}/structures.o ${OBJ}/binlog.o ${OBJ}/tgl.o ${OBJ}/updates.o ${OBJ}/tgl-net.o ${OBJ}/tgl-timers.o ${OBJ}/tg-mime-types.o ${OBJ}/mtproto-utils.o +TGL_OBJECTS=${OBJ}/mtproto-common.o ${OBJ}/mtproto-client.o ${OBJ}/mtproto-key.o ${OBJ}/queries.o ${OBJ}/structures.o ${OBJ}/binlog.o ${OBJ}/tgl.o ${OBJ}/updates.o ${OBJ}/tgl-net.o ${OBJ}/tgl-timers.o ${OBJ}/tg-mime-types.o ${OBJ}/mtproto-utils.o ${OBJ}/crypto/bn_openssl.o ${OBJ}/crypto/bn_altern.o ${OBJ}/crypto/rsa_pem_openssl.o ${OBJ}/crypto/rsa_pem_altern.o ${OBJ}/crypto/md5_openssl.o ${OBJ}/crypto/md5_altern.o ${OBJ}/crypto/sha_openssl.o ${OBJ}/crypto/sha_altern.o ${OBJ}/crypto/aes_openssl.o ${OBJ}/crypto/aes_altern.o TGL_OBJECTS_AUTO=${OBJ}/auto/auto-skip.o ${OBJ}/auto/auto-fetch.o ${OBJ}/auto/auto-store.o ${OBJ}/auto/auto-autocomplete.o ${OBJ}/auto/auto-types.o ${OBJ}/auto/auto-fetch-ds.o ${OBJ}/auto/auto-free-ds.o ${OBJ}/auto/auto-store-ds.o ${OBJ}/auto/auto-print-ds.o TLD_OBJECTS=${OBJ}/dump-tl-file.o GENERATE_OBJECTS=${OBJ}/generate.o -TGL_COMMON_OBJECTS=${OBJ}/tools.o +TGL_COMMON_OBJECTS=${OBJ}/tools.o ${OBJ}/crypto/rand_openssl.o ${OBJ}/crypto/rand_altern.o ${OBJ}/crypto/err_openssl.o ${OBJ}/crypto/err_altern.o TGL_OBJ_C=${GENERATE_OBJECTS} ${TGL_COMMON_OBJECTS} ${TGL_OBJECTS} ${TLD_OBJECTS} .SUFFIXES: @@ -41,10 +41,10 @@ ${AUTO}/scheme2.tl: ${AUTO}/scheme.tl ${EXE}/tl-parser ${EXE}/tl-parser -E ${AUTO}/scheme.tl 2> $@ || ( cat $@ && rm $@ && false ) ${AUTO}/auto-%.c: ${AUTO}/scheme.tlo ${EXE}/generate auto/constants.h ${AUTO}/auto-%.h | create_dirs_and_headers - ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.c,%,$@) ${AUTO}/scheme.tlo > $@ || rm $@ + ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.c,%,$@) ${AUTO}/scheme.tlo > $@ || ( rm $@ && false ) ${AUTO}/auto-%.h: ${AUTO}/scheme.tlo ${EXE}/generate - ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.h,%-header,$@) ${AUTO}/scheme.tlo > $@ || rm $@ + ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.h,%-header,$@) ${AUTO}/scheme.tlo > $@ || ( rm $@ && false ) ${AUTO}/constants.h: ${AUTO}/scheme2.tl ${srcdir}/tgl/gen_constants_h.awk awk -f ${srcdir}/tgl/gen_constants_h.awk < $< > $@ diff --git a/Makefile.tl-parser b/Makefile.tl-parser index eb3284df..654d1d48 100644 --- a/Makefile.tl-parser +++ b/Makefile.tl-parser @@ -1,4 +1,4 @@ -TL_PARSER_OBJECTS=${OBJ}/tl-parser.o ${OBJ}/tlc.o ${OBJ}/crc32.o +TL_PARSER_OBJECTS=${OBJ}/tl-parser.o ${OBJ}/tlc.o ${TL_PARSER_OBJECTS}: ${OBJ}/%.o: ${srcdir}/tgl/tl-parser/%.c | create_dirs ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl/tl-parser -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< diff --git a/README-LUA b/README-LUA index 3ef81653..b991e953 100644 --- a/README-LUA +++ b/README-LUA @@ -51,6 +51,7 @@ Function_list (arguments are listed aside from cb_function and cb_extra, : load_document_thumb(msg) chat_info (chat) + channel_info (channel) user_info (user) get_history (peer, limit) diff --git a/config.h.in b/config.h.in index bb5f2d60..73e7ee7f 100644 --- a/config.h.in +++ b/config.h.in @@ -36,12 +36,12 @@ /* Define to 1 if you have the `event' library (-levent). */ #undef HAVE_LIBEVENT +/* Define to 1 if you have the `gcrypt' library (-lgcrypt). */ +#undef HAVE_LIBGCRYPT + /* Define to 1 if you have the `jansson' library (-ljansson). */ #undef HAVE_LIBJANSSON -/* Define to 1 if you have the `m' library (-lm). */ -#undef HAVE_LIBM - /* Define to 1 if you have `z' library (-lz) */ #undef HAVE_LIBZ @@ -158,6 +158,10 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* avoid OpenSSL entirely, use libgcrypt instead (this can't read *.pub files, + though.) */ +#undef TGL_AVOID_OPENSSL + /* use json */ #undef USE_JSON diff --git a/config.sample b/config.sample index dffcc44f..9e0c60d9 100644 --- a/config.sample +++ b/config.sample @@ -7,14 +7,12 @@ test_dc1 = { config_directory = ".telegram/test_dc1"; test = true; msg_num = true; - binlog_enabled = true; }; binlog = { config_directory = ".telegram/binlog"; test = false; msg_num = true; - binlog_enabled = true; log_level = 2; }; @@ -22,7 +20,6 @@ binlog_mts = { config_directory = ".telegram/binlog_mts"; test = false; msg_num = true; - binlog_enabled = true; log_level = 2; }; @@ -30,7 +27,6 @@ mega = { config_directory = ".telegram/mega"; test = false; msg_num = true; - binlog_enabled = true; log_level = 2; }; @@ -55,12 +51,11 @@ test = { test1 = { config_directory = ".telegram/test1"; msg_num = true; - binlog_enabled = true; }; test2 = { config_directory = ".telegram/test2"; msg_num = true; - binlog_enabled = true; + pfs_enabled = true; }; diff --git a/configure b/configure index dcb65cb4..fa7e189f 100755 --- a/configure +++ b/configure @@ -695,6 +695,7 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking +enable_openssl with_openssl with_zlib enable_libconfig @@ -1326,6 +1327,8 @@ Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-openssl disables OpenSSL, and don't link against it + (this can't read *.pub files, though.) --enable-libconfig/--disable-libconfig --enable-extf/--disable-extf --enable-liblua/--disable-liblua @@ -3497,51 +3500,6 @@ LDFLAGS="$LDFLAGS -L/usr/local/lib" # Checks for libraries. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 -$as_echo_n "checking for sqrt in -lm... " >&6; } -if ${ac_cv_lib_m_sqrt+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lm $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char sqrt (); -int -main () -{ -return sqrt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_m_sqrt=yes -else - ac_cv_lib_m_sqrt=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5 -$as_echo "$ac_cv_lib_m_sqrt" >&6; } -if test "x$ac_cv_lib_m_sqrt" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBM 1 -_ACEOF - - LIBS="-lm $LIBS" - -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 $as_echo_n "checking for library containing clock_gettime... " >&6; } if ${ac_cv_search_clock_gettime+:} false; then : @@ -4129,6 +4087,62 @@ EXTRA_LIBS="" # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required +# Check whether --enable-openssl was given. +if test "${enable_openssl+set}" = set; then : + enableval=$enable_openssl; + if test "x$enableval" = "xno" ; then + +$as_echo "#define TGL_AVOID_OPENSSL 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcry_mpi_snatch in -lgcrypt" >&5 +$as_echo_n "checking for gcry_mpi_snatch in -lgcrypt... " >&6; } +if ${ac_cv_lib_gcrypt_gcry_mpi_snatch+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcrypt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gcry_mpi_snatch (); +int +main () +{ +return gcry_mpi_snatch (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_gcrypt_gcry_mpi_snatch=yes +else + ac_cv_lib_gcrypt_gcry_mpi_snatch=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gcrypt_gcry_mpi_snatch" >&5 +$as_echo "$ac_cv_lib_gcrypt_gcry_mpi_snatch" >&6; } +if test "x$ac_cv_lib_gcrypt_gcry_mpi_snatch" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBGCRYPT 1 +_ACEOF + + LIBS="-lgcrypt $LIBS" + +else + as_fn_error $? "\"Need libgcrypt >= 1.60\"" "$LINENO" 5 +fi + + else + # Don't be annoying, so don't inform the user about --disable-openssl found=false @@ -4267,7 +4281,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - as_fn_error $? "No openssl found" "$LINENO" 5 + as_fn_error $? "No openssl found." "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext \ @@ -4280,6 +4294,164 @@ rm -f core conftest.err conftest.$ac_objext \ + fi + +else + + + found=false + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; + case "$withval" in + "" | y | ye | yes | n | no) + as_fn_error $? "Invalid --with-openssl value" "$LINENO" 5 + ;; + *) ssldirs="$withval" + ;; + esac + +else + + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test x"$PKG_CONFIG" != x""; then + OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` + if test $? = 0; then + OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` + OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + + +fi + + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 +$as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" + OPENSSL_LIBS="-lssl -lcrypto" + found=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 +$as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; } + echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ + "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$OPENSSL_LIBS $LIBS" + CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +SSL_new(NULL) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "No openssl found. With --disable-openssl, libtgl will use libgcrypt instead." "$LINENO" 5 + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + + + + + +fi + # # Handle user hints # @@ -5936,7 +6108,7 @@ $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 + if test "x$enableval" = "xyes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else @@ -6173,235 +6345,8 @@ $as_echo "#define USE_PYTHON 1" >>confdefs.h 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.5 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 - as_ac_Lib=`$as_echo "ac_cv_lib_${ax_python_bin}mu''_main" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -l${ax_python_bin}mu" >&5 -$as_echo_n "checking for main in -l${ax_python_bin}mu... " >&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}mu $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}mu -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 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 +$as_echo "disabled" >&6; } fi diff --git a/configure.ac b/configure.ac index a2c09e57..2d97c36a 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,6 @@ CPPFLAGS="$CPPFLAGS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" # Checks for libraries. -AC_CHECK_LIB([m], [sqrt]) AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([backtrace], [execinfo]) AC_CHECK_LIB([event], [event_base_new], [], [AC_MSG_ERROR([no libevent found])]) @@ -34,7 +33,19 @@ EXTRA_LIBS="" # OPENSSL_LIBS to the -l directives required # OPENSSL_LDFLAGS to the -L or -R flags required -AX_CHECK_OPENSSL(,[AC_MSG_ERROR([No openssl found])]) +AC_ARG_ENABLE(openssl,[ --disable-openssl disables OpenSSL, and don't link against it + (this can't read *.pub files, though.)], + [ + if test "x$enableval" = "xno" ; then + AC_DEFINE([TGL_AVOID_OPENSSL],[1],[avoid OpenSSL entirely, use libgcrypt instead (this can't read *.pub files, though.)]) + AC_CHECK_LIB([gcrypt], [gcry_mpi_snatch], [], [AC_MSG_ERROR(["Need libgcrypt >= 1.60"])]) + else + # Don't be annoying, so don't inform the user about --disable-openssl + AX_CHECK_OPENSSL(,[AC_MSG_ERROR([No openssl found.])]) + fi + ],[ + AX_CHECK_OPENSSL(,[AC_MSG_ERROR([No openssl found. With --disable-openssl, libtgl will use libgcrypt instead.])]) + ]) AX_CHECK_ZLIB(, [AC_MSG_ERROR([No zlib found])]) AC_CHECK_LIB([readline], [rl_save_prompt], [ EXTRA_LIBS="${EXTRA_LIBS} -lreadline" ; ], [AC_MSG_ERROR([no libreadline found])]) @@ -98,7 +109,7 @@ 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 + if test "x$enableval" = "xyes" ; then AC_MSG_RESULT([disabled]) else AC_MSG_RESULT([enabled]) @@ -116,19 +127,7 @@ AC_ARG_ENABLE(python,[--enable-python/--disable-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_RESULT([disabled]) ]) diff --git a/interface.c b/interface.c index 47b9bcf8..f78619a3 100644 --- a/interface.c +++ b/interface.c @@ -69,6 +69,7 @@ //#include "mtproto-common.h" #include +#include #include "loop.h" #ifndef PATH_MAX @@ -92,6 +93,21 @@ #include "auto/auto-types.h" #include "auto/auto-free-ds.h" +#include + +#include "tgl/tree.h" + +struct username_peer_pair { + const char *username; + tgl_peer_t *peer; +}; + +#define username_peer_pair_cmp(a,b) strcmp (a->username, b->username) +DEFINE_TREE (username_peer_pair, struct username_peer_pair *, username_peer_pair_cmp, NULL) +struct tree_username_peer_pair *username_peer_pair; + +struct username_peer_pair *current_map; + #define ALLOW_MULT 1 char *default_prompt = "> "; @@ -103,9 +119,13 @@ extern int one_string_flags; extern int enable_json; int disable_auto_accept; int msg_num_mode; +int permanent_msg_id_mode; +int permanent_peer_id_mode; int disable_colors; extern int alert_sound; extern int binlog_read; +extern char *home_directory; +int do_html; int safe_quit; @@ -329,7 +349,7 @@ void next_token_end_ac (void) { } #define NOT_FOUND (int)0x80000000 -tgl_peer_id_t TGL_PEER_NOT_FOUND = {.id = NOT_FOUND}; +tgl_peer_id_t TGL_PEER_NOT_FOUND = {.peer_id = NOT_FOUND}; long long cur_token_int (void) { if (cur_token_len <= 0) { @@ -348,6 +368,82 @@ long long cur_token_int (void) { } } +int hex2int (char c) { + if (c >= '0' && c <= '9') { return c - '0'; } + if (c >= 'a' && c <= 'f') { return c - 'a' + 10; } + assert (0); + return 0; +} + +char *print_permanent_msg_id (tgl_message_id_t id) { + static char buf[2 * sizeof (tgl_message_id_t) + 1]; + + unsigned char *s = (void *)&id; + int i; + for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) { + sprintf (buf + 2 * i, "%02x", (unsigned)s[i]); + } + return buf; +} + +char *print_permanent_peer_id (tgl_peer_id_t id) { + static char buf[2 * sizeof (tgl_peer_id_t) + 2]; + buf[0] = '$'; + + unsigned char *s = (void *)&id; + int i; + for (i = 0; i < (int)sizeof (tgl_peer_id_t); i++) { + sprintf (buf + 1 + 2 * i, "%02x", (unsigned)s[i]); + } + return buf; +} + +tgl_message_id_t parse_input_msg_id (const char *s, int l) { + if (!s || l <= 0) { + tgl_message_id_t id; + memset (&id, 0, sizeof (id)); + id.peer_type = 0; + return id; + } else { + tgl_message_id_t id; + memset (&id, 0, sizeof (id)); + + if (l == 2 * sizeof (tgl_message_id_t)) { + int i; + for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) { + if ( + (s[i] < '0' || s[i] > '9') && + (s[i] < 'a' || s[i] > 'f') + ) { + id.peer_type = 0; + return id; + } + } + unsigned char *d = (void *)&id; + for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) { + d[i] = hex2int (s[2 * i]) * 16 + hex2int (s[2 * i + 1]); + } + return id; + } else { + char *sc = tstrndup (s, l); + char *end = 0; + long long x = strtoll (sc, &end, 0); + tfree_str (sc); + if (end != sc + l) { + id.peer_type = 0; + } else { + id.peer_type = TGL_PEER_TEMP_ID; + id.id = x; + } + return id; + } + } +} + +tgl_message_id_t cur_token_msg_id (void) { + return parse_input_msg_id (cur_token, cur_token_len); +} + double cur_token_double (void) { if (cur_token_len <= 0) { return NOT_FOUND; @@ -365,142 +461,97 @@ double cur_token_double (void) { } } -tgl_peer_id_t cur_token_user (void) { - if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; } - int l = cur_token_len; - char *s = cur_token; +tgl_peer_id_t parse_input_peer_id (const char *s, int l, int mask) { + if (!s || l <= 0) { return TGL_PEER_NOT_FOUND; } - char c = cur_token[cur_token_len]; - cur_token[cur_token_len] = 0; + if (*s == '$') { + s ++; + l --; + if (l != 2 * sizeof (tgl_peer_id_t)) { + return TGL_PEER_NOT_FOUND; + } - if (l >= 8 && !memcmp (s, "user#id", 7)) { - s += 7; - l -= 7; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); } - else { return TGL_PEER_NOT_FOUND; } - } - if (l >= 6 && !memcmp (s, "user#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); } - else { return TGL_PEER_NOT_FOUND; } + tgl_peer_id_t res; + unsigned char *r = (void *)&res; + int i; + for (i = 0; i < l; i++) { + if ((s[i] < '0' || s[i] > '9') && + (s[i] < 'a' || s[i] > 'f')) { + return TGL_PEER_NOT_FOUND; + } + } + for (i = 0; i < (int)sizeof (tgl_peer_id_t); i++) { + r[i] = hex2int (s[2 * i]) * 16 + hex2int (s[2 * i + 1]); + } + + if (mask && tgl_get_peer_type (res) != mask) { + return TGL_PEER_NOT_FOUND; + } + + return res; } - tgl_peer_t *P = tgl_peer_get_by_name (TLS, s); - cur_token[cur_token_len] = c; - - if (P && tgl_get_peer_type (P->id) == TGL_PEER_USER) { - return P->id; - } else { - return TGL_PEER_NOT_FOUND; + if (*s == '@') { + s ++; + l --; + char *tmp = tstrndup (s, l); + struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&tmp); + tfree_str (tmp); + if (p && (!mask || tgl_get_peer_type (p->peer->id) == mask)) { + return p->peer->id; + } else { + return TGL_PEER_NOT_FOUND; + } } -} -tgl_peer_id_t cur_token_chat (void) { - if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; } - int l = cur_token_len; - char *s = cur_token; + const char *ss[] = {"user#id", "user#", "chat#id", "chat#", "secret_chat#id", "secret_chat#", "channel#id", "channel#"}; + int tt[] = {TGL_PEER_USER, TGL_PEER_USER, TGL_PEER_CHAT, TGL_PEER_CHAT, TGL_PEER_ENCR_CHAT, TGL_PEER_ENCR_CHAT, TGL_PEER_CHANNEL, TGL_PEER_CHANNEL}; - char c = cur_token[cur_token_len]; - cur_token[cur_token_len] = 0; - - if (l >= 8 && !memcmp (s, "chat#id", 7)) { - s += 7; - l -= 7; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); } - else { return TGL_PEER_NOT_FOUND; } - } - if (l >= 6 && !memcmp (s, "chat#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); } - else { return TGL_PEER_NOT_FOUND; } + char *sc = tstrndup (s, l); + + int i; + for (i = 0; i < 8; i++) if (!mask || mask == tt[i]) { + int x = strlen (ss[i]); + if (l > x && !memcmp (s, ss[i], x)) { + int r = atoi (sc + x); + tfree_str (sc); + if (r < 0) { return TGL_PEER_NOT_FOUND; } + tgl_peer_t *P = tgl_peer_get (TLS, tgl_set_peer_id (tt[i], r)); + if (!P) { return TGL_PEER_NOT_FOUND; } + return P->id; + } } - tgl_peer_t *P = tgl_peer_get_by_name (TLS, s); - cur_token[cur_token_len] = c; + tgl_peer_t *P = tgl_peer_get_by_name (TLS, sc); + tfree_str (sc); - if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { + if (P && (!mask || tgl_get_peer_type (P->id) == mask)) { return P->id; } else { return TGL_PEER_NOT_FOUND; } } +tgl_peer_id_t cur_token_user (void) { + return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_USER); +} + +tgl_peer_id_t cur_token_chat (void) { + return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_CHAT); +} + tgl_peer_id_t cur_token_encr_chat (void) { - if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; } - char *s = cur_token; - char c = cur_token[cur_token_len]; - cur_token[cur_token_len] = 0; + return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_ENCR_CHAT); +} - tgl_peer_t *P = tgl_peer_get_by_name (TLS, s); - cur_token[cur_token_len] = c; - - if (P && tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) { - return P->id; - } else { - return TGL_PEER_NOT_FOUND; - } +tgl_peer_id_t cur_token_channel (void) { + return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_CHANNEL); } tgl_peer_id_t cur_token_peer (void) { - if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; } - int l = cur_token_len; - char *s = cur_token; - char c = cur_token[cur_token_len]; - cur_token[cur_token_len] = 0; - - if (l >= 8 && !memcmp (s, "user#id", 7)) { - s += 7; - l -= 7; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); } - else { return TGL_PEER_NOT_FOUND; } - } - if (l >= 8 && !memcmp (s, "chat#id", 7)) { - s += 7; - l -= 7; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); } - else { return TGL_PEER_NOT_FOUND; } - } - if (l >= 6 && !memcmp (s, "user#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); } - else { return TGL_PEER_NOT_FOUND; } - } - if (l >= 6 && !memcmp (s, "chat#", 5)) { - s += 5; - l -= 5; - int r = atoi (s); - cur_token[cur_token_len] = c; - if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); } - else { return TGL_PEER_NOT_FOUND; } - } - - tgl_peer_t *P = tgl_peer_get_by_name (TLS, s); - cur_token[cur_token_len] = c; - - if (P) { - return P->id; - } else { - return TGL_PEER_NOT_FOUND; - } + return parse_input_peer_id (cur_token, cur_token_len, 0); } - +/* static tgl_peer_t *mk_peer (tgl_peer_id_t id) { if (tgl_get_peer_type (id) == NOT_FOUND) { return 0; } tgl_peer_t *P = tgl_peer_get (TLS, id); @@ -514,7 +565,7 @@ static tgl_peer_t *mk_peer (tgl_peer_id_t id) { P = tgl_peer_get (TLS, id); } return P; -} +}*/ char *get_default_prompt (void) { static char buf[1000]; @@ -577,6 +628,7 @@ char *modifiers[] = { "[offline]", "[enable_preview]", "[disable_preview]", + "[html]", "[reply=", 0 }; @@ -594,6 +646,7 @@ enum command_argument { ca_user, ca_chat, ca_secret_chat, + ca_channel, ca_peer, ca_file_name, ca_file_name_end, @@ -606,6 +659,7 @@ enum command_argument { ca_modifier, ca_command, ca_extf, + ca_msg_id, ca_optional = 256 @@ -613,12 +667,14 @@ enum command_argument { struct arg { int flags; - struct { - tgl_peer_t *P; - struct tgl_message *M; + union { + //tgl_peer_t *P; + //struct tgl_message *M; char *str; long long num; double dval; + tgl_message_id_t msg_id; + tgl_peer_id_t peer_id; }; }; @@ -637,9 +693,11 @@ int disable_msg_preview; void print_user_list_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_user *UL[]); void print_msg_list_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]); +void print_msg_list_history_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]); void print_msg_list_success_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]); -void print_dialog_list_gw (struct tgl_state *TLS, void *extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]); +void print_dialog_list_gw (struct tgl_state *TLS, void *extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]); void print_chat_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C); +void print_channel_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_channel *C); void print_user_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_user *C); void print_filename_gw (struct tgl_state *TLS, void *extra, int success, const char *name); void print_string_gw (struct tgl_state *TLS, void *extra, int success, const char *name); @@ -647,6 +705,7 @@ void open_filename_gw (struct tgl_state *TLS, void *extra, int success, const ch void print_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E); void print_card_gw (struct tgl_state *TLS, void *extra, int success, int size, int *card); void print_user_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U); +void print_peer_gw (struct tgl_state *TLS, void *extra, int success, tgl_peer_t *U); void print_msg_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M); void print_msg_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M); void print_encr_chat_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E);; @@ -656,14 +715,22 @@ struct command commands[]; /* {{{ client methods */ void do_help (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { - assert (!arg_num); + assert (arg_num == 1); if (ev) { mprint_start (ev); } + int total = 0; mpush_color (ev, COLOR_YELLOW); struct command *cmd = commands; while (cmd->name) { - mprintf (ev, "%s\n", cmd->desc); + if (!args[0].str || !strcmp (args[0].str, cmd->name)) { + mprintf (ev, "%s\n", cmd->desc); + total ++; + } cmd ++; } + if (!total) { + assert (arg_num == 1); + mprintf (ev, "Unknown command '%s'\n", args[0].str); + } mpop_color (ev); if (ev) { mprint_end (ev); } if (!ev) { @@ -671,6 +738,12 @@ void do_help (struct command *command, int arg_num, struct arg args[], struct in } } +void do_get_terms_of_service (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (!arg_num); + if (ev) { ev->refcnt ++; } + tgl_do_get_terms_of_service (TLS, print_string_gw, ev); +} + void do_stats (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (!arg_num); static char stat_buf[1 << 15]; @@ -723,7 +796,7 @@ void do_set (struct command *command, int arg_num, struct arg args[], struct in_ void do_chat_with_peer (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { if (!ev) { in_chat_mode = 1; - chat_mode_id = args[0].P->id; + chat_mode_id = args[0].peer_id; } } @@ -734,6 +807,24 @@ void do_main_session (struct command *command, int arg_num, struct arg args[], s notify_ev = ev; if (ev) { ev->refcnt ++; } } + +void do_version (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (!arg_num); + if (ev) { mprint_start (ev); } + mpush_color (ev, COLOR_YELLOW); + mprintf (ev, "Telegram-cli version %s (uses tgl version %s)\n", TELEGRAM_CLI_VERSION, TGL_VERSION); + #ifdef TGL_AVOID_OPENSSL + mprintf (ev, "uses libgcrypt for encryption\n"); + #else + mprintf (ev, "uses libopenssl for encryption\n"); + #endif + mpop_color (ev); + if (ev) { mprint_end (ev); } + if (!ev) { + fflush (stdout); + } + +} /* }}} */ #define ARG2STR_DEF(n,def) args[n].str ? args[n].str : def, args[n].str ? strlen (args[n].str) : strlen (def) @@ -754,7 +845,14 @@ void do_msg (struct command *command, int arg_num, struct arg args[], struct in_ assert (arg_num == 2); if (ev) { ev->refcnt ++; } vlogprintf (E_DEBUG, "reply_id=%d, disable=%d\n", reply_id, disable_msg_preview); - tgl_do_send_message (TLS, args[0].P->id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview, NULL, print_msg_success_gw, ev); + tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, NULL, print_msg_success_gw, ev); +} + +void do_post (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + vlogprintf (E_DEBUG, "reply_id=%d, disable=%d\n", reply_id, disable_msg_preview); + tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | TGLMF_POST_AS_CHANNEL | do_html, NULL, print_msg_success_gw, ev); } void do_msg_kbd (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -772,7 +870,7 @@ void do_msg_kbd (struct command *command, int arg_num, struct arg args[], struct struct tl_ds_reply_markup *DS_RM = fetch_ds_type_reply_markup (TYPE_TO_PARAM (reply_markup)); assert (DS_RM); - tgl_do_send_message (TLS, args[0].P->id, ARG2STR(2), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview, DS_RM, print_msg_success_gw, ev); + tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(2), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, DS_RM, print_msg_success_gw, ev); free_ds_type_reply_markup (DS_RM, TYPE_TO_PARAM (reply_markup)); } @@ -780,25 +878,30 @@ void do_msg_kbd (struct command *command, int arg_num, struct arg args[], struct void do_reply (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_reply_message (TLS, args[0].num, ARG2STR(1), disable_msg_preview, print_msg_success_gw, ev); + tgl_do_reply_message (TLS, &args[0].msg_id, ARG2STR(1), disable_msg_preview | do_html, print_msg_success_gw, ev); } void do_send_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_send_text (TLS, args[0].P->id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview, print_msg_success_gw, ev); + tgl_do_send_text (TLS, args[0].peer_id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, print_msg_success_gw, ev); +} + +void do_post_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + tgl_do_send_text (TLS, args[0].peer_id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | TGLMF_POST_AS_CHANNEL | do_html, print_msg_success_gw, ev); } - void do_reply_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_reply_text (TLS, args[0].num, args[1].str, disable_msg_preview, print_msg_success_gw, ev); + tgl_do_reply_text (TLS, &args[0].msg_id, args[1].str, disable_msg_preview | do_html, print_msg_success_gw, ev); } static void _do_send_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev, unsigned long long flags) { assert (arg_num >= 2); if (ev) { ev->refcnt ++; } - tgl_do_send_document (TLS, args[0].P->id, args[1].str, arg_num == 2 ? NULL : args[2].str, arg_num == 2 ? 0 : strlen (args[2].str), flags | TGL_SEND_MSG_FLAG_REPLY (reply_id), print_msg_success_gw, ev); + tgl_do_send_document (TLS, args[0].peer_id, args[1].str, arg_num == 2 ? NULL : args[2].str, arg_num == 2 ? 0 : strlen (args[2].str), flags | TGL_SEND_MSG_FLAG_REPLY (reply_id), print_msg_success_gw, ev); } @@ -822,10 +925,30 @@ void do_send_document (struct command *command, int arg_num, struct arg args[], _do_send_file (command, arg_num, args, ev, 0); } +void do_post_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO | TGLMF_POST_AS_CHANNEL); +} + +void do_post_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO | TGLMF_POST_AS_CHANNEL); +} + +void do_post_audio (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO | TGLMF_POST_AS_CHANNEL); +} + +void do_post_video (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO | TGLMF_POST_AS_CHANNEL); +} + +void do_post_document (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + _do_send_file (command, arg_num, args, ev, TGLMF_POST_AS_CHANNEL); +} + void _do_reply_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev, unsigned long long flags) { assert (arg_num >= 2); if (ev) { ev->refcnt ++; } - tgl_do_reply_document (TLS, args[0].num, args[1].str, arg_num == 2 ? NULL : args[2].str, arg_num == 2 ? 0 : strlen (args[2].str), flags, print_msg_success_gw, ev); + tgl_do_reply_document (TLS, &args[0].msg_id, args[1].str, arg_num == 2 ? NULL : args[2].str, arg_num == 2 ? 0 : strlen (args[2].str), flags, print_msg_success_gw, ev); } void do_reply_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -852,46 +975,52 @@ void do_fwd (struct command *command, int arg_num, struct arg args[], struct in_ assert (arg_num >= 2); if (ev) { ev->refcnt ++; } assert (arg_num <= 1000); - if (arg_num == 2) { - tgl_do_forward_message (TLS, args[0].P->id, args[1].num, 0, print_msg_success_gw, ev); - } else { - static int list[1000]; + //if (arg_num == 2) { + // tgl_do_forward_message (TLS, args[0].P->id, &args[1].msg_id, 0, print_msg_success_gw, ev); + //} else { + static tgl_message_id_t *list[1000]; int i; for (i = 0; i < arg_num - 1; i++) { - list[i] = args[i + 1].num; + list[i] = &args[i + 1].msg_id; } - tgl_do_forward_messages (TLS, args[0].P->id, arg_num - 1, list, 0, print_msg_list_success_gw, ev); - } + tgl_do_forward_messages (TLS, args[0].peer_id, arg_num - 1, (void *)list, 0, print_msg_list_success_gw, ev); + //} } void do_fwd_media (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_forward_media (TLS, args[0].P->id, args[1].num, 0, print_msg_success_gw, ev); + tgl_do_forward_media (TLS, args[0].peer_id, &args[1].msg_id, 0, print_msg_success_gw, ev); } void do_send_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 4); if (ev) { ev->refcnt ++; } - tgl_do_send_contact (TLS, args[0].P->id, ARG2STR (1), ARG2STR (2), ARG2STR (3), TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev); + tgl_do_send_contact (TLS, args[0].peer_id, ARG2STR (1), ARG2STR (2), ARG2STR (3), TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev); } void do_reply_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 4); if (ev) { ev->refcnt ++; } - tgl_do_reply_contact (TLS, args[0].num, ARG2STR (1), ARG2STR (2), ARG2STR (3), 0, print_msg_success_gw, ev); + tgl_do_reply_contact (TLS, &args[0].msg_id, ARG2STR (1), ARG2STR (2), ARG2STR (3), 0, print_msg_success_gw, ev); } void do_send_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); if (ev) { ev->refcnt ++; } - tgl_do_send_location (TLS, args[0].P->id, args[1].dval, args[2].dval, TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev); + tgl_do_send_location (TLS, args[0].peer_id, args[1].dval, args[2].dval, TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev); +} + +void do_post_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 3); + if (ev) { ev->refcnt ++; } + tgl_do_send_location (TLS, args[0].peer_id, args[1].dval, args[2].dval, TGL_SEND_MSG_FLAG_REPLY(reply_id) | TGLMF_POST_AS_CHANNEL, print_msg_success_gw, ev); } void do_reply_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); if (ev) { ev->refcnt ++; } - tgl_do_reply_location (TLS, args[0].num, args[1].dval, args[2].dval, 0, print_msg_success_gw, ev); + tgl_do_reply_location (TLS, &args[0].msg_id, args[1].dval, args[2].dval, 0, print_msg_success_gw, ev); } void do_broadcast (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -899,10 +1028,10 @@ void do_broadcast (struct command *command, int arg_num, struct arg args[], stru static tgl_peer_id_t ids[1000]; int i; for (i = 0; i < arg_num - 1; i++) { - ids[i] = args[i].P->id; + ids[i] = args[i].peer_id; } if (ev) { ev->refcnt ++; } - tgl_do_send_broadcast (TLS, arg_num - 1, ids, args[arg_num - 1].str, strlen (args[arg_num - 1].str), disable_msg_preview, print_msg_list_success_gw, ev); + tgl_do_send_broadcast (TLS, arg_num - 1, ids, args[arg_num - 1].str, strlen (args[arg_num - 1].str), disable_msg_preview | do_html, print_msg_list_success_gw, ev); } /* }}} */ @@ -911,7 +1040,7 @@ void do_broadcast (struct command *command, int arg_num, struct arg args[], stru void do_get_self(struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { if (ev) { ev->refcnt ++; } - tgl_do_get_user_info (TLS, TGL_MK_USER(TLS->our_id), 0, print_user_info_gw, ev); + tgl_do_get_user_info (TLS, TLS->our_id, 0, print_user_info_gw, ev); } void do_set_profile_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -932,6 +1061,12 @@ void do_set_username (struct command *command, int arg_num, struct arg args[], s tgl_do_set_username (TLS, ARG2STR (0), print_user_gw, ev); } +void do_set_phone_number (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 1); + if (ev) { ev->refcnt ++; } + tgl_do_set_phone_number (TLS, ARG2STR (0), print_success_gw, ev); +} + void do_status_online (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (!arg_num); if (ev) { ev->refcnt ++; } @@ -957,31 +1092,37 @@ void do_export_card (struct command *command, int arg_num, struct arg args[], st void do_chat_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_set_chat_photo (TLS, args[0].P->id, args[1].str, print_success_gw, ev); + tgl_do_set_chat_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); } void do_rename_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_rename_chat (TLS, args[0].P->id, ARG2STR (1), print_success_gw, ev); + tgl_do_rename_chat (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev); } void do_chat_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_get_chat_info (TLS, args[0].P->id, offline_mode, print_chat_info_gw, ev); + tgl_do_get_chat_info (TLS, args[0].peer_id, offline_mode, print_chat_info_gw, ev); +} + +void do_channel_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 1); + if (ev) { ev->refcnt ++; } + tgl_do_get_channel_info (TLS, args[0].peer_id, offline_mode, print_channel_info_gw, ev); } void do_chat_add_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); if (ev) { ev->refcnt ++; } - tgl_do_add_user_to_chat (TLS, args[0].P->id, args[1].P->id, args[2].num != NOT_FOUND ? args[2].num : 100, print_success_gw, ev); + tgl_do_add_user_to_chat (TLS, args[0].peer_id, args[1].peer_id, args[2].num != NOT_FOUND ? args[2].num : 100, print_success_gw, ev); } void do_chat_del_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_del_user_from_chat (TLS, args[0].P->id, args[1].P->id, print_success_gw, ev); + tgl_do_del_user_from_chat (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev); } void do_create_group_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -989,7 +1130,7 @@ void do_create_group_chat (struct command *command, int arg_num, struct arg args static tgl_peer_id_t ids[1000]; int i; for (i = 0; i < arg_num - 1; i++) { - ids[i] = args[i + 1].P->id; + ids[i] = args[i + 1].peer_id; } if (ev) { ev->refcnt ++; } @@ -999,7 +1140,7 @@ void do_create_group_chat (struct command *command, int arg_num, struct arg args void do_export_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_export_chat_link (TLS, args[0].P->id, print_string_gw, ev); + tgl_do_export_chat_link (TLS, args[0].peer_id, print_string_gw, ev); } void do_import_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1008,6 +1149,37 @@ void do_import_chat_link (struct command *command, int arg_num, struct arg args[ tgl_do_import_chat_link (TLS, ARG2STR (0), print_success_gw, ev); } +void do_channel_invite (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + tgl_do_channel_invite_user (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev); +} + +void do_channel_kick (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + tgl_do_channel_kick_user (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev); +} + +void do_channel_get_members (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 3); + if (ev) { ev->refcnt ++; } + tgl_do_channel_get_members (TLS, args[0].peer_id, args[1].num == NOT_FOUND ? 100 : args[1].num, args[2].num == NOT_FOUND ? 0 : args[2].num, 0, print_user_list_gw, ev); +} + +void do_channel_get_admins (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 3); + if (ev) { ev->refcnt ++; } + tgl_do_channel_get_members (TLS, args[0].peer_id, args[1].num == NOT_FOUND ? 100 : args[1].num, args[2].num == NOT_FOUND ? 0 : args[2].num, 1, print_user_list_gw, ev); +} + +void do_chat_upgrade (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 1); + if (ev) { ev->refcnt ++; } + tgl_do_upgrade_group (TLS, args[0].peer_id, print_success_gw, ev); +} + + /* }}} */ /* {{{ WORKING WITH USERS */ @@ -1016,7 +1188,7 @@ void do_import_chat_link (struct command *command, int arg_num, struct arg args[ void do_user_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_get_user_info (TLS, args[0].P->id, offline_mode, print_user_info_gw, ev); + tgl_do_get_user_info (TLS, args[0].peer_id, offline_mode, print_user_info_gw, ev); } void do_add_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1027,9 +1199,11 @@ void do_add_contact (struct command *command, int arg_num, struct arg args[], st void do_rename_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); - if (args[0].P->user.phone) { + + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); + if (P && P->user.phone) { if (ev) { ev->refcnt ++; } - tgl_do_add_contact (TLS, args[0].P->user.phone, strlen (args[0].P->user.phone), args[1].str, strlen (args[1].str), args[2].str, strlen (args[2].str), 0, print_user_list_gw, ev); + tgl_do_add_contact (TLS, P->user.phone, strlen (P->user.phone), args[1].str, strlen (args[1].str), args[2].str, strlen (args[2].str), 0, print_user_list_gw, ev); } else { if (ev) { ev->refcnt ++; } print_success_gw (TLS, ev, 0); @@ -1039,7 +1213,7 @@ void do_rename_contact (struct command *command, int arg_num, struct arg args[], void do_del_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_del_contact (TLS, args[0].P->id, print_success_gw, ev); + tgl_do_del_contact (TLS, args[0].peer_id, print_success_gw, ev); } @@ -1078,13 +1252,13 @@ void do_import_card (struct command *command, int arg_num, struct arg args[], st void do_block_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_block_user (TLS, args[0].P->id, print_success_gw, ev); + tgl_do_block_user (TLS, args[0].peer_id, print_success_gw, ev); } void do_unblock_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_unblock_user (TLS, args[0].P->id, print_success_gw, ev); + tgl_do_unblock_user (TLS, args[0].peer_id, print_success_gw, ev); } /* }}} */ @@ -1093,16 +1267,22 @@ void do_unblock_user (struct command *command, int arg_num, struct arg args[], s void do_accept_secret_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_accept_encr_chat_request (TLS, &args[0].P->encr_chat, print_encr_chat_success_gw, ev); + + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); + if (P) { + tgl_do_accept_encr_chat_request (TLS, &P->encr_chat, print_encr_chat_success_gw, ev); + } else { + print_success_gw (TLS, ev, 0); + } } void do_set_ttl (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); - if (args[0].P->encr_chat.state == sc_ok) { - if (ev) { ev->refcnt ++; } - tgl_do_set_encr_chat_ttl (TLS, &args[0].P->encr_chat, args[1].num, print_msg_success_gw, ev); + if (ev) { ev->refcnt ++; } + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); + if (P && P->encr_chat.state == sc_ok) { + tgl_do_set_encr_chat_ttl (TLS, &P->encr_chat, args[1].num, print_msg_success_gw, ev); } else { - if (ev) { ev->refcnt ++; } print_success_gw (TLS, ev, 0); } } @@ -1112,8 +1292,7 @@ void do_visualize_key (struct command *command, int arg_num, struct arg args[], static char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN}; static unsigned char buf[16]; memset (buf, 0, sizeof (buf)); - tgl_peer_id_t id = args[0].P->id; - tgl_do_visualize_key (TLS, id, buf); + tgl_do_visualize_key (TLS, args[0].peer_id, buf); mprint_start (ev); int i; for (i = 0; i < 16; i++) { @@ -1159,7 +1338,71 @@ void do_visualize_key (struct command *command, int arg_num, struct arg args[], void do_create_secret_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_create_secret_chat (TLS, args[0].P->id, print_secret_chat_gw, ev); + tgl_do_create_secret_chat (TLS, args[0].peer_id, print_secret_chat_gw, ev); +} + +/* }}} */ + +/* WORKING WITH CHANNELS {{{ */ + +void do_rename_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + tgl_do_rename_channel (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev); +} + +void do_channel_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + tgl_do_set_channel_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); +} + +void do_channel_set_about (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + tgl_do_channel_set_about (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev); +} + +void do_channel_set_admin (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 3); + if (ev) { ev->refcnt ++; } + tgl_do_channel_set_admin (TLS, args[0].peer_id, args[1].peer_id, args[2].num, print_success_gw, ev); +} + +void do_channel_set_username (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 2); + if (ev) { ev->refcnt ++; } + tgl_do_channel_set_username (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev); +} + +void do_create_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num >= 2 && arg_num <= 1000); + static tgl_peer_id_t ids[1000]; + int i; + for (i = 0; i < arg_num - 2; i++) { + ids[i] = args[i + 2].peer_id; + } + + if (ev) { ev->refcnt ++; } + tgl_do_create_channel (TLS, arg_num - 2, ids, ARG2STR (0), ARG2STR (1), 1, print_success_gw, ev); +} + +void do_join_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 1); + if (ev) { ev->refcnt ++; } + tgl_do_join_channel (TLS, args[0].peer_id, print_success_gw, ev); +} + +void do_leave_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 1); + if (ev) { ev->refcnt ++; } + tgl_do_leave_channel (TLS, args[0].peer_id, print_success_gw, ev); +} + +void do_export_channel_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num == 1); + if (ev) { ev->refcnt ++; } + tgl_do_export_channel_link (TLS, args[0].peer_id, print_string_gw, ev); } /* }}} */ @@ -1172,10 +1415,16 @@ void do_dialog_list (struct command *command, int arg_num, struct arg args[], st tgl_do_get_dialog_list (TLS, args[0].num != NOT_FOUND ? args[0].num : 100, args[1].num != NOT_FOUND ? args[1].num : 0, print_dialog_list_gw, ev); } +void do_channel_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { + assert (arg_num <= 2); + if (ev) { ev->refcnt ++; } + tgl_do_get_channels_dialog_list (TLS, args[0].num != NOT_FOUND ? args[0].num : 100, args[1].num != NOT_FOUND ? args[1].num : 0, print_dialog_list_gw, ev); +} + void do_resolve_username (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_contact_search (TLS, args[0].str, strlen (args[0].str), print_user_gw, ev); + tgl_do_contact_search (TLS, args[0].str, strlen (args[0].str), print_peer_gw, ev); } void do_contact_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1191,13 +1440,13 @@ void do_contact_list (struct command *command, int arg_num, struct arg args[], s void do_mark_read (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_mark_read (TLS, args[0].P->id, print_success_gw, ev); + tgl_do_mark_read (TLS, args[0].peer_id, print_success_gw, ev); } void do_history (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); if (ev) { ev->refcnt ++; } - tgl_do_get_history (TLS, args[0].P->id, args[2].num != NOT_FOUND ? args[2].num : 0, args[1].num != NOT_FOUND ? args[1].num : 40, offline_mode, print_msg_list_gw, ev); + tgl_do_get_history (TLS, args[0].peer_id, args[2].num != NOT_FOUND ? args[2].num : 0, args[1].num != NOT_FOUND ? args[1].num : 40, offline_mode, print_msg_list_history_gw, ev); } void print_fail (struct in_ev *ev); @@ -1213,13 +1462,13 @@ void do_send_typing (struct command *command, int arg_num, struct arg args[], st status = (enum tgl_typing_status) args[1].num; // if the status parameter is given, and is in range. } if (ev) { ev->refcnt ++; } - tgl_do_send_typing (TLS, args[0].P->id, status, print_success_gw, ev); + tgl_do_send_typing (TLS, args[0].peer_id, status, print_success_gw, ev); } void do_send_typing_abort (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_send_typing (TLS, args[0].P->id, tgl_typing_cancel, print_success_gw, ev); + tgl_do_send_typing (TLS, args[0].peer_id, tgl_typing_cancel, print_success_gw, ev); } /* }}} */ @@ -1229,13 +1478,17 @@ void do_send_typing_abort (struct command *command, int arg_num, struct arg args #define DO_LOAD_PHOTO(tp,act,actf) \ void do_ ## act ## _ ## tp (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \ assert (arg_num == 1);\ - struct tgl_message *M = tgl_message_get (TLS, args[0].num);\ + struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id);\ if (M && !(M->flags & TGLMF_SERVICE)) {\ if (ev) { ev->refcnt ++; } \ if (M->media.type == tgl_message_media_photo) { \ tgl_do_load_photo (TLS, M->media.photo, actf, ev);\ } else if (M->media.type == tgl_message_media_document) {\ tgl_do_load_document (TLS, M->media.document, actf, ev);\ + } else if (M->media.type == tgl_message_media_video) {\ + tgl_do_load_video (TLS, M->media.document, actf, ev);\ + } else if (M->media.type == tgl_message_media_audio) {\ + tgl_do_load_audio (TLS, M->media.document, actf, ev);\ } else if (M->media.type == tgl_message_media_document_encr) {\ tgl_do_load_encr_document (TLS, M->media.encr_document, actf, ev); \ } else if (M->media.type == tgl_message_media_webpage) {\ @@ -1251,7 +1504,7 @@ void do_ ## act ## _ ## tp (struct command *command, int arg_num, struct arg arg #define DO_LOAD_PHOTO_THUMB(tp,act,actf) \ void do_ ## act ## _ ## tp ## _thumb (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \ assert (arg_num == 1);\ - struct tgl_message *M = tgl_message_get (TLS, args[0].num);\ + struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id);\ if (M && !(M->flags & TGLMF_SERVICE)) {\ if (M->media.type == tgl_message_media_document) {\ if (ev) { ev->refcnt ++; } \ @@ -1281,13 +1534,25 @@ DO_LOAD_PHOTO(any, open, open_filename_gw) void do_load_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_load_file_location (TLS, &args[0].P->user.photo_big, print_filename_gw, ev); + + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); + if (P) { + tgl_do_load_file_location (TLS, &P->user.photo_big, print_filename_gw, ev); + } else { + print_filename_gw (TLS, ev, 0, NULL); + } } void do_view_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_load_file_location (TLS, &args[0].P->user.photo_big, open_filename_gw, ev); + + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); + if (P) { + tgl_do_load_file_location (TLS, &P->user.photo_big, print_filename_gw, ev); + } else { + open_filename_gw (TLS, ev, 0, NULL); + } } /* }}} */ @@ -1296,12 +1561,6 @@ void do_view_user_photo (struct command *command, int arg_num, struct arg args[ void do_search (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 6); - tgl_peer_id_t id; - if (args[0].P) { - id = args[0].P->id; - } else { - id = TGL_PEER_NOT_FOUND; - } int limit; if (args[1].num != NOT_FOUND) { limit = args[1].num; @@ -1327,18 +1586,18 @@ void do_search (struct command *command, int arg_num, struct arg args[], struct offset = 0; } if (ev) { ev->refcnt ++; } - tgl_do_msg_search (TLS, id, from, to, limit, offset, args[5].str, strlen (args[5].str), print_msg_list_gw, ev); + tgl_do_msg_search (TLS, args[0].peer_id, from, to, limit, offset, args[5].str, strlen (args[5].str), print_msg_list_gw, ev); } void do_delete_msg (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { if (ev) { ev->refcnt ++; } - tgl_do_delete_msg (TLS, args[0].num, print_success_gw, ev); + tgl_do_delete_msg (TLS, &args[0].msg_id, print_success_gw, ev); } void do_get_message (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - tgl_do_get_message (TLS, args[0].num, print_msg_gw, ev); + tgl_do_get_message (TLS, &args[0].msg_id, print_msg_gw, ev); } /* }}} */ @@ -1348,7 +1607,7 @@ void do_get_message (struct command *command, int arg_num, struct arg args[], st void do_start_bot (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); if (ev) { ev->refcnt ++; } - tgl_do_start_bot (TLS, args[0].P->id, args[1].P->id, ARG2STR(2), print_success_gw, ev); + tgl_do_start_bot (TLS, args[0].peer_id, args[1].peer_id, ARG2STR(2), print_success_gw, ev); } /* }}} */ @@ -1368,21 +1627,25 @@ extern struct event *term_ev; void do_clear (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { logprintf ("Do_clear\n"); free (default_username); - free (config_filename); + tfree_str (config_filename); //free (prefix); - free (auth_file_name); - free (state_file_name); - free (secret_chat_file_name); - free (downloads_directory); - free (config_directory); - free (binlog_file_name); - free (lua_file); - free (python_file); + tfree_str (auth_file_name); + tfree_str (state_file_name); + tfree_str (secret_chat_file_name); + tfree_str (downloads_directory); + //tfree_str (config_directory); + tfree_str (binlog_file_name); + tfree_str (lua_file); + tfree_str (python_file); + if (home_directory) { + tfree_str (home_directory); + } clear_history (); event_free (term_ev); struct event_base *ev_base = TLS->ev_base; tgl_free_all (TLS); event_base_free (ev_base); + logprintf ("Bytes left allocated: %lld\n", tgl_get_allocated_bytes ()); do_halt (0); } @@ -1393,64 +1656,91 @@ struct command commands[MAX_COMMANDS_SIZE] = { {"add_contact", {ca_string, ca_string, ca_string, ca_none}, do_add_contact, "add_contact \tTries to add user to contact list", NULL}, {"block_user", {ca_user, ca_none}, do_block_user, "block_user \tBlocks user", NULL}, {"broadcast", {ca_user, ca_period, ca_string_end, ca_none}, do_broadcast, "broadcast + \tSends text to several users at once", NULL}, + {"channel_get_admins", {ca_channel, ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_channel_get_admins, "channel_get_admins [limit=100] [offset=0]\tGets channel admins", NULL}, + {"channel_get_members", {ca_channel, ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_channel_get_members, "channel_get_members [limit=100] [offset=0]\tGets channel members", NULL}, + {"channel_info", {ca_channel, ca_none}, do_channel_info, "channel_info \tPrints info about channel (id, members, admin, etc.)", NULL}, + {"channel_invite", {ca_channel, ca_user, ca_none}, do_channel_invite, "channel_invite \tInvites user to channel", NULL}, + {"channel_join", {ca_channel, ca_none}, do_join_channel, "channel_join \tJoins to channel", NULL}, + {"channel_kick", {ca_channel, ca_user, ca_none}, do_channel_kick, "channel_kick \tKicks user from channel", NULL}, + {"channel_leave", {ca_channel, ca_none}, do_leave_channel, "channel_leave \tLeaves from channel", NULL}, + {"channel_list", {ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_channel_list, "channel_list [limit=100] [offset=0]\tList of last channels", NULL}, + {"channel_set_about", {ca_channel, ca_string, ca_none}, do_channel_set_about, "channel_set_about \tSets channel about info.", NULL}, + {"channel_set_admin", {ca_channel, ca_user, ca_number, ca_none}, do_channel_set_admin, "channel_set_admin \tSets channel admin. 0 - not admin, 1 - moderator, 2 - editor", NULL}, + {"channel_set_username", {ca_channel, ca_string, ca_none}, do_channel_set_username, "channel_set_username \tSets channel username info.", NULL}, + {"channel_set_photo", {ca_channel, ca_file_name_end, ca_none}, do_channel_set_photo, "channel_set_photo \tSets channel photo. Photo will be cropped to square", NULL}, {"chat_add_user", {ca_chat, ca_user, ca_number | ca_optional, ca_none}, do_chat_add_user, "chat_add_user [msgs-to-forward]\tAdds user to chat. Sends him last msgs-to-forward message from this chat. Default 100", NULL}, {"chat_del_user", {ca_chat, ca_user, ca_none}, do_chat_del_user, "chat_del_user \tDeletes user from chat", NULL}, {"chat_info", {ca_chat, ca_none}, do_chat_info, "chat_info \tPrints info about chat (id, members, admin, etc.)", NULL}, {"chat_set_photo", {ca_chat, ca_file_name_end, ca_none}, do_chat_set_photo, "chat_set_photo \tSets chat photo. Photo will be cropped to square", NULL}, + {"chat_upgrade", {ca_chat, ca_none}, do_chat_upgrade, "chat_upgrade \tUpgrades chat to megagroup", NULL}, {"chat_with_peer", {ca_peer, ca_none}, do_chat_with_peer, "chat_with_peer \tInterface option. All input will be treated as messages to this peer. Type /quit to end this mode", NULL}, {"clear", {ca_none}, do_clear, "clear\tClears all data and exits. For debug.", NULL}, {"contact_list", {ca_none}, do_contact_list, "contact_list\tPrints contact list", NULL}, {"contact_search", {ca_string, ca_none}, do_resolve_username, "contact_search username\tSearches user by username", NULL}, + {"create_channel", {ca_string, ca_string, ca_user | ca_optional, ca_period, ca_none}, do_create_channel, "create_channel +\tCreates channel with users", NULL}, {"create_group_chat", {ca_string, ca_user, ca_period, ca_none}, do_create_group_chat, "create_group_chat +\tCreates group chat with users", NULL}, {"create_secret_chat", {ca_user, ca_none}, do_create_secret_chat, "create_secret_chat \tStarts creation of secret chat", NULL}, {"del_contact", {ca_user, ca_none}, do_del_contact, "del_contact \tDeletes contact from contact list", NULL}, - {"delete_msg", {ca_number, ca_none}, do_delete_msg, "delete_msg \tDeletes message", NULL}, + {"delete_msg", {ca_msg_id, ca_none}, do_delete_msg, "delete_msg \tDeletes message", NULL}, {"dialog_list", {ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_dialog_list, "dialog_list [limit=100] [offset=0]\tList of last conversations", NULL}, {"export_card", {ca_none}, do_export_card, "export_card\tPrints card that can be imported by another user with import_card method", NULL}, + {"export_channel_link", {ca_channel, ca_none}, do_export_channel_link, "export_channel_link\tPrints channel link that can be used to join to channel", NULL}, {"export_chat_link", {ca_chat, ca_none}, do_export_chat_link, "export_chat_link\tPrints chat link that can be used to join to chat", NULL}, - {"fwd", {ca_peer, ca_number, ca_period, ca_none}, do_fwd, "fwd +\tForwards message to peer. Forward to secret chats is forbidden", NULL}, - {"fwd_media", {ca_peer, ca_number, ca_none}, do_fwd_media, "fwd_media \tForwards message media to peer. Forward to secret chats is forbidden. Result slightly differs from fwd", NULL}, - {"get_message", {ca_number, ca_none}, do_get_message, "get_message \tGet message by id", NULL}, + {"fwd", {ca_peer, ca_msg_id, ca_period, ca_none}, do_fwd, "fwd +\tForwards message to peer. Forward to secret chats is forbidden", NULL}, + {"fwd_media", {ca_peer, ca_msg_id, ca_none}, do_fwd_media, "fwd_media \tForwards message media to peer. Forward to secret chats is forbidden. Result slightly differs from fwd", NULL}, + {"get_terms_of_service", {ca_none}, do_get_terms_of_service, "get_terms_of_service\tPrints telegram's terms of service", NULL}, + {"get_message", {ca_msg_id, ca_none}, do_get_message, "get_message \tGet message by id", NULL}, {"get_self", {ca_none}, do_get_self, "get_self \tGet our user info", NULL}, - {"help", {ca_none}, do_help, "help\tPrints this help", NULL}, + {"help", {ca_command | ca_optional, ca_none}, do_help, "help [command]\tPrints this help", NULL}, {"history", {ca_peer, ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_history, "history [limit] [offset]\tPrints messages with this peer (most recent message lower). Also marks messages as read", NULL}, {"import_card", {ca_string, ca_none}, do_import_card, "import_card \tGets user by card and prints it name. You can then send messages to him as usual", NULL}, {"import_chat_link", {ca_string, ca_none}, do_import_chat_link, "import_chat_link \tJoins to chat by link", NULL}, - {"load_audio", {ca_number, ca_none}, do_load_audio, "load_audio \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"import_channel_link", {ca_string, ca_none}, do_import_chat_link, "import_channel_link \tJoins to channel by link", NULL}, + {"load_audio", {ca_msg_id, ca_none}, do_load_audio, "load_audio \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_channel_photo", {ca_channel, ca_none}, do_load_user_photo, "load_channel_photo \tDownloads file to downloads dirs. Prints file name after download end", NULL}, {"load_chat_photo", {ca_chat, ca_none}, do_load_user_photo, "load_chat_photo \tDownloads file to downloads dirs. Prints file name after download end", NULL}, - {"load_document", {ca_number, ca_none}, do_load_document, "load_document \tDownloads file to downloads dirs. Prints file name after download end", NULL}, - {"load_document_thumb", {ca_number, ca_none}, do_load_document_thumb, "load_document_thumb \tDownloads file to downloads dirs. Prints file name after download end", NULL}, - {"load_file", {ca_number, ca_none}, do_load_file, "load_file \tDownloads file to downloads dirs. Prints file name after download end", NULL}, - {"load_file_thumb", {ca_number, ca_none}, do_load_file_thumb, "load_file_thumb \tDownloads file to downloads dirs. Prints file name after download end", NULL}, - {"load_photo", {ca_number, ca_none}, do_load_photo, "load_photo \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_document", {ca_msg_id, ca_none}, do_load_document, "load_document \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_document_thumb", {ca_msg_id, ca_none}, do_load_document_thumb, "load_document_thumb \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_file", {ca_msg_id, ca_none}, do_load_file, "load_file \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_file_thumb", {ca_msg_id, ca_none}, do_load_file_thumb, "load_file_thumb \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_photo", {ca_msg_id, ca_none}, do_load_photo, "load_photo \tDownloads file to downloads dirs. Prints file name after download end", NULL}, {"load_user_photo", {ca_user, ca_none}, do_load_user_photo, "load_user_photo \tDownloads file to downloads dirs. Prints file name after download end", NULL}, - {"load_video", {ca_number, ca_none}, do_load_video, "load_video \tDownloads file to downloads dirs. Prints file name after download end", NULL}, - {"load_video_thumb", {ca_number, ca_none}, do_load_video_thumb, "load_video_thumb \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_video", {ca_msg_id, ca_none}, do_load_video, "load_video \tDownloads file to downloads dirs. Prints file name after download end", NULL}, + {"load_video_thumb", {ca_msg_id, ca_none}, do_load_video_thumb, "load_video_thumb \tDownloads file to downloads dirs. Prints file name after download end", NULL}, {"main_session", {ca_none}, do_main_session, "main_session\tSends updates to this connection (or terminal). Useful only with listening socket", NULL}, {"mark_read", {ca_peer, ca_none}, do_mark_read, "mark_read \tMarks messages with peer as read", NULL}, {"msg", {ca_peer, ca_msg_string_end, ca_none}, do_msg, "msg \tSends text message to peer", NULL}, {"msg_kbd", {ca_peer, ca_string, ca_msg_string_end, ca_none}, do_msg_kbd, "msg \tSends text message to peer with custom kbd", NULL}, + {"post", {ca_peer, ca_msg_string_end, ca_none}, do_post, "post \tSends text message to peer as admin", NULL}, + {"post_audio", {ca_peer, ca_file_name, ca_none}, do_post_audio, "post_audio \tPosts audio to peer", NULL}, + {"post_document", {ca_peer, ca_file_name, ca_none}, do_post_document, "post_document \tPosts document to peer", NULL}, + {"post_file", {ca_peer, ca_file_name, ca_none}, do_post_file, "post_file \tSends document to peer", NULL}, + {"post_location", {ca_peer, ca_double, ca_double, ca_none}, do_post_location, "post_location \tSends geo location", NULL}, + {"post_photo", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_post_photo, "post_photo [caption]\tSends photo to peer", NULL}, + {"post_text", {ca_peer, ca_file_name_end, ca_none}, do_post_text, "post_text \tSends contents of text file as plain text message", NULL}, + {"post_video", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_post_video, "post_video [caption]\tSends video to peer", NULL}, {"quit", {ca_none}, do_quit, "quit\tQuits immediately", NULL}, + {"rename_channel", {ca_channel, ca_string_end, ca_none}, do_rename_channel, "rename_channel \tRenames channel", NULL}, {"rename_chat", {ca_chat, ca_string_end, ca_none}, do_rename_chat, "rename_chat \tRenames chat", NULL}, {"rename_contact", {ca_user, ca_string, ca_string, ca_none}, do_rename_contact, "rename_contact \tRenames contact", NULL}, - {"reply", {ca_number, ca_msg_string_end, ca_none}, do_reply, "reply \tSends text reply to message", NULL}, - {"reply_audio", {ca_number, ca_file_name, ca_none}, do_send_audio, "reply_audio \tSends audio to peer", NULL}, - {"reply_contact", {ca_number, ca_string, ca_string, ca_string, ca_none}, do_reply_contact, "reply_contact \tSends contact (not necessary telegram user)", NULL}, - {"reply_document", {ca_number, ca_file_name, ca_none}, do_reply_document, "reply_document \tSends document to peer", NULL}, - {"reply_file", {ca_number, ca_file_name, ca_none}, do_reply_file, "reply_file \tSends document to peer", NULL}, - {"reply_location", {ca_number, ca_double, ca_double, ca_none}, do_reply_location, "reply_location \tSends geo location", NULL}, - {"reply_photo", {ca_number, ca_file_name, ca_string_end | ca_optional, ca_none}, do_reply_photo, "reply_photo [caption]\tSends photo to peer", NULL}, + {"reply", {ca_msg_id, ca_msg_string_end, ca_none}, do_reply, "reply \tSends text reply to message", NULL}, + {"reply_audio", {ca_msg_id, ca_file_name, ca_none}, do_send_audio, "reply_audio \tSends audio to peer", NULL}, + {"reply_contact", {ca_msg_id, ca_string, ca_string, ca_string, ca_none}, do_reply_contact, "reply_contact \tSends contact (not necessary telegram user)", NULL}, + {"reply_document", {ca_msg_id, ca_file_name, ca_none}, do_reply_document, "reply_document \tSends document to peer", NULL}, + {"reply_file", {ca_msg_id, ca_file_name, ca_none}, do_reply_file, "reply_file \tSends document to peer", NULL}, + {"reply_location", {ca_msg_id, ca_double, ca_double, ca_none}, do_reply_location, "reply_location \tSends geo location", NULL}, + {"reply_photo", {ca_msg_id, ca_file_name, ca_string_end | ca_optional, ca_none}, do_reply_photo, "reply_photo [caption]\tSends photo to peer", NULL}, //{"reply_text", {ca_number, ca_file_name_end, ca_none}, do_reply_text, "reply_text \tSends contents of text file as plain text message", NULL}, - {"reply_video", {ca_number, ca_file_name, ca_none}, do_reply_video, "reply_video \tSends video to peer", NULL}, + {"reply_video", {ca_msg_id, ca_file_name, ca_none}, do_reply_video, "reply_video \tSends video to peer", NULL}, {"resolve_username", {ca_string, ca_none}, do_resolve_username, "resolve_username username\tSearches user by username", NULL}, //{"restore_msg", {ca_number, ca_none}, do_restore_msg, "restore_msg \tRestores message. Only available shortly (one hour?) after deletion", NULL}, {"safe_quit", {ca_none}, do_safe_quit, "safe_quit\tWaits for all queries to end, then quits", NULL}, {"search", {ca_peer | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_string_end}, do_search, "search [peer] [limit] [from] [to] [offset] pattern\tSearch for pattern in messages from date from to date to (unixtime) in messages with peer (if peer not present, in all messages)", NULL}, //{"secret_chat_rekey", { ca_secret_chat, ca_none}, do_secret_chat_rekey, "generate new key for active secret chat", NULL}, - {"send_audio", {ca_peer, ca_file_name, ca_none}, do_send_audio, "send_audio \tSends audio to peer", NULL}, + {"send_audio", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_audio, "send_audio \tSends audio to peer", NULL}, {"send_contact", {ca_peer, ca_string, ca_string, ca_string, ca_none}, do_send_contact, "send_contact \tSends contact (not necessary telegram user)", NULL}, - {"send_document", {ca_peer, ca_file_name, ca_none}, do_send_document, "send_document \tSends document to peer", NULL}, - {"send_file", {ca_peer, ca_file_name, ca_none}, do_send_file, "send_file \tSends document to peer", NULL}, + {"send_document", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_document, "send_document \tSends document to peer", NULL}, + {"send_file", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_file, "send_file \tSends document to peer", NULL}, {"send_location", {ca_peer, ca_double, ca_double, ca_none}, do_send_location, "send_location \tSends geo location", NULL}, {"send_photo", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_photo, "send_photo [caption]\tSends photo to peer", NULL}, {"send_text", {ca_peer, ca_file_name_end, ca_none}, do_send_text, "send_text \tSends contents of text file as plain text message", NULL}, @@ -1463,6 +1753,7 @@ struct command commands[MAX_COMMANDS_SIZE] = { {"set_profile_photo", {ca_file_name_end, ca_none}, do_set_profile_photo, "set_profile_photo \tSets profile photo. Photo will be cropped to square", NULL}, {"set_ttl", {ca_secret_chat, ca_number, ca_none}, do_set_ttl, "set_ttl \tSets secret chat ttl. Client itself ignores ttl", NULL}, {"set_username", {ca_string, ca_none}, do_set_username, "set_username \tSets username.", NULL}, + {"set_phone_number", {ca_string, ca_none}, do_set_phone_number, "set_phone_number \tChanges the phone number of this account", NULL}, {"show_license", {ca_none}, do_show_license, "show_license\tPrints contents of GPL license", NULL}, {"start_bot", {ca_user, ca_chat, ca_string, ca_none}, do_start_bot, "start_bot \tAdds bot to chat", NULL}, {"stats", {ca_none}, do_stats, "stats\tFor debug purpose", NULL}, @@ -1470,18 +1761,20 @@ struct command commands[MAX_COMMANDS_SIZE] = { {"status_offline", {ca_none}, do_status_offline, "status_offline\tSets status as offline", NULL}, {"unblock_user", {ca_user, ca_none}, do_unblock_user, "unblock_user \tUnblocks user", NULL}, {"user_info", {ca_user, ca_none}, do_user_info, "user_info \tPrints info about user (id, last online, phone)", NULL}, - {"view_audio", {ca_number, ca_none}, do_open_audio, "view_audio \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"version", {ca_none}, do_version, "version\tPrints client and library version", NULL}, + {"view_audio", {ca_msg_id, ca_none}, do_open_audio, "view_audio \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view_channel_photo", {ca_channel, ca_none}, do_view_user_photo, "view_channel_photo \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, {"view_chat_photo", {ca_chat, ca_none}, do_view_user_photo, "view_chat_photo \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view_document", {ca_number, ca_none}, do_open_document, "view_document \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view_document_thumb", {ca_number, ca_none}, do_open_document_thumb, "view_document_thumb \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view_file", {ca_number, ca_none}, do_open_file, "view_file \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view_file_thumb", {ca_number, ca_none}, do_open_file_thumb, "view_file_thumb \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view_photo", {ca_number, ca_none}, do_open_photo, "view_photo \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view_document", {ca_msg_id, ca_none}, do_open_document, "view_document \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view_document_thumb", {ca_msg_id, ca_none}, do_open_document_thumb, "view_document_thumb \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view_file", {ca_msg_id, ca_none}, do_open_file, "view_file \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view_file_thumb", {ca_msg_id, ca_none}, do_open_file_thumb, "view_file_thumb \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view_photo", {ca_msg_id, ca_none}, do_open_photo, "view_photo \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, {"view_user_photo", {ca_user, ca_none}, do_view_user_photo, "view_user_photo \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view_video", {ca_number, ca_none}, do_open_video, "view_video \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view_video_thumb", {ca_number, ca_none}, do_open_video_thumb, "view_video_thumb \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, - {"view", {ca_number, ca_none}, do_open_any, "view \tTries to view message contents", NULL}, - {"visualize_key", {ca_secret_chat, ca_none}, do_visualize_key, "visualize_key \tPrints visualization of encryption key (first 16 bytes sha1 of it in fact}", NULL} + {"view_video", {ca_msg_id, ca_none}, do_open_video, "view_video \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view_video_thumb", {ca_msg_id, ca_none}, do_open_video_thumb, "view_video_thumb \tDownloads file to downloads dirs. Then tries to open it with system default action", NULL}, + {"view", {ca_msg_id, ca_none}, do_open_any, "view \tTries to view message contents", NULL}, + {"visualize_key", {ca_secret_chat, ca_none}, do_visualize_key, "visualize_key \tPrints visualization of encryption key (first 16 bytes sha1 of it in fact)", NULL} }; void register_new_command (struct command *cmd) { @@ -1494,13 +1787,13 @@ void register_new_command (struct command *cmd) { } tgl_peer_t *autocomplete_peer; -int autocomplete_id; +tgl_message_id_t autocomplete_id; enum command_argument get_complete_mode (void) { force_end_mode = 0; line_ptr = rl_line_buffer; autocomplete_peer = NULL; - autocomplete_id = 0; + autocomplete_id.peer_type = NOT_FOUND; while (1) { next_token (); @@ -1559,7 +1852,7 @@ enum command_argument get_complete_mode (void) { char *save = line_ptr; next_token (); - if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double) { + if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double || op == ca_msg_id || op == ca_command || op == ca_channel) { if (cur_token_quoted) { if (opt) { line_ptr = save; @@ -1586,23 +1879,32 @@ enum command_argument get_complete_mode (void) { case ca_secret_chat: ok = (tgl_get_peer_type (cur_token_encr_chat ()) != NOT_FOUND); break; + case ca_channel: + ok = (tgl_get_peer_type (cur_token_channel ()) != NOT_FOUND); + break; case ca_peer: ok = (tgl_get_peer_type (cur_token_peer ()) != NOT_FOUND); if (ok) { autocomplete_peer = tgl_peer_get (TLS, cur_token_peer ()); - autocomplete_id = 0; + autocomplete_id.peer_type = NOT_FOUND; } break; case ca_number: ok = (cur_token_int () != NOT_FOUND); + break; + case ca_msg_id: + ok = (cur_token_msg_id ().peer_type != 0); if (ok) { autocomplete_peer = NULL; - autocomplete_id = cur_token_int (); + autocomplete_id = cur_token_msg_id (); } break; case ca_double: ok = (cur_token_double () != NOT_FOUND); break; + case ca_command: + ok = cur_token_len > 0; + break; default: assert (0); } @@ -1774,6 +2076,44 @@ int complete_chat_command (tgl_peer_t *P, int index, const char *text, int len, } } +int complete_username (int mode, int index, const char *text, int len, char **R) { + *R = NULL; + if (len > 0 && *text == '@') { + text ++; + len --; + } + index ++; + while (index < TLS->peer_num) { + tgl_peer_t *P = TLS->Peers[index]; + if (mode && tgl_get_peer_type (P->id) != mode) { + index ++; + continue; + } + char *u = NULL; + if (tgl_get_peer_type (P->id) == TGL_PEER_USER) { + u = P->user.username; + } else if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) { + u = P->channel.username; + } + if (!u) { + index ++; + continue; + } + if ((int)strlen (u) < len || memcmp (u, text, len)) { + index ++; + continue; + } + *R = malloc (strlen (u) + 2); + *R[0] = '@'; + memcpy (*R + 1, u, strlen (u) + 1); + break; + } + if (index == TLS->peer_num) { + return -1; + } + return index; +} + char *command_generator (const char *text, int state) { #ifndef DISABLE_EXTF static int len; @@ -1805,7 +2145,7 @@ char *command_generator (const char *text, int state) { if (mode != ca_file_name && mode != ca_file_name_end && index == -1) { return 0; } } - if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double) { + if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double || mode == ca_msg_id) { if (c) { rl_line_buffer[rl_point] = c; } return 0; } @@ -1818,11 +2158,19 @@ char *command_generator (const char *text, int state) { if (c) { rl_line_buffer[rl_point] = c; } return R; case ca_user: - index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R); + if (command_len && command_pos[0] == '@') { + index = complete_username (TGL_PEER_USER, index, command_pos, command_len, &R); + } else { + index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R); + } if (c) { rl_line_buffer[rl_point] = c; } return R; case ca_peer: - index = tgl_complete_peer_list (TLS, index, command_pos, command_len, &R); + if (command_len && command_pos[0] == '@') { + index = complete_username (0, index, command_pos, command_len, &R); + } else { + index = tgl_complete_peer_list (TLS, index, command_pos, command_len, &R); + } if (c) { rl_line_buffer[rl_point] = c; } return R; case ca_file_name: @@ -1838,6 +2186,14 @@ char *command_generator (const char *text, int state) { index = tgl_complete_encr_chat_list (TLS, index, command_pos, command_len, &R); if (c) { rl_line_buffer[rl_point] = c; } return R; + case ca_channel: + if (command_len && command_pos[0] == '@') { + index = complete_username (TGL_PEER_CHANNEL, index, command_pos, command_len, &R); + } else { + index = tgl_complete_channel_list (TLS, index, command_pos, command_len, &R); + } + if (c) { rl_line_buffer[rl_point] = c; } + return R; case ca_modifier: index = complete_string_list (modifiers, index, command_pos, command_len, &R); if (c) { rl_line_buffer[rl_point] = c; } @@ -1851,8 +2207,8 @@ char *command_generator (const char *text, int state) { index = complete_chat_command (autocomplete_peer, index, command_pos, command_len, &R); } } - if (autocomplete_id) { - struct tgl_message *M = tgl_message_get (TLS, autocomplete_id); + if (autocomplete_id.peer_type != (unsigned)NOT_FOUND) { + struct tgl_message *M = tgl_message_get (TLS, &autocomplete_id); if (M) { if (command_len > 0 && *command_pos == '/') { tgl_peer_t *P = tgl_peer_get (TLS, M->from_id); @@ -1886,6 +2242,9 @@ void work_modifier (const char *s, int l) { if (sscanf (s, "[reply=%d]", &reply_id) >= 1) { } + if (is_same_word (s, l, "[html]")) { + do_html = TGLMF_HTML; + } if (is_same_word (s, l, "[disable_preview]")) { disable_msg_preview = TGL_SEND_MSG_FLAG_DISABLE_PREVIEW; } @@ -2022,6 +2381,17 @@ void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int nu mprint_end (ev); } +void print_msg_list_history_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_message *ML[]) { + print_msg_list_gw (TLSR, extra, success, num, ML); + if (num > 0) { + if (tgl_cmp_peer_id (ML[0]->to_id, TLS->our_id)) { + tgl_do_messages_mark_read (TLS, ML[0]->to_id, ML[0]->server_id, 0, NULL, NULL); + } else { + tgl_do_messages_mark_read (TLS, ML[0]->from_id, ML[0]->server_id, 0, NULL, NULL); + } + } +} + void print_msg_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_message *M) { assert (TLS == TLSR); struct in_ev *ev = extra; @@ -2101,6 +2471,75 @@ void print_user_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl mprint_end (ev); } +void print_chat_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_chat *U) { + assert (TLS == TLSR); + struct in_ev *ev = extra; + if (ev && !--ev->refcnt) { + free (ev); + return; + } + if (!success) { print_fail (ev); return; } + mprint_start (ev); + if (!enable_json) { + print_chat_name (ev, U->id, (void *)U); + mprintf (ev, "\n"); + } else { + #ifdef USE_JSON + json_t *res = json_pack_peer (U->id); + char *s = json_dumps (res, 0); + mprintf (ev, "%s\n", s); + json_decref (res); + free (s); + #endif + } + mprint_end (ev); +} + +void print_channel_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_channel *U) { + assert (TLS == TLSR); + struct in_ev *ev = extra; + if (ev && !--ev->refcnt) { + free (ev); + return; + } + if (!success) { print_fail (ev); return; } + mprint_start (ev); + if (!enable_json) { + print_channel_name (ev, U->id, (void *)U); + mprintf (ev, "\n"); + } else { + #ifdef USE_JSON + json_t *res = json_pack_peer (U->id); + char *s = json_dumps (res, 0); + mprintf (ev, "%s\n", s); + json_decref (res); + free (s); + #endif + } + mprint_end (ev); +} + + +void print_peer_gw (struct tgl_state *TLSR, void *extra, int success, tgl_peer_t *U) { + if (!success) { + print_user_gw (TLSR, extra, success, (void *)U); + return; + } + switch (tgl_get_peer_type (U->id)) { + case TGL_PEER_USER: + print_user_gw (TLSR, extra, success, (void *)U); + break; + case TGL_PEER_CHAT: + print_chat_gw (TLSR, extra, success, (void *)U); + break; + case TGL_PEER_CHANNEL: + print_channel_gw (TLSR, extra, success, (void *)U); + break; + default: + assert (0); + } +} + void print_filename_gw (struct tgl_state *TLSR, void *extra, int success, const char *name) { assert (TLS == TLSR); struct in_ev *ev = extra; @@ -2214,6 +2653,53 @@ void print_chat_info_gw (struct tgl_state *TLSR, void *extra, int success, struc mprint_end (ev); } +void print_channel_info_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_channel *C) { + assert (TLS == TLSR); + struct in_ev *ev = extra; + if (ev && !--ev->refcnt) { + free (ev); + return; + } + if (!success) { print_fail (ev); return; } + mprint_start (ev); + + if (!enable_json) { + tgl_peer_t *U = (void *)C; + mpush_color (ev, COLOR_YELLOW); + mprintf (ev, "Channel "); + if (U->flags & TGLCHF_OFFICIAL) { + mprintf (ev, "[verified] "); + } + if (U->flags & TGLCHF_BROADCAST) { + mprintf (ev, "[broadcast] "); + } + if (U->flags & TGLCHF_MEGAGROUP) { + mprintf (ev, "[megagroup] "); + } + if (U->flags & TGLCHF_DEACTIVATED) { + mprintf (ev, "[deactivated] "); + } + print_channel_name (ev, U->id, U); + if (C->username) { + mprintf (ev, " @%s", C->username); + } + mprintf (ev, " (#%d):\n", tgl_get_peer_id (U->id)); + mprintf (ev, "\tabout: %s\n", C->about); + mprintf (ev, "\t%d participants, %d admins, %d kicked\n", C->participants_count, C->admins_count, C->kicked_count); + mpop_color (ev); + } else { + #ifdef USE_JSON + json_t *res = json_pack_peer (C->id); + char *s = json_dumps (res, 0); + mprintf (ev, "%s\n", s); + json_decref (res); + free (s); + #endif + } + + mprint_end (ev); +} + void print_user_status (struct tgl_user_status *S, struct in_ev *ev) { assert(!enable_json); //calling functions print_user_info_gw() and user_status_upd() already check. if (S->online > 0) { @@ -2310,7 +2796,7 @@ void print_secret_chat_gw (struct tgl_state *TLSR, void *extra, int success, str mprint_end (ev); } -void print_dialog_list_gw (struct tgl_state *TLSR, void *extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) { +void print_dialog_list_gw (struct tgl_state *TLSR, void *extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]) { assert (TLS == TLSR); struct in_ev *ev = extra; if (ev && !--ev->refcnt) { @@ -2337,6 +2823,12 @@ void print_dialog_list_gw (struct tgl_state *TLSR, void *extra, int success, int print_chat_name (ev, peers[i], UC); mprintf (ev, ": %d unread\n", unread_count[i]); break; + case TGL_PEER_CHANNEL: + UC = tgl_peer_get (TLS, peers[i]); + mprintf (ev, "Channel "); + print_channel_name (ev, peers[i], UC); + mprintf (ev, ": %d unread\n", unread_count[i]); + break; } } mpop_color (ev); @@ -2401,7 +2893,7 @@ void print_read_list (int num, struct tgl_message *list[]) { #endif } tgl_peer_id_t to_id; - if (tgl_get_peer_type (list[i]->to_id) == TGL_PEER_USER && tgl_get_peer_id (list[i]->to_id) == TLS->our_id) { + if (!tgl_cmp_peer_id (list[i]->to_id, TLS->our_id)) { to_id = list[i]->from_id; } else { to_id = list[i]->to_id; @@ -2411,7 +2903,7 @@ void print_read_list (int num, struct tgl_message *list[]) { int c2 = 0; for (j = i; j < num; j++) if (list[j]) { tgl_peer_id_t end_id; - if (tgl_get_peer_type (list[j]->to_id) == TGL_PEER_USER && tgl_get_peer_id (list[j]->to_id) == TLS->our_id) { + if (!tgl_cmp_peer_id (list[j]->to_id, TLS->our_id)) { end_id = list[j]->from_id; } else { end_id = list[j]->to_id; @@ -2589,7 +3081,7 @@ void print_message_gw (struct tgl_state *TLSR, struct tgl_message *M) { mprint_end (ev); } -void our_id_gw (struct tgl_state *TLSR, int id) { +void our_id_gw (struct tgl_state *TLSR, tgl_peer_id_t id) { assert (TLSR == TLS); #ifdef USE_LUA lua_our_id (id); @@ -2657,6 +3149,39 @@ void json_peer_update (struct in_ev *ev, tgl_peer_t *P, unsigned flags) { #endif } +void peer_update_username (tgl_peer_t *P, const char *username) { + if (!username) { + if (P->extra) { + struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra); + assert (p); + username_peer_pair = tree_delete_username_peer_pair (username_peer_pair, p); + tfree_str (P->extra); + tfree (p, sizeof (*p)); + P->extra = NULL; + } + return; + } + assert (username); + if (P->extra && !strcmp (P->extra, username)) { + return; + } + if (P->extra) { + struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra); + assert (p); + username_peer_pair = tree_delete_username_peer_pair (username_peer_pair, p); + tfree_str (P->extra); + tfree (p, sizeof (*p)); + P->extra = NULL; + } + + P->extra = tstrdup (username); + struct username_peer_pair *p = talloc (sizeof (*p)); + p->peer = P; + p->username = P->extra; + + username_peer_pair = tree_insert_username_peer_pair (username_peer_pair, p, rand ()); +} + void user_update_gw (struct tgl_state *TLSR, struct tgl_user *U, unsigned flags) { assert (TLSR == TLS); #ifdef USE_LUA @@ -2665,6 +3190,8 @@ void user_update_gw (struct tgl_state *TLSR, struct tgl_user *U, unsigned flags) #ifdef USE_PYTHON py_user_update (U, flags); #endif + + peer_update_username ((void *)U, U->username); if (disable_output && !notify_ev) { return; } if (!binlog_read) { return; } @@ -2733,8 +3260,6 @@ void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, u #ifdef USE_PYTHON py_secret_chat_update (U, flags); #endif - - if ((flags & TGL_UPDATE_WORKING) || (flags & TGL_UPDATE_DELETED)) { write_secret_chat_file (); @@ -2772,6 +3297,15 @@ void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, u } } +void channel_update_gw (struct tgl_state *TLSR, struct tgl_channel *U, unsigned flags) { + assert (TLSR == TLS); + + peer_update_username ((void *)U, U->username); + + if (disable_output && !notify_ev) { return; } + if (!binlog_read) { return; } +} + void print_card_gw (struct tgl_state *TLSR, void *extra, int success, int size, int *card) { assert (TLSR == TLS); struct in_ev *ev = extra; @@ -2857,6 +3391,7 @@ void user_status_upd (struct tgl_state *TLS, struct tgl_user *U) { } void on_login (struct tgl_state *TLS); +void on_failed_login (struct tgl_state *TLS); void on_started (struct tgl_state *TLS); void do_get_values (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values, void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), void *arg); @@ -2878,13 +3413,15 @@ struct tgl_update_callback upd_cb = { .user_update = user_update_gw, .chat_update = chat_update_gw, .secret_chat_update = secret_chat_update_gw, + .channel_update = channel_update_gw, .msg_receive = print_message_gw, .our_id = our_id_gw, - .user_status_update = user_status_upd + .user_status_update = user_status_upd, + .on_failed_login = on_failed_login }; -void interpreter_ex (char *line, void *ex) { +void interpreter_ex (char *line, void *ex) { force_end_mode = 1; assert (!in_readline); in_readline = 1; @@ -2894,6 +3431,7 @@ void interpreter_ex (char *line, void *ex) { return; } + do_html = 0; line_ptr = line; offline_mode = 0; reply_id = 0; @@ -2986,6 +3524,8 @@ void interpreter_ex (char *line, void *ex) { int period = 0; if (*flags == ca_period) { flags --; + } + if (*flags != ca_none && *(flags + 1) == ca_period) { period = 1; } enum command_argument op = (*flags) & 255; @@ -3031,14 +3571,16 @@ void interpreter_ex (char *line, void *ex) { break; } - if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double) { + if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double || op == ca_msg_id || op == ca_channel) { if (cur_token_quoted) { if (opt) { - if (op != ca_number && op != ca_double) { - args[args_num ++].P = 0; + if (op != ca_number && op != ca_double && op != ca_msg_id) { + args[args_num ++].peer_id = TGL_PEER_NOT_FOUND; } else { if (op == ca_number) { args[args_num ++].num = NOT_FOUND; + } else if (op == ca_msg_id) { + args[args_num ++].msg_id.peer_type = 0; } else { args[args_num ++].dval = NOT_FOUND; } @@ -3056,11 +3598,13 @@ void interpreter_ex (char *line, void *ex) { } else { if (cur_token_end_str) { if (opt) { - if (op != ca_number && op != ca_double) { - args[args_num ++].P = 0; + if (op != ca_number && op != ca_double && op != ca_msg_id) { + args[args_num ++].peer_id = TGL_PEER_NOT_FOUND; } else { if (op == ca_number) { args[args_num ++].num = NOT_FOUND; + } else if (op == ca_msg_id) { + args[args_num ++].msg_id.peer_type = 0; } else { args[args_num ++].dval = NOT_FOUND; } @@ -3079,25 +3623,33 @@ void interpreter_ex (char *line, void *ex) { int ok = 1; switch (op) { case ca_user: - args[args_num ++].P = mk_peer (cur_token_user ()); - ok = args[args_num - 1].P != NULL; + args[args_num ++].peer_id = cur_token_user (); + ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_chat: - args[args_num ++].P = mk_peer (cur_token_chat ()); - ok = args[args_num - 1].P != NULL; + args[args_num ++].peer_id = cur_token_chat (); + ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_secret_chat: - args[args_num ++].P = mk_peer (cur_token_encr_chat ()); - ok = args[args_num - 1].P != NULL; + args[args_num ++].peer_id = cur_token_encr_chat (); + ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; + break; + case ca_channel: + args[args_num ++].peer_id = cur_token_channel (); + ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_peer: - args[args_num ++].P = mk_peer (cur_token_peer ()); - ok = args[args_num - 1].P != NULL; + args[args_num ++].peer_id = cur_token_peer (); + ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_number: args[args_num ++].num = cur_token_int (); ok = (args[args_num - 1].num != NOT_FOUND); break; + case ca_msg_id: + args[args_num ++].msg_id = cur_token_msg_id (); + ok = (args[args_num - 1].msg_id.peer_type != 0); + break; case ca_double: args[args_num ++].dval = cur_token_double (); ok = (args[args_num - 1].dval != NOT_FOUND); @@ -3106,17 +3658,17 @@ void interpreter_ex (char *line, void *ex) { assert (0); } - if (opt && !ok) { - line_ptr = save; - flags ++; - continue; - } if (period && !ok) { line_ptr = save; flags += 2; args_num --; continue; } + if (opt && !ok) { + line_ptr = save; + flags ++; + continue; + } if (!ok) { fail_interface (TLS, ex, ENOSYS, "can not parse arg #%d", args_num); break; @@ -3126,8 +3678,13 @@ void interpreter_ex (char *line, void *ex) { continue; } } - if (op == ca_string || op == ca_file_name) { + if (op == ca_string || op == ca_file_name || op == ca_command) { if (cur_token_end_str || cur_token_len < 0) { + if (opt) { + args[args_num ++].str = NULL; + flags ++; + continue; + } fail_interface (TLS, ex, ENOSYS, "can not parse string arg #%d", args_num); break; } else { @@ -3244,6 +3801,11 @@ void logprintf (const char *format, ...) { printf (COLOR_GREY); } printf (" *** "); + + + double T = tglt_get_double_time (); + printf ("%.6lf ", T); + va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); @@ -3295,6 +3857,8 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } return; case tgl_message_media_document: + case tgl_message_media_audio: + case tgl_message_media_video: mprintf (ev, "["); assert (M->document); if (M->document->flags & TGLDF_IMAGE) { @@ -3450,9 +4014,18 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { int unknown_user_list_pos; int unknown_user_list[1000]; +void print_peer_permanent_name (struct in_ev *ev, tgl_peer_id_t id) { + mprintf (ev, "%s", print_permanent_peer_id (id)); +} + void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U) { assert (tgl_get_peer_type (id) == TGL_PEER_USER); mpush_color (ev, COLOR_RED); + if (permanent_peer_id_mode) { + print_peer_permanent_name (ev, id); + mpop_color (ev); + return; + } if (!U) { mprintf (ev, "user#%d", tgl_get_peer_id (id)); int i; @@ -3494,6 +4067,11 @@ void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U) { void print_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) { assert (tgl_get_peer_type (id) == TGL_PEER_CHAT); mpush_color (ev, COLOR_MAGENTA); + if (permanent_peer_id_mode) { + print_peer_permanent_name (ev, id); + mpop_color (ev); + return; + } if (!C || use_ids) { mprintf (ev, "chat#%d", tgl_get_peer_id (id)); } else { @@ -3502,20 +4080,30 @@ void print_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) { mpop_color (ev); } -void print_encr_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) { - assert (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT); - mpush_color (ev, COLOR_MAGENTA); +void print_channel_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) { + assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL); + mpush_color (ev, COLOR_CYAN); + if (permanent_peer_id_mode) { + print_peer_permanent_name (ev, id); + mpop_color (ev); + return; + } if (!C || use_ids) { - mprintf (ev, "encr_chat#%d", tgl_get_peer_id (id)); + mprintf (ev, "channel#%d", tgl_get_peer_id (id)); } else { - mprintf (ev, "%s", C->print_name); + mprintf (ev, "%s", C->channel.title); } mpop_color (ev); } -void print_encr_chat_name_full (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) { +void print_encr_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) { assert (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT); mpush_color (ev, COLOR_MAGENTA); + if (permanent_peer_id_mode) { + print_peer_permanent_name (ev, id); + mpop_color (ev); + return; + } if (!C || use_ids) { mprintf (ev, "encr_chat#%d", tgl_get_peer_id (id)); } else { @@ -3524,6 +4112,25 @@ void print_encr_chat_name_full (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t * mpop_color (ev); } +void print_peer_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) { + switch (tgl_get_peer_type (id)) { + case TGL_PEER_USER: + print_user_name (ev, id, C); + return; + case TGL_PEER_CHAT: + print_chat_name (ev, id, C); + return; + case TGL_PEER_CHANNEL: + print_channel_name (ev, id, C); + return; + case TGL_PEER_ENCR_CHAT: + print_encr_chat_name (ev, id, C); + return; + default: + assert (0); + } +} + static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; void print_date (struct in_ev *ev, long t) { struct tm *tm = localtime ((void *)&t); @@ -3541,26 +4148,48 @@ void print_date_full (struct in_ev *ev, long t) { mprintf (ev, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } +void print_msg_id (struct in_ev *ev, tgl_message_id_t msg_id, struct tgl_message *M) { + if (msg_num_mode) { + if (!permanent_msg_id_mode) { + if (M) { + mprintf (ev, "%d", M->temp_id); + } else { + mprintf (ev, "???"); + } + } else { + mprintf (ev, "%s", print_permanent_msg_id (msg_id)); + } + } +} + void print_service_message (struct in_ev *ev, struct tgl_message *M) { assert (M); //print_start (); mpush_color (ev, COLOR_GREY); - - mpush_color (ev, COLOR_MAGENTA); - if (msg_num_mode) { - mprintf (ev, "%lld ", M->id); + + if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL) { + mpush_color (ev, COLOR_CYAN); + } else { + mpush_color (ev, COLOR_MAGENTA); } + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); print_date (ev, M->date); mpop_color (ev); mprintf (ev, " "); if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) { print_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id)); + } else if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL) { + print_channel_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id)); } else { assert (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT); print_encr_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id)); } - mprintf (ev, " "); - print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id)); + + if (tgl_get_peer_type (M->from_id) == TGL_PEER_USER) { + mprintf (ev, " "); + print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id)); + } switch (M->action.type) { case tgl_message_action_none: @@ -3585,9 +4214,14 @@ void print_service_message (struct in_ev *ev, struct tgl_message *M) { case tgl_message_action_chat_delete_photo: mprintf (ev, " deleted photo\n"); break; - case tgl_message_action_chat_add_user: - mprintf (ev, " added user "); - print_user_name (ev, tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user))); + case tgl_message_action_chat_add_users: + mprintf (ev, " added users:"); + { + int i; + for (i = 0; i < M->action.user_num; i++) { + print_user_name (ev, tgl_set_peer_id (TGL_PEER_USER, M->action.users[i]), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.users[i]))); + } + } mprintf (ev, "\n"); break; case tgl_message_action_chat_add_user_by_link: @@ -3640,6 +4274,15 @@ void print_service_message (struct in_ev *ev, struct tgl_message *M) { case tgl_message_action_abort_key: mprintf (ev, " abort rekey #%016llx\n", M->action.exchange_id); break; + case tgl_message_action_channel_create: + mprintf (ev, " created channel %s\n", M->action.title); + break; + case tgl_message_action_migrated_to: + mprintf (ev, " migrated to channel\n"); + break; + case tgl_message_action_migrated_from: + mprintf (ev, " migrated from group '%s'\n", M->action.title); + break; } mpop_color (ev); //print_end (); @@ -3670,9 +4313,8 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) { if (M->flags & TGLMF_OUT) { mpush_color (ev, COLOR_GREEN); - if (msg_num_mode) { - mprintf (ev, "%lld ", M->id); - } + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); print_date (ev, M->date); mpop_color (ev); mprintf (ev, " "); @@ -3685,9 +4327,8 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { } } else { mpush_color (ev, COLOR_BLUE); - if (msg_num_mode) { - mprintf (ev, "%lld ", M->id); - } + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); print_date (ev, M->date); mpop_color (ev); mprintf (ev, " "); @@ -3704,9 +4345,8 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { assert (P); if (M->flags & TGLMF_UNREAD) { mpush_color (ev, COLOR_GREEN); - if (msg_num_mode) { - mprintf (ev, "%lld ", M->id); - } + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); print_date (ev, M->date); mprintf (ev, " "); mpush_color (ev, COLOR_CYAN); @@ -3719,9 +4359,8 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { } } else { mpush_color (ev, COLOR_BLUE); - if (msg_num_mode) { - mprintf (ev, "%lld ", M->id); - } + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); print_date (ev, M->date); mpush_color (ev, COLOR_CYAN); mprintf (ev, " %s", P->print_name); @@ -3732,19 +4371,17 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { mprintf (ev, " »»» "); } } - } else { - assert (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT); + } else if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) { mpush_color (ev, COLOR_MAGENTA); - if (msg_num_mode) { - mprintf (ev, "%lld ", M->id); - } + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); print_date (ev, M->date); mpop_color (ev); mprintf (ev, " "); print_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id)); mprintf (ev, " "); print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id)); - if ((tgl_get_peer_type (M->from_id) == TGL_PEER_USER) && (tgl_get_peer_id (M->from_id) == TLS->our_id)) { + if (!tgl_cmp_peer_id (M->from_id, TLS->our_id)) { mpush_color (ev, COLOR_GREEN); } else { mpush_color (ev, COLOR_BLUE); @@ -3754,14 +4391,48 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { } else { mprintf (ev, " »»» "); } + } else { + assert (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL); + + mpush_color (ev, COLOR_CYAN); + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); + print_date (ev, M->date); + mpop_color (ev); + mprintf (ev, " "); + print_channel_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id)); + + if (tgl_get_peer_type (M->from_id) == TGL_PEER_USER) { + mprintf (ev, " "); + print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id)); + if (!tgl_cmp_peer_id (M->from_id, TLS->our_id)) { + mpush_color (ev, COLOR_GREEN); + } else { + mpush_color (ev, COLOR_BLUE); + } + } else { + mpush_color (ev, COLOR_BLUE); + } + if (M->flags & TGLMF_UNREAD) { + mprintf (ev, " >>> "); + } else { + mprintf (ev, " »»» "); + } } - if (tgl_get_peer_type (M->fwd_from_id) == TGL_PEER_USER) { + if (tgl_get_peer_type (M->fwd_from_id) > 0) { mprintf (ev, "[fwd from "); - print_user_name (ev, M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id)); + print_peer_name (ev, M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id)); + mprintf (ev, " "); + print_date (ev, M->date); mprintf (ev, "] "); } if (M->reply_id) { - mprintf (ev, "[reply to %d] ", M->reply_id); + mprintf (ev, "[reply to "); + tgl_message_id_t msg_id = M->permanent_id; + msg_id.id = M->reply_id; + struct tgl_message *N = tgl_message_get (TLS, &msg_id); + print_msg_id (ev, msg_id, N); + mprintf (ev, "] "); } if (M->flags & TGLMF_MENTION) { mprintf (ev, "[mention] "); diff --git a/interface.h b/interface.h index 1585090d..c05dc364 100644 --- a/interface.h +++ b/interface.h @@ -68,6 +68,7 @@ struct tgl_message; struct in_ev; void print_message (struct in_ev *ev, struct tgl_message *M); void print_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C); +void print_channel_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C); void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U); void print_encr_chat_name_full (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C); void print_encr_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C); @@ -83,4 +84,9 @@ void print_date (struct in_ev *ev, long t); void play_sound (void); void update_prompt (void); void set_interface_callbacks (void); + +char *print_permanent_msg_id (tgl_message_id_t id); +char *print_permanent_peer_id (tgl_peer_id_t id); +tgl_peer_id_t parse_input_peer_id (const char *s, int l, int mask); +tgl_message_id_t parse_input_msg_id (const char *s, int l); #endif diff --git a/json-tg.c b/json-tg.c index 57e33c8c..a58e70ad 100644 --- a/json-tg.c +++ b/json-tg.c @@ -5,6 +5,7 @@ #include "json-tg.h" #include #include +#include "interface.h" #include //format time: #include @@ -19,13 +20,16 @@ void json_pack_peer_type (json_t *res, tgl_peer_id_t id) { int x = tgl_get_peer_type (id); switch (x) { case TGL_PEER_USER: - assert (json_object_set (res, "type", json_string ("user")) >= 0); + assert (json_object_set (res, "peer_type", json_string ("user")) >= 0); break; case TGL_PEER_CHAT: - assert (json_object_set (res, "type", json_string ("chat")) >= 0); + assert (json_object_set (res, "peer_type", json_string ("chat")) >= 0); break; case TGL_PEER_ENCR_CHAT: - assert (json_object_set (res, "type", json_string ("encr_chat")) >= 0); + assert (json_object_set (res, "peer_type", json_string ("encr_chat")) >= 0); + break; + case TGL_PEER_CHANNEL: + assert (json_object_set (res, "peer_type", json_string ("channel")) >= 0); break; default: assert (0); @@ -89,6 +93,14 @@ void json_pack_chat (json_t *res, tgl_peer_t *P) { } } +void json_pack_channel (json_t *res, tgl_peer_t *P) { + assert (P->channel.title); + assert (json_object_set (res, "title", json_string (P->channel.title)) >= 0); + assert (json_object_set (res, "participants_count", json_integer (P->channel.participants_count)) >= 0); + assert (json_object_set (res, "admins_count", json_integer (P->channel.admins_count)) >= 0); + assert (json_object_set (res, "kicked_count", json_integer (P->channel.kicked_count)) >= 0); +} + void json_pack_encr_chat (json_t *res, tgl_peer_t *P) { assert (json_object_set (res, "user", json_pack_peer (TGL_MK_USER (P->encr_chat.user_id))) >= 0); @@ -98,9 +110,10 @@ json_t *json_pack_peer (tgl_peer_id_t id) { tgl_peer_t *P = tgl_peer_get (TLS, id); //assert (P); json_t *res = json_object (); - assert (json_object_set (res, "id", json_integer (tgl_get_peer_id (id))) >= 0); + assert (json_object_set (res, "id", json_string (print_permanent_peer_id (id))) >= 0); json_pack_peer_type (res, id); + assert (json_object_set (res, "peer_id", json_integer (tgl_get_peer_id (id))) >= 0); assert (res); @@ -113,6 +126,9 @@ json_t *json_pack_peer (tgl_peer_id_t id) { case TGL_PEER_CHAT: sprintf (s, "chat#%d", tgl_get_peer_id (id)); break; + case TGL_PEER_CHANNEL: + sprintf (s, "channel#%d", tgl_get_peer_id (id)); + break; case TGL_PEER_ENCR_CHAT: sprintf (s, "encr_chat#%d", tgl_get_peer_id (id)); break; @@ -140,6 +156,9 @@ json_t *json_pack_peer (tgl_peer_id_t id) { case TGL_PEER_ENCR_CHAT: json_pack_encr_chat (res, P); break; + case TGL_PEER_CHANNEL: + json_pack_channel (res, P); + break; default: assert (0); } @@ -210,6 +229,8 @@ json_t *json_pack_media (struct tgl_message_media *M) { } break; case tgl_message_media_document: + case tgl_message_media_audio: + case tgl_message_media_video: case tgl_message_media_document_encr: assert (json_object_set (res, "type", json_string ("document")) >= 0); break; @@ -332,9 +353,9 @@ json_t *json_pack_service (struct tgl_message *M) { case tgl_message_action_chat_delete_photo: assert (json_object_set (res, "type", json_string ("chat_delete_photo")) >= 0); break; - case tgl_message_action_chat_add_user: + case tgl_message_action_chat_add_users: assert (json_object_set (res, "type", json_string ("chat_add_user")) >= 0); - assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); + assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.users[0]))) >= 0); break; case tgl_message_action_chat_add_user_by_link: assert (json_object_set (res, "type", json_string ("chat_add_user_link")) >= 0); @@ -389,6 +410,16 @@ json_t *json_pack_service (struct tgl_message *M) { case tgl_message_action_abort_key: assert (json_object_set (res, "type", json_string ("abort_key")) >= 0); break; + case tgl_message_action_channel_create: + assert (json_object_set (res, "type", json_string ("channel_created")) >= 0); + assert (json_object_set (res, "title", json_string (M->action.title)) >= 0); + break; + case tgl_message_action_migrated_to: + assert (json_object_set (res, "type", json_string ("migrated_to")) >= 0); + break; + case tgl_message_action_migrated_from: + assert (json_object_set (res, "type", json_string ("migrated_from")) >= 0); + break; default: assert (json_object_set (res, "type", json_string ("???")) >= 0); break; @@ -401,7 +432,7 @@ json_t *json_pack_message (struct tgl_message *M) { assert (json_object_set (res, "event", json_string ("message")) >= 0); //will overwriten to service, if service. - assert (json_object_set (res, "id", json_integer (M->id)) >= 0); + assert (json_object_set (res, "id", json_string (print_permanent_msg_id (M->permanent_id))) >= 0); if (!(M->flags & TGLMF_CREATED)) { return res; } assert (json_object_set (res, "flags", json_integer (M->flags)) >= 0); @@ -412,7 +443,10 @@ json_t *json_pack_message (struct tgl_message *M) { } if (M->reply_id) { - assert (json_object_set (res, "reply_id", json_integer (M->reply_id)) >= 0); + tgl_message_id_t msg_id = M->permanent_id; + msg_id.id = M->reply_id; + + assert (json_object_set (res, "reply_id", json_string (print_permanent_msg_id (msg_id))) >= 0); } if (M->flags & TGLMF_MENTION) { diff --git a/loop.c b/loop.c index 54f012e9..5426a33a 100644 --- a/loop.c +++ b/loop.c @@ -70,6 +70,7 @@ #include #include #include +#include #include @@ -349,13 +350,13 @@ void net_loop (void) { write_state_file (); update_prompt (); - if (unknown_user_list_pos) { +/* if (unknown_user_list_pos) { int i; for (i = 0; i < unknown_user_list_pos; i++) { tgl_do_get_user_info (TLS, TGL_MK_USER (unknown_user_list[i]), 0, 0, 0); } unknown_user_list_pos = 0; - } + } */ } if (term_ev) { @@ -484,7 +485,7 @@ void write_auth_file (void) { tgl_dc_iterator_ex (TLS, write_dc, &auth_file_fd); - assert (write (auth_file_fd, &TLS->our_id, 4) == 4); + assert (write (auth_file_fd, &TLS->our_id.peer_id, 4) == 4); close (auth_file_fd); } @@ -554,23 +555,23 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { assert (read (auth_file_fd, auth_key, 256) == 256); //bl_do_add_dc (id, ip, l, port, auth_key_id, auth_key); - bl_do_dc_option (TLS, id, "DC", 2, ip, l, port); + bl_do_dc_option (TLS, 0, id, "DC", 2, ip, l, port); bl_do_set_auth_key (TLS, id, auth_key); bl_do_dc_signed (TLS, id); } void empty_auth_file (void) { if (TLS->test_mode) { - bl_do_dc_option (TLS, 1, "", 0, TG_SERVER_TEST_1, strlen (TG_SERVER_TEST_1), 443); - bl_do_dc_option (TLS, 2, "", 0, TG_SERVER_TEST_2, strlen (TG_SERVER_TEST_2), 443); - bl_do_dc_option (TLS, 3, "", 0, TG_SERVER_TEST_3, strlen (TG_SERVER_TEST_3), 443); + bl_do_dc_option (TLS, 0, 1, "", 0, TG_SERVER_TEST_1, strlen (TG_SERVER_TEST_1), 443); + bl_do_dc_option (TLS, 0, 2, "", 0, TG_SERVER_TEST_2, strlen (TG_SERVER_TEST_2), 443); + bl_do_dc_option (TLS, 0, 3, "", 0, TG_SERVER_TEST_3, strlen (TG_SERVER_TEST_3), 443); bl_do_set_working_dc (TLS, TG_SERVER_TEST_DEFAULT); } else { - bl_do_dc_option (TLS, 1, "", 0, TG_SERVER_1, strlen (TG_SERVER_1), 443); - bl_do_dc_option (TLS, 2, "", 0, TG_SERVER_2, strlen (TG_SERVER_2), 443); - bl_do_dc_option (TLS, 3, "", 0, TG_SERVER_3, strlen (TG_SERVER_3), 443); - bl_do_dc_option (TLS, 4, "", 0, TG_SERVER_4, strlen (TG_SERVER_4), 443); - bl_do_dc_option (TLS, 5, "", 0, TG_SERVER_5, strlen (TG_SERVER_5), 443); + bl_do_dc_option (TLS, 0, 1, "", 0, TG_SERVER_1, strlen (TG_SERVER_1), 443); + bl_do_dc_option (TLS, 0, 2, "", 0, TG_SERVER_2, strlen (TG_SERVER_2), 443); + bl_do_dc_option (TLS, 0, 3, "", 0, TG_SERVER_3, strlen (TG_SERVER_3), 443); + bl_do_dc_option (TLS, 0, 4, "", 0, TG_SERVER_4, strlen (TG_SERVER_4), 443); + bl_do_dc_option (TLS, 0, 5, "", 0, TG_SERVER_5, strlen (TG_SERVER_5), 443); bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT); } } @@ -611,7 +612,7 @@ void read_auth_file (void) { assert (!l); } if (our_id) { - bl_do_set_our_id (TLS, our_id); + bl_do_set_our_id (TLS, TGL_MK_USER (our_id)); } close (auth_file_fd); } @@ -636,11 +637,7 @@ void read_secret_chat (int fd, int v) { assert (read (fd, &state, 4) == 4); assert (read (fd, &key_fingerprint, 8) == 8); assert (read (fd, &key, 256) == 256); - if (v >= 2) { - assert (read (fd, sha, 20) == 20); - } else { - SHA1 ((void *)key, 256, sha); - } + assert (read (fd, sha, 20) == 20); int in_seq_no = 0, out_seq_no = 0, last_in_seq_no = 0; if (v >= 1) { assert (read (fd, &in_seq_no, 4) == 4); @@ -648,7 +645,7 @@ void read_secret_chat (int fd, int v) { assert (read (fd, &out_seq_no, 4) == 4); } - bl_do_encr_chat_new (TLS, id, + bl_do_encr_chat (TLS, id, &access_hash, &date, &admin_id, @@ -663,7 +660,8 @@ void read_secret_chat (int fd, int v) { &last_in_seq_no, &out_seq_no, &key_fingerprint, - TGLECF_CREATE | TGLECF_CREATED + TGLECF_CREATE | TGLECF_CREATED, + NULL, 0 ); } @@ -758,11 +756,22 @@ void on_login (struct tgl_state *TLS) { write_auth_file (); } +void on_failed_login (struct tgl_state *TLS) { + logprintf ("login failed\n"); + logprintf ("login error #%d: %s\n", TLS->error_code, TLS->error); + logprintf ("you can relogin by deleting auth file or running telegram-cli with '-q' flag\n"); + exit (2); +} + void on_started (struct tgl_state *TLS); -void dlist_cb (struct tgl_state *TLSR, void *callback_extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) { +void clist_cb (struct tgl_state *TLSR, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]) { on_started (TLS); } +void dlist_cb (struct tgl_state *TLSR, void *callback_extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]) { + tgl_do_get_channels_dialog_list (TLS, 100, 0, clist_cb, 0); +} + void on_started (struct tgl_state *TLS) { if (wait_dialog_list) { wait_dialog_list = 0; @@ -812,9 +821,9 @@ int loop (void) { if (disable_link_preview) { tgl_disable_link_preview (TLS); } - tgl_init (TLS); + assert (tgl_init (TLS) >= 0); - if (binlog_enabled) { + /*if (binlog_enabled) { double t = tglt_get_double_time (); if (verbosity >= E_DEBUG) { logprintf ("replay log start\n"); @@ -824,11 +833,11 @@ int loop (void) { logprintf ("replay log end in %lf seconds\n", tglt_get_double_time () - t); } tgl_reopen_binlog_for_writing (TLS); - } else { + } else {*/ read_auth_file (); read_state_file (); read_secret_chat_file (); - } + //} binlog_read = 1; #ifdef USE_LUA @@ -850,7 +859,7 @@ int loop (void) { update_prompt (); if (reset_authorization) { - tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (TLS->our_id)); + tgl_peer_t *P = tgl_peer_get (TLS, TLS->our_id); if (P && P->user.phone && reset_authorization == 1) { set_default_username (P->user.phone); } diff --git a/lua-tg.c b/lua-tg.c index 592df608..454a0a66 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -42,6 +42,7 @@ lua_State *luaState; //#include "interface.h" //#include "auto/constants.h" #include +#include #include "interface.h" #include @@ -73,6 +74,15 @@ void lua_add_string_field (const char *name, const char *value) { lua_settable (luaState, -3); } +void lua_add_lstring_field (const char *name, const char *value, int len) { + assert (name && strlen (name)); + if (!value || !len) { return; } + my_lua_checkstack (luaState, 3); + lua_pushstring (luaState, name); + lua_pushlstring (luaState, value, len); + lua_settable (luaState, -3); +} + void lua_add_string_field_arr (int num, const char *value) { if (!value || !strlen (value)) { return; } my_lua_checkstack (luaState, 3); @@ -100,6 +110,9 @@ void push_tgl_peer_type (int x) { case TGL_PEER_ENCR_CHAT: lua_pushstring (luaState, "encr_chat"); break; + case TGL_PEER_CHANNEL: + lua_pushstring (luaState, "channel"); + break; default: assert (0); } @@ -144,6 +157,15 @@ void push_encr_chat (tgl_peer_t *P) { lua_settable (luaState, -3); } +void push_channel (tgl_peer_t *P) { + my_lua_checkstack (luaState, 4); + lua_add_string_field ("title", P->channel.title); + lua_add_string_field ("about", P->channel.about); + lua_add_num_field ("participants_count", P->channel.participants_count); + lua_add_num_field ("admins_count", P->channel.admins_count); + lua_add_num_field ("kicked_count", P->channel.kicked_count); +} + void push_update_types (unsigned flags) { my_lua_checkstack (luaState, 4); lua_newtable (luaState); @@ -203,12 +225,12 @@ void push_update_types (unsigned flags) { void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { lua_newtable (luaState); - - lua_add_num_field ("id", tgl_get_peer_id (id)); - lua_pushstring (luaState, "type"); + + lua_add_string_field ("id", print_permanent_peer_id (P ? P->id : id)); + lua_pushstring (luaState, "peer_type"); push_tgl_peer_type (tgl_get_peer_type (id)); lua_settable (luaState, -3); - + lua_add_num_field ("peer_id", tgl_get_peer_id (id)); if (!P || !(P->flags & TGLPF_CREATED)) { lua_pushstring (luaState, "print_name"); @@ -223,6 +245,9 @@ void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { case TGL_PEER_ENCR_CHAT: sprintf (s, "encr_chat#%d", tgl_get_peer_id (id)); break; + case TGL_PEER_CHANNEL: + sprintf (s, "channel#%d", tgl_get_peer_id (id)); + break; default: assert (0); } @@ -245,6 +270,9 @@ void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { case TGL_PEER_ENCR_CHAT: push_encr_chat (P); break; + case TGL_PEER_CHANNEL: + push_channel (P); + break; default: assert (0); } @@ -260,6 +288,8 @@ void push_media (struct tgl_message_media *M) { lua_add_string_field ("caption", M->caption); break; case tgl_message_media_document: + case tgl_message_media_audio: + case tgl_message_media_video: case tgl_message_media_document_encr: lua_newtable (luaState); lua_add_string_field ("type", "document"); @@ -334,12 +364,12 @@ void push_service (struct tgl_message *M) { lua_newtable (luaState); lua_add_string_field ("type", "chat_delete_photo"); break; - case tgl_message_action_chat_add_user: + case tgl_message_action_chat_add_users: lua_newtable (luaState); lua_add_string_field ("type", "chat_add_user"); lua_pushstring (luaState, "user"); - push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user))); + push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.users[0]), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.users[0]))); lua_settable (luaState, -3); break; case tgl_message_action_chat_add_user_by_link: @@ -415,6 +445,19 @@ void push_service (struct tgl_message *M) { lua_newtable (luaState); lua_add_string_field ("type", "abort_rekey"); break; + case tgl_message_action_channel_create: + lua_newtable (luaState); + lua_add_string_field ("type", "channel_created"); + lua_add_string_field ("title", M->action.title); + break; + case tgl_message_action_migrated_to: + lua_newtable (luaState); + lua_add_string_field ("type", "migrated_to"); + break; + case tgl_message_action_migrated_from: + lua_newtable (luaState); + lua_add_string_field ("type", "migrated_from"); + break; default: lua_pushstring (luaState, "???"); break; @@ -426,9 +469,7 @@ void push_message (struct tgl_message *M) { my_lua_checkstack (luaState, 10); lua_newtable (luaState); - static char s[30]; - snprintf (s, 30, "%lld", M->id); - lua_add_string_field ("id", s); + lua_add_string_field ("id", print_permanent_msg_id (M->permanent_id)); if (!(M->flags & TGLMF_CREATED)) { return; } lua_add_num_field ("flags", M->flags); @@ -441,7 +482,10 @@ void push_message (struct tgl_message *M) { } if (M->reply_id) { - lua_add_num_field ("reply_id", M->reply_id); + tgl_message_id_t msg_id = M->permanent_id; + msg_id.id = M->reply_id; + + lua_add_string_field ("reply_id", print_permanent_msg_id (msg_id)); } if (M->flags & TGLMF_MENTION) { @@ -520,13 +564,13 @@ void lua_diff_end (void) { } } -void lua_our_id (int id) { +void lua_our_id (tgl_peer_id_t id) { if (!have_file) { return; } lua_settop (luaState, 0); //lua_checkstack (luaState, 20); my_lua_checkstack (luaState, 20); lua_getglobal (luaState, "on_our_id"); - lua_pushnumber (luaState, id); + lua_pushnumber (luaState, tgl_get_peer_id (id)); assert (lua_gettop (luaState) == 2); int r = ps_lua_pcall (luaState, 1, 0, 0); @@ -602,7 +646,19 @@ void lua_chat_update (struct tgl_chat *C, unsigned flags) { //extern int peer_num; #define MAX_LUA_COMMANDS 1000 -void *lua_ptr[MAX_LUA_COMMANDS]; + +struct lua_arg { + int flags; + union { + tgl_message_id_t msg_id; + tgl_peer_id_t peer_id; + char *str; + long long num; + double dnum; + void *ptr; + }; +}; +struct lua_arg lua_ptr[MAX_LUA_COMMANDS]; static int pos; static inline tgl_peer_t *get_peer (const char *s) { @@ -613,6 +669,7 @@ enum lua_query_type { lq_contact_list, lq_dialog_list, lq_msg, + lq_msg_channel, lq_send_typing, lq_send_typing_abort, lq_rename_chat, @@ -622,12 +679,14 @@ enum lua_query_type { lq_set_profile_name, lq_send_video, lq_send_text, + lq_reply, lq_fwd, lq_fwd_media, lq_load_photo, lq_load_video_thumb, lq_load_video, lq_chat_info, + lq_channel_info, lq_user_info, lq_history, lq_chat_add_user, @@ -654,7 +713,12 @@ enum lua_query_type { lq_status_offline, lq_send_location, lq_extf, - lq_import_chat_link + lq_import_chat_link, + lq_export_chat_link, + lq_channel_invite_user, + lq_channel_kick_user, + lq_channel_get_admins, + lq_channel_get_users }; struct lua_query_extra { @@ -726,7 +790,7 @@ void lua_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, i free (cb); } -void lua_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], int msgs[], int unread[]) { +void lua_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], tgl_message_id_t *msgs[], int unread[]) { assert (TLSR == TLS); struct lua_query_extra *cb = cb_extra; lua_settop (luaState, 0); @@ -812,6 +876,38 @@ void lua_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl free (cb); } +void lua_one_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, int size, struct tgl_message *M[]) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success && size > 0 && M[0] && (M[0]->flags & TGLMF_CREATED)) { + push_message (M[0]); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = ps_lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + void lua_msg_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_message *M[]) { assert (TLSR == TLS); struct lua_query_extra *cb = cb_extra; @@ -946,6 +1042,38 @@ void lua_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, st free (cb); } +void lua_channel_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_channel *C) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + push_peer (C->id, (void *)C); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = ps_lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + void lua_user_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_user *C) { assert (TLSR == TLS); struct lua_query_extra *cb = cb_extra; @@ -1010,246 +1138,231 @@ void lua_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char free (cb); } +#define LUA_STR_ARG(n) lua_ptr[n].str, strlen (lua_ptr[n].str) + void lua_do_all (void) { int p = 0; while (p < pos) { - int l = (long)lua_ptr[p ++]; + int l = lua_ptr[p ++].num; assert (p + l + 1 <= pos); - enum lua_query_type f = (long)lua_ptr[p ++]; + enum lua_query_type f = lua_ptr[p ++].num; struct tgl_message *M; - char *s, *s1, *s2, *s3; + int q = p; + tgl_message_id_t *tmp_msg_id; switch (f) { case lq_contact_list: - tgl_do_update_contact_list (TLS, lua_contact_list_cb, lua_ptr[p ++]); + tgl_do_update_contact_list (TLS, lua_contact_list_cb, lua_ptr[p ++].ptr); break; case lq_dialog_list: - tgl_do_get_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++]); + tgl_do_get_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++].ptr); break; case lq_msg: - tgl_do_send_message (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], strlen (lua_ptr[p + 2]), 0, NULL, lua_msg_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_send_message (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), 0, NULL, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_msg_channel: + tgl_do_send_message (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), 256, NULL, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_send_typing: - tgl_do_send_typing (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, tgl_typing_typing, lua_empty_cb, lua_ptr[p]); + tgl_do_send_typing (TLS, lua_ptr[p + 1].peer_id, tgl_typing_typing, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; case lq_send_typing_abort: - tgl_do_send_typing (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, tgl_typing_cancel, lua_empty_cb, lua_ptr[p]); + tgl_do_send_typing (TLS, lua_ptr[p + 1].peer_id, tgl_typing_cancel, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; case lq_rename_chat: - tgl_do_rename_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], strlen (lua_ptr[p + 2]), lua_empty_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_rename_chat (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); p += 3; break; case lq_send_photo: - tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, lua_msg_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_send_video: - tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, lua_msg_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_send_audio: - tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, lua_msg_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_send_document: - tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, 0, lua_msg_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, 0, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_send_file: - tgl_do_send_document (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, lua_msg_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_send_text: - tgl_do_send_text (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], 0, lua_msg_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_send_text (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, 0, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_chat_set_photo: - tgl_do_set_chat_photo (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_ptr[p + 2], lua_empty_cb, lua_ptr[p]); - free (lua_ptr[p + 2]); + tgl_do_set_chat_photo (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, lua_empty_cb, lua_ptr[p].ptr); p += 3; break; case lq_load_photo: case lq_load_video: case lq_load_audio: case lq_load_document: - M = lua_ptr[p + 1]; + M = tgl_message_get (TLS, &lua_ptr[p + 1].msg_id); if (!M || (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_document && M->media.type != tgl_message_media_document_encr)) { - lua_file_cb (TLS, lua_ptr[p], 0, 0); + lua_file_cb (TLS, lua_ptr[p].ptr, 0, 0); } else { if (M->media.type == tgl_message_media_photo) { assert (M->media.photo); - tgl_do_load_photo (TLS, M->media.photo, lua_file_cb, lua_ptr[p]); + tgl_do_load_photo (TLS, M->media.photo, lua_file_cb, lua_ptr[p].ptr); } else if (M->media.type == tgl_message_media_document) { assert (M->media.document); - tgl_do_load_document (TLS, M->media.document, lua_file_cb, lua_ptr[p]); + tgl_do_load_document (TLS, M->media.document, lua_file_cb, lua_ptr[p].ptr); } else { - tgl_do_load_encr_document (TLS, M->media.encr_document, lua_file_cb, lua_ptr[p]); + tgl_do_load_encr_document (TLS, M->media.encr_document, lua_file_cb, lua_ptr[p].ptr); } } p += 2; break; case lq_load_video_thumb: case lq_load_document_thumb: - M = lua_ptr[p + 1]; + M = tgl_message_get (TLS, &lua_ptr[p + 1].msg_id); if (!M || (M->media.type != tgl_message_media_document)) { - lua_file_cb (TLS, lua_ptr[p], 0, 0); + lua_file_cb (TLS, lua_ptr[p].ptr, 0, 0); } else { - tgl_do_load_document_thumb (TLS, M->media.document, lua_file_cb, lua_ptr[p]); + tgl_do_load_document_thumb (TLS, M->media.document, lua_file_cb, lua_ptr[p].ptr); } p += 2; break; + case lq_reply: + tgl_do_reply_message (TLS, &lua_ptr[p + 1].msg_id, LUA_STR_ARG (p + 2), 0, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; case lq_fwd: - tgl_do_forward_message (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((struct tgl_message *)lua_ptr[p + 2])->id, 0, lua_msg_cb, lua_ptr[p]); + tmp_msg_id = &lua_ptr[p + 2].msg_id; + tgl_do_forward_messages (TLS, lua_ptr[p + 1].peer_id, 1, (void *)&tmp_msg_id, 0, lua_one_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_fwd_media: - tgl_do_forward_media (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((struct tgl_message *)lua_ptr[p + 2])->id, 0, lua_msg_cb, lua_ptr[p]); + tgl_do_forward_media (TLS, lua_ptr[p + 1].peer_id, &lua_ptr[p + 2].msg_id, 0, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; case lq_chat_info: - tgl_do_get_chat_info (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, lua_chat_cb, lua_ptr[p]); + tgl_do_get_chat_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_chat_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_channel_info: + tgl_do_get_channel_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_channel_cb, lua_ptr[p].ptr); p += 2; break; case lq_user_info: - tgl_do_get_user_info (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, lua_user_cb, lua_ptr[p]); + tgl_do_get_user_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_user_cb, lua_ptr[p].ptr); p += 2; break; case lq_history: - tgl_do_get_history (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, (long)lua_ptr[p + 2], 0, lua_msg_list_cb, lua_ptr[p]); + tgl_do_get_history (TLS, lua_ptr[p + 1].peer_id, 0, lua_ptr[p + 2].num, 0, lua_msg_list_cb, lua_ptr[p].ptr); p += 3; break; case lq_chat_add_user: - tgl_do_add_user_to_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((tgl_peer_t *)lua_ptr[p + 2])->id, 10, lua_empty_cb, lua_ptr[p]); + tgl_do_add_user_to_chat (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 10, lua_empty_cb, lua_ptr[p].ptr); p += 3; break; case lq_chat_del_user: - tgl_do_del_user_from_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, ((tgl_peer_t *)lua_ptr[p + 2])->id, lua_empty_cb, lua_ptr[p]); + tgl_do_del_user_from_chat (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 3; break; case lq_add_contact: - s1 = lua_ptr[p + 1]; - s2 = lua_ptr[p + 2]; - s3 = lua_ptr[p + 3]; - tgl_do_add_contact (TLS, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 0, lua_contact_list_cb, lua_ptr[p]); - free (s1); - free (s2); - free (s3); + tgl_do_add_contact (TLS, LUA_STR_ARG (p + 1), LUA_STR_ARG (p + 2), LUA_STR_ARG (p + 3), 0, lua_contact_list_cb, lua_ptr[p].ptr); p += 4; break; case lq_del_contact: - tgl_do_del_contact (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); + tgl_do_del_contact (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; case lq_rename_contact: - s1 = lua_ptr[p + 1]; - s2 = lua_ptr[p + 2]; - s3 = lua_ptr[p + 3]; - tgl_do_add_contact (TLS, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 1, lua_contact_list_cb, lua_ptr[p]); - free (s1); - free (s2); - free (s3); + tgl_do_add_contact (TLS, LUA_STR_ARG (p + 1), LUA_STR_ARG (p + 2), LUA_STR_ARG (p + 3), 1, lua_contact_list_cb, lua_ptr[p].ptr); p += 4; break; case lq_search: - s = lua_ptr[p + 2]; - tgl_do_msg_search (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, 0, 0, 40, 0, s, strlen (s), lua_msg_list_cb, lua_ptr[p]); - free (s); + tgl_do_msg_search (TLS, lua_ptr[p + 1].peer_id, 0, 0, 40, 0, LUA_STR_ARG (p + 2), lua_msg_list_cb, lua_ptr[p].ptr); p += 3; break; case lq_global_search: - s = lua_ptr[p + 1]; - tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, s, strlen (s), lua_msg_list_cb, lua_ptr[p]); - free (s); + tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, LUA_STR_ARG (p + 1), lua_msg_list_cb, lua_ptr[p].ptr); p += 2; break; case lq_mark_read: - tgl_do_mark_read (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); + tgl_do_mark_read (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; case lq_set_profile_photo: - s = lua_ptr[p + 1]; - tgl_do_set_profile_photo (TLS, s, lua_empty_cb, lua_ptr[p]); - free (s); + tgl_do_set_profile_photo (TLS, lua_ptr[p + 1].str, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; case lq_set_profile_name: - s1 = lua_ptr[p + 1]; - s2 = lua_ptr[p + 1]; - tgl_do_set_profile_name (TLS, s1, strlen (s1), s2, strlen (s2), lua_user_cb, lua_ptr[p]); - free (s1); - free (s2); + tgl_do_set_profile_name (TLS, LUA_STR_ARG (p + 1), LUA_STR_ARG (p + 2), lua_user_cb, lua_ptr[p].ptr); p += 3; break; case lq_create_secret_chat: - tgl_do_create_secret_chat (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, lua_secret_chat_cb, lua_ptr[p]); + tgl_do_create_secret_chat (TLS, lua_ptr[p + 1].peer_id, lua_secret_chat_cb, lua_ptr[p].ptr); p += 2; break; case lq_create_group_chat: - s = lua_ptr[p + 2]; - tgl_do_create_group_chat (TLS, 1, &((tgl_peer_t *)lua_ptr[p + 1])->id, s, strlen (s), lua_empty_cb, lua_ptr[p]); - free (s); + tgl_do_create_group_chat (TLS, 1, &lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); p += 3; break; case lq_delete_msg: - tgl_do_delete_msg (TLS, ((struct tgl_message *)lua_ptr[p + 1])->id, lua_empty_cb, lua_ptr[p]); - p += 2; - break; - case lq_restore_msg: - tgl_do_delete_msg (TLS, (long)lua_ptr[p + 1], lua_empty_cb, lua_ptr[p]); + tgl_do_delete_msg (TLS, &lua_ptr[p + 1].msg_id, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; case lq_accept_secret_chat: - tgl_do_accept_encr_chat_request (TLS, lua_ptr[p + 1], lua_secret_chat_cb, lua_ptr[p]); + tgl_do_accept_encr_chat_request (TLS, (void *)tgl_peer_get (TLS, lua_ptr[p + 1].peer_id), lua_secret_chat_cb, lua_ptr[p].ptr); p += 2; break; case lq_send_contact: - s1 = lua_ptr[p + 2]; - s2 = lua_ptr[p + 3]; - s3 = lua_ptr[p + 4]; - tgl_do_send_contact (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id, s1, strlen (s1), s2, strlen (s2), s3, strlen (s3), 0, lua_msg_cb, lua_ptr[p]); - free (s1); - free (s2); - free (s3); + tgl_do_send_contact (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), LUA_STR_ARG (p + 3), LUA_STR_ARG (p + 4), 0, lua_msg_cb, lua_ptr[p].ptr); p += 5; break; case lq_status_online: - tgl_do_update_status (TLS, 1, lua_empty_cb, lua_ptr[p]); + tgl_do_update_status (TLS, 1, lua_empty_cb, lua_ptr[p].ptr); p ++; break; case lq_status_offline: - tgl_do_update_status (TLS, 0, lua_empty_cb, lua_ptr[p]); + tgl_do_update_status (TLS, 0, lua_empty_cb, lua_ptr[p].ptr); p ++; break; case lq_extf: - s = lua_ptr[p + 1]; - tgl_do_send_extf (TLS, s, strlen (s), lua_str_cb, lua_ptr[p]); - free (s); + tgl_do_send_extf (TLS, LUA_STR_ARG (p + 1), lua_str_cb, lua_ptr[p].ptr); p += 2; break; case lq_import_chat_link: - s = lua_ptr[p + 1]; - tgl_do_import_chat_link (TLS, s, strlen (s), lua_empty_cb, lua_ptr[p]); - free (s); + tgl_do_import_chat_link (TLS, LUA_STR_ARG (p + 1), lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_export_chat_link: + tgl_do_export_chat_link (TLS, lua_ptr[p + 1].peer_id, lua_str_cb, lua_ptr[p].ptr); p += 2; break; case lq_send_location: - if (sizeof (void *) == 4) { - tgl_do_send_location (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id , *(float *)(lua_ptr + p + 2), *(float *)(lua_ptr + p + 3), 0, lua_msg_cb, lua_ptr[p]); - } else { - tgl_do_send_location (TLS, ((tgl_peer_t *)lua_ptr[p + 1])->id , *(double *)(lua_ptr + p + 2), *(double *)(lua_ptr + p + 3), 0, lua_msg_cb, lua_ptr[p]); - } + tgl_do_send_location (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].dnum, lua_ptr[p + 3].dnum, 0, lua_msg_cb, lua_ptr[p].ptr); p += 4; break; + case lq_channel_invite_user: + tgl_do_channel_invite_user (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_kick_user: + tgl_do_channel_kick_user (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_get_admins: + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 100, 0, 1, lua_contact_list_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_channel_get_users: + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 100, 0, 0, lua_contact_list_cb, lua_ptr[p].ptr); + p += 2; + break; /* lq_delete_msg, lq_restore_msg, @@ -1269,6 +1382,12 @@ void lua_do_all (void) { default: assert (0); } + while (q < p) { + if (lua_ptr[q].flags & 1) { + tfree_str (lua_ptr[q].str); + } + q ++; + } } pos = 0; } @@ -1278,6 +1397,7 @@ enum lua_function_param { lfp_none, lfp_peer, lfp_chat, + lfp_channel, lfp_user, lfp_secret_chat, lfp_string, @@ -1299,6 +1419,7 @@ struct lua_function functions[] = { {"get_dialog_list", lq_dialog_list, { lfp_none }}, {"rename_chat", lq_rename_chat, { lfp_chat, lfp_string, lfp_none }}, {"send_msg", lq_msg, { lfp_peer, lfp_string, lfp_none }}, + {"post_msg", lq_msg_channel, { lfp_channel, lfp_string, lfp_none }}, {"send_typing", lq_send_typing, { lfp_peer, lfp_none }}, {"send_typing_abort", lq_send_typing_abort, { lfp_peer, lfp_none }}, {"send_photo", lq_send_photo, { lfp_peer, lfp_string, lfp_none }}, @@ -1314,9 +1435,11 @@ struct lua_function functions[] = { {"load_audio", lq_load_audio, { lfp_msg, lfp_none }}, {"load_document", lq_load_document, { lfp_msg, lfp_none }}, {"load_document_thumb", lq_load_document_thumb, { lfp_msg, lfp_none }}, + {"reply_msg", lq_reply, { lfp_msg, lfp_string, lfp_none }}, {"fwd_msg", lq_fwd, { lfp_peer, lfp_msg, lfp_none }}, {"fwd_media", lq_fwd_media, { lfp_peer, lfp_msg, lfp_none }}, {"chat_info", lq_chat_info, { lfp_chat, lfp_none }}, + {"channel_info", lq_channel_info, { lfp_channel, lfp_none }}, {"user_info", lq_user_info, { lfp_user, lfp_none }}, {"get_history", lq_history, { lfp_peer, lfp_nonnegative_number, lfp_none }}, {"chat_add_user", lq_chat_add_user, { lfp_chat, lfp_user, lfp_none }}, @@ -1340,6 +1463,11 @@ struct lua_function functions[] = { {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, {"ext_function", lq_extf, { lfp_string, lfp_none }}, {"import_chat_link", lq_import_chat_link, { lfp_string, lfp_none }}, + {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, + {"channel_invite_user", lq_channel_invite_user, { lfp_channel, lfp_user, lfp_none }}, + {"channel_kick_user", lq_channel_kick_user, { lfp_channel, lfp_user, lfp_none }}, + {"channel_get_admins", lq_channel_get_admins, { lfp_channel, lfp_none }}, + {"channel_get_users", lq_channel_get_users, { lfp_channel, lfp_none }}, { 0, 0, { lfp_none}} }; @@ -1361,9 +1489,9 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { assert (pos + 3 + p < MAX_LUA_COMMANDS); - lua_ptr[pos ++] = (void *)(long)(p + 1); - lua_ptr[pos ++] = (void *)(long)F->type; - lua_ptr[pos ++] = e; + lua_ptr[pos ++].num = (p + 1); + lua_ptr[pos ++].num = F->type; + lua_ptr[pos ++].ptr = e; int sp = p; int ok = 1; @@ -1372,10 +1500,10 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { p --; cc ++; const char *s; - tgl_peer_t *P; long long num; double dval; - struct tgl_message *M; + tgl_peer_id_t peer_id; + lua_ptr[pos + p].flags = 0; switch (F->params[p]) { case lfp_none: assert (0); @@ -1383,40 +1511,32 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { case lfp_peer: case lfp_user: case lfp_chat: + case lfp_channel: case lfp_secret_chat: s = lua_tostring (L, -cc); if (!s) { ok = 0; break; } - if (sscanf (s, "user#id%lld", &num) == 1 && num > 0) { - tgl_insert_empty_user (TLS, num); - P = tgl_peer_get (TLS, TGL_MK_USER (num)); - } else if (sscanf (s, "chat#id%lld", &num) == 1 && num > 0) { - tgl_insert_empty_chat (TLS, num); - P = tgl_peer_get (TLS, TGL_MK_CHAT (num)); - } else if (sscanf (s, "user#%lld", &num) == 1 && num > 0) { - tgl_insert_empty_user (TLS, num); - P = tgl_peer_get (TLS, TGL_MK_USER (num)); - } else if (sscanf (s, "chat#%lld", &num) == 1 && num > 0) { - tgl_insert_empty_chat (TLS, num); - P = tgl_peer_get (TLS, TGL_MK_CHAT (num)); + + if (F->params[p] == lfp_user) { + peer_id = parse_input_peer_id (s, strlen (s), TGL_PEER_USER); + } else if (F->params[p] == lfp_chat) { + peer_id = parse_input_peer_id (s, strlen (s), TGL_PEER_CHAT); + } else if (F->params[p] == lfp_secret_chat) { + peer_id = parse_input_peer_id (s, strlen (s), TGL_PEER_ENCR_CHAT); + } else if (F->params[p] == lfp_channel) { + peer_id = parse_input_peer_id (s, strlen (s), TGL_PEER_CHANNEL); } else { - P = get_peer (s); + peer_id = parse_input_peer_id (s, strlen (s), 0); } - if (!P/* || !(P->flags & FLAG_CREATED)*/) { + + if (!peer_id.peer_type) { ok = 0; break; } - if (F->params[p] != lfp_peer) { - if ((tgl_get_peer_type (P->id) == TGL_PEER_USER && F->params[p] != lfp_user) || - (tgl_get_peer_type (P->id) == TGL_PEER_CHAT && F->params[p] != lfp_chat) || - (tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT && F->params[p] != lfp_secret_chat)) { - ok = 0; - break; - } - } - lua_ptr[pos + p] = P; + + lua_ptr[pos + p].peer_id = peer_id; break; case lfp_string: @@ -1425,23 +1545,31 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { ok = 0; break; } - lua_ptr[pos + p] = (void *)s; + lua_ptr[pos + p].str = (void *)s; + lua_ptr[pos + p].flags |= 1; break; case lfp_number: num = lua_tonumber (L, -cc); - lua_ptr[pos + p] = (void *)(long)num; + lua_ptr[pos + p].num = num; break; case lfp_double: - dval = lua_tonumber (L, -cc); - - if (sizeof (void *) == 4) { - *(float *)(lua_ptr + pos + p) = dval; - } else { - assert (sizeof (void *) >= 8); - *(double *)(lua_ptr + pos + p) = dval; + dval = lua_tonumber (L, -cc); + lua_ptr[pos + p].dnum = dval; + break; + + case lfp_msg: + s = lua_tostring (L, -cc); + if (!s) { + ok = 0; + break; + } + lua_ptr[pos + p].msg_id = parse_input_msg_id (s, strlen (s)); + if (lua_ptr[pos + p].msg_id.peer_type == 0) { + ok = 0; + break; } break; @@ -1452,7 +1580,7 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { break; } - lua_ptr[pos + p] = (void *)(long)num; + lua_ptr[pos + p].num = num; break; case lfp_nonnegative_number: @@ -1462,26 +1590,7 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { break; } - lua_ptr[pos + p] = (void *)(long)num; - break; - - case lfp_msg: - s = lua_tostring (L, -cc); - if (!s || !strlen (s)) { - ok = 0; - break; - } - - num = atoll (s); - - M = tgl_message_get (TLS, num); - - if (!M || !(M->flags & TGLMF_CREATED)) { - ok = 0; - break; - } - - lua_ptr[pos + p] = M; + lua_ptr[pos + p].num = num; break; default: @@ -1499,7 +1608,7 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { for (p = 0; p < sp; p++) { if (F->params[p] == lfp_string) { - lua_ptr[pos + p] = strdup (lua_ptr[pos + p]); + lua_ptr[pos + p].str = tstrdup (lua_ptr[pos + p].str); } } pos += p; @@ -1608,6 +1717,7 @@ enum command_argument { ca_user, ca_chat, ca_secret_chat, + ca_channel, ca_peer, ca_file_name, ca_file_name_end, diff --git a/lua-tg.h b/lua-tg.h index d7bfc02f..c0ae60a2 100644 --- a/lua-tg.h +++ b/lua-tg.h @@ -24,7 +24,7 @@ void lua_init (const char *file); void lua_new_msg (struct tgl_message *M); -void lua_our_id (int id); +void lua_our_id (tgl_peer_id_t id); void lua_secret_chat_update (struct tgl_secret_chat *U, unsigned flags); void lua_user_update (struct tgl_user *U, unsigned flags); void lua_chat_update (struct tgl_chat *C, unsigned flags); diff --git a/main.c b/main.c index d6af164a..4776f073 100644 --- a/main.c +++ b/main.c @@ -37,19 +37,7 @@ #include #include #endif -#if (READLINE == GNU) #include -#else -#include -#endif -#ifdef EVENT_V2 -#include -#include -#include -#else -#include -#include "event-old.h" -#endif #include #include @@ -74,6 +62,7 @@ #include "interface.h" #include #include +#include #ifdef USE_LUA # include "lua-tg.h" @@ -130,6 +119,9 @@ int disable_link_preview; int enable_json; int alert_sound; int exit_code; +int permanent_msg_id_mode; +int permanent_peer_id_mode; +char *home_directory; struct tgl_state *TLS; @@ -176,11 +168,11 @@ int str_empty (char *str) { } char *get_home_directory (void) { - static char *home_directory = NULL; + if (home_directory) { return home_directory; } home_directory = getenv("TELEGRAM_HOME"); - if (!str_empty (home_directory)) { return tstrdup (home_directory); } + if (!str_empty (home_directory)) { return home_directory = tstrdup (home_directory); } home_directory = getenv("HOME"); - if (!str_empty (home_directory)) { return tstrdup (home_directory); } + if (!str_empty (home_directory)) { return home_directory = tstrdup (home_directory); } struct passwd *current_passwd; uid_t user_id; setpwent (); @@ -273,7 +265,7 @@ void running_for_first_time (void) { // printf ("I: config file=[%s]\n", config_filename); int config_file_fd; - char *config_directory = get_config_directory (); + //char *config_directory = get_config_directory (); //char *downloads_directory = get_downloads_directory (); if (!mkdir (config_directory, CONFIG_DIRECTORY_MODE)) { @@ -298,18 +290,6 @@ void running_for_first_time (void) { exit (EXIT_FAILURE); } close (config_file_fd); - /*int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); - int x = -1; - assert (write (auth_file_fd, &x, 4) == 4); - close (auth_file_fd); - - printf ("[%s] created\n", config_filename);*/ - - /* create downloads directory */ - /*if (mkdir (downloads_directory, 0755) !=0) { - perror ("creating download directory"); - exit (EXIT_FAILURE); - }*/ } } @@ -393,9 +373,13 @@ void parse_config (void) { if (!python_file) { parse_config_val (&conf, &python_file, "python_script", 0, config_directory); } - + + #if 0 strcpy (buf + l, "binlog_enabled"); config_lookup_bool (&conf, buf, &binlog_enabled); + #else + binlog_enabled = 0; + #endif int pfs_enabled = 0; strcpy (buf + l, "pfs_enabled"); @@ -426,6 +410,8 @@ void parse_config (void) { printf ("[%s] created\n", downloads_directory); } } + tfree_str (config_directory); + config_directory = NULL; config_destroy (&conf); } #else @@ -434,7 +420,7 @@ void parse_config (void) { printf ("libconfig not enabled\n"); } tasprintf (&downloads_directory, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, DOWNLOADS_DIRECTORY); - + if (binlog_enabled) { tasprintf (&binlog_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, BINLOG_FILE); tgl_set_binlog_mode (TLS, 1); @@ -470,8 +456,10 @@ void usage (void) { printf (" --config/-c config file name\n"); printf (" --profile/-p use specified profile\n"); #else + #if 0 printf (" --enable-binlog/-B enable binlog\n"); #endif + #endif printf (" --log-level/-l log level\n"); printf (" --sync-from-start/-f during authorization fetch all messages since registration\n"); printf (" --disable-auto-accept/-E disable auto accept of encrypted chats\n"); @@ -502,6 +490,8 @@ void usage (void) { #ifdef USE_PYTHON printf (" --python-script/-Z python script file\n"); #endif + printf (" --permanent-msg-ids use permanent msg ids\n"); + printf (" --permanent-peer-ids use permanent peer ids\n"); exit (1); } @@ -622,7 +612,9 @@ void args_parse (int argc, char **argv) { {"config", required_argument, 0, 'c'}, {"profile", required_argument, 0, 'p'}, #else + #if 0 {"enable-binlog", no_argument, 0, 'B'}, + #endif #endif {"log-level", required_argument, 0, 'l'}, {"sync-from-start", no_argument, 0, 'f'}, @@ -652,6 +644,8 @@ void args_parse (int argc, char **argv) { {"disable-link-preview", no_argument, 0, 1002}, {"json", no_argument, 0, 1003}, {"python-script", required_argument, 0, 'Z'}, + {"permanent-msg-ids", no_argument, 0, 1004}, + {"permanent-peer-ids", no_argument, 0, 1005}, {0, 0, 0, 0 } }; @@ -662,7 +656,9 @@ void args_parse (int argc, char **argv) { #ifdef HAVE_LIBCONFIG "c:p:" #else + #if 0 "B" + #endif #endif #ifdef USE_LUA "s:" @@ -709,9 +705,11 @@ void args_parse (int argc, char **argv) { assert (strlen (prefix) <= 100); break; #else + #if 0 case 'B': binlog_enabled = 1; break; + #endif #endif case 'l': log_level = atoi (optarg); @@ -786,6 +784,12 @@ void args_parse (int argc, char **argv) { case 1003: enable_json = 1; break; + case 1004: + permanent_msg_id_mode = 1; + break; + case 1005: + permanent_peer_id_mode = 1; + break; case 'h': default: usage (); @@ -974,8 +978,10 @@ 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" +#ifndef TGL_AVOID_OPENSSL "Telegram-cli includes software developed by the OpenSSL Project\n" "for use in the OpenSSL Toolkit. (http://www.openssl.org/)\n" +#endif #ifdef USE_PYTHON "Telegram-cli uses libpython version " PY_VERSION "\n" #endif @@ -991,6 +997,7 @@ int main (int argc, char **argv) { #endif tgl_set_rsa_key (TLS, "tg-server.pub"); + tgl_set_rsa_key_direct (TLS, tglmp_get_default_e (), tglmp_get_default_key_len (), tglmp_get_default_key ()); get_terminal_attributes (); diff --git a/telegram.h b/telegram.h index ce92a095..dd1be8ac 100644 --- a/telegram.h +++ b/telegram.h @@ -21,4 +21,4 @@ #define PROG_NAME "telegram-cli" #endif -#define TELEGRAM_CLI_VERSION "1.3.3" +#define TELEGRAM_CLI_VERSION "1.4.1" From 93fc1f96ffcc32eb89bc5112cb8aa98e6af42556 Mon Sep 17 00:00:00 2001 From: Rondoozle Date: Mon, 7 Mar 2016 23:56:18 -0500 Subject: [PATCH 046/164] Update .gitmodules --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index dffe6ca1..df2f8d2d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tgl"] path = tgl - url = https://github.com/vysheng/tgl.git + url = https://github.com/Rondoozle/tgl.git From 1def4cba371584bd4c00a028c102d7a109c90b17 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Wed, 9 Mar 2016 03:11:26 +0000 Subject: [PATCH 047/164] SuperGroups and Channels for TeleSeed v4! --- .gitmodules | 2 +- lua-tg.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 173 insertions(+), 17 deletions(-) diff --git a/.gitmodules b/.gitmodules index dffe6ca1..df2f8d2d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tgl"] path = tgl - url = https://github.com/vysheng/tgl.git + url = https://github.com/Rondoozle/tgl.git diff --git a/lua-tg.c b/lua-tg.c index 454a0a66..56bcc088 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -127,7 +127,7 @@ void push_user (tgl_peer_t *P) { lua_add_string_field ("phone", P->user.phone); lua_add_string_field ("username", P->user.username); if (P->user.access_hash) { - lua_add_num_field ("access_hash", 1); + lua_add_num_field ("access_hash", P->user.access_hash); } } @@ -161,6 +161,7 @@ void push_channel (tgl_peer_t *P) { my_lua_checkstack (luaState, 4); lua_add_string_field ("title", P->channel.title); lua_add_string_field ("about", P->channel.about); + lua_add_string_field ("username", P->channel.username); lua_add_num_field ("participants_count", P->channel.participants_count); lua_add_num_field ("admins_count", P->channel.admins_count); lua_add_num_field ("kicked_count", P->channel.kicked_count); @@ -288,11 +289,24 @@ void push_media (struct tgl_message_media *M) { lua_add_string_field ("caption", M->caption); break; case tgl_message_media_document: + lua_newtable (luaState); + lua_add_string_field ("type", "document"); + lua_add_string_field ("caption", M->document->caption); + break; case tgl_message_media_audio: + lua_newtable (luaState); + lua_add_string_field ("type", "audio"); + lua_add_string_field ("caption", M->caption); + break; case tgl_message_media_video: + lua_newtable (luaState); + lua_add_string_field ("type", "video"); + lua_add_string_field ("caption", M->caption); + break; case tgl_message_media_document_encr: lua_newtable (luaState); - lua_add_string_field ("type", "document"); + lua_add_string_field ("type", "encr_document"); + lua_add_string_field ("caption", M->document->caption); break; case tgl_message_media_unsupported: lua_newtable (luaState); @@ -470,6 +484,7 @@ void push_message (struct tgl_message *M) { lua_newtable (luaState); lua_add_string_field ("id", print_permanent_msg_id (M->permanent_id)); + lua_add_num_field ("temp_id", (M->temp_id)); if (!(M->flags & TGLMF_CREATED)) { return; } lua_add_num_field ("flags", M->flags); @@ -686,7 +701,6 @@ enum lua_query_type { lq_load_video_thumb, lq_load_video, lq_chat_info, - lq_channel_info, lq_user_info, lq_history, lq_chat_add_user, @@ -696,6 +710,7 @@ enum lua_query_type { lq_rename_contact, lq_search, lq_global_search, + lq_resolve_username, lq_mark_read, lq_create_secret_chat, lq_create_group_chat, @@ -707,6 +722,7 @@ enum lua_query_type { lq_load_document_thumb, lq_delete_msg, lq_restore_msg, + lq_get_message, lq_accept_secret_chat, lq_send_contact, lq_status_online, @@ -715,10 +731,27 @@ enum lua_query_type { lq_extf, lq_import_chat_link, lq_export_chat_link, - lq_channel_invite_user, - lq_channel_kick_user, + lq_channels_dialog_list, + lq_chat_upgrade, + lq_create_channel, + lq_channel_info, + lq_export_channel_link, + lq_channel_invite, + lq_channel_join, + lq_leave_channel, + lq_channel_kick, lq_channel_get_admins, - lq_channel_get_users + lq_channel_get_users, + lq_channel_get_bots, + lq_channel_get_kicked, + lq_channel_unblock, + lq_rename_channel, + lq_channel_set_photo, + lq_channel_set_about, + lq_channel_set_username, + lq_channel_set_admin, + lq_channel_set_mod, + lq_channel_demote }; struct lua_query_extra { @@ -1140,6 +1173,38 @@ void lua_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char #define LUA_STR_ARG(n) lua_ptr[n].str, strlen (lua_ptr[n].str) +void lua_contact_search_cb (struct tgl_state *TLSR, void *cb_extra, int success, tgl_peer_t *C) { + assert (TLSR == TLS); + struct lua_query_extra *cb = cb_extra; + lua_settop (luaState, 0); + //lua_checkstack (luaState, 20); + my_lua_checkstack (luaState, 20); + + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->func); + lua_rawgeti (luaState, LUA_REGISTRYINDEX, cb->param); + + lua_pushnumber (luaState, success); + + if (success) { + push_peer (C->id, (void *)C); + } else { + lua_pushboolean (luaState, 0); + } + + assert (lua_gettop (luaState) == 4); + + int r = ps_lua_pcall (luaState, 3, 0, 0); + + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->func); + luaL_unref (luaState, LUA_REGISTRYINDEX, cb->param); + + if (r) { + logprintf ("lua: %s\n", lua_tostring (luaState, -1)); + } + + free (cb); +} + void lua_do_all (void) { int p = 0; while (p < pos) { @@ -1251,10 +1316,6 @@ void lua_do_all (void) { tgl_do_get_chat_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_chat_cb, lua_ptr[p].ptr); p += 2; break; - case lq_channel_info: - tgl_do_get_channel_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_channel_cb, lua_ptr[p].ptr); - p += 2; - break; case lq_user_info: tgl_do_get_user_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_user_cb, lua_ptr[p].ptr); p += 2; @@ -1290,6 +1351,10 @@ void lua_do_all (void) { case lq_global_search: tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, LUA_STR_ARG (p + 1), lua_msg_list_cb, lua_ptr[p].ptr); p += 2; + break; + case lq_resolve_username: + tgl_do_contact_search (TLS, LUA_STR_ARG (p + 1), lua_contact_search_cb, lua_ptr[p].ptr); + p += 2; break; case lq_mark_read: tgl_do_mark_read (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); @@ -1315,6 +1380,10 @@ void lua_do_all (void) { tgl_do_delete_msg (TLS, &lua_ptr[p + 1].msg_id, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; + case lq_get_message: + tgl_do_get_message (TLS, &lua_ptr[p + 1].msg_id, lua_msg_cb, lua_ptr[p].ptr); + p += 2; + break; case lq_accept_secret_chat: tgl_do_accept_encr_chat_request (TLS, (void *)tgl_peer_get (TLS, lua_ptr[p + 1].peer_id), lua_secret_chat_cb, lua_ptr[p].ptr); p += 2; @@ -1347,11 +1416,39 @@ void lua_do_all (void) { tgl_do_send_location (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].dnum, lua_ptr[p + 3].dnum, 0, lua_msg_cb, lua_ptr[p].ptr); p += 4; break; - case lq_channel_invite_user: + //channels and megagroups + case lq_channels_dialog_list: + tgl_do_get_channels_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++].ptr); + break; + case lq_chat_upgrade: + tgl_do_upgrade_group (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_create_channel: + tgl_do_create_channel (TLS, 1, &lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), LUA_STR_ARG (p + 3), 1,lua_empty_cb, lua_ptr[p].ptr); + p += 4; + break; + case lq_channel_info: + tgl_do_get_channel_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_channel_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_export_channel_link: + tgl_do_export_channel_link (TLS, lua_ptr[p + 1].peer_id, lua_str_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_channel_invite: tgl_do_channel_invite_user (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 3; break; - case lq_channel_kick_user: + case lq_channel_join: + tgl_do_join_channel (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_leave_channel: + tgl_do_leave_channel (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_channel_kick: tgl_do_channel_kick_user (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 3; break; @@ -1360,9 +1457,49 @@ void lua_do_all (void) { p += 2; break; case lq_channel_get_users: - tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 100, 0, 0, lua_contact_list_cb, lua_ptr[p].ptr); + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 0, lua_contact_list_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_channel_get_bots: + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 4, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; + case lq_channel_get_kicked: + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 3, lua_contact_list_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_channel_unblock: + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_rename_channel: + tgl_do_rename_channel (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_photo: + tgl_do_set_channel_photo (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_about: + tgl_do_channel_set_about (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_username: + tgl_do_channel_set_username (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_admin: + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 2, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_mod: + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 1, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_demote: + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; /* lq_delete_msg, lq_restore_msg, @@ -1449,6 +1586,7 @@ struct lua_function functions[] = { {"rename_contact", lq_rename_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, {"msg_search", lq_search, { lfp_peer, lfp_string, lfp_none }}, {"msg_global_search", lq_global_search, { lfp_string, lfp_none }}, + {"resolve_username", lq_resolve_username, { lfp_string, lfp_none }}, {"mark_read", lq_mark_read, { lfp_peer, lfp_none }}, {"set_profile_photo", lq_set_profile_photo, { lfp_string, lfp_none }}, {"set_profile_name", lq_set_profile_name, { lfp_string, lfp_none }}, @@ -1456,6 +1594,7 @@ struct lua_function functions[] = { {"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }}, {"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }}, {"restore_msg", lq_restore_msg, { lfp_positive_number, lfp_none }}, + {"get_message", lq_get_message, { lfp_msg, lfp_none }}, {"accept_secret_chat", lq_accept_secret_chat, { lfp_secret_chat, lfp_none }}, {"send_contact", lq_send_contact, { lfp_peer, lfp_string, lfp_string, lfp_string, lfp_none }}, {"status_online", lq_status_online, { lfp_none }}, @@ -1464,10 +1603,27 @@ struct lua_function functions[] = { {"ext_function", lq_extf, { lfp_string, lfp_none }}, {"import_chat_link", lq_import_chat_link, { lfp_string, lfp_none }}, {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, - {"channel_invite_user", lq_channel_invite_user, { lfp_channel, lfp_user, lfp_none }}, - {"channel_kick_user", lq_channel_kick_user, { lfp_channel, lfp_user, lfp_none }}, + {"get_channels_dialog_list", lq_channels_dialog_list, { lfp_none }}, + {"chat_upgrade", lq_chat_upgrade, { lfp_peer, lfp_none }}, + {"create_channel", lq_create_channel, { lfp_peer, lfp_string, lfp_string, lfp_none }}, + {"channel_info", lq_channel_info, { lfp_channel, lfp_none }}, + {"export_channel_link", lq_export_channel_link, { lfp_channel, lfp_none }}, + {"channel_invite", lq_channel_invite, { lfp_channel, lfp_user, lfp_none }}, + {"channel_join", lq_channel_join, { lfp_channel, lfp_none }}, + {"leave_channel", lq_leave_channel, { lfp_channel, lfp_none }}, + {"channel_kick", lq_channel_kick, { lfp_channel, lfp_user, lfp_none }}, {"channel_get_admins", lq_channel_get_admins, { lfp_channel, lfp_none }}, {"channel_get_users", lq_channel_get_users, { lfp_channel, lfp_none }}, + {"channel_get_bots", lq_channel_get_bots, { lfp_channel, lfp_none }}, + {"channel_get_kicked", lq_channel_get_kicked, { lfp_channel, lfp_none }}, + {"channel_unblock", lq_channel_unblock, { lfp_channel, lfp_peer, lfp_none }}, + {"rename_channel", lq_rename_channel, { lfp_channel, lfp_string, lfp_none }}, + {"channel_set_photo", lq_channel_set_photo, { lfp_channel, lfp_string, lfp_none }}, + {"channel_set_about", lq_channel_set_about, { lfp_channel, lfp_string, lfp_none }}, + {"channel_set_username", lq_channel_set_username, { lfp_channel, lfp_string, lfp_none }}, + {"channel_set_admin", lq_channel_set_admin, { lfp_channel, lfp_peer, lfp_none }}, + {"channel_set_mod", lq_channel_set_mod, { lfp_channel, lfp_peer, lfp_none }}, + {"channel_demote", lq_channel_demote, { lfp_channel, lfp_peer, lfp_none }}, { 0, 0, { lfp_none}} }; @@ -1937,4 +2093,4 @@ void lua_init (const char *file) { } } -#endif +#endif \ No newline at end of file From af705113254272b59eaab2c22a8290659d3cc690 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Wed, 9 Mar 2016 04:04:59 +0000 Subject: [PATCH 048/164] Update tgl --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index 08b6340c..b17c2ac9 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 08b6340c1cbf1ef59690007b0207de9d5c904c07 +Subproject commit b17c2ac9bd2819066c118b481f5763a7b35535c9 From 2c67f1e8ae91c268ce52e7c0a902af2354770728 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Wed, 9 Mar 2016 07:45:49 +0000 Subject: [PATCH 049/164] lua-tg.c fixes --- lua-tg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua-tg.c b/lua-tg.c index 30824f54..56bcc088 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -1416,7 +1416,7 @@ void lua_do_all (void) { tgl_do_send_location (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].dnum, lua_ptr[p + 3].dnum, 0, lua_msg_cb, lua_ptr[p].ptr); p += 4; break; - //channel Support + //channels and megagroups case lq_channels_dialog_list: tgl_do_get_channels_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++].ptr); break; From e2b54ec4b75e6e99d81ee5ddeedfc67826da1461 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Wed, 9 Mar 2016 08:02:06 +0000 Subject: [PATCH 050/164] lua-tg.c spacing fixes --- lua-tg.c | 104 +++++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index 56bcc088..a40294d2 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -1416,23 +1416,23 @@ void lua_do_all (void) { tgl_do_send_location (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].dnum, lua_ptr[p + 3].dnum, 0, lua_msg_cb, lua_ptr[p].ptr); p += 4; break; - //channels and megagroups - case lq_channels_dialog_list: - tgl_do_get_channels_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++].ptr); - break; - case lq_chat_upgrade: - tgl_do_upgrade_group (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); - p += 2; - break; + //channel Support + case lq_channels_dialog_list: + tgl_do_get_channels_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++].ptr); + break; + case lq_chat_upgrade: + tgl_do_upgrade_group (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; case lq_create_channel: - tgl_do_create_channel (TLS, 1, &lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), LUA_STR_ARG (p + 3), 1,lua_empty_cb, lua_ptr[p].ptr); - p += 4; - break; - case lq_channel_info: + tgl_do_create_channel (TLS, 1, &lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), LUA_STR_ARG (p + 3), 1,lua_empty_cb, lua_ptr[p].ptr); + p += 4; + break; + case lq_channel_info: tgl_do_get_channel_info (TLS, lua_ptr[p + 1].peer_id, 0, lua_channel_cb, lua_ptr[p].ptr); p += 2; break; - case lq_export_channel_link: + case lq_export_channel_link: tgl_do_export_channel_link (TLS, lua_ptr[p + 1].peer_id, lua_str_cb, lua_ptr[p].ptr); p += 2; break; @@ -1440,13 +1440,13 @@ void lua_do_all (void) { tgl_do_channel_invite_user (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 3; break; - case lq_channel_join: - tgl_do_join_channel (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); - p += 2; - break; - case lq_leave_channel: - tgl_do_leave_channel (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); - p += 2; + case lq_channel_join: + tgl_do_join_channel (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_leave_channel: + tgl_do_leave_channel (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; break; case lq_channel_kick: tgl_do_channel_kick_user (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); @@ -1460,46 +1460,46 @@ void lua_do_all (void) { tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 0, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; - case lq_channel_get_bots: + case lq_channel_get_bots: tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 4, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; - case lq_channel_get_kicked: + case lq_channel_get_kicked: tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 3, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; - case lq_channel_unblock: - tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; - case lq_rename_channel: - tgl_do_rename_channel (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; - case lq_channel_set_photo: - tgl_do_set_channel_photo (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; - case lq_channel_set_about: - tgl_do_channel_set_about (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; - case lq_channel_set_username: - tgl_do_channel_set_username (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; - case lq_channel_set_admin: - tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 2, lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; + case lq_channel_unblock: + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_rename_channel: + tgl_do_rename_channel (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_photo: + tgl_do_set_channel_photo (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_about: + tgl_do_channel_set_about (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_username: + tgl_do_channel_set_username (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_set_admin: + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 2, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; case lq_channel_set_mod: - tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 1, lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 1, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; case lq_channel_demote: - tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; /* lq_delete_msg, lq_restore_msg, From 5ffb71ddc7302efe8aefddb737b3426d6c0ae640 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Wed, 9 Mar 2016 16:03:50 +0000 Subject: [PATCH 051/164] Update tgl and .gitmodules --- .gitmodules | 2 +- tgl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index df2f8d2d..2735f9b4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tgl"] path = tgl - url = https://github.com/Rondoozle/tgl.git + url = https://github.com/Rondoozle/tgl.git \ No newline at end of file diff --git a/tgl b/tgl index b17c2ac9..8c57fa83 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit b17c2ac9bd2819066c118b481f5763a7b35535c9 +Subproject commit 8c57fa83d995b0b8b399d0b522e8a67d2f519f49 From ac30a97e1b83c8c35f941a7c7b2f32d6666e836d Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Wed, 9 Mar 2016 18:21:57 +0000 Subject: [PATCH 052/164] Fixes --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index 08b6340c..418f81be 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 08b6340c1cbf1ef59690007b0207de9d5c904c07 +Subproject commit 418f81be448fdebb04c3809795f8c160ee13280c From 24985457b93f26b811496e08dece1e55afb8de14 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Wed, 9 Mar 2016 21:18:50 +0000 Subject: [PATCH 053/164] Updated tgl --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index 418f81be..79d091fd 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 418f81be448fdebb04c3809795f8c160ee13280c +Subproject commit 79d091fdd4c71571dcb6f23d783cba2cef96b056 From 33cf197fe2e0b2ef8cbadb9d71ea5ff5454ef488 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Fri, 11 Mar 2016 10:36:06 +0000 Subject: [PATCH 054/164] Update tgl --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index 79d091fd..dfdf42b9 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 79d091fdd4c71571dcb6f23d783cba2cef96b056 +Subproject commit dfdf42b9ed419f38a391c171bcb3f4e5a9efce1f From ad44d65cd29b3aca58ee37439aa04a97d4cd59e7 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Thu, 17 Mar 2016 01:43:10 +0000 Subject: [PATCH 055/164] Update lua-tg.c --- lua-tg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua-tg.c b/lua-tg.c index a40294d2..a4183753 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -1457,7 +1457,7 @@ void lua_do_all (void) { p += 2; break; case lq_channel_get_users: - tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 0, lua_contact_list_cb, lua_ptr[p].ptr); + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 5000, 0, 0, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; case lq_channel_get_bots: From c702188eb7312615f6678720bbe1d8a69a171eab Mon Sep 17 00:00:00 2001 From: Michele Sorcinelli Date: Fri, 16 Oct 2015 16:36:52 +0200 Subject: [PATCH 056/164] Automatic 'mark_read' after 'msg|reply|fwd' --- interface.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/interface.c b/interface.c index f78619a3..bbb9b112 100644 --- a/interface.c +++ b/interface.c @@ -846,6 +846,7 @@ void do_msg (struct command *command, int arg_num, struct arg args[], struct in_ if (ev) { ev->refcnt ++; } vlogprintf (E_DEBUG, "reply_id=%d, disable=%d\n", reply_id, disable_msg_preview); tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, NULL, print_msg_success_gw, ev); + tgl_do_mark_read (TLS, args[0].peer_id, 0, 0); } void do_post (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -879,6 +880,15 @@ void do_reply (struct command *command, int arg_num, struct arg args[], struct i assert (arg_num == 2); if (ev) { ev->refcnt ++; } tgl_do_reply_message (TLS, &args[0].msg_id, ARG2STR(1), disable_msg_preview | do_html, print_msg_success_gw, ev); + + /* attempt to mark the conversation as read */ + struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id); + if (M) { + /* if it's a chat get its id, else get the user id that is != from our */ + tgl_peer_id_t id = (M->to_id.peer_type == TGL_PEER_CHAT || + M->to_id.peer_id != TLS->our_id.peer_id)? M->to_id : M->from_id; + tgl_do_mark_read (TLS, id, 0, 0); + } } void do_send_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -977,6 +987,7 @@ void do_fwd (struct command *command, int arg_num, struct arg args[], struct in_ assert (arg_num <= 1000); //if (arg_num == 2) { // tgl_do_forward_message (TLS, args[0].P->id, &args[1].msg_id, 0, print_msg_success_gw, ev); + // tgl_do_mark_read (TLS, args[0].P->id, 0, 0); //} else { static tgl_message_id_t *list[1000]; int i; @@ -984,6 +995,7 @@ void do_fwd (struct command *command, int arg_num, struct arg args[], struct in_ list[i] = &args[i + 1].msg_id; } tgl_do_forward_messages (TLS, args[0].peer_id, arg_num - 1, (void *)list, 0, print_msg_list_success_gw, ev); + tgl_do_mark_read (TLS, args[0].peer_id, 0, 0); //} } From a5119adbb5d5e7515c94b0650be2c97a7d8325dc Mon Sep 17 00:00:00 2001 From: Michele Sorcinelli Date: Fri, 16 Oct 2015 17:03:14 +0200 Subject: [PATCH 057/164] Auto 'mark_read' on msg in 'chat_with_peer' mode --- interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/interface.c b/interface.c index bbb9b112..77c3c751 100644 --- a/interface.c +++ b/interface.c @@ -2881,6 +2881,7 @@ void interpreter_chat_mode (char *line) { } if (strlen (line) > 0) { tgl_do_send_message (TLS, chat_mode_id, line, strlen (line), 0, NULL, 0, 0); + tgl_do_mark_read (TLS, chat_mode_id, 0, 0); } } From 55f9fedf064d3bc10bef0fd8db332ef23f7ab9b1 Mon Sep 17 00:00:00 2001 From: Jacco Date: Thu, 31 Mar 2016 10:11:48 +0200 Subject: [PATCH 058/164] Update control with build dep: libjansson --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index ecc7fc58..f86120f6 100644 --- a/debian/control +++ b/debian/control @@ -7,6 +7,7 @@ Build-Depends: debhelper (>= 8.0.0), autoconf-archive, libreadline-dev, libconfig-dev, + libjansson-dev, libssl-dev, lua5.1, liblua5.1-dev, From 13420a1484d1f2e47b2358469f3f48038fe6918f Mon Sep 17 00:00:00 2001 From: Emil Laine Date: Fri, 1 Apr 2016 18:43:53 +0300 Subject: [PATCH 059/164] Line up command descriptions in 'help' --- interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index f78619a3..bc44be6d 100644 --- a/interface.c +++ b/interface.c @@ -722,7 +722,8 @@ void do_help (struct command *command, int arg_num, struct arg args[], struct in struct command *cmd = commands; while (cmd->name) { if (!args[0].str || !strcmp (args[0].str, cmd->name)) { - mprintf (ev, "%s\n", cmd->desc); + int tab_index = strchr (cmd->desc, '\t') - cmd->desc; + mprintf (ev, "%-55.*s %s\n", tab_index, cmd->desc, cmd->desc + tab_index + 1); total ++; } cmd ++; From d2e6d1ac21dfffa1e0c311175831a32f8da4f89a Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Sat, 16 Apr 2016 01:13:20 +0100 Subject: [PATCH 060/164] Update lua-tg.c and tgl --- lua-tg.c | 34 +++++++++++++++++++++++----------- tgl | 2 +- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index a4183753..88ef6606 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -692,6 +692,7 @@ enum lua_query_type { lq_chat_set_photo, lq_set_profile_photo, lq_set_profile_name, + lq_set_profile_username, lq_send_video, lq_send_text, lq_reply, @@ -1274,7 +1275,7 @@ void lua_do_all (void) { case lq_load_audio: case lq_load_document: M = tgl_message_get (TLS, &lua_ptr[p + 1].msg_id); - if (!M || (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_document && M->media.type != tgl_message_media_document_encr)) { + if (!M || (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_document && M->media.type != tgl_message_media_video && M->media.type != tgl_message_media_audio && M->media.type != tgl_message_media_document_encr)) { lua_file_cb (TLS, lua_ptr[p].ptr, 0, 0); } else { if (M->media.type == tgl_message_media_photo) { @@ -1283,6 +1284,12 @@ void lua_do_all (void) { } else if (M->media.type == tgl_message_media_document) { assert (M->media.document); tgl_do_load_document (TLS, M->media.document, lua_file_cb, lua_ptr[p].ptr); + } else if (M->media.type == tgl_message_media_video) { + assert (M->media.document); + tgl_do_load_audio (TLS, M->media.document, lua_file_cb, lua_ptr[p].ptr); + } else if (M->media.type == tgl_message_media_audio) { + assert (M->media.document); + tgl_do_load_audio (TLS, M->media.document, lua_file_cb, lua_ptr[p].ptr); } else { tgl_do_load_encr_document (TLS, M->media.encr_document, lua_file_cb, lua_ptr[p].ptr); } @@ -1364,8 +1371,12 @@ void lua_do_all (void) { tgl_do_set_profile_photo (TLS, lua_ptr[p + 1].str, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; - case lq_set_profile_name: - tgl_do_set_profile_name (TLS, LUA_STR_ARG (p + 1), LUA_STR_ARG (p + 2), lua_user_cb, lua_ptr[p].ptr); + case lq_set_profile_username: + tgl_do_set_username (TLS, lua_ptr[p + 1].str, strlen(lua_ptr[p + 1].str), lua_user_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_set_profile_name: + tgl_do_set_profile_name (TLS, lua_ptr[p + 1].str, strlen(lua_ptr[p + 1].str),lua_ptr[p + 2].str, strlen(lua_ptr[p + 2].str), lua_user_cb, lua_ptr[p].ptr); p += 3; break; case lq_create_secret_chat: @@ -1461,17 +1472,17 @@ void lua_do_all (void) { p += 2; break; case lq_channel_get_bots: - tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 4, lua_contact_list_cb, lua_ptr[p].ptr); + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 5000, 0, 4, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; case lq_channel_get_kicked: - tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 1000, 0, 3, lua_contact_list_cb, lua_ptr[p].ptr); + tgl_do_channel_get_members (TLS, lua_ptr[p + 1].peer_id, 5000, 0, 3, lua_contact_list_cb, lua_ptr[p].ptr); p += 2; break; - case lq_channel_unblock: - tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); - p += 3; - break; + //case lq_channel_unblock: + //tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); + //p += 3; + //break; case lq_rename_channel: tgl_do_rename_channel (TLS, lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), lua_empty_cb, lua_ptr[p].ptr); p += 3; @@ -1589,7 +1600,8 @@ struct lua_function functions[] = { {"resolve_username", lq_resolve_username, { lfp_string, lfp_none }}, {"mark_read", lq_mark_read, { lfp_peer, lfp_none }}, {"set_profile_photo", lq_set_profile_photo, { lfp_string, lfp_none }}, - {"set_profile_name", lq_set_profile_name, { lfp_string, lfp_none }}, + {"set_profile_name", lq_set_profile_name, { lfp_string,lfp_string, lfp_none }}, + {"set_profile_username", lq_set_profile_username, { lfp_string, lfp_none }}, {"create_secret_chat", lq_create_secret_chat, { lfp_user, lfp_none }}, {"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }}, {"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }}, @@ -2093,4 +2105,4 @@ void lua_init (const char *file) { } } -#endif \ No newline at end of file +#endif diff --git a/tgl b/tgl index dfdf42b9..dba887f3 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit dfdf42b9ed419f38a391c171bcb3f4e5a9efce1f +Subproject commit dba887f36f029eaa53b7a9ece21c2a13c84da8f3 From 46224cf722894e5e5fe5291901a06f141d74370e Mon Sep 17 00:00:00 2001 From: Andre Abadesso Date: Sat, 16 Apr 2016 15:33:34 -0300 Subject: [PATCH 061/164] feat(): identifying groups by appending a GROUP: to the message --- compile_osx.sh | 5 +++++ interface.c | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 compile_osx.sh diff --git a/compile_osx.sh b/compile_osx.sh new file mode 100644 index 00000000..f323e9f8 --- /dev/null +++ b/compile_osx.sh @@ -0,0 +1,5 @@ +export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.3.8/lib" +export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.3.8/include" + +./configure --with-openssl=/usr/local/opt/openssl --disable-liblua +make diff --git a/interface.c b/interface.c index f78619a3..3d5b4bab 100644 --- a/interface.c +++ b/interface.c @@ -4310,6 +4310,8 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { last_to_id = M->to_id; //print_start (); + + // Sending to a USER if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) { if (M->flags & TGLMF_OUT) { mpush_color (ev, COLOR_GREEN); @@ -4371,14 +4373,21 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { mprintf (ev, " »»» "); } } - } else if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) { + } + // Sending to a CHAT + else if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) { + mpush_color (ev, COLOR_MAGENTA); + print_msg_id (ev, M->permanent_id, M); + mprintf (ev, " "); print_date (ev, M->date); mpop_color (ev); mprintf (ev, " "); + mprintf (ev, "[GROUP:"); print_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id)); + mprintf (ev, "]"); mprintf (ev, " "); print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id)); if (!tgl_cmp_peer_id (M->from_id, TLS->our_id)) { @@ -4391,6 +4400,7 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { } else { mprintf (ev, " »»» "); } + } else { assert (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL); From d66f8f039a7c577f0004db3089fc779b08bcfb14 Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Sat, 16 Apr 2016 21:16:33 +0100 Subject: [PATCH 062/164] Update tgl --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index b17c2ac9..213db7c7 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit b17c2ac9bd2819066c118b481f5763a7b35535c9 +Subproject commit 213db7c75ad174d672ce96f8cbdf4f17ce237d3f From cfd6a33fabfac6998a8dfa0ab661e2db3b4247aa Mon Sep 17 00:00:00 2001 From: Garemyah Johnson Date: Sat, 16 Apr 2016 21:25:35 +0100 Subject: [PATCH 063/164] Update tgl --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index 213db7c7..f3079900 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 213db7c75ad174d672ce96f8cbdf4f17ce237d3f +Subproject commit f3079900a8bdf3fc03fd24945a9473b1903ba81f From 4bf748da9bf364fc2c3e0f5798cef4ce61fe8ec8 Mon Sep 17 00:00:00 2001 From: Jason Chiang Date: Sat, 18 Jun 2016 08:12:13 +0800 Subject: [PATCH 064/164] 1. fix partial python support for now(type fix) 2. fix configure mistake for --enable-python/--disable-python --- configure | 2 +- interface.c | 244 ++++++++++++++++++++++++------------------------- python-tg.c | 142 ++++++++++++++-------------- python-types.c | 102 +++++++++++---------- 4 files changed, 246 insertions(+), 244 deletions(-) diff --git a/configure b/configure index fa7e189f..2cb1f398 100755 --- a/configure +++ b/configure @@ -6108,7 +6108,7 @@ $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" = "xyes" ; then + if test "x$enableval" = "xno" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else diff --git a/interface.c b/interface.c index f78619a3..8a735c33 100644 --- a/interface.c +++ b/interface.c @@ -202,12 +202,12 @@ void socket_answer_end (struct in_ev *ev) { #define mprintf(ev,...) \ if (ev) { socket_answer_add_printf (__VA_ARGS__); } \ - else { printf (__VA_ARGS__); } + else { printf (__VA_ARGS__); } #define mprint_start(ev,...) \ if (!ev) { print_start (__VA_ARGS__); } \ else { socket_answer_start (); } - + #define mprint_end(ev,...) \ if (!ev) { print_end (__VA_ARGS__); } \ else { socket_answer_end (ev); } @@ -299,13 +299,13 @@ static void next_token (void) { void next_token_end (void) { skip_wspc (); - + if (*line_ptr && *line_ptr != '"' && *line_ptr != '\'') { cur_token_quoted = 0; cur_token = line_ptr; while (*line_ptr) { line_ptr ++; } cur_token_len = line_ptr - cur_token; - while (((unsigned char)cur_token[cur_token_len - 1]) <= ' ' && cur_token_len >= 0) { + while (((unsigned char)cur_token[cur_token_len - 1]) <= ' ' && cur_token_len >= 0) { cur_token_len --; } assert (cur_token_len > 0); @@ -316,7 +316,7 @@ void next_token_end (void) { next_token (); skip_wspc (); if (*line_ptr) { - cur_token_len = -1; + cur_token_len = -1; } } else { next_token (); @@ -326,7 +326,7 @@ void next_token_end (void) { void next_token_end_ac (void) { skip_wspc (); - + if (*line_ptr && *line_ptr != '"' && *line_ptr != '\'') { cur_token_quoted = 0; cur_token = line_ptr; @@ -340,7 +340,7 @@ void next_token_end_ac (void) { next_token (); skip_wspc (); if (*line_ptr) { - cur_token_len = -1; + cur_token_len = -1; } } else { next_token (); @@ -377,7 +377,7 @@ int hex2int (char c) { char *print_permanent_msg_id (tgl_message_id_t id) { static char buf[2 * sizeof (tgl_message_id_t) + 1]; - + unsigned char *s = (void *)&id; int i; for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) { @@ -389,7 +389,7 @@ char *print_permanent_msg_id (tgl_message_id_t id) { char *print_permanent_peer_id (tgl_peer_id_t id) { static char buf[2 * sizeof (tgl_peer_id_t) + 2]; buf[0] = '$'; - + unsigned char *s = (void *)&id; int i; for (i = 0; i < (int)sizeof (tgl_peer_id_t); i++) { @@ -404,7 +404,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { memset (&id, 0, sizeof (id)); id.peer_type = 0; return id; - } else { + } else { tgl_message_id_t id; memset (&id, 0, sizeof (id)); @@ -414,7 +414,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { if ( (s[i] < '0' || s[i] > '9') && (s[i] < 'a' || s[i] > 'f') - ) { + ) { id.peer_type = 0; return id; } @@ -422,7 +422,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { unsigned char *d = (void *)&id; for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) { d[i] = hex2int (s[2 * i]) * 16 + hex2int (s[2 * i + 1]); - } + } return id; } else { char *sc = tstrndup (s, l); @@ -430,7 +430,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { long long x = strtoll (sc, &end, 0); tfree_str (sc); if (end != sc + l) { - id.peer_type = 0; + id.peer_type = 0; } else { id.peer_type = TGL_PEER_TEMP_ID; id.id = x; @@ -475,7 +475,7 @@ tgl_peer_id_t parse_input_peer_id (const char *s, int l, int mask) { unsigned char *r = (void *)&res; int i; for (i = 0; i < l; i++) { - if ((s[i] < '0' || s[i] > '9') && + if ((s[i] < '0' || s[i] > '9') && (s[i] < 'a' || s[i] > 'f')) { return TGL_PEER_NOT_FOUND; } @@ -522,9 +522,9 @@ tgl_peer_id_t parse_input_peer_id (const char *s, int l, int mask) { } } - tgl_peer_t *P = tgl_peer_get_by_name (TLS, sc); + tgl_peer_t *P = tgl_peer_get_by_name (TLS, sc); tfree_str (sc); - + if (P && (!mask || tgl_get_peer_type (P->id) == mask)) { return P->id; } else { @@ -595,7 +595,7 @@ char *get_default_prompt (void) { l += snprintf (buf + l, 999 - l, "]" COLOR_NORMAL); l += snprintf (buf + l, 999 - l, "%s", default_prompt); return buf; - } + } l += snprintf (buf + l, 999 - l, "%s", default_prompt); return buf; } @@ -758,7 +758,7 @@ void do_stats (struct command *command, int arg_num, struct arg args[], struct i void do_show_license (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (!arg_num); - static char *b = + static char *b = #include "LICENSE.h" ; if (ev) { mprint_start (ev); } @@ -783,7 +783,7 @@ void do_safe_quit (struct command *command, int arg_num, struct arg args[], stru void do_set (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { int num = args[1].num; if (!strcmp (args[0].str, "debug_verbosity")) { - tgl_set_verbosity (TLS, num); + tgl_set_verbosity (TLS, num); } else if (!strcmp (args[0].str, "log_level")) { log_level = num; } else if (!strcmp (args[0].str, "msg_num")) { @@ -813,7 +813,7 @@ void do_version (struct command *command, int arg_num, struct arg args[], struct if (ev) { mprint_start (ev); } mpush_color (ev, COLOR_YELLOW); mprintf (ev, "Telegram-cli version %s (uses tgl version %s)\n", TELEGRAM_CLI_VERSION, TGL_VERSION); - #ifdef TGL_AVOID_OPENSSL + #ifdef TGL_AVOID_OPENSSL mprintf (ev, "uses libgcrypt for encryption\n"); #else mprintf (ev, "uses libopenssl for encryption\n"); @@ -859,9 +859,9 @@ void do_msg_kbd (struct command *command, int arg_num, struct arg args[], struct assert (arg_num == 3); if (ev) { ev->refcnt ++; } - clear_packet (); + clear_packet (); if (tglf_store_type (TLS, ARG2STR(1), TYPE_TO_PARAM (reply_markup)) < 0) { - fail_interface (TLS, ev, ENOSYS, "can not parse reply markup"); + fail_interface (TLS, ev, ENOSYS, "can not parse reply markup"); return; } in_ptr = packet_buffer; @@ -886,7 +886,7 @@ void do_send_text (struct command *command, int arg_num, struct arg args[], stru if (ev) { ev->refcnt ++; } tgl_do_send_text (TLS, args[0].peer_id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, print_msg_success_gw, ev); } - + void do_post_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } @@ -1029,7 +1029,7 @@ void do_broadcast (struct command *command, int arg_num, struct arg args[], stru int i; for (i = 0; i < arg_num - 1; i++) { ids[i] = args[i].peer_id; - } + } if (ev) { ev->refcnt ++; } tgl_do_send_broadcast (TLS, arg_num - 1, ids, args[arg_num - 1].str, strlen (args[arg_num - 1].str), disable_msg_preview | do_html, print_msg_list_success_gw, ev); } @@ -1092,7 +1092,7 @@ void do_export_card (struct command *command, int arg_num, struct arg args[], st void do_chat_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_set_chat_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); + tgl_do_set_chat_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); } void do_rename_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1124,7 +1124,7 @@ void do_chat_del_user (struct command *command, int arg_num, struct arg args[], if (ev) { ev->refcnt ++; } tgl_do_del_user_from_chat (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev); } - + void do_create_group_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num >= 1 && arg_num <= 1000); static tgl_peer_id_t ids[1000]; @@ -1134,7 +1134,7 @@ void do_create_group_chat (struct command *command, int arg_num, struct arg args } if (ev) { ev->refcnt ++; } - tgl_do_create_group_chat (TLS, arg_num - 1, ids, ARG2STR (0), print_success_gw, ev); + tgl_do_create_group_chat (TLS, arg_num - 1, ids, ARG2STR (0), print_success_gw, ev); } void do_export_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1199,7 +1199,7 @@ void do_add_contact (struct command *command, int arg_num, struct arg args[], st void do_rename_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); - + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); if (P && P->user.phone) { if (ev) { ev->refcnt ++; } @@ -1233,7 +1233,7 @@ void do_import_card (struct command *command, int arg_num, struct arg args[], st } else if (s[i] >= 'a' && s[i] <= 'f') { cur = cur * 16 + s[i] - 'a' + 10; } else if (s[i] == ':') { - if (pp >= 9) { + if (pp >= 9) { ok = 0; break; } @@ -1298,7 +1298,7 @@ void do_visualize_key (struct command *command, int arg_num, struct arg args[], for (i = 0; i < 16; i++) { int x = buf[i]; int j; - for (j = 0; j < 4; j ++) { + for (j = 0; j < 4; j ++) { if (!ev) { mpush_color (ev, colors[x & 3]); mpush_color (ev, COLOR_INVERSE); @@ -1327,8 +1327,8 @@ void do_visualize_key (struct command *command, int arg_num, struct arg args[], } x = x >> 2; } - if (i & 1) { - mprintf (ev, "\n"); + if (i & 1) { + mprintf (ev, "\n"); } } mprint_end (ev); @@ -1354,7 +1354,7 @@ void do_rename_channel (struct command *command, int arg_num, struct arg args[], void do_channel_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_set_channel_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); + tgl_do_set_channel_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); } void do_channel_set_about (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1374,7 +1374,7 @@ void do_channel_set_username (struct command *command, int arg_num, struct arg a if (ev) { ev->refcnt ++; } tgl_do_channel_set_username (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev); } - + void do_create_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num >= 2 && arg_num <= 1000); static tgl_peer_id_t ids[1000]; @@ -1384,7 +1384,7 @@ void do_create_channel (struct command *command, int arg_num, struct arg args[], } if (ev) { ev->refcnt ++; } - tgl_do_create_channel (TLS, arg_num - 2, ids, ARG2STR (0), ARG2STR (1), 1, print_success_gw, ev); + tgl_do_create_channel (TLS, arg_num - 2, ids, ARG2STR (0), ARG2STR (1), 1, print_success_gw, ev); } void do_join_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1430,7 +1430,7 @@ void do_resolve_username (struct command *command, int arg_num, struct arg args[ void do_contact_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (!arg_num); if (ev) { ev->refcnt ++; } - tgl_do_update_contact_list (TLS, print_user_list_gw, ev); + tgl_do_update_contact_list (TLS, print_user_list_gw, ev); } /* }}} */ @@ -1546,7 +1546,7 @@ void do_load_user_photo (struct command *command, int arg_num, struct arg args[ void do_view_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); if (P) { tgl_do_load_file_location (TLS, &P->user.photo_big, print_filename_gw, ev); @@ -1563,25 +1563,25 @@ void do_search (struct command *command, int arg_num, struct arg args[], struct assert (arg_num == 6); int limit; if (args[1].num != NOT_FOUND) { - limit = args[1].num; + limit = args[1].num; } else { limit = 40; } int from; if (args[2].num != NOT_FOUND) { - from = args[2].num; + from = args[2].num; } else { from = 0; } int to; if (args[3].num != NOT_FOUND) { - to = args[3].num; + to = args[3].num; } else { to = 0; } int offset; if (args[4].num != NOT_FOUND) { - offset = args[4].num; + offset = args[4].num; } else { offset = 0; } @@ -1801,7 +1801,7 @@ enum command_argument get_complete_mode (void) { if (cur_token_len <= 0) { return ca_command; } if (*cur_token == '[') { if (cur_token_end_str) { - return ca_modifier; + return ca_modifier; } if (cur_token[cur_token_len - 1] != ']') { return ca_none; @@ -1813,7 +1813,7 @@ enum command_argument get_complete_mode (void) { if (cur_token_quoted) { return ca_none; } if (cur_token_end_str) { return ca_command; } if (*cur_token == '(') { return ca_extf; } - + struct command *command = commands; int n = 0; struct tgl_command; @@ -1824,7 +1824,7 @@ enum command_argument get_complete_mode (void) { n ++; command ++; } - + if (!command->name) { return ca_none; } @@ -1843,13 +1843,13 @@ enum command_argument get_complete_mode (void) { if (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) { next_token_end_ac (); - if (cur_token_len < 0 || !cur_token_end_str) { + if (cur_token_len < 0 || !cur_token_end_str) { return ca_none; } else { return op; } } - + char *save = line_ptr; next_token (); if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double || op == ca_msg_id || op == ca_command || op == ca_channel) { @@ -1867,7 +1867,7 @@ enum command_argument get_complete_mode (void) { } } else { if (cur_token_end_str) { return op; } - + int ok = 1; switch (op) { case ca_user: @@ -1984,7 +1984,7 @@ int complete_spec_message_answer (struct tgl_message *M, int index, const char * while (index < total && strncmp (M->reply_markup->buttons[index], text, len)) { index ++; } - + if (index < total) { *R = strdup (M->reply_markup->buttons[index]); assert (*R); @@ -2019,7 +2019,7 @@ int complete_user_command (tgl_peer_t *P, int index, const char *text, int len, if (index >= U->bot_info->commands_num) { return U->bot_info->commands_num + complete_message_answer (P, index - U->bot_info->commands_num, text - 1, len + 1, R); } - + index ++; while (index < U->bot_info->commands_num && strncmp (U->bot_info->commands[index].command, text, len)) { index ++; @@ -2045,7 +2045,7 @@ int complete_chat_command (tgl_peer_t *P, int index, const char *text, int len, int tot = 0; int i; - for (i = 0; i < P->chat.user_list_size; i++) { + for (i = 0; i < P->chat.user_list_size; i++) { struct tgl_user *U = (void *)tgl_peer_get (TLS, TGL_MK_USER (P->chat.user_list[i].user_id)); if (!U) { continue; } if (!U->bot_info) { continue; } @@ -2114,7 +2114,7 @@ int complete_username (int mode, int index, const char *text, int len, char **R) return index; } -char *command_generator (const char *text, int state) { +char *command_generator (const char *text, int state) { #ifndef DISABLE_EXTF static int len; #endif @@ -2128,7 +2128,7 @@ char *command_generator (const char *text, int state) { index = complete_string_list (in_chat_commands, index, text, rl_point, &R); return R; } - + char c = 0; c = rl_line_buffer[rl_point]; rl_line_buffer[rl_point] = 0; @@ -2137,17 +2137,17 @@ char *command_generator (const char *text, int state) { len = strlen (text); #endif index = -1; - + mode = get_complete_mode (); command_pos = cur_token; command_len = cur_token_len; } else { if (mode != ca_file_name && mode != ca_file_name_end && index == -1) { return 0; } } - - if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double || mode == ca_msg_id) { + + if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double || mode == ca_msg_id) { if (c) { rl_line_buffer[rl_point] = c; } - return 0; + return 0; } assert (command_len >= 0); @@ -2161,7 +2161,7 @@ char *command_generator (const char *text, int state) { if (command_len && command_pos[0] == '@') { index = complete_username (TGL_PEER_USER, index, command_pos, command_len, &R); } else { - index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R); + index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R); } if (c) { rl_line_buffer[rl_point] = c; } return R; @@ -2190,7 +2190,7 @@ char *command_generator (const char *text, int state) { if (command_len && command_pos[0] == '@') { index = complete_username (TGL_PEER_CHANNEL, index, command_pos, command_len, &R); } else { - index = tgl_complete_channel_list (TLS, index, command_pos, command_len, &R); + index = tgl_complete_channel_list (TLS, index, command_pos, command_len, &R); } if (c) { rl_line_buffer[rl_point] = c; } return R; @@ -2241,7 +2241,7 @@ void work_modifier (const char *s, int l) { } if (sscanf (s, "[reply=%d]", &reply_id) >= 1) { } - + if (is_same_word (s, l, "[html]")) { do_html = TGLMF_HTML; } @@ -2370,7 +2370,7 @@ void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int nu int i; for (i = num - 1; i >= 0; i--) { json_t *a = json_pack_message (ML[i]); - assert (json_array_append (res, a) >= 0); + assert (json_array_append (res, a) >= 0); } char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); @@ -2521,7 +2521,7 @@ void print_channel_gw (struct tgl_state *TLSR, void *extra, int success, struct void print_peer_gw (struct tgl_state *TLSR, void *extra, int success, tgl_peer_t *U) { - if (!success) { + if (!success) { print_user_gw (TLSR, extra, success, (void *)U); return; } @@ -2619,7 +2619,7 @@ void print_chat_info_gw (struct tgl_state *TLSR, void *extra, int success, struc } if (!success) { print_fail (ev); return; } mprint_start (ev); - + if (!enable_json) { tgl_peer_t *U = (void *)C; mpush_color (ev, COLOR_YELLOW); @@ -2662,7 +2662,7 @@ void print_channel_info_gw (struct tgl_state *TLSR, void *extra, int success, st } if (!success) { print_fail (ev); return; } mprint_start (ev); - + if (!enable_json) { tgl_peer_t *U = (void *)C; mpush_color (ev, COLOR_YELLOW); @@ -3058,7 +3058,7 @@ void print_message_gw (struct tgl_state *TLSR, struct tgl_message *M) { py_new_msg (M); #endif if (!binlog_read) { return; } - if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) { + if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) { write_secret_chat_file (); } if (alert_sound) { @@ -3087,7 +3087,7 @@ void our_id_gw (struct tgl_state *TLSR, tgl_peer_id_t id) { lua_our_id (id); #endif #ifdef USE_PYTHON - py_our_id (id); + py_our_id (tgl_get_peer_id (id)); #endif } @@ -3152,7 +3152,7 @@ void json_peer_update (struct in_ev *ev, tgl_peer_t *P, unsigned flags) { void peer_update_username (tgl_peer_t *P, const char *username) { if (!username) { if (P->extra) { - struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra); + struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra); assert (p); username_peer_pair = tree_delete_username_peer_pair (username_peer_pair, p); tfree_str (P->extra); @@ -3178,7 +3178,7 @@ void peer_update_username (tgl_peer_t *P, const char *username) { struct username_peer_pair *p = talloc (sizeof (*p)); p->peer = P; p->username = P->extra; - + username_peer_pair = tree_insert_username_peer_pair (username_peer_pair, p, rand ()); } @@ -3192,7 +3192,7 @@ void user_update_gw (struct tgl_state *TLSR, struct tgl_user *U, unsigned flags) #endif peer_update_username ((void *)U, U->username); - + if (disable_output && !notify_ev) { return; } if (!binlog_read) { return; } struct in_ev *ev = notify_ev; @@ -3226,7 +3226,7 @@ void chat_update_gw (struct tgl_state *TLSR, struct tgl_chat *U, unsigned flags) #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; @@ -3264,14 +3264,14 @@ void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, u if ((flags & TGL_UPDATE_WORKING) || (flags & TGL_UPDATE_DELETED)) { write_secret_chat_file (); } - + if (!binlog_read) { return; } if ((flags & TGL_UPDATE_REQUESTED) && !disable_auto_accept) { //tgl_do_accept_encr_chat_request (TLS, U, 0, 0); tgl_do_accept_encr_chat_request (TLS, U, print_encr_chat_success_gw, 0); } - + if (disable_output && !notify_ev) { return; } struct in_ev *ev = notify_ev; @@ -3299,9 +3299,9 @@ void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, u void channel_update_gw (struct tgl_state *TLSR, struct tgl_channel *U, unsigned flags) { assert (TLSR == TLS); - + peer_update_username ((void *)U, U->username); - + if (disable_output && !notify_ev) { return; } if (!binlog_read) { return; } } @@ -3421,7 +3421,7 @@ struct tgl_update_callback upd_cb = { }; -void interpreter_ex (char *line, void *ex) { +void interpreter_ex (char *line, void *ex) { force_end_mode = 1; assert (!in_readline); in_readline = 1; @@ -3437,10 +3437,10 @@ void interpreter_ex (char *line, void *ex) { reply_id = 0; disable_msg_preview = 0; count = 1; - if (!line) { + if (!line) { do_safe_quit (NULL, 0, NULL, NULL); in_readline = 0; - return; + return; } if (!*line) { in_readline = 0; @@ -3450,53 +3450,53 @@ void interpreter_ex (char *line, void *ex) { if (line && *line) { add_history (line); } - - if (*line == '(') { + + if (*line == '(') { struct in_ev *ev = ex; if (ev) { ev->refcnt ++; } tgl_do_send_extf (TLS, line, strlen (line), callback_extf, ev); in_readline = 0; - return; + return; } while (1) { next_token (); - if (cur_token_quoted) { + if (cur_token_quoted) { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } - if (cur_token_len <= 0) { + if (cur_token_len <= 0) { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } - + if (*cur_token == '[') { if (cur_token_end_str) { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } if (cur_token[cur_token_len - 1] != ']') { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } work_modifier (cur_token, cur_token_len); continue; } break; } - if (cur_token_quoted || cur_token_end_str) { + if (cur_token_quoted || cur_token_end_str) { fail_interface (TLS, ex, ENOSYS, "can not parse command name"); in_readline = 0; - return; + return; } - - - + + + struct command *command = commands; int n = 0; struct tgl_command; @@ -3507,11 +3507,11 @@ void interpreter_ex (char *line, void *ex) { n ++; command ++; } - + if (!command->name) { fail_interface (TLS, ex, ENOSYS, "can not find command '%.*s'", cur_token_len, cur_token); in_readline = 0; - return; + return; } enum command_argument *flags = command->args; @@ -3531,7 +3531,7 @@ void interpreter_ex (char *line, void *ex) { enum command_argument op = (*flags) & 255; int opt = (*flags) & ca_optional; - if (op == ca_none) { + if (op == ca_none) { next_token (); if (cur_token_end_str) { int z; @@ -3543,10 +3543,10 @@ void interpreter_ex (char *line, void *ex) { } break; } - + if (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) { next_token_end (); - if (cur_token_len < 0) { + if (cur_token_len < 0) { fail_interface (TLS, ex, ENOSYS, "can not parse string_end arg #%d", args_num); break; } else { @@ -3596,7 +3596,7 @@ void interpreter_ex (char *line, void *ex) { break; } } else { - if (cur_token_end_str) { + if (cur_token_end_str) { if (opt) { if (op != ca_number && op != ca_double && op != ca_msg_id) { args[args_num ++].peer_id = TGL_PEER_NOT_FOUND; @@ -3623,23 +3623,23 @@ void interpreter_ex (char *line, void *ex) { int ok = 1; switch (op) { case ca_user: - args[args_num ++].peer_id = cur_token_user (); + args[args_num ++].peer_id = cur_token_user (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_chat: - args[args_num ++].peer_id = cur_token_chat (); + args[args_num ++].peer_id = cur_token_chat (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_secret_chat: - args[args_num ++].peer_id = cur_token_encr_chat (); + args[args_num ++].peer_id = cur_token_encr_chat (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_channel: - args[args_num ++].peer_id = cur_token_channel (); + args[args_num ++].peer_id = cur_token_channel (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_peer: - args[args_num ++].peer_id = cur_token_peer (); + args[args_num ++].peer_id = cur_token_peer (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_number: @@ -3702,7 +3702,7 @@ void interpreter_ex (char *line, void *ex) { free (args[i].str); } } - + update_prompt (); in_readline = 0; } @@ -3772,9 +3772,9 @@ void print_start (void) { void print_end (void) { if (in_readline) { return; } - if (readline_disabled) { + if (readline_disabled) { fflush (stdout); - return; + return; } assert (prompt_was); if (readline_active) { @@ -3788,7 +3788,7 @@ void print_end (void) { int *ptr = in_ptr; while (ptr < in_end) { mprintf (ev, " %08x", *(ptr ++)); } mprintf (ev, "\n"); - mprint_end (ev); + mprint_end (ev); }*/ void logprintf (const char *format, ...) { @@ -3878,7 +3878,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, ":"); } - + if (M->document->mime_type) { mprintf (ev, " type=%s", M->document->mime_type); } @@ -3890,7 +3890,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { if (M->document->duration) { mprintf (ev, " duration=%d", M->document->duration); } - + mprintf (ev, " size="); if (M->document->size < (1 << 10)) { mprintf (ev, "%dB", M->document->size); @@ -3901,9 +3901,9 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, "%dGiB", M->document->size >> 30); } - + mprintf (ev, "]"); - + if (M->caption) { mprintf (ev, " %s", M->caption); } @@ -3928,7 +3928,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, ":"); } - + if (M->encr_document->mime_type) { mprintf (ev, " type=%s", M->encr_document->mime_type); } @@ -3940,7 +3940,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { if (M->encr_document->duration) { mprintf (ev, " duration=%d", M->encr_document->duration); } - + mprintf (ev, " size="); if (M->encr_document->size < (1 << 10)) { mprintf (ev, "%dB", M->encr_document->size); @@ -3951,7 +3951,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, "%dGiB", M->encr_document->size >> 30); } - + mprintf (ev, "]"); return; @@ -3987,11 +3987,11 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { break; case tgl_message_media_venue: mprintf (ev, "[geo https://maps.google.com/?q=%.6lf,%.6lf", M->venue.geo.latitude, M->venue.geo.longitude); - + if (M->venue.title) { mprintf (ev, " title:'%s'", M->venue.title); } - + if (M->venue.address) { mprintf (ev, " address:'%s'", M->venue.address); } @@ -4004,7 +4004,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { mprintf (ev, "]"); return; - + default: mprintf (ev, "x = %d\n", M->type); assert (0); @@ -4055,7 +4055,7 @@ void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U) { } else if (!U->user.last_name || !strlen (U->user.last_name)) { mprintf (ev, "%s", U->user.first_name); } else { - mprintf (ev, "%s %s", U->user.first_name, U->user.last_name); + mprintf (ev, "%s %s", U->user.first_name, U->user.last_name); } if (U->flags & (TGLUF_SELF | TGLUF_CONTACT)) { mpop_color (ev); @@ -4190,7 +4190,7 @@ void print_service_message (struct in_ev *ev, struct tgl_message *M) { mprintf (ev, " "); print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id)); } - + switch (M->action.type) { case tgl_message_action_none: mprintf (ev, "\n"); @@ -4205,7 +4205,7 @@ void print_service_message (struct in_ev *ev, struct tgl_message *M) { mprintf (ev, " created chat %s. %d users\n", M->action.title, M->action.user_num); break; case tgl_message_action_chat_edit_title: - mprintf (ev, " changed title to %s\n", + mprintf (ev, " changed title to %s\n", M->action.new_title); break; case tgl_message_action_chat_edit_photo: @@ -4393,7 +4393,7 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { } } else { assert (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL); - + mpush_color (ev, COLOR_CYAN); print_msg_id (ev, M->permanent_id, M); mprintf (ev, " "); @@ -4461,8 +4461,8 @@ void set_interface_callbacks (void) { readline_active = 1; rl_filename_quote_characters = strdup (" "); rl_basic_word_break_characters = strdup (" "); - - + + rl_callback_handler_install (get_default_prompt (), interpreter); rl_completion_entry_function = command_generator; } diff --git a/python-tg.c b/python-tg.c index 09885f38..ba51ca77 100644 --- a/python-tg.c +++ b/python-tg.c @@ -156,16 +156,16 @@ PyObject* get_tgl_peer_type (int x) { PyObject* get_update_types (unsigned flags) { PyObject* types; - types = PyList_New(0); + 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"); } @@ -218,10 +218,10 @@ PyObject* get_peer (tgl_peer_id_t id, tgl_peer_t *P) { return peer; } -PyObject* get_message (struct tgl_message *M) { +PyObject* get_message (struct tgl_message *M) { assert (M); PyObject *msg; - + msg = tgl_Msg_FromTglMsg(M); return msg; } @@ -235,11 +235,11 @@ void py_binlog_end (void) { 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)) @@ -257,7 +257,7 @@ void py_diff_end (void) { logprintf("Callback not set for on_diff_end"); return; } - + arglist = Py_BuildValue("()"); result = PyEval_CallObject(_py_diff_end, arglist); Py_DECREF(arglist); @@ -306,7 +306,7 @@ void py_new_msg (struct tgl_message *M) { result = PyEval_CallObject(_py_new_msg, arglist); Py_DECREF(arglist); - if(result == NULL) + if(result == NULL) PyErr_Print(); else if(PyUnicode_Check(result)) logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result))); @@ -317,7 +317,7 @@ void py_new_msg (struct tgl_message *M) { void py_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) { if (!python_loaded) { return; } PyObject *peer, *types; - PyObject *arglist, *result; + PyObject *arglist, *result; if(_py_secret_chat_update == NULL) { logprintf("Callback not set for on_secret_chat_update"); @@ -419,10 +419,10 @@ void py_on_loop () { void *py_ptr[MAX_PY_COMMANDS]; static int pos; // -//static inline tgl_peer_t *get_peer (const char *s) { +//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, @@ -481,13 +481,13 @@ void py_empty_cb (struct tgl_state *TLSR, void *cb_extra, int success) { 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); } @@ -495,9 +495,9 @@ void py_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, in assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *peers = NULL; + PyObject *peers = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { peers = PyList_New(0); if (success) { @@ -510,24 +510,24 @@ void py_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, in 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[]) { +void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], tgl_message_id_t msgs[], int unread[]) { assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *dialog_list = NULL; + PyObject *dialog_list = NULL; PyObject *dialog = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { dialog_list = PyList_New(0); if (success) { @@ -535,8 +535,8 @@ void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int 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]); + + struct tgl_message *M = tgl_message_get (TLS, &msgs[i]); if (M && (M->flags & TGLMF_CREATED)) { PyDict_SetItemString(dialog, "message", get_message(M)); } @@ -549,10 +549,10 @@ void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int 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); } @@ -563,9 +563,9 @@ void py_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_ assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *msg = NULL; + PyObject *msg = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { if (success && M && (M->flags & TGLMF_CREATED)) { msg = get_message(M); @@ -577,10 +577,10 @@ void py_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_ 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); } @@ -591,9 +591,9 @@ void py_msg_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int nu assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *msgs = NULL; + PyObject *msgs = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { msgs = PyList_New(0); if (success) { @@ -606,10 +606,10 @@ void py_msg_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int nu 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); } @@ -620,9 +620,9 @@ void py_file_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *filename = NULL; + PyObject *filename = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { if(success) filename = PyUnicode_FromString(file_name); @@ -634,10 +634,10 @@ void py_file_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char 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); } @@ -648,9 +648,9 @@ void py_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *peer = NULL; + PyObject *peer = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { if (success) { peer = get_peer(C->id, (void *)C); @@ -662,10 +662,10 @@ void py_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl 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); } @@ -676,9 +676,9 @@ void py_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, str assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *peer = NULL; + PyObject *peer = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { if (success) { peer = get_peer(C->id, (void *)C); @@ -690,10 +690,10 @@ void py_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, str 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); } @@ -704,9 +704,9 @@ void py_user_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *peer = NULL; + PyObject *peer = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { if (success) { peer = get_peer(C->id, (void *)C); @@ -718,10 +718,10 @@ void py_user_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl 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); } @@ -732,9 +732,9 @@ void py_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; - PyObject *str = NULL; + PyObject *str = NULL; PyObject *result = NULL; - + if(PyCallable_Check(callable)) { if(success) str = PyUnicode_FromString(data); @@ -746,10 +746,10 @@ void py_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char 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); } @@ -1043,7 +1043,7 @@ void py_do_all (void) { break; */ case pq_send_contact: - if(PyArg_ParseTuple(args, "O!s#s#s#|O", &tgl_PeerType, &peer, &str1, &len1, &str2, &len2, + 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 @@ -1075,7 +1075,7 @@ void py_do_all (void) { 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), + 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); @@ -1088,7 +1088,7 @@ void py_do_all (void) { // 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); @@ -1238,7 +1238,7 @@ static PyMethodDef py_tgl_methods[] = { {"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, ""}, + {"send_location", py_send_location, METH_VARARGS, ""}, {"ext_function", py_extf, METH_VARARGS, ""}, {"import_chat_link", py_import_chat_link, METH_VARARGS, ""}, {"set_on_binlog_replay_end", set_py_binlog_end, METH_VARARGS, ""}, @@ -1264,7 +1264,7 @@ void py_add_action_enums(PyObject *m) PyModule_AddIntConstant(m, "ACTION_CHAT_EDIT_TITLE", tgl_message_action_chat_edit_title); PyModule_AddIntConstant(m, "ACTION_CHAT_EDIT_PHOTO", tgl_message_action_chat_edit_photo); PyModule_AddIntConstant(m, "ACTION_CHAT_DELETE_PHOTO", tgl_message_action_chat_delete_photo); - PyModule_AddIntConstant(m, "ACTION_CHAT_ADD_USER", tgl_message_action_chat_add_user); + PyModule_AddIntConstant(m, "ACTION_CHAT_ADD_USER", tgl_message_action_chat_add_users); PyModule_AddIntConstant(m, "ACTION_CHAT_ADD_USER_BY_LINK", tgl_message_action_chat_add_user_by_link); PyModule_AddIntConstant(m, "ACTION_CHAT_DELETE_USER", tgl_message_action_chat_delete_user); PyModule_AddIntConstant(m, "ACTION_SET_MESSAGE_TTL", tgl_message_action_set_message_ttl); @@ -1310,30 +1310,30 @@ MOD_INIT(tgl) 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); + + return MOD_SUCCESS_VAL(m); } 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 @@ -1341,7 +1341,7 @@ void py_init (const char *file) { strncpy(filename, file, 1024); - + #if PY_MAJOR_VERSION >= 3 PyImport_AppendInittab("tgl", &PyInit_tgl); Py_Initialize(); @@ -1353,16 +1353,16 @@ void py_init (const char *file) { 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) + 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(); diff --git a/python-types.c b/python-types.c index da3cd5a2..4bbb4534 100644 --- a/python-types.c +++ b/python-types.c @@ -58,9 +58,9 @@ 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)) + if(!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, + &peer_id.peer_type, + &peer_id.peer_id)) { PyErr_Format(PeerError, "Peer must specify type and id"); return -1; @@ -77,7 +77,7 @@ tgl_Peer_getname (tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: ret = PyUnicode_FromString(self->peer->user.print_name); break; @@ -102,14 +102,14 @@ tgl_Peer_getuser_id (tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: - ret = PyLong_FromLong(self->peer->id.id); + ret = PyLong_FromLong(self->peer->id.peer_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); @@ -130,7 +130,7 @@ tgl_Peer_getuser_list (tgl_Peer *self, void *closure) int i; struct tgl_chat_user *user_list; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_CHAT: ret = PyList_New(0); for(i = 0; i < self->peer->chat.user_list_size; i++) { @@ -158,7 +158,7 @@ tgl_Peer_getuser_status(tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: ret = PyDict_New(); PyDict_SetItemString(ret, "online", self->peer->user.status.online? Py_True : Py_False); @@ -184,7 +184,7 @@ tgl_Peer_getphone (tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: if(self->peer->user.phone) ret = PyUnicode_FromString(self->peer->user.phone); @@ -210,7 +210,7 @@ tgl_Peer_getusername (tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: if(self->peer->user.username) ret = PyUnicode_FromString(self->peer->user.username); @@ -236,7 +236,7 @@ tgl_Peer_getfirst_name (tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: if(self->peer->user.first_name) ret = PyUnicode_FromString(self->peer->user.first_name); @@ -262,7 +262,7 @@ tgl_Peer_getlast_name (tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: if(self->peer->user.last_name) ret = PyUnicode_FromString(self->peer->user.last_name); @@ -288,7 +288,7 @@ tgl_Peer_getuser (tgl_Peer *self, void *closure) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_ENCR_CHAT: ret = tgl_Peer_FromTglPeer(tgl_peer_get(TLS, TGL_MK_USER (self->peer->encr_chat.user_id))); break; @@ -313,7 +313,7 @@ tgl_Peer_gettype_name(tgl_Peer* self) { PyObject *name; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: name = PyUnicode_FromString("user"); break; @@ -334,7 +334,7 @@ tgl_Peer_getid (tgl_Peer *self, void *closure) { PyObject *ret; - ret = PyLong_FromLong(self->peer->id.id); + ret = PyLong_FromLong(self->peer->id.peer_id); Py_XINCREF(ret); return ret; @@ -345,7 +345,7 @@ tgl_Peer_gettype (tgl_Peer *self, void *closure) { PyObject *ret; - ret = PyLong_FromLong(self->peer->id.type); + ret = PyLong_FromLong(self->peer->id.peer_type); Py_XINCREF(ret); return ret; @@ -496,7 +496,7 @@ tgl_Peer_rename_chat (tgl_Peer *self, PyObject *args, PyObject *kwargs) char * title; PyObject *callback = NULL; - if(self->peer->id.type != TGL_PEER_CHAT) { + if(self->peer->id.peer_type != TGL_PEER_CHAT) { PyErr_SetString(PeerError, "Only a chat peer can be renamed"); Py_XINCREF(Py_False); return Py_False; @@ -698,7 +698,7 @@ tgl_Peer_chat_set_photo (tgl_Peer *self, PyObject *args, PyObject *kwargs) char * filename; PyObject *callback = NULL; - if(self->peer->id.type != TGL_PEER_CHAT) { + if(self->peer->id.peer_type != TGL_PEER_CHAT) { PyErr_SetString(PeerError, "Only a chat peer can have a chat photo set."); Py_XINCREF(Py_False); return Py_False; @@ -732,7 +732,7 @@ tgl_Peer_chat_add_user (tgl_Peer *self, PyObject *args, PyObject *kwargs) PyObject *peer; PyObject *callback = NULL; - if(self->peer->id.type != TGL_PEER_CHAT) { + if(self->peer->id.peer_type != TGL_PEER_CHAT) { PyErr_SetString(PeerError, "Only a chat peer can have a user added."); Py_XINCREF(Py_False); return Py_False; @@ -766,7 +766,7 @@ tgl_Peer_chat_del_user (tgl_Peer *self, PyObject *args, PyObject *kwargs) PyObject *peer; PyObject *callback = NULL; - if(self->peer->id.type != TGL_PEER_CHAT) { + if(self->peer->id.peer_type != TGL_PEER_CHAT) { PyErr_SetString(PeerError, "Only a chat peer can have a user deleted."); Py_XINCREF(Py_False); return Py_False; @@ -827,7 +827,7 @@ tgl_Peer_info (tgl_Peer *self, PyObject *args, PyObject *kwargs) PyObject *callback = NULL; - if(self->peer->id.type == TGL_PEER_ENCR_CHAT) { + if(self->peer->id.peer_type == TGL_PEER_ENCR_CHAT) { PyErr_SetString(PeerError, "Secret chats currently have no info."); Py_XINCREF(Py_False); return Py_False; @@ -843,7 +843,7 @@ tgl_Peer_info (tgl_Peer *self, PyObject *args, PyObject *kwargs) Py_INCREF(Py_None); Py_XINCREF(api_call); - if(self->peer->id.type == TGL_PEER_USER) + if(self->peer->id.peer_type == TGL_PEER_USER) return py_user_info(Py_None, api_call); else return py_chat_info(Py_None, api_call); @@ -970,13 +970,13 @@ tgl_Peer_repr(tgl_Peer *self) { PyObject *ret; - switch(self->peer->id.type) { + switch(self->peer->id.peer_type) { case TGL_PEER_USER: #if PY_VERSION_HEX < 0x02070900 - ret = PyUnicode_FromFormat("", self->peer->id.id); + ret = PyUnicode_FromFormat("", self->peer->id.peer_id); #else ret = PyUnicode_FromFormat("", - self->peer->id.id, + self->peer->id.peer_id, PyObject_GetAttrString((PyObject*)self, "username"), PyObject_GetAttrString((PyObject*)self, "name"), PyObject_GetAttrString((PyObject*)self, "first_name"), @@ -987,11 +987,11 @@ tgl_Peer_repr(tgl_Peer *self) break; case TGL_PEER_CHAT: ret = PyUnicode_FromFormat("", - self->peer->id.id, self->peer->chat.print_title); + self->peer->id.peer_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, + self->peer->id.peer_id, self->peer->encr_chat.print_name, PyObject_GetAttrString((PyObject*)self, "user")); break; default: @@ -1021,10 +1021,10 @@ tgl_Peer_RichCompare(PyObject *self, PyObject *other, int cmp) } else { switch (cmp) { case Py_EQ: - result = ((tgl_Peer*)self)->peer->id.id == ((tgl_Peer*)other)->peer->id.id ? Py_True : Py_False; + result = ((tgl_Peer*)self)->peer->id.peer_id == ((tgl_Peer*)other)->peer->id.peer_id ? Py_True : Py_False; break; case Py_NE: - result = ((tgl_Peer*)self)->peer->id.id == ((tgl_Peer*)other)->peer->id.id ? Py_False : Py_True; + result = ((tgl_Peer*)self)->peer->id.peer_id == ((tgl_Peer*)other)->peer->id.peer_id ? Py_False : Py_True; break; case Py_LE: case Py_GE: @@ -1122,7 +1122,7 @@ tgl_Msg_getid (tgl_Msg *self, void *closure) { PyObject *ret; - ret = PyLong_FromLong(self->msg->id); + ret = PyLong_FromLong(self->msg->permanent_id.id); Py_XINCREF(ret); return ret; @@ -1259,10 +1259,10 @@ 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: @@ -1370,21 +1370,23 @@ tgl_Msg_getfwd_date (tgl_Msg *self, void *closure) 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; +// PyObject *ret; +// +// if(self->msg->reply_id) { +// struct tgl_message *MR = tgl_message_get (TLS, self->msg->reply_id); //I don't know how to fix this line(reply_id type error), so I have disabled this function. +// if(MR) { +// ret = tgl_Msg_FromTglMsg(MR); +// } else { +// Py_RETURN_NONE; +// } +// } else { +// Py_RETURN_NONE; +// } +// +// Py_XINCREF(ret); +// return ret; +// + Py_RETURN_NONE; } static PyObject * @@ -1460,7 +1462,7 @@ tgl_Msg_repr(tgl_Msg *self) #else ret = PyUnicode_FromFormat("", - self->msg->id, self->msg->flags, + self->msg->permanent_id.id, self->msg->flags, PyObject_GetAttrString((PyObject*)self, "mention"), PyObject_GetAttrString((PyObject*)self, "out"), PyObject_GetAttrString((PyObject*)self, "unread"), @@ -1484,7 +1486,7 @@ 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}, + {"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}, From 3ff1edfd3eab0a0fe07de14f6137e0d2897f6a86 Mon Sep 17 00:00:00 2001 From: Jason Chiang Date: Sat, 18 Jun 2016 09:25:26 +0800 Subject: [PATCH 065/164] fix missing header. --- python-tg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/python-tg.c b/python-tg.c index ba51ca77..696be47a 100644 --- a/python-tg.c +++ b/python-tg.c @@ -82,6 +82,7 @@ extern PyTypeObject tgl_MsgType; //#include "interface.h" //#include "auto/constants.h" #include +#include #include "interface.h" #include From a77f0b29632ed627207f13b800fceb6c393392a4 Mon Sep 17 00:00:00 2001 From: Jason Chiang Date: Sat, 18 Jun 2016 11:04:24 +0800 Subject: [PATCH 066/164] adopt to structure tgl_message_id_t --- python-tg.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/python-tg.c b/python-tg.c index 696be47a..369d951d 100644 --- a/python-tg.c +++ b/python-tg.c @@ -521,7 +521,7 @@ void py_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, in Py_XDECREF(callable); } -void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], tgl_message_id_t msgs[], int unread[]) { +void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], tgl_message_id_t *msgs[], int unread[]) { assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; @@ -537,7 +537,7 @@ void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int 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]); + struct tgl_message *M = tgl_message_get (TLS, msgs[i]); if (M && (M->flags & TGLMF_CREATED)) { PyDict_SetItemString(dialog, "message", get_message(M)); } @@ -758,6 +758,7 @@ void py_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char } #define PY_PEER_ID(x) (tgl_peer_id_t)((tgl_Peer*)x)->peer->id +#define PY_MSG_ID(x) (tgl_message_id_t*)x void py_do_all (void) { int p = 0; @@ -920,13 +921,13 @@ void py_do_all (void) { 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); + tgl_do_forward_message (TLS, PY_PEER_ID(peer), PY_MSG_ID(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); + tgl_do_forward_media (TLS, PY_PEER_ID(peer), PY_MSG_ID(msg_id), 0, py_msg_cb, cb_extra); else PyErr_Print(); break; @@ -1034,7 +1035,7 @@ void py_do_all (void) { 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); + tgl_do_delete_msg (TLS, PY_MSG_ID(msg_id), py_empty_cb, cb_extra); else PyErr_Print(); break; From 48b13cdb55ad76b7fcf06d0f310df6a3eae61346 Mon Sep 17 00:00:00 2001 From: Jason Chiang Date: Tue, 21 Jun 2016 11:59:05 +0800 Subject: [PATCH 067/164] Fix python script for variable scope mistake and argument errors for on_user_update() and on_chat_update(). --- tg-test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tg-test.py b/tg-test.py index 1e53a9ea..d95378c5 100644 --- a/tg-test.py +++ b/tg-test.py @@ -9,12 +9,14 @@ binlog_done = False; def on_binlog_replay_end(): + global binlog_done binlog_done = True; def on_get_difference_end(): pass def on_our_id(id): + global our_id our_id = id return "Set ID: " + str(our_id) @@ -45,17 +47,17 @@ def on_msg_receive(msg): peer = msg.dest pp.pprint(msg) - if msg.text.startswith("!ping"): + if msg.text is not None and msg.text.startswith("!ping"): peer.send_msg("PONG! google.com", preview=False, reply=msg.id) def on_secret_chat_update(peer, types): return "on_secret_chat_update" -def on_user_update(): +def on_user_update(peer, what_changed): pass -def on_chat_update(): +def on_chat_update(peer, what_changed): pass # Set callbacks From f219d8d3a727fba2122454ce9fe909993ded05f2 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:10:36 +0800 Subject: [PATCH 068/164] use travis-ci's apt addon to install packages See: https://docs.travis-ci.com/user/installing-dependencies/#Installing-Packages-with-the-APT-Addon --- .travis.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0f293e45..9bcaa7a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ compiler: - gcc - clang +<<<<<<< HEAD install: - sudo apt-get update - sudo apt-get install libconfig8-dev @@ -13,6 +14,20 @@ install: - sudo apt-get install python-dev python - sudo apt-get install libevent-dev - sudo apt-get install libjansson-dev +======= +addons: + apt: + packages: + - libconfig8-dev + - libreadline6-dev + - libssl-dev + - liblua5.2-dev + - lua5.2 + - python-dev + - python + - libevent-dev + - libjansson-dev +>>>>>>> use travis-ci's apt addon to install packages script: - git submodule update --init --recursive From dde0e6cd3b542ecedb3eca4c01a700d1c204a662 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:11:47 +0800 Subject: [PATCH 069/164] Enable container-based infrastructure on travis-ci To make the build faster. Reference: https://docs.travis-ci.com/user/workers/container-based-infrastructure/ --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9bcaa7a6..92278cd8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,8 @@ addons: - libjansson-dev >>>>>>> use travis-ci's apt addon to install packages +sudo: false + script: - git submodule update --init --recursive - ./configure From 06c2f6883579a31eba7a333fe58764956c292468 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:13:05 +0800 Subject: [PATCH 070/164] Decrease git clone depth to speed up the build. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 92278cd8..c67b9075 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,9 @@ addons: sudo: false +git: + depth: 10 + script: - git submodule update --init --recursive - ./configure From 99d51d619cbf019ac2c67b1d773feed02b5391ff Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Thu, 28 Jan 2016 22:22:18 +0800 Subject: [PATCH 071/164] add -Wno-unused-function to compile flags --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 83424620..4740603b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@ CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@ DEFS=@DEFS@ -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 +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 -Wno-unused-function EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ @OPENSSL_LIBS@ LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} From 7350a1bda4640a838020ed767d4ed7510575d8a5 Mon Sep 17 00:00:00 2001 From: Jason Chiang Date: Tue, 21 Jun 2016 19:53:06 +0800 Subject: [PATCH 072/164] fix travis-ci and update Travis-ci badge in README --- .travis.yml | 15 +-------------- README.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index c67b9075..06cfa188 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,17 +4,6 @@ compiler: - gcc - clang -<<<<<<< HEAD -install: - - sudo apt-get update - - sudo apt-get install libconfig8-dev - - sudo apt-get install libreadline6-dev - - sudo apt-get install libssl-dev - - sudo apt-get install liblua5.2-dev lua5.2 - - sudo apt-get install python-dev python - - sudo apt-get install libevent-dev - - sudo apt-get install libjansson-dev -======= addons: apt: packages: @@ -27,7 +16,6 @@ addons: - python - libevent-dev - libjansson-dev ->>>>>>> use travis-ci's apt addon to install packages sudo: false @@ -37,5 +25,4 @@ git: script: - git submodule update --init --recursive - ./configure - - make - + - make \ No newline at end of file diff --git a/README.md b/README.md index 4a9e0fa6..d07c4c96 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) +## Telegram messenger CLI [![Build Status](https://travis-ci.org/Cojad/tg.png)](https://travis-ci.org/Cojad/tg) Command-line interface for [Telegram](http://telegram.org). Uses readline interface. @@ -33,9 +33,9 @@ Python support is currently limited to Python 2.7 or Python 3.1+. Other versions 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: +On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-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: @@ -86,7 +86,7 @@ If using [Homebrew](http://brew.sh/): Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. If using [MacPorts](https://www.macports.org): - + sudo port install libconfig-hr sudo port install readline sudo port install lua51 @@ -111,14 +111,14 @@ Then build: If you manage to launch it on other UNIX, please let me know. -### Contacts +### Contacts If you would like to ask a question, you can write to my telegram or to the github (or both). To contact me via telegram, you should use import_card method with argument 000653bf:0738ca5d:5521fbac:29246815:a27d0cda ### Usage bin/telegram-cli -k - + By default, the public key is stored in tg-server.pub in the same folder or in /etc/telegram-cli/server.pub. If not, specify where to find it: bin/telegram-cli -k tg-server.pub @@ -128,10 +128,10 @@ Client support TAB completion and command history. Peer refers to the name of the contact or dialog and can be accessed by TAB completion. For user contacts peer name is Name Lastname with all spaces changed to underscores. For chats it is it's title with all spaces changed to underscores -For encrypted chats it is Name Lastname with all spaces changed to underscores. +For encrypted chats it is Name Lastname with all spaces changed to underscores. If two or more peers have same name, number is appended to the name. (for example A_B, A_B#1, A_B#2 and so on) - + ### Supported commands #### Messaging From 4e56d7840eeb6df5a202690cec6277f994f9a73b Mon Sep 17 00:00:00 2001 From: Michele Sorcinelli Date: Tue, 21 Jun 2016 15:34:12 +0200 Subject: [PATCH 073/164] Add auto_mark_read switch --- interface.c | 33 +++++++++++++++++++++------------ main.c | 8 +++++++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/interface.c b/interface.c index 77c3c751..00f873e7 100644 --- a/interface.c +++ b/interface.c @@ -123,6 +123,7 @@ int permanent_msg_id_mode; int permanent_peer_id_mode; int disable_colors; extern int alert_sound; +extern int auto_mark_read; extern int binlog_read; extern char *home_directory; int do_html; @@ -790,6 +791,8 @@ void do_set (struct command *command, int arg_num, struct arg args[], struct in_ msg_num_mode = num; } else if (!strcmp (args[0].str, "alert")) { alert_sound = num; + } else if (!strcmp (args[0].str, "auto_mark_read")) { + auto_mark_read = num; } } @@ -846,7 +849,8 @@ void do_msg (struct command *command, int arg_num, struct arg args[], struct in_ if (ev) { ev->refcnt ++; } vlogprintf (E_DEBUG, "reply_id=%d, disable=%d\n", reply_id, disable_msg_preview); tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, NULL, print_msg_success_gw, ev); - tgl_do_mark_read (TLS, args[0].peer_id, 0, 0); + if (auto_mark_read) + tgl_do_mark_read (TLS, args[0].peer_id, 0, 0); } void do_post (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -881,13 +885,15 @@ void do_reply (struct command *command, int arg_num, struct arg args[], struct i if (ev) { ev->refcnt ++; } tgl_do_reply_message (TLS, &args[0].msg_id, ARG2STR(1), disable_msg_preview | do_html, print_msg_success_gw, ev); - /* attempt to mark the conversation as read */ - struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id); - if (M) { - /* if it's a chat get its id, else get the user id that is != from our */ - tgl_peer_id_t id = (M->to_id.peer_type == TGL_PEER_CHAT || - M->to_id.peer_id != TLS->our_id.peer_id)? M->to_id : M->from_id; - tgl_do_mark_read (TLS, id, 0, 0); + if (auto_mark_read) { + /* attempt to mark the conversation as read */ + struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id); + if (M) { + /* if it's a chat get its id, else get the user id that is != from our */ + tgl_peer_id_t id = (M->to_id.peer_type == TGL_PEER_CHAT || + M->to_id.peer_id != TLS->our_id.peer_id)? M->to_id : M->from_id; + tgl_do_mark_read (TLS, id, 0, 0); + } } } @@ -987,7 +993,8 @@ void do_fwd (struct command *command, int arg_num, struct arg args[], struct in_ assert (arg_num <= 1000); //if (arg_num == 2) { // tgl_do_forward_message (TLS, args[0].P->id, &args[1].msg_id, 0, print_msg_success_gw, ev); - // tgl_do_mark_read (TLS, args[0].P->id, 0, 0); + // if (auto_mark_read) + // tgl_do_mark_read (TLS, args[0].P->id, 0, 0); //} else { static tgl_message_id_t *list[1000]; int i; @@ -995,7 +1002,8 @@ void do_fwd (struct command *command, int arg_num, struct arg args[], struct in_ list[i] = &args[i + 1].msg_id; } tgl_do_forward_messages (TLS, args[0].peer_id, arg_num - 1, (void *)list, 0, print_msg_list_success_gw, ev); - tgl_do_mark_read (TLS, args[0].peer_id, 0, 0); + if (auto_mark_read) + tgl_do_mark_read (TLS, args[0].peer_id, 0, 0); //} } @@ -1759,7 +1767,7 @@ struct command commands[MAX_COMMANDS_SIZE] = { {"send_typing", {ca_peer, ca_number | ca_optional, ca_none}, do_send_typing, "send_typing [status]\tSends typing notification. You can supply a custom status (range 0-10): none, typing, cancel, record video, upload video, record audio, upload audio, upload photo, upload document, geo, choose contact.", NULL}, {"send_typing_abort", {ca_peer, ca_none}, do_send_typing_abort, "send_typing_abort \tSends typing notification abort", NULL}, {"send_video", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_video, "send_video [caption]\tSends video to peer", NULL}, - {"set", {ca_string, ca_number, ca_none}, do_set, "set \tSets value of param. Currently available: log_level, debug_verbosity, alarm, msg_num", NULL}, + {"set", {ca_string, ca_number, ca_none}, do_set, "set \tSets value of param. Currently available: log_level, debug_verbosity, alarm, auto_mark_read, msg_num", NULL}, {"set_password", {ca_string | ca_optional, ca_none}, do_set_password, "set_password \tSets password", NULL}, {"set_profile_name", {ca_string, ca_string, ca_none}, do_set_profile_name, "set_profile_name \tSets profile name.", NULL}, {"set_profile_photo", {ca_file_name_end, ca_none}, do_set_profile_photo, "set_profile_photo \tSets profile photo. Photo will be cropped to square", NULL}, @@ -2881,7 +2889,8 @@ void interpreter_chat_mode (char *line) { } if (strlen (line) > 0) { tgl_do_send_message (TLS, chat_mode_id, line, strlen (line), 0, NULL, 0, 0); - tgl_do_mark_read (TLS, chat_mode_id, 0, 0); + if (auto_mark_read) + tgl_do_mark_read (TLS, chat_mode_id, 0, 0); } } diff --git a/main.c b/main.c index 4776f073..a35567f4 100644 --- a/main.c +++ b/main.c @@ -118,6 +118,7 @@ char *start_command; int disable_link_preview; int enable_json; int alert_sound; +int auto_mark_read; int exit_code; int permanent_msg_id_mode; int permanent_peer_id_mode; @@ -470,6 +471,7 @@ void usage (void) { printf (" --disable-colors/-C disable color output\n"); printf (" --disable-readline/-R disable readline\n"); printf (" --alert/-A enable bell notifications\n"); + printf (" --auto-mark-read/-M mark read conversation after sending a message\n"); printf (" --daemonize/-d daemon mode\n"); printf (" --logname/-L log file name\n"); printf (" --username/-U change uid after start\n"); @@ -627,6 +629,7 @@ void args_parse (int argc, char **argv) { {"disable-colors", no_argument, 0, 'C'}, {"disable-readline", no_argument, 0, 'R'}, {"alert", no_argument, 0, 'A'}, + {"auto-mark-read", no_argument, 0, 'M'}, {"daemonize", no_argument, 0, 'd'}, {"logname", required_argument, 0, 'L'}, {"username", required_argument, 0, 'U'}, @@ -652,7 +655,7 @@ void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt_long (argc, argv, "u:hk:vNl:fEwWCRAdL:DU:G:qP:S:e:I6b" + while ((opt = getopt_long (argc, argv, "u:hk:vNl:fEwWCRAMdL:DU:G:qP:S:e:I6b" #ifdef HAVE_LIBCONFIG "c:p:" #else @@ -745,6 +748,9 @@ void args_parse (int argc, char **argv) { case 'A': alert_sound = 1; break; + case 'M': + auto_mark_read = 1; + break; case 'd': daemonize ++; break; From c69b2289a5a315a997cc3ae3f01ed965e46d3353 Mon Sep 17 00:00:00 2001 From: Ivo von Putzer Reibegg Date: Wed, 22 Jun 2016 16:23:15 +0200 Subject: [PATCH 074/164] adds homebrew formula to readme --- README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4a9e0fa6..51adb7ef 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ Python support is currently limited to Python 2.7 or Python 3.1+. Other versions 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: +On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-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: @@ -78,6 +78,11 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea If using [Homebrew](http://brew.sh/): + brew tap ivoputzer/tg + brew install tg + +or manually: + brew install libconfig readline lua python libevent jansson 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" @@ -86,7 +91,7 @@ If using [Homebrew](http://brew.sh/): Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. If using [MacPorts](https://www.macports.org): - + sudo port install libconfig-hr sudo port install readline sudo port install lua51 @@ -111,14 +116,14 @@ Then build: If you manage to launch it on other UNIX, please let me know. -### Contacts +### Contacts If you would like to ask a question, you can write to my telegram or to the github (or both). To contact me via telegram, you should use import_card method with argument 000653bf:0738ca5d:5521fbac:29246815:a27d0cda ### Usage bin/telegram-cli -k - + By default, the public key is stored in tg-server.pub in the same folder or in /etc/telegram-cli/server.pub. If not, specify where to find it: bin/telegram-cli -k tg-server.pub @@ -128,10 +133,10 @@ Client support TAB completion and command history. Peer refers to the name of the contact or dialog and can be accessed by TAB completion. For user contacts peer name is Name Lastname with all spaces changed to underscores. For chats it is it's title with all spaces changed to underscores -For encrypted chats it is Name Lastname with all spaces changed to underscores. +For encrypted chats it is Name Lastname with all spaces changed to underscores. If two or more peers have same name, number is appended to the name. (for example A_B, A_B#1, A_B#2 and so on) - + ### Supported commands #### Messaging From dc9ee85bd78dd719256d8b43135bf0e537a5adc8 Mon Sep 17 00:00:00 2001 From: Jason Chiang Date: Thu, 23 Jun 2016 17:25:07 +0800 Subject: [PATCH 075/164] add support for peer type: channel, fixed some python log does not display properly to user, fix error message in demo python script. --- python-tg.c | 18 +++++++++--------- python-types.c | 9 ++++++++- tg-test.py | 4 ++++ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/python-tg.c b/python-tg.c index 369d951d..803011bf 100644 --- a/python-tg.c +++ b/python-tg.c @@ -233,7 +233,7 @@ void py_binlog_end (void) { PyObject *arglist, *result; if(_py_binlog_end == NULL) { - logprintf("Callback not set for on_binlog_end"); + logprintf("Callback not set for on_binlog_end\n"); return; } @@ -255,7 +255,7 @@ void py_diff_end (void) { PyObject *arglist, *result; if(_py_diff_end == NULL) { - logprintf("Callback not set for on_diff_end"); + logprintf("Callback not set for on_diff_end\n"); return; } @@ -276,7 +276,7 @@ void py_our_id (int id) { PyObject *arglist, *result; if(_py_our_id == NULL) { - logprintf("Callback not set for on_our_id"); + logprintf("Callback not set for on_our_id\n"); return; } @@ -297,7 +297,7 @@ void py_new_msg (struct tgl_message *M) { PyObject *arglist, *result; if(_py_new_msg == NULL) { - logprintf("Callback not set for on_new_msg"); + logprintf("Callback not set for on_new_msg\n"); return; } @@ -321,7 +321,7 @@ void py_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) { PyObject *arglist, *result; if(_py_secret_chat_update == NULL) { - logprintf("Callback not set for on_secret_chat_update"); + logprintf("Callback not set for on_secret_chat_update\n"); return; } @@ -347,7 +347,7 @@ void py_user_update (struct tgl_user *U, unsigned flags) { PyObject *arglist, *result; if(_py_user_update == NULL) { - logprintf("Callback not set for on_user_update"); + logprintf("Callback not set for on_user_update\n"); return; } @@ -373,7 +373,7 @@ void py_chat_update (struct tgl_chat *C, unsigned flags) { PyObject *arglist, *result; if(_py_chat_update == NULL) { - logprintf("Callback not set for on_chat_update"); + logprintf("Callback not set for on_chat_update\n"); return; } @@ -398,7 +398,7 @@ void py_on_loop () { PyObject *result; if(_py_on_loop == NULL) { - logprintf("Callback not set for on_chat_update"); + logprintf("Callback not set for on_loop\n"); return; } @@ -1027,7 +1027,7 @@ void py_do_all (void) { 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"); + logprintf("create_group_chat: Argument 1 must be a list of at least 3 peers\n"); } } Py_XDECREF(pyObj1); diff --git a/python-types.c b/python-types.c index 4bbb4534..8c341575 100644 --- a/python-types.c +++ b/python-types.c @@ -84,6 +84,9 @@ tgl_Peer_getname (tgl_Peer *self, void *closure) case TGL_PEER_CHAT: ret = PyUnicode_FromString(self->peer->chat.print_title); break; + case TGL_PEER_CHANNEL: + ret = PyUnicode_FromString(self->peer->channel.print_title); + break; case TGL_PEER_ENCR_CHAT: ret = PyUnicode_FromString(self->peer->encr_chat.print_name); break; @@ -994,8 +997,12 @@ tgl_Peer_repr(tgl_Peer *self) self->peer->id.peer_id, self->peer->encr_chat.print_name, PyObject_GetAttrString((PyObject*)self, "user")); break; + case TGL_PEER_CHANNEL: + ret = PyUnicode_FromFormat("", + self->peer->id.peer_id, self->peer->channel.print_title); + break; default: - ret = PyUnicode_FromFormat(""); + ret = PyUnicode_FromFormat("",self->peer->id.peer_type); } return ret; diff --git a/tg-test.py b/tg-test.py index d95378c5..3a2e6ef7 100644 --- a/tg-test.py +++ b/tg-test.py @@ -60,6 +60,9 @@ def on_user_update(peer, what_changed): def on_chat_update(peer, what_changed): pass +def on_loop(): + pass + # Set callbacks tgl.set_on_binlog_replay_end(on_binlog_replay_end) tgl.set_on_get_difference_end(on_get_difference_end) @@ -68,4 +71,5 @@ def on_chat_update(peer, what_changed): 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) +tgl.set_on_loop(on_loop) From 231242d9ce2393ab1960dda601dd5a0fc801a017 Mon Sep 17 00:00:00 2001 From: gianduja Date: Mon, 25 Jul 2016 00:08:26 +0200 Subject: [PATCH 076/164] modified to work without errors under cygwin --- README-Cygwin.md | 130 +++++++++++++++++++++----------------- telegram-cli-cygwin.patch | 36 +++++++++-- 2 files changed, 102 insertions(+), 64 deletions(-) diff --git a/README-Cygwin.md b/README-Cygwin.md index 42ed0118..375c2fa4 100755 --- a/README-Cygwin.md +++ b/README-Cygwin.md @@ -1,57 +1,73 @@ -### Installation on Windows -To use telegram-cli in Windows, you should compile with Cygwin which has POSIX API functionality. - -Install [Cygwin](https://www.cygwin.com/) and cygwin's package manager, [apt-cyg](https://github.com/transcode-open/apt-cyg). - -In Cygwin Terminal, install compiler and tools : - - apt-cyg install cygwin32-gcc-core cygwin32-gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip - -Now you have a compiler, but no libraries. You need readline, openssl, libconfig, liblua, python and libjansson to use telegram-cli's full functionality. - - -Then Clone GitHub Repository in Cygwin Terminal - - git clone --recursive https://github.com/vysheng/tg.git - - -In Cygwin Terminal, type: - - apt-cyg install libevent-devel openssl-devel libreadline-devel lua-devel python3 -(Install package 'python' to use Python 2.7, or install package 'python3' to use Python 3) - -libconfig and libjansson is not in cygwin's package, so you should compile yourself. - -Compile libconfig - - wget http://www.hyperrealm.com/libconfig/libconfig-1.5.tar.gz - tar xvf libconfig-1.5.tar.gz && cd libconfig-1.5 - ./configure - make && make install && cd .. - -Compile libjansson - - wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz - tar xvf jansson-2.7.tar.gz && cd jansson-2.7 - ./configure - make && make install && cd .. - -Then, go to tg directory then generate Makefile. - - cd tg - ./configure - -We need to patch Makefile and loop.c to compile in cygwin. Download this [patch](https://gist.github.com/ied206/d774a445f36004d263ab) then untar. Then, patch in tg directory. - - patch -p1 < telegram-cli-cygwin.patch - -Then - make - -After compile is done, **telegram-cli.exe** will be generated in **bin** directory. - -To run telegram-cli, type - - bin/telegram-cli -k tg-server.pub - -**Caution**: A binary compiled with Cygwin should be run in Cygwin Terminal. +### Installation on Windows +To use telegram-cli in Windows, you should compile with Cygwin which has POSIX API functionality. + +Install [Cygwin](https://www.cygwin.com/) and cygwin's package manager, [apt-cyg](https://github.com/transcode-open/apt-cyg). + +In Cygwin Terminal, install cygwin's package manager, apt-cyg: + + lynx -source rawgit.com/transcode-open/apt-cyg/master/apt-cyg > apt-cyg + install apt-cyg /bin + +Then install compiler and tools: if you're on the 32-bit version of cygwin, + + apt-cyg install gcc-core gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip + +Whereas on the 64-bit version, + + apt-cyg install cygwin32-gcc-core cygwin32-gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip zlib-devel + +Now you have a compiler, but no libraries. You need readline, openssl, libconfig, liblua, python and libjansson to use telegram-cli's full functionality. + + +Then Clone GitHub Repository in Cygwin Terminal + + git clone --recursive https://github.com/vysheng/tg.git + + +In Cygwin Terminal, type: + + apt-cyg install libevent-devel openssl-devel libreadline-devel lua-devel python3 +(Install package 'python' to use Python 2.7, or install package 'python3' to use Python 3) + +libconfig and libjansson is not in cygwin's package, so you should compile yourself. + +Compile libconfig + + wget http://www.hyperrealm.com/libconfig/libconfig-1.5.tar.gz + tar xvf libconfig-1.5.tar.gz && cd libconfig-1.5 + ./configure + make && make install && cd .. + +Compile libjansson + + wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz + tar xvf jansson-2.7.tar.gz && cd jansson-2.7 + ./configure + make && make install && cd .. + +Then, go to tg directory then generate Makefile. + + cd tg + ./configure + +In case configure fails, it might be because of the CRLF line endings, so: + + dos2unix -f configure + +And again, + ./configure + +We need to patch Makefile and loop.c to compile in cygwin. The patch is included, so just type: + + patch -p1 < telegram-cli-cygwin.patch + +Then + make + +After compile is done, **telegram-cli.exe** will be generated in **bin** directory. + +To run telegram-cli, type + + bin/telegram-cli -k tg-server.pub + +**Caution**: A binary compiled with Cygwin should be run in Cygwin Terminal. diff --git a/telegram-cli-cygwin.patch b/telegram-cli-cygwin.patch index a8ca3ae0..2dd104b7 100644 --- a/telegram-cli-cygwin.patch +++ b/telegram-cli-cygwin.patch @@ -1,16 +1,38 @@ -Binary files tg/.git/index and tg-cygwin/.git/index differ -diff -urN tg/Makefile tg-cygwin/Makefile ---- tg/Makefile 2015-06-16 12:39:34.931053900 +0900 -+++ tg-cygwin/Makefile 2015-06-16 12:44:12.584342300 +0900 +--- tg/Makefile 2016-07-24 18:04:11.022621500 +0200 ++++ tg-cygwin/Makefile 2016-07-24 22:55:32.710938800 +0200 @@ -4,9 +4,9 @@ - LDFLAGS= -L/usr/local/lib -L/usr/lib -L/usr/lib -L/usr/lib - CPPFLAGS= -I/usr/local/include -I/usr/include -I/usr/include -I/usr/include/python3.4m -I/usr/include + LDFLAGS= -L/usr/local/lib -L/usr/lib -L/usr/lib + CPPFLAGS= -I/usr/local/include -I/usr/include -I/usr/include DEFS=-DHAVE_CONFIG_H -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 +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 - EXTRA_LIBS=-ljansson -lconfig -lz -levent -lm -lreadline -llua-5.2 -lpython3.4m -lssl -lcrypto + EXTRA_LIBS=-ljansson -lconfig -lz -levent -lreadline -llua-5.2 -lssl -lcrypto -LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil +LOCAL_LDFLAGS=-ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} DEP=dep +--- tg\loop.c Sun Jul 24 15:30:11 2016 ++++ tg-cygwin\loop.c Sat Jul 23 17:51:49 2016 +@@ -489,8 +489,9 @@ + close (auth_file_fd); + } + +-void write_secret_chat (tgl_peer_t *Peer, void *extra) { +- struct tgl_secret_chat *P = (void *)Peer; ++// In Cygwin's Python, _P is marco constant. So change tgl_peer_t *_P -> tgl_peer_t *_Peer ++void write_secret_chat (tgl_peer_t *_Peer, void *extra) { ++ struct tgl_secret_chat *P = (void *)_Peer; + if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { return; } + if (P->state != sc_ok) { return; } + int *a = extra; +@@ -737,7 +738,8 @@ + vlogprintf (E_WARNING, "Accepting incoming connection\n"); + socklen_t clilen = 0; + struct sockaddr_in cli_addr; +- int fd = accept (efd, (struct sockaddr *)&cli_addr, &clilen); ++ // In Cygwin, put unsigned int in socklen_t produce warning. Add (socklen_t *) casting ++ int fd = accept (efd, (struct sockaddr *)&cli_addr, (socklen_t *)&clilen); + + assert (fd >= 0); + struct bufferevent *bev = bufferevent_socket_new (TLS->ev_base, fd, 0); From 89fe66183a0c700ff53282451c58e46417f8ec19 Mon Sep 17 00:00:00 2001 From: gianduja Date: Mon, 25 Jul 2016 00:54:34 +0200 Subject: [PATCH 077/164] unused function taken away --- lua-tg.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index 454a0a66..6426bfd4 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -661,10 +661,6 @@ struct lua_arg { struct lua_arg lua_ptr[MAX_LUA_COMMANDS]; static int pos; -static inline tgl_peer_t *get_peer (const char *s) { - return tgl_peer_get_by_name (TLS, s); -} - enum lua_query_type { lq_contact_list, lq_dialog_list, From 41e016ab84d09e2420f3a2aa98ffaa35e9c7b912 Mon Sep 17 00:00:00 2001 From: Valerio Perello Date: Mon, 25 Jul 2016 11:20:52 +0200 Subject: [PATCH 078/164] README improved --- README-Cygwin.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/README-Cygwin.md b/README-Cygwin.md index 375c2fa4..c918224d 100755 --- a/README-Cygwin.md +++ b/README-Cygwin.md @@ -1,72 +1,73 @@ ### Installation on Windows To use telegram-cli in Windows, you should compile with Cygwin which has POSIX API functionality. -Install [Cygwin](https://www.cygwin.com/) and cygwin's package manager, [apt-cyg](https://github.com/transcode-open/apt-cyg). +Install [Cygwin](https://www.cygwin.com/). -In Cygwin Terminal, install cygwin's package manager, apt-cyg: +In Cygwin Terminal, install cygwin's package manager, apt-cyg, as per apt-cyg's [project page](https://github.com/transcode-open/apt-cyg): lynx -source rawgit.com/transcode-open/apt-cyg/master/apt-cyg > apt-cyg install apt-cyg /bin -Then install compiler and tools: if you're on the 32-bit version of cygwin, +Then install compiler and tools: if you're on the **32-bit** version of cygwin, apt-cyg install gcc-core gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip -Whereas on the 64-bit version, +Whereas on the **64-bit** version, apt-cyg install cygwin32-gcc-core cygwin32-gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip zlib-devel -Now you have a compiler, but no libraries. You need readline, openssl, libconfig, liblua, python and libjansson to use telegram-cli's full functionality. +You need libraries *readline*, *openssl*, *libconfig*, *liblua*, *python* and *libjansson* to use telegram-cli's full functionality. - -Then Clone GitHub Repository in Cygwin Terminal +Clone this project's GitHub Repository in Cygwin Terminal git clone --recursive https://github.com/vysheng/tg.git - -In Cygwin Terminal, type: +Then type: apt-cyg install libevent-devel openssl-devel libreadline-devel lua-devel python3 + (Install package 'python' to use Python 2.7, or install package 'python3' to use Python 3) -libconfig and libjansson is not in cygwin's package, so you should compile yourself. +libconfig and libjansson are not included in the cygwin package, so you should compile them yourself. -Compile libconfig +Compile libconfig: wget http://www.hyperrealm.com/libconfig/libconfig-1.5.tar.gz tar xvf libconfig-1.5.tar.gz && cd libconfig-1.5 ./configure make && make install && cd .. -Compile libjansson +Compile libjansson: wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz tar xvf jansson-2.7.tar.gz && cd jansson-2.7 ./configure make && make install && cd .. -Then, go to tg directory then generate Makefile. +Then, change to the tg directory and generate the Makefile. cd tg ./configure -In case configure fails, it might be because of the CRLF line endings, so: +In case `configure` fails, it might be because of the CRLF line endings, so: dos2unix -f configure And again, + ./configure -We need to patch Makefile and loop.c to compile in cygwin. The patch is included, so just type: +We need to patch the Makefile and loop.c to compile properly in cygwin. The patch is included, so just type: patch -p1 < telegram-cli-cygwin.patch -Then +Then, + make -After compile is done, **telegram-cli.exe** will be generated in **bin** directory. +Once the compilation is complete, **telegram-cli.exe** will be found in the **bin** subdirectory. -To run telegram-cli, type +To run `telegram-cli`, type bin/telegram-cli -k tg-server.pub From 079d164ebb35b717fc9f723fe9e6762f7322ac6c Mon Sep 17 00:00:00 2001 From: dlahoti Date: Fri, 26 Aug 2016 00:18:53 -0500 Subject: [PATCH 079/164] update gentoo ebuild summary of changes: * use EAPI 6 instead of 5 * use git-r3 instead of git-2 * allow file to be copied as telegram-cli-.ebuild to get a previous version * disable lua and json by default to follow the usual Gentoo standard of minimalism; leave python enabled since it is installed on effectively every Gentoo system because of Portage --- .../telegram-cli/telegram-cli-9999.ebuild | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild index 6ac2994b..a0b7272e 100644 --- a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild +++ b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild @@ -1,43 +1,40 @@ -# Copyright 1999-2013 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Header: $ +EAPI=6 -EAPI=5 +inherit git-r3 -EGIT_REPO_URI="https://github.com/vysheng/tg.git" -EGIT_BRANCH="master" -EGIT_HAS_SUBMODULES=1 -inherit git-2 -IUSE="+lua +json +python" -DESCRIPTION="Command line interface client for Telegram" HOMEPAGE="https://github.com/vysheng/tg" +DESCRIPTION="Command line interface client for Telegram" +EGIT_REPO_URI="https://github.com/vysheng/tg.git" +if [[ "${PV}" -ne "9999" ]]; then + EGIT_COMMIT="refs/tags/${PV}" + KEYWORDS="~amd64 ~x86" +else + KEYWORDS="" +fi LICENSE="GPL-2" SLOT="0" -KEYWORDS="~amd64 ~x86" +IUSE="lua json +python" -DEPEND="sys-libs/zlib +DEPEND=" + sys-libs/zlib sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-libs/libevent lua? ( dev-lang/lua ) json? ( dev-libs/jansson ) - python? ( dev-lang/python )" - -src_unpack() { - git-2_src_unpack - cd $EGIT_SOURCEDIR - git submodule update --init --recursive -} + python? ( dev-lang/python ) + " +RDEPEND="${DEPEND}" src_configure() { - econf $(use_enable lua liblua ) - econf $(use_enable python python ) - econf $(use_enable json json ) + econf $(use_enable lua liblua) \ + $(use_enable python) \ + $(use_enable json) } src_install() { - newbin bin/telegram-cli telegram-cli + dobin bin/telegram-cli insinto /etc/telegram-cli/ newins tg-server.pub server.pub From 031582b4f4fb83ae393bb29e5ab8e0c51a2180b3 Mon Sep 17 00:00:00 2001 From: dlahoti Date: Fri, 26 Aug 2016 00:56:34 -0500 Subject: [PATCH 080/164] make python depend on lua and json for some reason, the configure script refuses to enable python unless lua and json are both enabled --- gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild | 1 + 1 file changed, 1 insertion(+) diff --git a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild index a0b7272e..96279021 100644 --- a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild +++ b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild @@ -14,6 +14,7 @@ fi LICENSE="GPL-2" SLOT="0" IUSE="lua json +python" +REQUIRED_USE="python? (lua json)" DEPEND=" sys-libs/zlib From b85d20c5d07d997abfa3f5d97fb9b1bd7a97dab9 Mon Sep 17 00:00:00 2001 From: dlahoti Date: Fri, 26 Aug 2016 00:58:10 -0500 Subject: [PATCH 081/164] make none of the use flags default since python depends on the other two --- gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild index 96279021..029e9f99 100644 --- a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild +++ b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild @@ -13,7 +13,7 @@ else fi LICENSE="GPL-2" SLOT="0" -IUSE="lua json +python" +IUSE="lua json python" REQUIRED_USE="python? (lua json)" DEPEND=" From 6245fce0b9b813b9597671943970a29e3f51b998 Mon Sep 17 00:00:00 2001 From: dlahoti Date: Fri, 26 Aug 2016 01:03:14 -0500 Subject: [PATCH 082/164] add spaces for REQUIRED_USE so it actually works --- gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild index 029e9f99..da9b47cc 100644 --- a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild +++ b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild @@ -14,7 +14,7 @@ fi LICENSE="GPL-2" SLOT="0" IUSE="lua json python" -REQUIRED_USE="python? (lua json)" +REQUIRED_USE="python? ( lua json )" DEPEND=" sys-libs/zlib From 6ad8952d2a72416db0e580b154861181f7555efe Mon Sep 17 00:00:00 2001 From: dlahoti Date: Fri, 26 Aug 2016 01:04:38 -0500 Subject: [PATCH 083/164] undo all that stuff cause apparently it won't compile with python no matter what --- gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild | 1 - 1 file changed, 1 deletion(-) diff --git a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild index da9b47cc..12c8d6a6 100644 --- a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild +++ b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild @@ -14,7 +14,6 @@ fi LICENSE="GPL-2" SLOT="0" IUSE="lua json python" -REQUIRED_USE="python? ( lua json )" DEPEND=" sys-libs/zlib From 87e6ce78679ecc7ebf14946ada13e9f4e7bb5d92 Mon Sep 17 00:00:00 2001 From: dlahoti Date: Fri, 26 Aug 2016 01:13:39 -0500 Subject: [PATCH 084/164] drop python support altogether since it apparently doesn't work --- gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild index 12c8d6a6..4c1b09ca 100644 --- a/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild +++ b/gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild @@ -13,7 +13,7 @@ else fi LICENSE="GPL-2" SLOT="0" -IUSE="lua json python" +IUSE="lua json" DEPEND=" sys-libs/zlib @@ -23,13 +23,11 @@ DEPEND=" dev-libs/libevent lua? ( dev-lang/lua ) json? ( dev-libs/jansson ) - python? ( dev-lang/python ) " RDEPEND="${DEPEND}" src_configure() { econf $(use_enable lua liblua) \ - $(use_enable python) \ $(use_enable json) } From adc9931fafbb40cb4b8a6f08f5870e8d9221345e Mon Sep 17 00:00:00 2001 From: Aidan Lloyd-Tucker Date: Sat, 3 Sep 2016 16:26:14 -0700 Subject: [PATCH 085/164] Changed the venue type to title Changed the venue title field to be title instead of type --- json-tg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-tg.c b/json-tg.c index a58e70ad..7b4e0112 100644 --- a/json-tg.c +++ b/json-tg.c @@ -269,7 +269,7 @@ json_t *json_pack_media (struct tgl_message_media *M) { assert (json_object_set (res, "longitude", json_real (M->venue.geo.longitude)) >= 0); assert (json_object_set (res, "latitude", json_real (M->venue.geo.latitude)) >= 0); if (M->venue.title) { - assert (json_object_set (res, "type", json_string (M->venue.title)) >= 0); + assert (json_object_set (res, "title", json_string (M->venue.title)) >= 0); } if (M->venue.address) { assert (json_object_set (res, "address", json_string (M->venue.address)) >= 0); From ce43e9ce5863cc8938fb9738dddc82a3c19f7f00 Mon Sep 17 00:00:00 2001 From: Aidan Lloyd-Tucker Date: Sat, 3 Sep 2016 16:44:51 -0700 Subject: [PATCH 086/164] Added type field for all types --- json-tg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/json-tg.c b/json-tg.c index 7b4e0112..27be4828 100644 --- a/json-tg.c +++ b/json-tg.c @@ -229,10 +229,16 @@ json_t *json_pack_media (struct tgl_message_media *M) { } break; case tgl_message_media_document: + assert (json_object_set (res, "type", json_string ("document")) >= 0); + break; case tgl_message_media_audio: + assert (json_object_set (res, "type", json_string ("audio")) >= 0); + break; case tgl_message_media_video: + assert (json_object_set (res, "type", json_string ("video")) >= 0); + break; case tgl_message_media_document_encr: - assert (json_object_set (res, "type", json_string ("document")) >= 0); + assert (json_object_set (res, "type", json_string ("document_encr")) >= 0); break; case tgl_message_media_unsupported: assert (json_object_set (res, "type", json_string ("unsupported")) >= 0); @@ -282,7 +288,7 @@ json_t *json_pack_media (struct tgl_message_media *M) { } break; default: - assert (json_object_set (res, "type", json_string ("???")) >= 0); + assert (json_object_set (res, "type", json_string ("unknown")) >= 0); } return res; } From 3bd3f48568c1f63470e065681f02c8b88584ebe1 Mon Sep 17 00:00:00 2001 From: Aidan Lloyd-Tucker Date: Sat, 3 Sep 2016 16:49:09 -0700 Subject: [PATCH 087/164] Removed unused funtion --- lua-tg.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index 454a0a66..b455b9f0 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -660,10 +660,6 @@ struct lua_arg { }; struct lua_arg lua_ptr[MAX_LUA_COMMANDS]; static int pos; - -static inline tgl_peer_t *get_peer (const char *s) { - return tgl_peer_get_by_name (TLS, s); -} enum lua_query_type { lq_contact_list, From ba5eb642fdfca6713cf26392c43a17cd0b12c4a7 Mon Sep 17 00:00:00 2001 From: Aidan Lloyd-Tucker Date: Sun, 4 Sep 2016 09:26:02 -0700 Subject: [PATCH 088/164] Switched ??? to unknown for all fields --- json-tg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json-tg.c b/json-tg.c index 27be4828..91809bfc 100644 --- a/json-tg.c +++ b/json-tg.c @@ -330,7 +330,7 @@ json_t *json_pack_typing (enum tgl_typing_status status) { assert (json_object_set (res, "status", json_string ("choosing contact")) >= 0); break; default: - assert (json_object_set (res, "status", json_string ("???")) >= 0); + assert (json_object_set (res, "status", json_string ("unknown")) >= 0); break; } return res; @@ -427,7 +427,7 @@ json_t *json_pack_service (struct tgl_message *M) { assert (json_object_set (res, "type", json_string ("migrated_from")) >= 0); break; default: - assert (json_object_set (res, "type", json_string ("???")) >= 0); + assert (json_object_set (res, "type", json_string ("unknown")) >= 0); break; } return res; From ec3d68f7a375a8d62f7c1f45c4f6ba3f2782bad9 Mon Sep 17 00:00:00 2001 From: Aidan Lloyd-Tucker Date: Sun, 4 Sep 2016 14:39:39 -0700 Subject: [PATCH 089/164] Fixed JSON memory leak as shown in vysheng#1075 --- interface.c | 276 ++++++++++++++++++++++---------------------- json-tg.c | 323 ++++++++++++++++++++++++++-------------------------- 2 files changed, 301 insertions(+), 298 deletions(-) diff --git a/interface.c b/interface.c index f78619a3..002dacd4 100644 --- a/interface.c +++ b/interface.c @@ -202,12 +202,12 @@ void socket_answer_end (struct in_ev *ev) { #define mprintf(ev,...) \ if (ev) { socket_answer_add_printf (__VA_ARGS__); } \ - else { printf (__VA_ARGS__); } + else { printf (__VA_ARGS__); } #define mprint_start(ev,...) \ if (!ev) { print_start (__VA_ARGS__); } \ else { socket_answer_start (); } - + #define mprint_end(ev,...) \ if (!ev) { print_end (__VA_ARGS__); } \ else { socket_answer_end (ev); } @@ -299,13 +299,13 @@ static void next_token (void) { void next_token_end (void) { skip_wspc (); - + if (*line_ptr && *line_ptr != '"' && *line_ptr != '\'') { cur_token_quoted = 0; cur_token = line_ptr; while (*line_ptr) { line_ptr ++; } cur_token_len = line_ptr - cur_token; - while (((unsigned char)cur_token[cur_token_len - 1]) <= ' ' && cur_token_len >= 0) { + while (((unsigned char)cur_token[cur_token_len - 1]) <= ' ' && cur_token_len >= 0) { cur_token_len --; } assert (cur_token_len > 0); @@ -316,7 +316,7 @@ void next_token_end (void) { next_token (); skip_wspc (); if (*line_ptr) { - cur_token_len = -1; + cur_token_len = -1; } } else { next_token (); @@ -326,7 +326,7 @@ void next_token_end (void) { void next_token_end_ac (void) { skip_wspc (); - + if (*line_ptr && *line_ptr != '"' && *line_ptr != '\'') { cur_token_quoted = 0; cur_token = line_ptr; @@ -340,7 +340,7 @@ void next_token_end_ac (void) { next_token (); skip_wspc (); if (*line_ptr) { - cur_token_len = -1; + cur_token_len = -1; } } else { next_token (); @@ -377,7 +377,7 @@ int hex2int (char c) { char *print_permanent_msg_id (tgl_message_id_t id) { static char buf[2 * sizeof (tgl_message_id_t) + 1]; - + unsigned char *s = (void *)&id; int i; for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) { @@ -389,7 +389,7 @@ char *print_permanent_msg_id (tgl_message_id_t id) { char *print_permanent_peer_id (tgl_peer_id_t id) { static char buf[2 * sizeof (tgl_peer_id_t) + 2]; buf[0] = '$'; - + unsigned char *s = (void *)&id; int i; for (i = 0; i < (int)sizeof (tgl_peer_id_t); i++) { @@ -404,7 +404,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { memset (&id, 0, sizeof (id)); id.peer_type = 0; return id; - } else { + } else { tgl_message_id_t id; memset (&id, 0, sizeof (id)); @@ -414,7 +414,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { if ( (s[i] < '0' || s[i] > '9') && (s[i] < 'a' || s[i] > 'f') - ) { + ) { id.peer_type = 0; return id; } @@ -422,7 +422,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { unsigned char *d = (void *)&id; for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) { d[i] = hex2int (s[2 * i]) * 16 + hex2int (s[2 * i + 1]); - } + } return id; } else { char *sc = tstrndup (s, l); @@ -430,7 +430,7 @@ tgl_message_id_t parse_input_msg_id (const char *s, int l) { long long x = strtoll (sc, &end, 0); tfree_str (sc); if (end != sc + l) { - id.peer_type = 0; + id.peer_type = 0; } else { id.peer_type = TGL_PEER_TEMP_ID; id.id = x; @@ -475,7 +475,7 @@ tgl_peer_id_t parse_input_peer_id (const char *s, int l, int mask) { unsigned char *r = (void *)&res; int i; for (i = 0; i < l; i++) { - if ((s[i] < '0' || s[i] > '9') && + if ((s[i] < '0' || s[i] > '9') && (s[i] < 'a' || s[i] > 'f')) { return TGL_PEER_NOT_FOUND; } @@ -522,9 +522,9 @@ tgl_peer_id_t parse_input_peer_id (const char *s, int l, int mask) { } } - tgl_peer_t *P = tgl_peer_get_by_name (TLS, sc); + tgl_peer_t *P = tgl_peer_get_by_name (TLS, sc); tfree_str (sc); - + if (P && (!mask || tgl_get_peer_type (P->id) == mask)) { return P->id; } else { @@ -595,7 +595,7 @@ char *get_default_prompt (void) { l += snprintf (buf + l, 999 - l, "]" COLOR_NORMAL); l += snprintf (buf + l, 999 - l, "%s", default_prompt); return buf; - } + } l += snprintf (buf + l, 999 - l, "%s", default_prompt); return buf; } @@ -758,7 +758,7 @@ void do_stats (struct command *command, int arg_num, struct arg args[], struct i void do_show_license (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (!arg_num); - static char *b = + static char *b = #include "LICENSE.h" ; if (ev) { mprint_start (ev); } @@ -783,7 +783,7 @@ void do_safe_quit (struct command *command, int arg_num, struct arg args[], stru void do_set (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { int num = args[1].num; if (!strcmp (args[0].str, "debug_verbosity")) { - tgl_set_verbosity (TLS, num); + tgl_set_verbosity (TLS, num); } else if (!strcmp (args[0].str, "log_level")) { log_level = num; } else if (!strcmp (args[0].str, "msg_num")) { @@ -813,7 +813,7 @@ void do_version (struct command *command, int arg_num, struct arg args[], struct if (ev) { mprint_start (ev); } mpush_color (ev, COLOR_YELLOW); mprintf (ev, "Telegram-cli version %s (uses tgl version %s)\n", TELEGRAM_CLI_VERSION, TGL_VERSION); - #ifdef TGL_AVOID_OPENSSL + #ifdef TGL_AVOID_OPENSSL mprintf (ev, "uses libgcrypt for encryption\n"); #else mprintf (ev, "uses libopenssl for encryption\n"); @@ -859,9 +859,9 @@ void do_msg_kbd (struct command *command, int arg_num, struct arg args[], struct assert (arg_num == 3); if (ev) { ev->refcnt ++; } - clear_packet (); + clear_packet (); if (tglf_store_type (TLS, ARG2STR(1), TYPE_TO_PARAM (reply_markup)) < 0) { - fail_interface (TLS, ev, ENOSYS, "can not parse reply markup"); + fail_interface (TLS, ev, ENOSYS, "can not parse reply markup"); return; } in_ptr = packet_buffer; @@ -886,7 +886,7 @@ void do_send_text (struct command *command, int arg_num, struct arg args[], stru if (ev) { ev->refcnt ++; } tgl_do_send_text (TLS, args[0].peer_id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, print_msg_success_gw, ev); } - + void do_post_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } @@ -1029,7 +1029,7 @@ void do_broadcast (struct command *command, int arg_num, struct arg args[], stru int i; for (i = 0; i < arg_num - 1; i++) { ids[i] = args[i].peer_id; - } + } if (ev) { ev->refcnt ++; } tgl_do_send_broadcast (TLS, arg_num - 1, ids, args[arg_num - 1].str, strlen (args[arg_num - 1].str), disable_msg_preview | do_html, print_msg_list_success_gw, ev); } @@ -1092,7 +1092,7 @@ void do_export_card (struct command *command, int arg_num, struct arg args[], st void do_chat_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_set_chat_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); + tgl_do_set_chat_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); } void do_rename_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1124,7 +1124,7 @@ void do_chat_del_user (struct command *command, int arg_num, struct arg args[], if (ev) { ev->refcnt ++; } tgl_do_del_user_from_chat (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev); } - + void do_create_group_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num >= 1 && arg_num <= 1000); static tgl_peer_id_t ids[1000]; @@ -1134,7 +1134,7 @@ void do_create_group_chat (struct command *command, int arg_num, struct arg args } if (ev) { ev->refcnt ++; } - tgl_do_create_group_chat (TLS, arg_num - 1, ids, ARG2STR (0), print_success_gw, ev); + tgl_do_create_group_chat (TLS, arg_num - 1, ids, ARG2STR (0), print_success_gw, ev); } void do_export_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1199,7 +1199,7 @@ void do_add_contact (struct command *command, int arg_num, struct arg args[], st void do_rename_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 3); - + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); if (P && P->user.phone) { if (ev) { ev->refcnt ++; } @@ -1233,7 +1233,7 @@ void do_import_card (struct command *command, int arg_num, struct arg args[], st } else if (s[i] >= 'a' && s[i] <= 'f') { cur = cur * 16 + s[i] - 'a' + 10; } else if (s[i] == ':') { - if (pp >= 9) { + if (pp >= 9) { ok = 0; break; } @@ -1298,7 +1298,7 @@ void do_visualize_key (struct command *command, int arg_num, struct arg args[], for (i = 0; i < 16; i++) { int x = buf[i]; int j; - for (j = 0; j < 4; j ++) { + for (j = 0; j < 4; j ++) { if (!ev) { mpush_color (ev, colors[x & 3]); mpush_color (ev, COLOR_INVERSE); @@ -1327,8 +1327,8 @@ void do_visualize_key (struct command *command, int arg_num, struct arg args[], } x = x >> 2; } - if (i & 1) { - mprintf (ev, "\n"); + if (i & 1) { + mprintf (ev, "\n"); } } mprint_end (ev); @@ -1354,7 +1354,7 @@ void do_rename_channel (struct command *command, int arg_num, struct arg args[], void do_channel_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 2); if (ev) { ev->refcnt ++; } - tgl_do_set_channel_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); + tgl_do_set_channel_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev); } void do_channel_set_about (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1374,7 +1374,7 @@ void do_channel_set_username (struct command *command, int arg_num, struct arg a if (ev) { ev->refcnt ++; } tgl_do_channel_set_username (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev); } - + void do_create_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num >= 2 && arg_num <= 1000); static tgl_peer_id_t ids[1000]; @@ -1384,7 +1384,7 @@ void do_create_channel (struct command *command, int arg_num, struct arg args[], } if (ev) { ev->refcnt ++; } - tgl_do_create_channel (TLS, arg_num - 2, ids, ARG2STR (0), ARG2STR (1), 1, print_success_gw, ev); + tgl_do_create_channel (TLS, arg_num - 2, ids, ARG2STR (0), ARG2STR (1), 1, print_success_gw, ev); } void do_join_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { @@ -1430,7 +1430,7 @@ void do_resolve_username (struct command *command, int arg_num, struct arg args[ void do_contact_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (!arg_num); if (ev) { ev->refcnt ++; } - tgl_do_update_contact_list (TLS, print_user_list_gw, ev); + tgl_do_update_contact_list (TLS, print_user_list_gw, ev); } /* }}} */ @@ -1546,7 +1546,7 @@ void do_load_user_photo (struct command *command, int arg_num, struct arg args[ void do_view_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { assert (arg_num == 1); if (ev) { ev->refcnt ++; } - + tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id); if (P) { tgl_do_load_file_location (TLS, &P->user.photo_big, print_filename_gw, ev); @@ -1563,25 +1563,25 @@ void do_search (struct command *command, int arg_num, struct arg args[], struct assert (arg_num == 6); int limit; if (args[1].num != NOT_FOUND) { - limit = args[1].num; + limit = args[1].num; } else { limit = 40; } int from; if (args[2].num != NOT_FOUND) { - from = args[2].num; + from = args[2].num; } else { from = 0; } int to; if (args[3].num != NOT_FOUND) { - to = args[3].num; + to = args[3].num; } else { to = 0; } int offset; if (args[4].num != NOT_FOUND) { - offset = args[4].num; + offset = args[4].num; } else { offset = 0; } @@ -1801,7 +1801,7 @@ enum command_argument get_complete_mode (void) { if (cur_token_len <= 0) { return ca_command; } if (*cur_token == '[') { if (cur_token_end_str) { - return ca_modifier; + return ca_modifier; } if (cur_token[cur_token_len - 1] != ']') { return ca_none; @@ -1813,7 +1813,7 @@ enum command_argument get_complete_mode (void) { if (cur_token_quoted) { return ca_none; } if (cur_token_end_str) { return ca_command; } if (*cur_token == '(') { return ca_extf; } - + struct command *command = commands; int n = 0; struct tgl_command; @@ -1824,7 +1824,7 @@ enum command_argument get_complete_mode (void) { n ++; command ++; } - + if (!command->name) { return ca_none; } @@ -1843,13 +1843,13 @@ enum command_argument get_complete_mode (void) { if (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) { next_token_end_ac (); - if (cur_token_len < 0 || !cur_token_end_str) { + if (cur_token_len < 0 || !cur_token_end_str) { return ca_none; } else { return op; } } - + char *save = line_ptr; next_token (); if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double || op == ca_msg_id || op == ca_command || op == ca_channel) { @@ -1867,7 +1867,7 @@ enum command_argument get_complete_mode (void) { } } else { if (cur_token_end_str) { return op; } - + int ok = 1; switch (op) { case ca_user: @@ -1984,7 +1984,7 @@ int complete_spec_message_answer (struct tgl_message *M, int index, const char * while (index < total && strncmp (M->reply_markup->buttons[index], text, len)) { index ++; } - + if (index < total) { *R = strdup (M->reply_markup->buttons[index]); assert (*R); @@ -2019,7 +2019,7 @@ int complete_user_command (tgl_peer_t *P, int index, const char *text, int len, if (index >= U->bot_info->commands_num) { return U->bot_info->commands_num + complete_message_answer (P, index - U->bot_info->commands_num, text - 1, len + 1, R); } - + index ++; while (index < U->bot_info->commands_num && strncmp (U->bot_info->commands[index].command, text, len)) { index ++; @@ -2045,7 +2045,7 @@ int complete_chat_command (tgl_peer_t *P, int index, const char *text, int len, int tot = 0; int i; - for (i = 0; i < P->chat.user_list_size; i++) { + for (i = 0; i < P->chat.user_list_size; i++) { struct tgl_user *U = (void *)tgl_peer_get (TLS, TGL_MK_USER (P->chat.user_list[i].user_id)); if (!U) { continue; } if (!U->bot_info) { continue; } @@ -2114,7 +2114,7 @@ int complete_username (int mode, int index, const char *text, int len, char **R) return index; } -char *command_generator (const char *text, int state) { +char *command_generator (const char *text, int state) { #ifndef DISABLE_EXTF static int len; #endif @@ -2128,7 +2128,7 @@ char *command_generator (const char *text, int state) { index = complete_string_list (in_chat_commands, index, text, rl_point, &R); return R; } - + char c = 0; c = rl_line_buffer[rl_point]; rl_line_buffer[rl_point] = 0; @@ -2137,17 +2137,17 @@ char *command_generator (const char *text, int state) { len = strlen (text); #endif index = -1; - + mode = get_complete_mode (); command_pos = cur_token; command_len = cur_token_len; } else { if (mode != ca_file_name && mode != ca_file_name_end && index == -1) { return 0; } } - - if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double || mode == ca_msg_id) { + + if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double || mode == ca_msg_id) { if (c) { rl_line_buffer[rl_point] = c; } - return 0; + return 0; } assert (command_len >= 0); @@ -2161,7 +2161,7 @@ char *command_generator (const char *text, int state) { if (command_len && command_pos[0] == '@') { index = complete_username (TGL_PEER_USER, index, command_pos, command_len, &R); } else { - index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R); + index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R); } if (c) { rl_line_buffer[rl_point] = c; } return R; @@ -2190,7 +2190,7 @@ char *command_generator (const char *text, int state) { if (command_len && command_pos[0] == '@') { index = complete_username (TGL_PEER_CHANNEL, index, command_pos, command_len, &R); } else { - index = tgl_complete_channel_list (TLS, index, command_pos, command_len, &R); + index = tgl_complete_channel_list (TLS, index, command_pos, command_len, &R); } if (c) { rl_line_buffer[rl_point] = c; } return R; @@ -2241,7 +2241,7 @@ void work_modifier (const char *s, int l) { } if (sscanf (s, "[reply=%d]", &reply_id) >= 1) { } - + if (is_same_word (s, l, "[html]")) { do_html = TGLMF_HTML; } @@ -2264,9 +2264,9 @@ void print_fail (struct in_ev *ev) { } else { #ifdef USE_JSON json_t *res = json_object (); - assert (json_object_set (res, "result", json_string ("FAIL")) >= 0); - assert (json_object_set (res, "error_code", json_integer (TLS->error_code)) >= 0); - assert (json_object_set (res, "error", json_string (TLS->error)) >= 0); + assert (json_object_set_new (res, "result", json_string ("FAIL")) >= 0); + assert (json_object_set_new (res, "error_code", json_integer (TLS->error_code)) >= 0); + assert (json_object_set_new (res, "error", json_string (TLS->error)) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -2292,9 +2292,9 @@ void fail_interface (struct tgl_state *TLS, struct in_ev *ev, int error_code, co } else { #ifdef USE_JSON json_t *res = json_object (); - assert (json_object_set (res, "result", json_string ("FAIL")) >= 0); - assert (json_object_set (res, "error_code", json_integer (error_code)) >= 0); - assert (json_object_set (res, "error", json_string (error)) >= 0); + assert (json_object_set_new (res, "result", json_string ("FAIL")) >= 0); + assert (json_object_set_new (res, "error_code", json_integer (error_code)) >= 0); + assert (json_object_set_new (res, "error", json_string (error)) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -2312,7 +2312,7 @@ void print_success (struct in_ev *ev) { } else { #ifdef USE_JSON json_t *res = json_object (); - assert (json_object_set (res, "result", json_string ("SUCCESS")) >= 0); + assert (json_object_set_new (res, "result", json_string ("SUCCESS")) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -2370,7 +2370,7 @@ void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int nu int i; for (i = num - 1; i >= 0; i--) { json_t *a = json_pack_message (ML[i]); - assert (json_array_append (res, a) >= 0); + assert (json_array_append_new (res, a) >= 0); } char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); @@ -2436,7 +2436,7 @@ void print_user_list_gw (struct tgl_state *TLSR, void *extra, int success, int n int i; for (i = num - 1; i >= 0; i--) { json_t *a = json_pack_peer (UL[i]->id); - assert (json_array_append (res, a) >= 0); + assert (json_array_append_new (res, a) >= 0); } char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); @@ -2521,7 +2521,7 @@ void print_channel_gw (struct tgl_state *TLSR, void *extra, int success, struct void print_peer_gw (struct tgl_state *TLSR, void *extra, int success, tgl_peer_t *U) { - if (!success) { + if (!success) { print_user_gw (TLSR, extra, success, (void *)U); return; } @@ -2554,8 +2554,8 @@ void print_filename_gw (struct tgl_state *TLSR, void *extra, int success, const } else { #ifdef USE_JSON json_t *res = json_object (); - assert (json_object_set (res, "result", json_string (name)) >= 0); - assert (json_object_set (res, "event", json_string ("download")) >= 0); + assert (json_object_set_new (res, "result", json_string (name)) >= 0); + assert (json_object_set_new (res, "event", json_string ("download")) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -2579,7 +2579,7 @@ void print_string_gw (struct tgl_state *TLSR, void *extra, int success, const ch } else { #ifdef USE_JSON json_t *res = json_object (); - assert (json_object_set (res, "result", json_string (name)) >= 0); + assert (json_object_set_new (res, "result", json_string (name)) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -2619,7 +2619,7 @@ void print_chat_info_gw (struct tgl_state *TLSR, void *extra, int success, struc } if (!success) { print_fail (ev); return; } mprint_start (ev); - + if (!enable_json) { tgl_peer_t *U = (void *)C; mpush_color (ev, COLOR_YELLOW); @@ -2662,7 +2662,7 @@ void print_channel_info_gw (struct tgl_state *TLSR, void *extra, int success, st } if (!success) { print_fail (ev); return; } mprint_start (ev); - + if (!enable_json) { tgl_peer_t *U = (void *)C; mpush_color (ev, COLOR_YELLOW); @@ -2838,7 +2838,7 @@ void print_dialog_list_gw (struct tgl_state *TLSR, void *extra, int success, int int i; for (i = size - 1; i >= 0; i--) { json_t *a = json_pack_peer (peers[i]); - assert (json_array_append (res, a) >= 0); + assert (json_array_append_new (res, a) >= 0); } char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); @@ -3058,7 +3058,7 @@ void print_message_gw (struct tgl_state *TLSR, struct tgl_message *M) { py_new_msg (M); #endif if (!binlog_read) { return; } - if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) { + if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) { write_secret_chat_file (); } if (alert_sound) { @@ -3139,9 +3139,9 @@ void print_peer_updates (struct in_ev *ev, int flags) { void json_peer_update (struct in_ev *ev, tgl_peer_t *P, unsigned flags) { #ifdef USE_JSON json_t *res = json_object (); - assert (json_object_set (res, "event", json_string ("updates")) >= 0); - assert (json_object_set (res, "peer", json_pack_peer (P->id)) >= 0); - assert (json_object_set (res, "updates", json_pack_updates (flags)) >= 0); + assert (json_object_set_new (res, "event", json_string ("updates")) >= 0); + assert (json_object_set_new (res, "peer", json_pack_peer (P->id)) >= 0); + assert (json_object_set_new (res, "updates", json_pack_updates (flags)) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -3152,7 +3152,7 @@ void json_peer_update (struct in_ev *ev, tgl_peer_t *P, unsigned flags) { void peer_update_username (tgl_peer_t *P, const char *username) { if (!username) { if (P->extra) { - struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra); + struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra); assert (p); username_peer_pair = tree_delete_username_peer_pair (username_peer_pair, p); tfree_str (P->extra); @@ -3178,7 +3178,7 @@ void peer_update_username (tgl_peer_t *P, const char *username) { struct username_peer_pair *p = talloc (sizeof (*p)); p->peer = P; p->username = P->extra; - + username_peer_pair = tree_insert_username_peer_pair (username_peer_pair, p, rand ()); } @@ -3192,7 +3192,7 @@ void user_update_gw (struct tgl_state *TLSR, struct tgl_user *U, unsigned flags) #endif peer_update_username ((void *)U, U->username); - + if (disable_output && !notify_ev) { return; } if (!binlog_read) { return; } struct in_ev *ev = notify_ev; @@ -3226,7 +3226,7 @@ void chat_update_gw (struct tgl_state *TLSR, struct tgl_chat *U, unsigned flags) #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; @@ -3264,14 +3264,14 @@ void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, u if ((flags & TGL_UPDATE_WORKING) || (flags & TGL_UPDATE_DELETED)) { write_secret_chat_file (); } - + if (!binlog_read) { return; } if ((flags & TGL_UPDATE_REQUESTED) && !disable_auto_accept) { //tgl_do_accept_encr_chat_request (TLS, U, 0, 0); tgl_do_accept_encr_chat_request (TLS, U, print_encr_chat_success_gw, 0); } - + if (disable_output && !notify_ev) { return; } struct in_ev *ev = notify_ev; @@ -3299,9 +3299,9 @@ void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, u void channel_update_gw (struct tgl_state *TLSR, struct tgl_channel *U, unsigned flags) { assert (TLSR == TLS); - + peer_update_username ((void *)U, U->username); - + if (disable_output && !notify_ev) { return; } if (!binlog_read) { return; } } @@ -3330,7 +3330,7 @@ void print_card_gw (struct tgl_state *TLSR, void *extra, int success, int size, pos += sprintf (q + pos, "%08x%s", card[i], i == size - 1 ? "" : ":"); } json_t *res = json_object (); - assert (json_object_set (res, "result", json_string (q)) >= 0); + assert (json_object_set_new (res, "result", json_string (q)) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -3353,7 +3353,7 @@ void callback_extf (struct tgl_state *TLS, void *extra, int success, const char } else { #ifdef USE_JSON json_t *res = json_object (); - assert (json_object_set (res, "result", json_string (buf)) >= 0); + assert (json_object_set_new (res, "result", json_string (buf)) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); @@ -3421,7 +3421,7 @@ struct tgl_update_callback upd_cb = { }; -void interpreter_ex (char *line, void *ex) { +void interpreter_ex (char *line, void *ex) { force_end_mode = 1; assert (!in_readline); in_readline = 1; @@ -3437,10 +3437,10 @@ void interpreter_ex (char *line, void *ex) { reply_id = 0; disable_msg_preview = 0; count = 1; - if (!line) { + if (!line) { do_safe_quit (NULL, 0, NULL, NULL); in_readline = 0; - return; + return; } if (!*line) { in_readline = 0; @@ -3450,53 +3450,53 @@ void interpreter_ex (char *line, void *ex) { if (line && *line) { add_history (line); } - - if (*line == '(') { + + if (*line == '(') { struct in_ev *ev = ex; if (ev) { ev->refcnt ++; } tgl_do_send_extf (TLS, line, strlen (line), callback_extf, ev); in_readline = 0; - return; + return; } while (1) { next_token (); - if (cur_token_quoted) { + if (cur_token_quoted) { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } - if (cur_token_len <= 0) { + if (cur_token_len <= 0) { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } - + if (*cur_token == '[') { if (cur_token_end_str) { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } if (cur_token[cur_token_len - 1] != ']') { in_readline = 0; fail_interface (TLS, ex, ENOSYS, "can not parse modifier"); - return; + return; } work_modifier (cur_token, cur_token_len); continue; } break; } - if (cur_token_quoted || cur_token_end_str) { + if (cur_token_quoted || cur_token_end_str) { fail_interface (TLS, ex, ENOSYS, "can not parse command name"); in_readline = 0; - return; + return; } - - - + + + struct command *command = commands; int n = 0; struct tgl_command; @@ -3507,11 +3507,11 @@ void interpreter_ex (char *line, void *ex) { n ++; command ++; } - + if (!command->name) { fail_interface (TLS, ex, ENOSYS, "can not find command '%.*s'", cur_token_len, cur_token); in_readline = 0; - return; + return; } enum command_argument *flags = command->args; @@ -3531,7 +3531,7 @@ void interpreter_ex (char *line, void *ex) { enum command_argument op = (*flags) & 255; int opt = (*flags) & ca_optional; - if (op == ca_none) { + if (op == ca_none) { next_token (); if (cur_token_end_str) { int z; @@ -3543,10 +3543,10 @@ void interpreter_ex (char *line, void *ex) { } break; } - + if (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) { next_token_end (); - if (cur_token_len < 0) { + if (cur_token_len < 0) { fail_interface (TLS, ex, ENOSYS, "can not parse string_end arg #%d", args_num); break; } else { @@ -3596,7 +3596,7 @@ void interpreter_ex (char *line, void *ex) { break; } } else { - if (cur_token_end_str) { + if (cur_token_end_str) { if (opt) { if (op != ca_number && op != ca_double && op != ca_msg_id) { args[args_num ++].peer_id = TGL_PEER_NOT_FOUND; @@ -3623,23 +3623,23 @@ void interpreter_ex (char *line, void *ex) { int ok = 1; switch (op) { case ca_user: - args[args_num ++].peer_id = cur_token_user (); + args[args_num ++].peer_id = cur_token_user (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_chat: - args[args_num ++].peer_id = cur_token_chat (); + args[args_num ++].peer_id = cur_token_chat (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_secret_chat: - args[args_num ++].peer_id = cur_token_encr_chat (); + args[args_num ++].peer_id = cur_token_encr_chat (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_channel: - args[args_num ++].peer_id = cur_token_channel (); + args[args_num ++].peer_id = cur_token_channel (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_peer: - args[args_num ++].peer_id = cur_token_peer (); + args[args_num ++].peer_id = cur_token_peer (); ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND; break; case ca_number: @@ -3702,7 +3702,7 @@ void interpreter_ex (char *line, void *ex) { free (args[i].str); } } - + update_prompt (); in_readline = 0; } @@ -3772,9 +3772,9 @@ void print_start (void) { void print_end (void) { if (in_readline) { return; } - if (readline_disabled) { + if (readline_disabled) { fflush (stdout); - return; + return; } assert (prompt_was); if (readline_active) { @@ -3788,7 +3788,7 @@ void print_end (void) { int *ptr = in_ptr; while (ptr < in_end) { mprintf (ev, " %08x", *(ptr ++)); } mprintf (ev, "\n"); - mprint_end (ev); + mprint_end (ev); }*/ void logprintf (const char *format, ...) { @@ -3878,7 +3878,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, ":"); } - + if (M->document->mime_type) { mprintf (ev, " type=%s", M->document->mime_type); } @@ -3890,7 +3890,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { if (M->document->duration) { mprintf (ev, " duration=%d", M->document->duration); } - + mprintf (ev, " size="); if (M->document->size < (1 << 10)) { mprintf (ev, "%dB", M->document->size); @@ -3901,9 +3901,9 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, "%dGiB", M->document->size >> 30); } - + mprintf (ev, "]"); - + if (M->caption) { mprintf (ev, " %s", M->caption); } @@ -3928,7 +3928,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, ":"); } - + if (M->encr_document->mime_type) { mprintf (ev, " type=%s", M->encr_document->mime_type); } @@ -3940,7 +3940,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { if (M->encr_document->duration) { mprintf (ev, " duration=%d", M->encr_document->duration); } - + mprintf (ev, " size="); if (M->encr_document->size < (1 << 10)) { mprintf (ev, "%dB", M->encr_document->size); @@ -3951,7 +3951,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { } else { mprintf (ev, "%dGiB", M->encr_document->size >> 30); } - + mprintf (ev, "]"); return; @@ -3987,11 +3987,11 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { break; case tgl_message_media_venue: mprintf (ev, "[geo https://maps.google.com/?q=%.6lf,%.6lf", M->venue.geo.latitude, M->venue.geo.longitude); - + if (M->venue.title) { mprintf (ev, " title:'%s'", M->venue.title); } - + if (M->venue.address) { mprintf (ev, " address:'%s'", M->venue.address); } @@ -4004,7 +4004,7 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { mprintf (ev, "]"); return; - + default: mprintf (ev, "x = %d\n", M->type); assert (0); @@ -4055,7 +4055,7 @@ void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U) { } else if (!U->user.last_name || !strlen (U->user.last_name)) { mprintf (ev, "%s", U->user.first_name); } else { - mprintf (ev, "%s %s", U->user.first_name, U->user.last_name); + mprintf (ev, "%s %s", U->user.first_name, U->user.last_name); } if (U->flags & (TGLUF_SELF | TGLUF_CONTACT)) { mpop_color (ev); @@ -4190,7 +4190,7 @@ void print_service_message (struct in_ev *ev, struct tgl_message *M) { mprintf (ev, " "); print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id)); } - + switch (M->action.type) { case tgl_message_action_none: mprintf (ev, "\n"); @@ -4205,7 +4205,7 @@ void print_service_message (struct in_ev *ev, struct tgl_message *M) { mprintf (ev, " created chat %s. %d users\n", M->action.title, M->action.user_num); break; case tgl_message_action_chat_edit_title: - mprintf (ev, " changed title to %s\n", + mprintf (ev, " changed title to %s\n", M->action.new_title); break; case tgl_message_action_chat_edit_photo: @@ -4393,7 +4393,7 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { } } else { assert (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL); - + mpush_color (ev, COLOR_CYAN); print_msg_id (ev, M->permanent_id, M); mprintf (ev, " "); @@ -4461,8 +4461,8 @@ void set_interface_callbacks (void) { readline_active = 1; rl_filename_quote_characters = strdup (" "); rl_basic_word_break_characters = strdup (" "); - - + + rl_callback_handler_install (get_default_prompt (), interpreter); rl_completion_entry_function = command_generator; } diff --git a/json-tg.c b/json-tg.c index 91809bfc..ae5780c0 100644 --- a/json-tg.c +++ b/json-tg.c @@ -20,16 +20,16 @@ void json_pack_peer_type (json_t *res, tgl_peer_id_t id) { int x = tgl_get_peer_type (id); switch (x) { case TGL_PEER_USER: - assert (json_object_set (res, "peer_type", json_string ("user")) >= 0); + assert (json_object_set_new (res, "peer_type", json_string ("user")) >= 0); break; case TGL_PEER_CHAT: - assert (json_object_set (res, "peer_type", json_string ("chat")) >= 0); + assert (json_object_set_new (res, "peer_type", json_string ("chat")) >= 0); break; case TGL_PEER_ENCR_CHAT: - assert (json_object_set (res, "peer_type", json_string ("encr_chat")) >= 0); + assert (json_object_set_new (res, "peer_type", json_string ("encr_chat")) >= 0); break; case TGL_PEER_CHANNEL: - assert (json_object_set (res, "peer_type", json_string ("channel")) >= 0); + assert (json_object_set_new (res, "peer_type", json_string ("channel")) >= 0); break; default: assert (0); @@ -44,38 +44,38 @@ int str_format_time(long when, char* string) void json_pack_user (json_t *res, tgl_peer_t *P) { if (P->user.first_name) { - assert (json_object_set (res, "first_name", json_string (P->user.first_name)) >= 0); + assert (json_object_set_new (res, "first_name", json_string (P->user.first_name)) >= 0); } if (P->user.status.when) { static char s[20]; str_format_time(P->user.status.when, s); - assert (json_object_set (res, "when", json_string (s)) >= 0); + assert (json_object_set_new (res, "when", json_string (s)) >= 0); } if (P->user.last_name) { - assert (json_object_set (res, "last_name", json_string (P->user.last_name)) >= 0); + assert (json_object_set_new (res, "last_name", json_string (P->user.last_name)) >= 0); } if (P->user.real_first_name) { - assert (json_object_set (res, "real_first_name", json_string (P->user.real_first_name)) >= 0); + assert (json_object_set_new (res, "real_first_name", json_string (P->user.real_first_name)) >= 0); } if (P->user.real_last_name) { - assert (json_object_set (res, "real_last_name", json_string (P->user.real_last_name)) >= 0); + assert (json_object_set_new (res, "real_last_name", json_string (P->user.real_last_name)) >= 0); } if (P->user.phone) { - assert (json_object_set (res, "phone", json_string (P->user.phone)) >= 0); + assert (json_object_set_new (res, "phone", json_string (P->user.phone)) >= 0); } if (P->user.username) { - assert (json_object_set (res, "username", json_string (P->user.username)) >= 0); + assert (json_object_set_new (res, "username", json_string (P->user.username)) >= 0); } } void json_pack_chat (json_t *res, tgl_peer_t *P) { assert (P->chat.title); - assert (json_object_set (res, "title", json_string (P->chat.title)) >= 0); + assert (json_object_set_new (res, "title", json_string (P->chat.title)) >= 0); tgl_peer_id_t admin_id = TGL_MK_USER (P->chat.admin_id); - assert (json_object_set (res, "admin", json_pack_peer (admin_id)) >= 0); - assert (json_object_set (res, "members_num", json_integer (P->chat.users_num)) >= 0); + assert (json_object_set_new (res, "admin", json_pack_peer (admin_id)) >= 0); + assert (json_object_set_new (res, "members_num", json_integer (P->chat.users_num)) >= 0); if (P->chat.user_list) { json_t *m = json_array (); assert (m); @@ -85,38 +85,38 @@ void json_pack_chat (json_t *res, tgl_peer_t *P) { tgl_peer_id_t user_id = TGL_MK_USER (P->chat.user_list[i].user_id); tgl_peer_id_t inviter_id = TGL_MK_USER (P->chat.user_list[i].inviter_id); json_t *peer = json_pack_peer (user_id); - assert (json_object_set (peer, "inviter", json_pack_peer (inviter_id)) >= 0); - assert (json_array_append (m, peer) >= 0); + assert (json_object_set_new (peer, "inviter", json_pack_peer (inviter_id)) >= 0); + assert (json_array_append_new (m, peer) >= 0); } - assert (json_object_set (res, "members", m) >= 0); + assert (json_object_set_new (res, "members", m) >= 0); } } void json_pack_channel (json_t *res, tgl_peer_t *P) { assert (P->channel.title); - assert (json_object_set (res, "title", json_string (P->channel.title)) >= 0); - assert (json_object_set (res, "participants_count", json_integer (P->channel.participants_count)) >= 0); - assert (json_object_set (res, "admins_count", json_integer (P->channel.admins_count)) >= 0); - assert (json_object_set (res, "kicked_count", json_integer (P->channel.kicked_count)) >= 0); + assert (json_object_set_new (res, "title", json_string (P->channel.title)) >= 0); + assert (json_object_set_new (res, "participants_count", json_integer (P->channel.participants_count)) >= 0); + assert (json_object_set_new (res, "admins_count", json_integer (P->channel.admins_count)) >= 0); + assert (json_object_set_new (res, "kicked_count", json_integer (P->channel.kicked_count)) >= 0); } void json_pack_encr_chat (json_t *res, tgl_peer_t *P) { - assert (json_object_set (res, "user", json_pack_peer (TGL_MK_USER (P->encr_chat.user_id))) >= 0); + assert (json_object_set_new (res, "user", json_pack_peer (TGL_MK_USER (P->encr_chat.user_id))) >= 0); } json_t *json_pack_peer (tgl_peer_id_t id) { tgl_peer_t *P = tgl_peer_get (TLS, id); //assert (P); json_t *res = json_object (); - assert (json_object_set (res, "id", json_string (print_permanent_peer_id (id))) >= 0); + assert (json_object_set_new (res, "id", json_string (print_permanent_peer_id (id))) >= 0); json_pack_peer_type (res, id); - assert (json_object_set (res, "peer_id", json_integer (tgl_get_peer_id (id))) >= 0); + assert (json_object_set_new (res, "peer_id", json_integer (tgl_get_peer_id (id))) >= 0); assert (res); - + if (!P || !(P->flags & TGLPF_CREATED)) { static char s[100]; switch (tgl_get_peer_type (id)) { @@ -135,17 +135,17 @@ json_t *json_pack_peer (tgl_peer_id_t id) { default: assert (0); } - - assert (json_object_set (res, "print_name", json_string (s)) >= 0); + + assert (json_object_set_new (res, "print_name", json_string (s)) >= 0); return res; } if(P->print_name != NULL){ - assert (json_object_set (res, "print_name", json_string (P->print_name)) >= 0); + assert (json_object_set_new (res, "print_name", json_string (P->print_name)) >= 0); } else { - assert (json_object_set (res, "print_name", json_string ("")) >= 0); + assert (json_object_set_new (res, "print_name", json_string ("")) >= 0); } - assert (json_object_set (res, "flags", json_integer (P->flags)) >= 0); - + assert (json_object_set_new (res, "flags", json_integer (P->flags)) >= 0); + switch (tgl_get_peer_type (id)) { case TGL_PEER_USER: json_pack_user (res, P); @@ -167,51 +167,54 @@ json_t *json_pack_peer (tgl_peer_id_t id) { json_t *json_pack_updates (unsigned flags) { json_t *a = json_array (); - + if (flags & TGL_UPDATE_CREATED) { - assert (json_array_append (a, json_string ("created")) >= 0); - } + assert (json_array_append_new (a, json_string ("created")) >= 0); + } if (flags & TGL_UPDATE_DELETED) { - assert (json_array_append (a, json_string ("deleted")) >= 0); - } + assert (json_array_append_new (a, json_string ("deleted")) >= 0); + } if (flags & TGL_UPDATE_PHONE) { - assert (json_array_append (a, json_string ("phone")) >= 0); + assert (json_array_append_new (a, json_string ("phone")) >= 0); } if (flags & TGL_UPDATE_CONTACT) { - assert (json_array_append (a, json_string ("contact")) >= 0); + assert (json_array_append_new (a, json_string ("contact")) >= 0); } if (flags & TGL_UPDATE_PHOTO) { - assert (json_array_append (a, json_string ("photo")) >= 0); + assert (json_array_append_new (a, json_string ("photo")) >= 0); } if (flags & TGL_UPDATE_BLOCKED) { - assert (json_array_append (a, json_string ("blocked")) >= 0); + assert (json_array_append_new (a, json_string ("blocked")) >= 0); } if (flags & TGL_UPDATE_REAL_NAME) { - assert (json_array_append (a, json_string ("real_name")) >= 0); + assert (json_array_append_new (a, json_string ("real_name")) >= 0); } if (flags & TGL_UPDATE_NAME) { - assert (json_array_append (a, json_string ("name")) >= 0); + assert (json_array_append_new (a, json_string ("name")) >= 0); } if (flags & TGL_UPDATE_REQUESTED) { - assert (json_array_append (a, json_string ("requested")) >= 0); + assert (json_array_append_new (a, json_string ("requested")) >= 0); } if (flags & TGL_UPDATE_WORKING) { - assert (json_array_append (a, json_string ("working")) >= 0); + assert (json_array_append_new (a, json_string ("working")) >= 0); } if (flags & TGL_UPDATE_FLAGS) { - assert (json_array_append (a, json_string ("flags")) >= 0); + assert (json_array_append_new (a, json_string ("flags")) >= 0); } if (flags & TGL_UPDATE_TITLE) { - assert (json_array_append (a, json_string ("title")) >= 0); + assert (json_array_append_new (a, json_string ("title")) >= 0); } if (flags & TGL_UPDATE_ADMIN) { - assert (json_array_append (a, json_string ("admin")) >= 0); + assert (json_array_append_new (a, json_string ("admin")) >= 0); } if (flags & TGL_UPDATE_MEMBERS) { - assert (json_array_append (a, json_string ("members")) >= 0); + assert (json_array_append_new (a, json_string ("members")) >= 0); + } + if (flags & TGL_UPDATE_ACCESS_HASH) { + assert (json_array_append_new (a, json_string ("access_hash")) >= 0); } if (flags & TGL_UPDATE_USERNAME) { - assert (json_array_append (a, json_string ("username")) >= 0); + assert (json_array_append_new (a, json_string ("username")) >= 0); } return a; @@ -223,72 +226,72 @@ json_t *json_pack_media (struct tgl_message_media *M) { switch (M->type) { case tgl_message_media_photo: - assert (json_object_set (res, "type", json_string ("photo")) >= 0); + assert (json_object_set_new (res, "type", json_string ("photo")) >= 0); if (M->caption) { - assert (json_object_set (res, "caption", json_string (M->caption)) >= 0); + assert (json_object_set_new (res, "caption", json_string (M->caption)) >= 0); } break; case tgl_message_media_document: - assert (json_object_set (res, "type", json_string ("document")) >= 0); + assert (json_object_set_new (res, "type", json_string ("document")) >= 0); break; case tgl_message_media_audio: - assert (json_object_set (res, "type", json_string ("audio")) >= 0); + assert (json_object_set_new (res, "type", json_string ("audio")) >= 0); break; case tgl_message_media_video: - assert (json_object_set (res, "type", json_string ("video")) >= 0); + assert (json_object_set_new (res, "type", json_string ("video")) >= 0); break; case tgl_message_media_document_encr: - assert (json_object_set (res, "type", json_string ("document_encr")) >= 0); + assert (json_object_set_new (res, "type", json_string ("document_encr")) >= 0); break; case tgl_message_media_unsupported: - assert (json_object_set (res, "type", json_string ("unsupported")) >= 0); + assert (json_object_set_new (res, "type", json_string ("unsupported")) >= 0); break; case tgl_message_media_geo: - assert (json_object_set (res, "type", json_string ("geo")) >= 0); - assert (json_object_set (res, "longitude", json_real (M->geo.longitude)) >= 0); - assert (json_object_set (res, "latitude", json_real (M->geo.latitude)) >= 0); + assert (json_object_set_new (res, "type", json_string ("geo")) >= 0); + assert (json_object_set_new (res, "longitude", json_real (M->geo.longitude)) >= 0); + assert (json_object_set_new (res, "latitude", json_real (M->geo.latitude)) >= 0); break; case tgl_message_media_contact: - assert (json_object_set (res, "type", json_string ("contact")) >= 0); - assert (json_object_set (res, "phone", json_string (M->phone)) >= 0); - assert (json_object_set (res, "first_name", json_string (M->first_name)) >= 0); - assert (json_object_set (res, "last_name", json_string (M->last_name)) >= 0); - assert (json_object_set (res, "user_id", json_integer (M->user_id)) >= 0); + assert (json_object_set_new (res, "type", json_string ("contact")) >= 0); + assert (json_object_set_new (res, "phone", json_string (M->phone)) >= 0); + assert (json_object_set_new (res, "first_name", json_string (M->first_name)) >= 0); + assert (json_object_set_new (res, "last_name", json_string (M->last_name)) >= 0); + assert (json_object_set_new (res, "user_id", json_integer (M->user_id)) >= 0); break; case tgl_message_media_webpage: - assert (json_object_set (res, "type", json_string ("webpage")) >= 0); + assert (json_object_set_new (res, "type", json_string ("webpage")) >= 0); if (M->webpage->url) { - assert (json_object_set (res, "url", json_string (M->webpage->url)) >= 0); + assert (json_object_set_new (res, "url", json_string (M->webpage->url)) >= 0); } if (M->webpage->title) { - assert (json_object_set (res, "title", json_string (M->webpage->title)) >= 0); + assert (json_object_set_new (res, "title", json_string (M->webpage->title)) >= 0); } if (M->webpage->description) { - assert (json_object_set (res, "description", json_string (M->webpage->description)) >= 0); + assert (json_object_set_new (res, "description", json_string (M->webpage->description)) >= 0); } if (M->webpage->author) { - assert (json_object_set (res, "author", json_string (M->webpage->author)) >= 0); + assert (json_object_set_new (res, "author", json_string (M->webpage->author)) >= 0); } break; case tgl_message_media_venue: - assert (json_object_set (res, "type", json_string ("venue")) >= 0); - assert (json_object_set (res, "longitude", json_real (M->venue.geo.longitude)) >= 0); - assert (json_object_set (res, "latitude", json_real (M->venue.geo.latitude)) >= 0); + assert (json_object_set_new (res, "type", json_string ("venue")) >= 0); + assert (json_object_set_new (res, "longitude", json_real (M->venue.geo.longitude)) >= 0); + assert (json_object_set_new (res, "latitude", json_real (M->venue.geo.latitude)) >= 0); if (M->venue.title) { - assert (json_object_set (res, "title", json_string (M->venue.title)) >= 0); + assert (json_object_set_new (res, "title", json_string (M->venue.title)) >= 0); } if (M->venue.address) { - assert (json_object_set (res, "address", json_string (M->venue.address)) >= 0); + assert (json_object_set_new (res, "address", json_string (M->venue.address)) >= 0); } if (M->venue.provider) { - assert (json_object_set (res, "provider", json_string (M->venue.provider)) >= 0); + assert (json_object_set_new (res, "provider", json_string (M->venue.provider)) >= 0); } if (M->venue.venue_id) { - assert (json_object_set (res, "venue_id", json_string (M->venue.venue_id)) >= 0); + assert (json_object_set_new (res, "venue_id", json_string (M->venue.venue_id)) >= 0); } break; default: - assert (json_object_set (res, "type", json_string ("unknown")) >= 0); + assert (json_object_set_new (res, "type", json_string ("unknown")) >= 0); } return res; } @@ -297,40 +300,40 @@ json_t *json_pack_typing (enum tgl_typing_status status) { json_t *res = json_object (); switch (status) { case tgl_typing_none: - assert (json_object_set (res, "status", json_string ("doing nothing")) >= 0); + assert (json_object_set_new (res, "status", json_string ("doing nothing")) >= 0); break; case tgl_typing_typing: - assert (json_object_set (res, "status", json_string ("typing")) >= 0); + assert (json_object_set_new (res, "status", json_string ("typing")) >= 0); break; case tgl_typing_cancel: - assert (json_object_set (res, "status", json_string ("deleting typed message")) >= 0); + assert (json_object_set_new (res, "status", json_string ("deleting typed message")) >= 0); break; case tgl_typing_record_video: - assert (json_object_set (res, "status", json_string ("recording video")) >= 0); + assert (json_object_set_new (res, "status", json_string ("recording video")) >= 0); break; case tgl_typing_upload_video: - assert (json_object_set (res, "status", json_string ("uploading video")) >= 0); + assert (json_object_set_new (res, "status", json_string ("uploading video")) >= 0); break; case tgl_typing_record_audio: - assert (json_object_set (res, "status", json_string ("recording audio")) >= 0); + assert (json_object_set_new (res, "status", json_string ("recording audio")) >= 0); break; case tgl_typing_upload_audio: - assert (json_object_set (res, "status", json_string ("uploading audio")) >= 0); + assert (json_object_set_new (res, "status", json_string ("uploading audio")) >= 0); break; case tgl_typing_upload_photo: - assert (json_object_set (res, "status", json_string ("uploading photo")) >= 0); + assert (json_object_set_new (res, "status", json_string ("uploading photo")) >= 0); break; case tgl_typing_upload_document: - assert (json_object_set (res, "status", json_string ("uploading document")) >= 0); + assert (json_object_set_new (res, "status", json_string ("uploading document")) >= 0); break; case tgl_typing_geo: - assert (json_object_set (res, "status", json_string ("choosing location")) >= 0); + assert (json_object_set_new (res, "status", json_string ("choosing location")) >= 0); break; case tgl_typing_choose_contact: - assert (json_object_set (res, "status", json_string ("choosing contact")) >= 0); + assert (json_object_set_new (res, "status", json_string ("choosing contact")) >= 0); break; default: - assert (json_object_set (res, "status", json_string ("unknown")) >= 0); + assert (json_object_set_new (res, "status", json_string ("unknown")) >= 0); break; } return res; @@ -340,164 +343,164 @@ json_t *json_pack_service (struct tgl_message *M) { json_t *res = json_object (); switch (M->action.type) { case tgl_message_action_geo_chat_create: - assert (json_object_set (res, "type", json_string ("geo_created")) >= 0); + assert (json_object_set_new (res, "type", json_string ("geo_created")) >= 0); break; case tgl_message_action_geo_chat_checkin: - assert (json_object_set (res, "type", json_string ("geo_checkin")) >= 0); + assert (json_object_set_new (res, "type", json_string ("geo_checkin")) >= 0); break; case tgl_message_action_chat_create: - assert (json_object_set (res, "type", json_string ("chat_created")) >= 0); - assert (json_object_set (res, "title", json_string (M->action.title)) >= 0); + assert (json_object_set_new (res, "type", json_string ("chat_created")) >= 0); + assert (json_object_set_new (res, "title", json_string (M->action.title)) >= 0); break; case tgl_message_action_chat_edit_title: - assert (json_object_set (res, "type", json_string ("chat_rename")) >= 0); - assert (json_object_set (res, "title", json_string (M->action.title)) >= 0); + assert (json_object_set_new (res, "type", json_string ("chat_rename")) >= 0); + assert (json_object_set_new (res, "title", json_string (M->action.title)) >= 0); break; case tgl_message_action_chat_edit_photo: - assert (json_object_set (res, "type", json_string ("chat_change_photo")) >= 0); + assert (json_object_set_new (res, "type", json_string ("chat_change_photo")) >= 0); break; case tgl_message_action_chat_delete_photo: - assert (json_object_set (res, "type", json_string ("chat_delete_photo")) >= 0); + assert (json_object_set_new (res, "type", json_string ("chat_delete_photo")) >= 0); break; case tgl_message_action_chat_add_users: - assert (json_object_set (res, "type", json_string ("chat_add_user")) >= 0); - assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.users[0]))) >= 0); + assert (json_object_set_new (res, "type", json_string ("chat_add_user")) >= 0); + assert (json_object_set_new (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.users[0]))) >= 0); break; case tgl_message_action_chat_add_user_by_link: - assert (json_object_set (res, "type", json_string ("chat_add_user_link")) >= 0); - assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); + assert (json_object_set_new (res, "type", json_string ("chat_add_user_link")) >= 0); + assert (json_object_set_new (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); break; case tgl_message_action_chat_delete_user: - assert (json_object_set (res, "type", json_string ("chat_del_user")) >= 0); - assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); + assert (json_object_set_new (res, "type", json_string ("chat_del_user")) >= 0); + assert (json_object_set_new (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); break; case tgl_message_action_set_message_ttl: - assert (json_object_set (res, "type", json_string ("set_ttl")) >= 0); - assert (json_object_set (res, "ttl", json_integer (M->action.ttl)) >= 0); + assert (json_object_set_new (res, "type", json_string ("set_ttl")) >= 0); + assert (json_object_set_new (res, "ttl", json_integer (M->action.ttl)) >= 0); break; case tgl_message_action_read_messages: - assert (json_object_set (res, "type", json_string ("read")) >= 0); - assert (json_object_set (res, "count", json_integer (M->action.read_cnt)) >= 0); + assert (json_object_set_new (res, "type", json_string ("read")) >= 0); + assert (json_object_set_new (res, "count", json_integer (M->action.read_cnt)) >= 0); break; case tgl_message_action_delete_messages: - assert (json_object_set (res, "type", json_string ("delete")) >= 0); - assert (json_object_set (res, "count", json_integer (M->action.delete_cnt)) >= 0); + assert (json_object_set_new (res, "type", json_string ("delete")) >= 0); + assert (json_object_set_new (res, "count", json_integer (M->action.delete_cnt)) >= 0); break; case tgl_message_action_screenshot_messages: - assert (json_object_set (res, "type", json_string ("screenshot")) >= 0); - assert (json_object_set (res, "count", json_integer (M->action.screenshot_cnt)) >= 0); + assert (json_object_set_new (res, "type", json_string ("screenshot")) >= 0); + assert (json_object_set_new (res, "count", json_integer (M->action.screenshot_cnt)) >= 0); break; case tgl_message_action_flush_history: - assert (json_object_set (res, "type", json_string ("flush")) >= 0); + assert (json_object_set_new (res, "type", json_string ("flush")) >= 0); break; case tgl_message_action_resend: - assert (json_object_set (res, "type", json_string ("resend")) >= 0); + assert (json_object_set_new (res, "type", json_string ("resend")) >= 0); break; case tgl_message_action_notify_layer: - assert (json_object_set (res, "type", json_string ("notify_layer")) >= 0); - assert (json_object_set (res, "layer", json_integer (M->action.layer)) >= 0); + assert (json_object_set_new (res, "type", json_string ("notify_layer")) >= 0); + assert (json_object_set_new (res, "layer", json_integer (M->action.layer)) >= 0); break; - case tgl_message_action_typing: - assert (json_object_set (res, "type", json_string ("typing")) >= 0); - assert (json_array_append (res, json_pack_typing (M->action.typing)) >= 0); + case tgl_message_action_typing: + assert (json_object_set_new (res, "type", json_string ("typing")) >= 0); + assert (json_array_append_new (res, json_pack_typing (M->action.typing)) >= 0); break; case tgl_message_action_noop: - assert (json_object_set (res, "type", json_string ("noop")) >= 0); + assert (json_object_set_new (res, "type", json_string ("noop")) >= 0); break; case tgl_message_action_request_key: - assert (json_object_set (res, "type", json_string ("request_key")) >= 0); + assert (json_object_set_new (res, "type", json_string ("request_key")) >= 0); break; case tgl_message_action_accept_key: - assert (json_object_set (res, "type", json_string ("accept_key")) >= 0); + assert (json_object_set_new (res, "type", json_string ("accept_key")) >= 0); break; case tgl_message_action_commit_key: - assert (json_object_set (res, "type", json_string ("commit_key")) >= 0); + assert (json_object_set_new (res, "type", json_string ("commit_key")) >= 0); break; case tgl_message_action_abort_key: - assert (json_object_set (res, "type", json_string ("abort_key")) >= 0); + assert (json_object_set_new (res, "type", json_string ("abort_key")) >= 0); break; case tgl_message_action_channel_create: - assert (json_object_set (res, "type", json_string ("channel_created")) >= 0); - assert (json_object_set (res, "title", json_string (M->action.title)) >= 0); + assert (json_object_set_new (res, "type", json_string ("channel_created")) >= 0); + assert (json_object_set_new (res, "title", json_string (M->action.title)) >= 0); break; case tgl_message_action_migrated_to: - assert (json_object_set (res, "type", json_string ("migrated_to")) >= 0); + assert (json_object_set_new (res, "type", json_string ("migrated_to")) >= 0); break; case tgl_message_action_migrated_from: - assert (json_object_set (res, "type", json_string ("migrated_from")) >= 0); + assert (json_object_set_new (res, "type", json_string ("migrated_from")) >= 0); break; default: - assert (json_object_set (res, "type", json_string ("unknown")) >= 0); + assert (json_object_set_new (res, "type", json_string ("unknown")) >= 0); break; } return res; } -json_t *json_pack_message (struct tgl_message *M) { +json_t *json_pack_message (struct tgl_message *M) { json_t *res = json_object (); - assert (json_object_set (res, "event", json_string ("message")) >= 0); + assert (json_object_set_new (res, "event", json_string ("message")) >= 0); //will overwriten to service, if service. - assert (json_object_set (res, "id", json_string (print_permanent_msg_id (M->permanent_id))) >= 0); + assert (json_object_set_new (res, "id", json_string (print_permanent_msg_id (M->permanent_id))) >= 0); if (!(M->flags & TGLMF_CREATED)) { return res; } - assert (json_object_set (res, "flags", json_integer (M->flags)) >= 0); - + assert (json_object_set_new (res, "flags", json_integer (M->flags)) >= 0); + if (tgl_get_peer_type (M->fwd_from_id)) { - assert (json_object_set (res, "fwd_from", json_pack_peer (M->fwd_from_id)) >= 0); - assert (json_object_set (res, "fwd_date", json_integer (M->fwd_date)) >= 0); + assert (json_object_set_new (res, "fwd_from", json_pack_peer (M->fwd_from_id)) >= 0); + assert (json_object_set_new (res, "fwd_date", json_integer (M->fwd_date)) >= 0); } if (M->reply_id) { tgl_message_id_t msg_id = M->permanent_id; msg_id.id = M->reply_id; - - assert (json_object_set (res, "reply_id", json_string (print_permanent_msg_id (msg_id))) >= 0); + + assert (json_object_set_new (res, "reply_id", json_string (print_permanent_msg_id (msg_id))) >= 0); } if (M->flags & TGLMF_MENTION) { - assert (json_object_set (res, "mention", json_true ()) >= 0); - } - - assert (json_object_set (res, "from", json_pack_peer (M->from_id)) >= 0); - assert (json_object_set (res, "to", json_pack_peer (M->to_id)) >= 0); - - assert (json_object_set (res, "out", json_boolean (M->flags & TGLMF_OUT)) >= 0); - assert (json_object_set (res, "unread", json_boolean (M->flags & TGLMF_UNREAD)) >= 0); - assert (json_object_set (res, "service", json_boolean (M->flags & TGLMF_SERVICE)) >= 0); - assert (json_object_set (res, "date", json_integer (M->date)) >= 0); - - if (!(M->flags & TGLMF_SERVICE)) { + assert (json_object_set_new (res, "mention", json_true ()) >= 0); + } + + assert (json_object_set_new (res, "from", json_pack_peer (M->from_id)) >= 0); + assert (json_object_set_new (res, "to", json_pack_peer (M->to_id)) >= 0); + + assert (json_object_set_new (res, "out", json_boolean (M->flags & TGLMF_OUT)) >= 0); + assert (json_object_set_new (res, "unread", json_boolean (M->flags & TGLMF_UNREAD)) >= 0); + assert (json_object_set_new (res, "service", json_boolean (M->flags & TGLMF_SERVICE)) >= 0); + assert (json_object_set_new (res, "date", json_integer (M->date)) >= 0); + + if (!(M->flags & TGLMF_SERVICE)) { if (M->message_len && M->message) { - assert (json_object_set (res, "text", json_string (M->message)) >= 0); + assert (json_object_set_new (res, "text", json_string (M->message)) >= 0); } if (M->media.type && M->media.type != tgl_message_media_none) { - assert (json_object_set (res, "media", json_pack_media (&M->media)) >= 0); + assert (json_object_set_new (res, "media", json_pack_media (&M->media)) >= 0); } } else { - assert (json_object_set (res, "event", json_string ("service")) >= 0); - assert (json_object_set (res, "action", json_pack_service (M)) >= 0); + assert (json_object_set_new (res, "event", json_string ("service")) >= 0); + assert (json_object_set_new (res, "action", json_pack_service (M)) >= 0); } return res; } json_t *json_pack_read (struct tgl_message *M) { json_t *res = json_pack_message (M); - assert (json_object_set (res, "event", json_string ("read")) >= 0); + assert (json_object_set_new (res, "event", json_string ("read")) >= 0); //this will overwrite "event":"message" to "event":"read". return res; } json_t *json_pack_user_status (struct tgl_user *U) { json_t *res = json_object (); - assert (json_object_set (res, "user", json_pack_peer (U->id)) >= 0); + assert (json_object_set_new (res, "user", json_pack_peer (U->id)) >= 0); struct tgl_user_status *S = &U->status; - assert (json_object_set (res, "online", json_boolean (S->online == 1)) >= 0); - assert (json_object_set (res, "state", json_integer (S->online)) >= 0); + assert (json_object_set_new (res, "online", json_boolean (S->online == 1)) >= 0); + assert (json_object_set_new (res, "state", json_integer (S->online)) >= 0); if (S->online > 0 || S->online == -1) { static char s[20]; str_format_time(S->when, s); - assert (json_object_set (res, "when", json_string (s)) >= 0); + assert (json_object_set_new (res, "when", json_string (s)) >= 0); } else if (S->online == 0) { assert (json_object_set(res, "when", json_string("long time ago")) >= 0); } else if (S->online == -2) { @@ -505,9 +508,9 @@ json_t *json_pack_user_status (struct tgl_user *U) { } else if (S->online == -3) { assert (json_object_set(res, "when", json_string("last week")) >= 0); } else if (S->online == -4) { - assert (json_object_set (res, "when", json_string ("last month")) >= 0); + assert (json_object_set_new (res, "when", json_string ("last month")) >= 0); } - assert (json_object_set (res, "event", json_string ("online-status")) >= 0); + assert (json_object_set_new (res, "event", json_string ("online-status")) >= 0); //this will overwrite "event":"message" to "event":"read". return res; } From e4ad461effb05a372869ed40fca4dec747c68b6a Mon Sep 17 00:00:00 2001 From: Leo Arias Date: Fri, 16 Sep 2016 20:23:15 +0000 Subject: [PATCH 090/164] Add the packaging metadata to build the Telegram CLI snap --- parts/plugins/x-autotools.py | 65 ++++++++++++++++++++++++++++++++++++ snapcraft.yaml | 33 ++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 parts/plugins/x-autotools.py create mode 100644 snapcraft.yaml diff --git a/parts/plugins/x-autotools.py b/parts/plugins/x-autotools.py new file mode 100644 index 00000000..9e044846 --- /dev/null +++ b/parts/plugins/x-autotools.py @@ -0,0 +1,65 @@ +# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- + +"""This is a modified version of snapcraft's autootools plugin. + +This plugin uses the common plugin keywords as well as those for "sources". +For more information check the 'plugins' topic for the former and the +'sources' topic for the latter. + +In addition, this plugin uses the following plugin-specific keywords: + + - configflags: + (list of strings) + configure flags to pass to the build such as those shown by running + './configure --help' +""" + +import os + +import snapcraft + + +class AutotoolsPlugin(snapcraft.BasePlugin): + + @classmethod + def schema(cls): + schema = super().schema() + schema['properties']['configflags'] = { + 'type': 'array', + 'minitems': 1, + 'uniqueItems': True, + 'items': { + 'type': 'string', + }, + 'default': [], + } + schema['properties']['artifacts'] = { + 'type': 'array', + 'minitems': 1, + 'uniqueItems': True, + 'items': { + 'type': 'string', + }, + 'default': [], + } + + # Inform Snapcraft of the properties associated with building. If these + # change in the YAML, Snapcraft will consider the build step dirty. + schema['build-properties'].extend(['configflags']) + + return schema + + def __init__(self, name, options, project): + super().__init__(name, options, project) + self.build_packages.append('make') + + def build(self): + super().build() + self.run(['./configure'] + self.options.configflags) + self.run(['make', '-j{}'.format(self.parallel_build_count)]) + for artifact in self.options.artifacts: + source_path = os.path.join(self.builddir, artifact) + destination_path = os.path.join(self.installdir, artifact) + os.makedirs(os.path.dirname(destination_path), exist_ok=True) + snapcraft.file_utils.link_or_copy( + source_path, destination_path) diff --git a/snapcraft.yaml b/snapcraft.yaml new file mode 100644 index 00000000..6e8e6135 --- /dev/null +++ b/snapcraft.yaml @@ -0,0 +1,33 @@ +name: telegram-cli +version: master +summary: Command-line interface for Telegram +description: | + Command-line interface for Telegram, the mssaging app with a focus on + security and speed. + +grade: devel +confinement: strict + +apps: + telegram-cli: + command: telegram-cli + plugs: [network] + +parts: + tg: + source: . + plugin: autotools + build-packages: + - g++ + - libreadline-dev + - libconfig-dev + - libssl-dev + - lua5.2 + - liblua5.2-dev + - libevent-dev + - libjansson-dev + - libpython-dev + artifacts: + - bin/generate + - bin/telegram-cli + - bin/tl-parser From 7a1e0a03431959044649bb386de2c58fb9bd7f7a Mon Sep 17 00:00:00 2001 From: Aidan Lloyd-Tucker Date: Sat, 1 Oct 2016 13:36:24 -0700 Subject: [PATCH 091/164] Added unread to dialog list --- interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/interface.c b/interface.c index 002dacd4..da61c258 100644 --- a/interface.c +++ b/interface.c @@ -2838,6 +2838,7 @@ void print_dialog_list_gw (struct tgl_state *TLSR, void *extra, int success, int int i; for (i = size - 1; i >= 0; i--) { json_t *a = json_pack_peer (peers[i]); + assert (json_object_set_new (a, "unread", json_integer (unread_count[i])) >= 0); assert (json_array_append_new (res, a) >= 0); } char *s = json_dumps (res, 0); From db864f8a05ed9b09f66afe7e4ea27a002a8b1912 Mon Sep 17 00:00:00 2001 From: Valerio Date: Wed, 5 Oct 2016 10:04:00 +0200 Subject: [PATCH 092/164] Build status for the correct project linked --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..ad3e7b69 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) +## Telegram messenger CLI [![Build Status](https://github.com/kolmogorov42/tg)](https://github.com/kolmogorov42/tg) Command-line interface for [Telegram](http://telegram.org). Uses readline interface. From d77bc81d4168c31e36281c6ee0bcba64ab9ad772 Mon Sep 17 00:00:00 2001 From: Valerio Date: Wed, 5 Oct 2016 10:10:38 +0200 Subject: [PATCH 093/164] travis-ci build status for the cygwin branch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad3e7b69..e9c56c95 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Telegram messenger CLI [![Build Status](https://github.com/kolmogorov42/tg)](https://github.com/kolmogorov42/tg) +## Telegram messenger CLI [![Build Status](https://travis-ci.org/kolmogorov42/tg.svg?branch=cygwin)](https://travis-ci.org/kolmogorov42/tg) Command-line interface for [Telegram](http://telegram.org). Uses readline interface. From e978bd9f5b53f8a49f5bf7b1663f65bc2edf7fea Mon Sep 17 00:00:00 2001 From: ComputeThis Date: Tue, 25 Oct 2016 21:34:10 +0300 Subject: [PATCH 094/164] Update Debian installation instructions Instructions on how to compile & install the Debian package. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..75f36e8c 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,9 @@ If you do not want to use them pass options --disable-libconfig, --disable-liblu On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make + sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make dpkg-dev debhelper autoconf-archive lua-lgi + dpkg-buildpackage -b + sudo dpkg -i ../telegram-cli_x.x.x-x_amd64.deb On gentoo: From d63728ae106ae3b7c1b6d4944ba3537db5a72418 Mon Sep 17 00:00:00 2001 From: Artem Date: Thu, 3 Nov 2016 13:03:13 +0300 Subject: [PATCH 095/164] Add key -X for launching from specific config directory, instead of /.telegram-cli --- CHANGELOG | 4 ++++ main.c | 20 +++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4ee66d02..b29e0d37 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +1.3.4 +* set config directory with key -X +* TGL-2.0.3 + 1.3.3 * support for sending custom keyboard * fixed contact_search diff --git a/main.c b/main.c index 4776f073..e768414a 100644 --- a/main.c +++ b/main.c @@ -100,6 +100,7 @@ char *state_file_name; char *secret_chat_file_name; char *downloads_directory; char *config_directory; +char *config_directory_force; char *binlog_file_name; char *lua_file; char *python_file; @@ -360,8 +361,16 @@ void parse_config (void) { config_lookup_bool (&conf, buf, &msg_num_mode); } - parse_config_val (&conf, &config_directory, "config_directory", CONFIG_DIRECTORY, 0); - config_directory = make_full_path (config_directory); + if( config_directory_force ){ + config_directory = config_directory_force; + + if( !disable_output ){ + printf( "Config directory force: [%s]\n", config_directory_force ); + } + }else{ + parse_config_val (&conf, &config_directory, "config_directory", CONFIG_DIRECTORY, 0); + config_directory = make_full_path (config_directory); + } parse_config_val (&conf, &auth_file_name, "auth_file", AUTH_KEY_FILE, config_directory); parse_config_val (&conf, &downloads_directory, "downloads", DOWNLOADS_DIRECTORY, config_directory); @@ -454,6 +463,7 @@ void usage (void) { printf (" --enable-msg-id/-N message num mode\n"); #ifdef HAVE_LIBCONFIG printf (" --config/-c config file name\n"); + printf (" --force-config-dir/-x set force config dir instead of profile\n"); printf (" --profile/-p use specified profile\n"); #else #if 0 @@ -610,6 +620,7 @@ void args_parse (int argc, char **argv) { {"enable-msg-id", no_argument, 0, 'N'}, #ifdef HAVE_LIBCONFIG {"config", required_argument, 0, 'c'}, + {"force-config-dir", required_argument, 0, 'X'}, {"profile", required_argument, 0, 'p'}, #else #if 0 @@ -652,7 +663,7 @@ void args_parse (int argc, char **argv) { int opt = 0; - while ((opt = getopt_long (argc, argv, "u:hk:vNl:fEwWCRAdL:DU:G:qP:S:e:I6b" + while ((opt = getopt_long (argc, argv, "u:hk:vNl:fEwWCRAdL:DU:G:qP:X:S:e:I6b" #ifdef HAVE_LIBCONFIG "c:p:" #else @@ -700,6 +711,9 @@ void args_parse (int argc, char **argv) { case 'c': config_filename = tstrdup (optarg); break; + case 'X': + config_directory_force = tstrdup (optarg); + break; case 'p': prefix = optarg; assert (strlen (prefix) <= 100); From 0369fcefa19106dce7d0bb0bfba1f6fedbdfb6c6 Mon Sep 17 00:00:00 2001 From: elviraux Date: Sat, 12 Nov 2016 16:07:24 +0500 Subject: [PATCH 096/164] misspelling --- debian/telegram-cli.upstart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/telegram-cli.upstart b/debian/telegram-cli.upstart index 21e074bc..64ce3e77 100644 --- a/debian/telegram-cli.upstart +++ b/debian/telegram-cli.upstart @@ -5,6 +5,6 @@ setgid telegramd script exec /usr/bin/telegram-cli -s /var/lib/telegram-cli/test.lua -W -d -C -vvvv -l 0 -L /var/lib/telegram-cli/telegram-cli.log -P 8002 - # This example for Daemon wich keep log in his home directory + # This example for Daemon which keep log in his home directory # This daemon can listen localhost:8002 tcp port end script From c4bead01d1b116bcae23dec5633f0b825fda5b90 Mon Sep 17 00:00:00 2001 From: George Jose Date: Thu, 17 Nov 2016 13:38:30 -0500 Subject: [PATCH 097/164] Updated build instructions to work on Sierra - Updated readline path - Added openssl lib & include paths to LDFLAGS & CFLAGS respectively --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a9e0fa6..ef01ffc7 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,12 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea If using [Homebrew](http://brew.sh/): brew install libconfig readline lua python libevent jansson - 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" + export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/7.0/include -I/usr/local/opt/openssl/include" + export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/7.0/lib -L/usr/local/opt/openssl/lib" ./configure && make +If you get a lua error on Sierra, you can configure & build without lua using + + ./configure --disable-liblua && make Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. From 627868e3478b9a7a88892023aceb5385dfb34b2c Mon Sep 17 00:00:00 2001 From: AnTo 'SamalonA Date: Wed, 18 Jan 2017 22:45:34 +0800 Subject: [PATCH 098/164] modified rules file --- debian/rules | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/rules b/debian/rules index 54f91471..e8e8cbcd 100755 --- a/debian/rules +++ b/debian/rules @@ -9,8 +9,10 @@ # Uncomment this to turn on verbose mode. export DH_VERBOSE=1 -VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') -PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') + VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') + PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') +override_dh_auto_configure: + ./configure --disable-openssl %: dh $@ --with autotools-dev build-orig: From 7fad505c344fdee68ea2af1096dc9357e50a8019 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Fri, 10 Feb 2017 23:49:47 +0000 Subject: [PATCH 099/164] Use correct default config file path on Mac OS X. --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 4776f073..cfa74113 100644 --- a/main.c +++ b/main.c @@ -990,7 +990,7 @@ int main (int argc, char **argv) { running_for_first_time (); parse_config (); - #ifdef __FreeBSD__ + #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)) tgl_set_rsa_key (TLS, "/usr/local/etc/" PROG_NAME "/server.pub"); #else tgl_set_rsa_key (TLS, "/etc/" PROG_NAME "/server.pub"); From 5f130b474fd7a8f82831cfb07ef8ea0962425660 Mon Sep 17 00:00:00 2001 From: Massimo Santini Date: Mon, 27 Feb 2017 11:39:26 +0100 Subject: [PATCH 100/164] Fixed OSX build instruction for homebrew Added a fix according to https://github.com/vysheng/tg/issues/811#issuecomment-156705551 that fixes the problem and does not pin to a specific libreadline or openssl version. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a9e0fa6..5ca89312 100644 --- a/README.md +++ b/README.md @@ -79,8 +79,8 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea If using [Homebrew](http://brew.sh/): brew install libconfig readline lua python libevent jansson - 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" + export CPPFLAGS="-I/usr/local/opt/openssl/include -I/usr/local/opt/readline/include" + export LDFLAGS="-L/usr/local/opt/openssl/lib -L/usr/local/opt/readline/lib" ./configure && make Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. From 95d3b2f67e12b9fd077bfb2c0a826f98024bb7e1 Mon Sep 17 00:00:00 2001 From: Cojad Date: Fri, 7 Apr 2017 16:17:01 +0800 Subject: [PATCH 101/164] fix msg id problem I didn't see. thanks to @diafour for pointing out the missing part that require for change. --- python-types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-types.c b/python-types.c index 8c341575..cf76cd7b 100644 --- a/python-types.c +++ b/python-types.c @@ -1465,7 +1465,7 @@ tgl_Msg_repr(tgl_Msg *self) { PyObject *ret; #if PY_VERSION_HEX < 0x02070900 - ret = PyUnicode_FromFormat("", self->msg->id); + ret = PyUnicode_FromFormat("", self->msg->permanent_id.id); #else ret = PyUnicode_FromFormat("", From 4ad0c9246c29da6f9f93316dbc95c36d8fda1edb Mon Sep 17 00:00:00 2001 From: davrodfer Date: Wed, 26 Jul 2017 12:58:23 +0200 Subject: [PATCH 102/164] Update README.es The clone command must be recursive --- README.es | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.es b/README.es index 46854245..bb52c97b 100644 --- a/README.es +++ b/README.es @@ -15,7 +15,7 @@ La documentación del protocolo MTproto está disponible aquí: http://core.tele Clona el Repositorio GitHub - $ git clone https://github.com/vysheng/tg.git && cd tg + $ git clone --recursive https://github.com/vysheng/tg.git && cd tg o descarga y descomprime el zip From 1caea547e957cb50e4c424087f5f5d5b678294ec Mon Sep 17 00:00:00 2001 From: Arindam Choudhury Date: Mon, 28 Aug 2017 10:27:15 +0200 Subject: [PATCH 103/164] fedora jansson-devel fedora repo has jansson-devel, not libjansson-devel --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..4cab341a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ On gentoo: On Fedora: - sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel + sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel On Archlinux: From 9055eddfd8dcda314663008e30720b8cb9ca6d1b Mon Sep 17 00:00:00 2001 From: amirreza hosseini Date: Mon, 28 Aug 2017 13:30:02 +0430 Subject: [PATCH 104/164] Fix jansson-devel --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..4cab341a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ On gentoo: On Fedora: - sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel + sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel On Archlinux: From bba6089a97f6a55ca160a8b3d000b89c3e0d624e Mon Sep 17 00:00:00 2001 From: Dmitry Semenyuk Date: Tue, 29 Aug 2017 22:24:11 -0600 Subject: [PATCH 105/164] Add link to docker build set --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4a9e0fa6..3774137a 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,10 @@ Then build: env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure make +#### Docker + +The set for dockerizing the app: https://github.com/semenyukdmitry/telegram_cli_docker. + #### Other UNIX If you manage to launch it on other UNIX, please let me know. From 384b332bea1c61e0bb1dcb55d570c45bc97ee971 Mon Sep 17 00:00:00 2001 From: Dmitry Semenyuk Date: Tue, 29 Aug 2017 22:33:54 -0600 Subject: [PATCH 106/164] Add channel_info command to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4a9e0fa6..c95041f6 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,10 @@ If two or more peers have same name, number is appended to the name. (for * **create_group_chat** \ \ \ \ ... - creates a groupchat with users, use chat_add_user to add more users * **chat_set_photo** \ \ - sets group chat photo. Same limits as for profile photos. +#### Channels + +* ***channel_info*** \ - prints info about channel + #### Search * **search** \ pattern - searches pattern in messages with peer From 09c76bbd8de721a2e03f496bd36dc71c30d725d3 Mon Sep 17 00:00:00 2001 From: Marina Kamalova Date: Tue, 19 Sep 2017 20:25:15 +0300 Subject: [PATCH 107/164] set v6 options --- loop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/loop.c b/loop.c index 5426a33a..b11399b0 100644 --- a/loop.c +++ b/loop.c @@ -572,6 +572,13 @@ void empty_auth_file (void) { bl_do_dc_option (TLS, 0, 3, "", 0, TG_SERVER_3, strlen (TG_SERVER_3), 443); bl_do_dc_option (TLS, 0, 4, "", 0, TG_SERVER_4, strlen (TG_SERVER_4), 443); bl_do_dc_option (TLS, 0, 5, "", 0, TG_SERVER_5, strlen (TG_SERVER_5), 443); + + bl_do_dc_option (TLS, 1, 1, "", 0, TG_SERVER_IPV6_1, strlen (TG_SERVER_IPV6_1), 443); + bl_do_dc_option (TLS, 1, 2, "", 0, TG_SERVER_IPV6_2, strlen (TG_SERVER_IPV6_2), 443); + bl_do_dc_option (TLS, 1, 3, "", 0, TG_SERVER_IPV6_3, strlen (TG_SERVER_IPV6_3), 443); + bl_do_dc_option (TLS, 1, 4, "", 0, TG_SERVER_IPV6_4, strlen (TG_SERVER_IPV6_4), 443); + bl_do_dc_option (TLS, 1, 5, "", 0, TG_SERVER_IPV6_5, strlen (TG_SERVER_IPV6_5), 443); + bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT); } } From 32abd53dfaba3c87cb0026ced98a2ad3a94a1d86 Mon Sep 17 00:00:00 2001 From: Marina Kamalova Date: Tue, 19 Sep 2017 20:49:24 +0300 Subject: [PATCH 108/164] read and write v6 options --- loop.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/loop.c b/loop.c index b11399b0..7481c953 100644 --- a/loop.c +++ b/loop.c @@ -470,6 +470,12 @@ void write_dc (struct tgl_dc *DC, void *extra) { int l = strlen (DC->options[0]->ip); assert (write (auth_file_fd, &l, 4) == 4); assert (write (auth_file_fd, DC->options[0]->ip, l) == l); + + assert (write (auth_file_fd, &DC->options[1]->port, 4) == 4); + l = strlen (DC->options[1]->ip); + assert (write (auth_file_fd, &l, 4) == 4); + assert (write (auth_file_fd, DC->options[1]->ip, l) == l); + assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (write (auth_file_fd, DC->auth_key, 256) == 256); } @@ -549,6 +555,15 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { assert (read (auth_file_fd, ip, l) == l); ip[l] = 0; + int port_v6 = 0; + assert (read (auth_file_fd, &port_v6, 4) == 4); + int l_v6 = 0; + assert (read (auth_file_fd, &l_v6, 4) == 4); + assert (l_v6 >= 0 && l_v6 < 100); + char ip_v6[100]; + assert (read (auth_file_fd, ip_v6, l_v6) == l_v6); + ip_v6[l_v6] = 0; + long long auth_key_id; static unsigned char auth_key[256]; assert (read (auth_file_fd, &auth_key_id, 8) == 8); @@ -556,6 +571,7 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { //bl_do_add_dc (id, ip, l, port, auth_key_id, auth_key); bl_do_dc_option (TLS, 0, id, "DC", 2, ip, l, port); + bl_do_dc_option (TLS, 1, id, "DC", 2, ip_v6, l_v6, port_v6); bl_do_set_auth_key (TLS, id, auth_key); bl_do_dc_signed (TLS, id); } From f8e32349bfaf9ac4c80cf0c19c2b195ea0b24f38 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Mon, 9 Oct 2017 19:43:50 +0330 Subject: [PATCH 109/164] add channel's commands --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 4a9e0fa6..8bae11c2 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,23 @@ If two or more peers have same name, number is appended to the name. (for * **create_group_chat** \ \ \ \ ... - creates a groupchat with users, use chat_add_user to add more users * **chat_set_photo** \ \ - sets group chat photo. Same limits as for profile photos. +### Channels + +* **channel_get_admins** \ [limit=100] [offset=0] - Gets channel admins +* **channel_get_members** \ [limit=100] [offset=0] - Gets channel members +* **channel_info** \ - Prints info about channel (id, members, admin, etc.) +* **channel_invite** \ \ - Invites user to channel +* **channel_join** \ - Joins to channel +* **channel_kick** \ \ - Kicks user from channel +* **channel_leave** \ - Leaves from channel +* **channel_list** [limit=100] [offset=0] - List of last channels +* **channel_set_about** \ \ - Sets channel about info. +* **channel_set_admin** \ \ \ - Sets channel admin. 0 - not admin, 1 - moderator, 2 - editor +* **channel_set_photo** \ \ - Sets channel photo. Photo will be cropped to square +* **channel_set_username** \ \ -Sets channel username info. + + + #### Search * **search** \ pattern - searches pattern in messages with peer From 8c889f11983e69329e02ca722c11359f701c4290 Mon Sep 17 00:00:00 2001 From: astolybko Date: Mon, 16 Oct 2017 11:31:20 +0100 Subject: [PATCH 110/164] Fixing hard crash everytime when posting to the chat or channel --- interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface.c b/interface.c index f78619a3..60137c69 100644 --- a/interface.c +++ b/interface.c @@ -4019,6 +4019,10 @@ void print_peer_permanent_name (struct in_ev *ev, tgl_peer_id_t id) { } void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U) { + if(tgl_get_peer_type (id) == TGL_PEER_CHAT) + { + return; + } assert (tgl_get_peer_type (id) == TGL_PEER_USER); mpush_color (ev, COLOR_RED); if (permanent_peer_id_mode) { From be58d3911e788ceea7452d82893c56960316cf96 Mon Sep 17 00:00:00 2001 From: astolybko Date: Fri, 20 Oct 2017 13:03:31 +0100 Subject: [PATCH 111/164] Removed unused method to pass travis check --- lua-tg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index 454a0a66..aa669c7d 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -661,9 +661,9 @@ struct lua_arg { struct lua_arg lua_ptr[MAX_LUA_COMMANDS]; static int pos; -static inline tgl_peer_t *get_peer (const char *s) { - return tgl_peer_get_by_name (TLS, s); -} +// static inline tgl_peer_t *get_peer (const char *s) { +// return tgl_peer_get_by_name (TLS, s); +// } enum lua_query_type { lq_contact_list, From 18a4e40cff4f6bf3d8688e571ea1b4c42d4031a1 Mon Sep 17 00:00:00 2001 From: Simon B Date: Sat, 3 Feb 2018 02:55:19 +0100 Subject: [PATCH 112/164] Update MacOS compile instructions Distilled ideas from https://github.com/vysheng/tg/issues/811 and https://github.com/vysheng/tg/issues/1132 and a trick to avoid failing the compile on any warning - otherwise make compile fails on an ununsed function --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4a9e0fa6..d1645a70 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,12 @@ The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/rea If using [Homebrew](http://brew.sh/): brew install libconfig readline lua python libevent jansson - 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" - ./configure && make + export READLINEPATH=$(brew --prefix readline) + export OPENSSLPATH=$(brew --prefix openssl) + export CFLAGS="-I/usr/local/include -I$READLINEPATH/include -I$OPENSSLPATH/include" + export LDFLAGS="-L/usr/local/lib -L$READLINEPATH/lib -L$OPENSSLPATH/lib" + export CPPFLAGS="-I/usr/local/opt/openssl/include -W" + ./configure --with-openssl=/usr/local/opt/openssl && make CFSUFFIX='-Wno-error=unused' Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. From b3a7c4dab5ccd6fe3bac4eb186ceb5a8447a1ad9 Mon Sep 17 00:00:00 2001 From: lxfr Date: Mon, 12 Mar 2018 14:41:50 +0300 Subject: [PATCH 113/164] Update readme Debian / Ubuntu need zlib1g-dev (apt-get install zlib1g-dev) for ./configure --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..1e47e0f8 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ If you do not want to use them pass options --disable-libconfig, --disable-liblu On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make + sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make zlib1g-dev On gentoo: From 7ccd059c923a5b0ea149e7c10e4377aba6432898 Mon Sep 17 00:00:00 2001 From: Mart van de Ven Date: Mon, 19 Mar 2018 17:03:40 +0800 Subject: [PATCH 114/164] Updated Fedora jansson-devel dependency --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a9e0fa6..3ba07029 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ On gentoo: On Fedora: - sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel + sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel On Archlinux: @@ -59,7 +59,7 @@ On OpenBSD: On openSUSE: - sudo zypper in lua-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel libopenssl-devel + sudo zypper in lua-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel libopenssl-devel Then, From 1a0089d02de31b3112bbc0d082c263b75c859fe2 Mon Sep 17 00:00:00 2001 From: Mart van de Ven Date: Mon, 19 Mar 2018 17:07:57 +0800 Subject: [PATCH 115/164] Adds Fedora libgcrypt-devel dependency for --disable-openssl --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ba07029..5a00e299 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ On gentoo: On Fedora: - sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel + sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel libgcrypt-devel On Archlinux: From 49d40d606e4b93f276bf09847d10bcd097eb201e Mon Sep 17 00:00:00 2001 From: Mart van de Ven Date: Mon, 19 Mar 2018 19:28:31 +0800 Subject: [PATCH 116/164] Trailing space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a00e299..73bdaf90 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ On OpenBSD: On openSUSE: - sudo zypper in lua-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel libopenssl-devel + sudo zypper in lua-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel libopenssl-devel Then, From 822bbdbbd7e9975b79118cf082cb23d8e891d285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milli=20=C4=B0=C5=9Fletim=20Sistemi=20=28Milis=20Linux=29?= Date: Mon, 14 May 2018 08:18:12 +0200 Subject: [PATCH 117/164] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4a9e0fa6..ae314312 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,10 @@ On Fedora: On Archlinux: yaourt -S telegram-cli-git + +On Milislinux: + + mps kur telegram-cli On FreeBSD: From 918a164cc6d78bd184ea737f5676d0ef53253796 Mon Sep 17 00:00:00 2001 From: spookyahell <9724215+spookyahell@users.noreply.github.com> Date: Mon, 21 May 2018 22:38:22 +0200 Subject: [PATCH 118/164] Working link for libconfig & more and also the missing tools for compiling it --- README-Cygwin.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README-Cygwin.md b/README-Cygwin.md index 42ed0118..f351bb87 100755 --- a/README-Cygwin.md +++ b/README-Cygwin.md @@ -5,7 +5,7 @@ Install [Cygwin](https://www.cygwin.com/) and cygwin's package manager, [apt-cyg In Cygwin Terminal, install compiler and tools : - apt-cyg install cygwin32-gcc-core cygwin32-gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip + apt-cyg install cygwin32-gcc-core cygwin32-gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip autoconf automake libtool git zlib-devel Now you have a compiler, but no libraries. You need readline, openssl, libconfig, liblua, python and libjansson to use telegram-cli's full functionality. @@ -24,8 +24,10 @@ libconfig and libjansson is not in cygwin's package, so you should compile yours Compile libconfig - wget http://www.hyperrealm.com/libconfig/libconfig-1.5.tar.gz - tar xvf libconfig-1.5.tar.gz && cd libconfig-1.5 + wget https://github.com/hyperrealm/libconfig/archive/v1.7.2.tar.gz + mv v1.7.2.tar.gz libconfig-1.7.2.tar.gz + tar xvf libconfig-1.7.2.tar.gz && cd libconfig-1.7.2 + autoreconf ./configure make && make install && cd .. From 00502db926bbf6d1f4de49069d459c70c1074593 Mon Sep 17 00:00:00 2001 From: Lorenzo Ancora <34890309+LorenzoAncora@users.noreply.github.com> Date: Sat, 17 Nov 2018 00:51:30 +0100 Subject: [PATCH 119/164] Correct the description of --exec The description now does not speak of multiple commands but of a single command and specifies that the output is safe (and therefore awaits the end of operations in progress). The --exec command executes a single command and then exits safely. --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 4776f073..d36e3de8 100644 --- a/main.c +++ b/main.c @@ -477,7 +477,7 @@ void usage (void) { printf (" --disable-output/-D disable output\n"); printf (" --tcp-port/-P port to listen for input commands\n"); printf (" --udp-socket/-S unix socket to create\n"); - printf (" --exec/-e make commands end exit\n"); + printf (" --exec/-e make a single command end then exit safely\n"); printf (" --disable-names/-I use user and chat IDs in updates instead of names\n"); printf (" --enable-ipv6/-6 use ipv6 (may be unstable)\n"); printf (" --help/-h prints this help\n"); From 171718cde032ae54f678a645307e0a5cddb1fb70 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 2 Feb 2019 17:35:48 +0000 Subject: [PATCH 120/164] Changes tgl submodule to point kenorb-contrib/tgl.git --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index dffe6ca1..f2bb8210 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tgl"] path = tgl - url = https://github.com/vysheng/tgl.git + url = https://github.com/kenorb-contrib/tgl.git From a700f972519b2d8977deaa423b03c0d5839540eb Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 2 Feb 2019 17:55:24 +0000 Subject: [PATCH 121/164] Fixes from Rondoozle fork --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index ffb04cac..df00d365 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit ffb04caca71de0cddf28cd33a4575922900a59ed +Subproject commit df00d3652e8b6ad60dbdc703e8f150394adfafe4 From f3fe47ff6b9eb91de2026f7ab86db77be6562ffb Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 2 Feb 2019 17:59:16 +0000 Subject: [PATCH 122/164] Adds missing libgcrypt-dev for RSA compilation errors as per vysheng/tg/issues/1562 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a9e0fa6..caf662c3 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ If you do not want to use them pass options --disable-libconfig, --disable-liblu On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make + sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev libgcrypt-dev make On gentoo: From ab27d089b80bbf72798573eacf93a86b00c55aa6 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 2 Feb 2019 18:31:56 +0000 Subject: [PATCH 123/164] Stop using -Werror: bad practice as not all warnings are true positives, see: http://blog.schmorp.de/2016-02-27-tidbits-for-the-love-of-god-dont-use-werror.html --- Makefile.in | 2 +- tgl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 83424620..139c3da9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,7 @@ CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@ CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@ DEFS=@DEFS@ -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 +COMPILE_FLAGS=${CFLAGS} ${CPFLAGS} ${CPPFLAGS} ${DEFS} -Wall -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} -ldl -lpthread -lutil LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} diff --git a/tgl b/tgl index df00d365..1fd30a9b 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit df00d3652e8b6ad60dbdc703e8f150394adfafe4 +Subproject commit 1fd30a9b85c12c182e604bfebdb398078ed20b73 From 41b3a44d4184fe7de95e4b5c7ac930d42022f18d Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 2 Feb 2019 21:55:12 +0000 Subject: [PATCH 124/164] Updates tgl --- tgl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgl b/tgl index 1fd30a9b..09a32d9c 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 1fd30a9b85c12c182e604bfebdb398078ed20b73 +Subproject commit 09a32d9c75980e0ba06c158d9ca9ec5100eaf79b From 8d3e35b325b5ae1408304a1a547001d2251bdc50 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 8 Jan 2016 15:31:10 +0100 Subject: [PATCH 125/164] Fix crash on unsupported media received --- interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface.c b/interface.c index ff8cc660..4dd3a07f 100644 --- a/interface.c +++ b/interface.c @@ -4008,7 +4008,8 @@ void print_media (struct in_ev *ev, struct tgl_message_media *M) { default: mprintf (ev, "x = %d\n", M->type); - assert (0); + M->type = tgl_message_media_unsupported; + break; } } From 2e1095cfa33ef4c92b9b7c5f1d21071ceb6a2ac0 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 01:14:35 +0000 Subject: [PATCH 126/164] Revert "read and write v6 options" This reverts commit 32abd53dfaba3c87cb0026ced98a2ad3a94a1d86. --- loop.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/loop.c b/loop.c index 7481c953..b11399b0 100644 --- a/loop.c +++ b/loop.c @@ -470,12 +470,6 @@ void write_dc (struct tgl_dc *DC, void *extra) { int l = strlen (DC->options[0]->ip); assert (write (auth_file_fd, &l, 4) == 4); assert (write (auth_file_fd, DC->options[0]->ip, l) == l); - - assert (write (auth_file_fd, &DC->options[1]->port, 4) == 4); - l = strlen (DC->options[1]->ip); - assert (write (auth_file_fd, &l, 4) == 4); - assert (write (auth_file_fd, DC->options[1]->ip, l) == l); - assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (write (auth_file_fd, DC->auth_key, 256) == 256); } @@ -555,15 +549,6 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { assert (read (auth_file_fd, ip, l) == l); ip[l] = 0; - int port_v6 = 0; - assert (read (auth_file_fd, &port_v6, 4) == 4); - int l_v6 = 0; - assert (read (auth_file_fd, &l_v6, 4) == 4); - assert (l_v6 >= 0 && l_v6 < 100); - char ip_v6[100]; - assert (read (auth_file_fd, ip_v6, l_v6) == l_v6); - ip_v6[l_v6] = 0; - long long auth_key_id; static unsigned char auth_key[256]; assert (read (auth_file_fd, &auth_key_id, 8) == 8); @@ -571,7 +556,6 @@ void read_dc (int auth_file_fd, int id, unsigned ver) { //bl_do_add_dc (id, ip, l, port, auth_key_id, auth_key); bl_do_dc_option (TLS, 0, id, "DC", 2, ip, l, port); - bl_do_dc_option (TLS, 1, id, "DC", 2, ip_v6, l_v6, port_v6); bl_do_set_auth_key (TLS, id, auth_key); bl_do_dc_signed (TLS, id); } From 5f3c675814c1a3624715678f05af989405bda585 Mon Sep 17 00:00:00 2001 From: ukwt Date: Mon, 21 Mar 2016 23:08:02 +0600 Subject: [PATCH 127/164] Fix Python API documentation errors This commit fixes two errors in Python API README: 1) It seems that Peer.get_history() method was renamed to Peer.history() a while ago and the old one does not longer work. 2) There is no Msg.delete_msg() method, but there is a method with the same name and calling syntax in tgl module. --- README-PY.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README-PY.md b/README-PY.md index 09ae1bb6..c5d386c8 100644 --- a/README-PY.md +++ b/README-PY.md @@ -57,6 +57,7 @@ All of these functions are accessed by importing the `tgl` module. |`tgl.set_profile_photo (file_path)`|Sets avatar to image found at `file_path`, no checking on the file.|`empty_cb`| |`tgl.create_secret_chat (user)`|Creates secret chat with user, callback recommended to get new peer for the secret chat.|`secret_chat_cb`| |`tgl.create_group_chat (peer_list, name)`|`peer_list` contains users to create group with, must be more than 1 peer.|`empty_cb`| +|`tgl.delete_msg (msg_id)`|Deletes the message from the local history.|`empty_cb`| |`tgl.restore_msg (msg_id)`|Restore a deleted message by message id.|`empty_cb`| |`tgl.status_online ()`|Sets status as online|`empty_cb`| |`tgl.status_offline ()`|Sets status as offline|`empty_cb`| @@ -100,20 +101,20 @@ Peer |`peer.chat_del_user (user)`|Removes `user`(`tgl.Peer`) from the group. The calling peer must be of type `tgl.PEER_CHAT`|`empty_cb`| |`peer.mark_read ()`|Marks the dialog with the peer as read. This cannot be done on message level.|`empty_cb`| |`peer.msg_search (text, callback)`|Get all messages that match the search text with the peer. *requires callback*|`msg_list_cb`| -|`peer.get_history (offset, limit, callback)`|Get all messages with the peer. `offset` specifies what message to start at, and `limit` specifies how many messages to retrieve. See example below for one method to get the entire history. *requires callback*|`msg_list_cb`| +|`peer.history (offset, limit, callback)`|Get all messages with the peer. `offset` specifies what message to start at, and `limit` specifies how many messages to retrieve. See example below for one method to get the entire history. *requires callback*|`msg_list_cb`| |`peer.info ()`|Gets peer info.|`peer_cb`| -Example usage for `peer.get_history`: +Example usage for `peer.history`: ``` from functools import partial history = [] # Get all the history, 100 msgs at a time -peer.get_history(0, 100, partial(history_callback, 100, peer)) +peer.history(0, 100, partial(history_callback, 100, peer)) -def history_callback(msg_count, peer, success, msgs) +def history_callback(msg_count, peer, success, msgs): history.extend(msgs) if len(msgs) == msg_count: - peer.get_history(len(history), msg_count, partial(history_callback, msg_count, peer)) + peer.history(len(history), msg_count, partial(history_callback, msg_count, peer)) ``` Msg @@ -172,4 +173,3 @@ Msg |`msg.load_audio(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| |`msg.load_document(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| |`msg.load_document_thumb(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| -|`msg.delete_msg ()`|Deletes the message from the local history|`empty_cb`| From 282e109acb844c3b2169284d3d741f3d1d023b7f Mon Sep 17 00:00:00 2001 From: Phil Ruffwind Date: Thu, 14 Apr 2016 17:18:04 -0400 Subject: [PATCH 128/164] Correctly set online flag in Peer class (Python) The online flag in 'struct tgl_user_status' is not a boolean. Rather, positive values indicate 'online' while negative values indicate 'offline'. --- python-types.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-types.c b/python-types.c index cf76cd7b..a578a47e 100644 --- a/python-types.c +++ b/python-types.c @@ -164,7 +164,7 @@ tgl_Peer_getuser_status(tgl_Peer *self, void *closure) switch(self->peer->id.peer_type) { case TGL_PEER_USER: ret = PyDict_New(); - PyDict_SetItemString(ret, "online", self->peer->user.status.online? Py_True : Py_False); + PyDict_SetItemString(ret, "online", self->peer->user.status.online > 0 ? Py_True : Py_False); PyDict_SetItemString(ret, "when", get_datetime(self->peer->user.status.when)); break; From 59c85a2a70a0756ef7ef6411905b68fb087733ff Mon Sep 17 00:00:00 2001 From: marcosramirezaranda Date: Fri, 7 Aug 2015 09:23:05 -0300 Subject: [PATCH 129/164] Fixes "assertion `TLS->enable_pfs' failed" when usign tg with proxychains. $ proxychains /bin/telegram-cli will die with assert error included below when you try to reconnect to Telegram. telegram-cli: tgl/mtproto-client.c:550: create_temp_auth_key: Assertion `TLS->enable_pfs' failed. --- loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loop.c b/loop.c index b11399b0..aa150f86 100644 --- a/loop.c +++ b/loop.c @@ -872,7 +872,7 @@ int loop (void) { } bl_do_reset_authorization (TLS); } - + tgl_enable_pfs(TLS); set_interface_callbacks (); tgl_login (TLS); net_loop (); From 0035cd423b0c759d41ae1a10ef4b6067582771ca Mon Sep 17 00:00:00 2001 From: Jakob Nixdorf Date: Thu, 16 Apr 2015 22:09:13 +0200 Subject: [PATCH 130/164] Set the 'ar' command as variable in Makefile.tgl Allows the location of the ar binary to be changed by passing the argument AR=/path/to/ar to make. --- Makefile.tgl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.tgl b/Makefile.tgl index 28447e17..bce7cb7e 100644 --- a/Makefile.tgl +++ b/Makefile.tgl @@ -8,6 +8,8 @@ GENERATE_OBJECTS=${OBJ}/generate.o TGL_COMMON_OBJECTS=${OBJ}/tools.o ${OBJ}/crypto/rand_openssl.o ${OBJ}/crypto/rand_altern.o ${OBJ}/crypto/err_openssl.o ${OBJ}/crypto/err_altern.o TGL_OBJ_C=${GENERATE_OBJECTS} ${TGL_COMMON_OBJECTS} ${TGL_OBJECTS} ${TLD_OBJECTS} +AR?=ar + .SUFFIXES: .SUFFIXES: .c .h .o @@ -26,7 +28,7 @@ ${TGL_OBJECTS_AUTO}: ${OBJ}/auto/%.o: ${AUTO}/%.c | create_dirs # ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl -c -MP -MD -MF ${DEP}/auto/auto.d -MQ ${OBJ}/auto/auto.o -o $@ $< ${LIB}/libtgl.a: ${TGL_OBJECTS} ${TGL_COMMON_OBJECTS} ${TGL_OBJECTS_AUTO} - rm -f $@ && ar ruv $@ $^ + rm -f $@ && ${AR} ruv $@ $^ ${EXE}/generate: ${GENERATE_OBJECTS} ${TGL_COMMON_OBJECTS} ${CC} ${GENERATE_OBJECTS} ${TGL_COMMON_OBJECTS} ${LINK_FLAGS} -o $@ From 477dd3b2b9946c4ba7bd2eed3bf0c0137e22b8de Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 01:59:16 +0000 Subject: [PATCH 131/164] Updates repo link --- README.es | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.es b/README.es index bb52c97b..231a2986 100644 --- a/README.es +++ b/README.es @@ -1,4 +1,4 @@ -## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) +## Telegram messenger CLI [![Build Status](https://travis-ci.org/kenorb-contrig/tg.png)](https://travis-ci.org/kenorb-contrig/tg) !!!! May be outdated. Please refer to english README as more actual. @@ -15,11 +15,11 @@ La documentación del protocolo MTproto está disponible aquí: http://core.tele Clona el Repositorio GitHub - $ git clone --recursive https://github.com/vysheng/tg.git && cd tg + $ git clone --recursive https://github.com/kenorb-contrig/tg.git && cd tg o descarga y descomprime el zip - $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip + $ wget https://github.com/kenorb-contrig/tg/archive/master.zip -O tg-master.zip $ unzip tg-master.zip && cd tg-master #### Linux From 2c25913f771d2edc246741bb3483208dcabd2a34 Mon Sep 17 00:00:00 2001 From: kyak Date: Tue, 30 Aug 2016 19:01:55 +0300 Subject: [PATCH 132/164] Correct readline terminating sequences for colors This changes definitions of color escape code to use correct readline terminating sequences. As a result, the interactive chat mode (chat_with_peer) now correctly works when input line exceeds terminal width (i.e. input line is wrapped correctly). --- interface.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/interface.h b/interface.h index c05dc364..10644b3f 100644 --- a/interface.h +++ b/interface.h @@ -21,18 +21,18 @@ #include #include -#define COLOR_RED "\033[0;31m" -#define COLOR_REDB "\033[1;31m" -#define COLOR_NORMAL "\033[0m" -#define COLOR_GREEN "\033[32;1m" -#define COLOR_GREY "\033[37;1m" -#define COLOR_YELLOW "\033[33;1m" -#define COLOR_BLUE "\033[34;1m" -#define COLOR_MAGENTA "\033[35;1m" -#define COLOR_CYAN "\033[36;1m" -#define COLOR_LCYAN "\033[0;36m" - -#define COLOR_INVERSE "\033[7m" +#define COLOR_RED "\001\033[0;31m\002" +#define COLOR_REDB "\001\033[1;31m\002" +#define COLOR_NORMAL "\001\033[0m\002" +#define COLOR_GREEN "\001\033[32;1m\002" +#define COLOR_GREY "\001\033[37;1m\002" +#define COLOR_YELLOW "\001\033[33;1m\002" +#define COLOR_BLUE "\001\033[34;1m\002" +#define COLOR_MAGENTA "\001\033[35;1m\002" +#define COLOR_CYAN "\001\033[36;1m\002" +#define COLOR_LCYAN "\001\033[0;36m\002" + +#define COLOR_INVERSE "\001\033[7m\002" char *get_default_prompt (void); char *complete_none (const char *text, int state); From 85d48a7a9d5e0e21b14aa3fab055350eebcab9cb Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 11 Apr 2015 01:37:30 +0200 Subject: [PATCH 133/164] resolved: crash after downloading photo/file in deamon/socket mode (-d -P port) --- interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface.c b/interface.c index 565a7b06..80168fcf 100644 --- a/interface.c +++ b/interface.c @@ -1499,6 +1499,7 @@ void do_send_typing_abort (struct command *command, int arg_num, struct arg args #define DO_LOAD_PHOTO(tp,act,actf) \ void do_ ## act ## _ ## tp (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \ assert (arg_num == 1);\ + if (ev) { ev->refcnt ++; vlogprintf (E_WARNING, "refcnt+\n"); }\ struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id);\ if (M && !(M->flags & TGLMF_SERVICE)) {\ if (ev) { ev->refcnt ++; } \ @@ -1525,6 +1526,7 @@ void do_ ## act ## _ ## tp (struct command *command, int arg_num, struct arg arg #define DO_LOAD_PHOTO_THUMB(tp,act,actf) \ void do_ ## act ## _ ## tp ## _thumb (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \ assert (arg_num == 1);\ + if (ev) { ev->refcnt ++; vlogprintf (E_WARNING, "refcnt+\n"); }\ struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id);\ if (M && !(M->flags & TGLMF_SERVICE)) {\ if (M->media.type == tgl_message_media_document) {\ From 44305412246186bae3990d404b31e66af1433582 Mon Sep 17 00:00:00 2001 From: Kimiyuki Onaka Date: Fri, 14 Oct 2016 17:06:40 +0900 Subject: [PATCH 134/164] Fix typo of option in usage --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 9e53d6f2..7ae6941a 100644 --- a/main.c +++ b/main.c @@ -488,7 +488,7 @@ void usage (void) { printf (" --groupname/-G change gid after start\n"); printf (" --disable-output/-D disable output\n"); printf (" --tcp-port/-P port to listen for input commands\n"); - printf (" --udp-socket/-S unix socket to create\n"); + printf (" --unix-socket/-S unix socket to create\n"); printf (" --exec/-e make a single command end then exit safely\n"); printf (" --disable-names/-I use user and chat IDs in updates instead of names\n"); printf (" --enable-ipv6/-6 use ipv6 (may be unstable)\n"); From ad55199e090ff68927c7ade5710393cbb282d1bb Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 02:26:38 +0000 Subject: [PATCH 135/164] Fixes conflict --- Makefile.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index 38877661..f0bfc76d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -60,7 +60,6 @@ ${EXE}/telegram-cli: ${TG_OBJECTS} ${LIB}/libtgl.a ${CC} $^ ${LINK_FLAGS} -o $@ clean: -<<<<<<< HEAD rm -rf ${DIR_LIST} distclean: @@ -69,6 +68,4 @@ distclean: install: all @mkdir -p $(INSTALL_BIN) $(INSTALL) telegram $(INSTALL_BIN) -======= rm -rf ${DIR_LIST} config.log config.status > /dev/null || echo "all clean" ->>>>>>> 628abe1e77827eed5c9dfca7bb1e1f5f5c19fa0a From 14e851774f5ff3ed4da4df85fa82a5451de7c853 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 02:37:20 +0000 Subject: [PATCH 136/164] Revert "Fixes "assertion `TLS->enable_pfs' failed" when usign tg with proxychains." This reverts commit 59c85a2a70a0756ef7ef6411905b68fb087733ff. --- loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loop.c b/loop.c index aa150f86..b11399b0 100644 --- a/loop.c +++ b/loop.c @@ -872,7 +872,7 @@ int loop (void) { } bl_do_reset_authorization (TLS); } - tgl_enable_pfs(TLS); + set_interface_callbacks (); tgl_login (TLS); net_loop (); From 221b9a3e82db5668903064df2550749a3c2e0488 Mon Sep 17 00:00:00 2001 From: Sahri Riza Umami Date: Fri, 22 Apr 2016 09:25:34 +0700 Subject: [PATCH 137/164] Lua binding improvements. --- lua-tg.c | 373 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 240 insertions(+), 133 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index 8d2335c0..dccccf93 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -180,14 +180,14 @@ void push_update_types (unsigned flags) { my_lua_checkstack (luaState, 4); lua_newtable (luaState); int cc = 0; - - + + if (flags & TGL_UPDATE_CREATED) { lua_add_string_field_arr (cc++, "created"); - } + } if (flags & TGL_UPDATE_DELETED) { lua_add_string_field_arr (cc++, "deleted"); - } + } if (flags & TGL_UPDATE_PHONE) { lua_add_string_field_arr (cc++, "phone"); } @@ -235,7 +235,7 @@ void push_update_types (unsigned flags) { void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { lua_newtable (luaState); - + lua_add_string_field ("id", print_permanent_peer_id (P ? P->id : id)); lua_pushstring (luaState, "peer_type"); push_tgl_peer_type (tgl_get_peer_type (id)); @@ -243,7 +243,7 @@ void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { lua_add_num_field ("peer_id", tgl_get_peer_id (id)); if (!P || !(P->flags & TGLPF_CREATED)) { - lua_pushstring (luaState, "print_name"); + lua_pushstring (luaState, "print_name"); static char s[100]; switch (tgl_get_peer_type (id)) { case TGL_PEER_USER: @@ -261,15 +261,15 @@ void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { default: assert (0); } - lua_pushstring (luaState, s); + lua_pushstring (luaState, s); lua_settable (luaState, -3); // flags - + return; } - + lua_add_string_field ("print_name", P->print_name); lua_add_num_field ("flags", P->flags); - + switch (tgl_get_peer_type (id)) { case TGL_PEER_USER: push_user (P); @@ -300,22 +300,22 @@ void push_media (struct tgl_message_media *M) { case tgl_message_media_document: lua_newtable (luaState); lua_add_string_field ("type", "document"); - lua_add_string_field ("caption", M->document->caption); + lua_add_string_field ("caption", M->document->caption); break; case tgl_message_media_audio: lua_newtable (luaState); lua_add_string_field ("type", "audio"); - lua_add_string_field ("caption", M->caption); + lua_add_string_field ("caption", M->caption); break; case tgl_message_media_video: lua_newtable (luaState); lua_add_string_field ("type", "video"); - lua_add_string_field ("caption", M->caption); + lua_add_string_field ("caption", M->caption); break; case tgl_message_media_document_encr: lua_newtable (luaState); lua_add_string_field ("type", "encr_document"); - lua_add_string_field ("caption", M->document->caption); + lua_add_string_field ("caption", M->document->caption); break; case tgl_message_media_unsupported: lua_newtable (luaState); @@ -390,7 +390,7 @@ void push_service (struct tgl_message *M) { case tgl_message_action_chat_add_users: lua_newtable (luaState); lua_add_string_field ("type", "chat_add_user"); - + lua_pushstring (luaState, "user"); push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.users[0]), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.users[0]))); lua_settable (luaState, -3); @@ -398,7 +398,7 @@ void push_service (struct tgl_message *M) { case tgl_message_action_chat_add_user_by_link: lua_newtable (luaState); lua_add_string_field ("type", "chat_add_user_link"); - + lua_pushstring (luaState, "link_issuer"); push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user))); lua_settable (luaState, -3); @@ -406,7 +406,7 @@ void push_service (struct tgl_message *M) { case tgl_message_action_chat_delete_user: lua_newtable (luaState); lua_add_string_field ("type", "chat_del_user"); - + lua_pushstring (luaState, "user"); push_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user))); lua_settable (luaState, -3); @@ -444,7 +444,7 @@ void push_service (struct tgl_message *M) { lua_add_string_field ("type", "set_layer"); lua_add_num_field ("layer", M->action.layer); break; - case tgl_message_action_typing: + case tgl_message_action_typing: lua_newtable (luaState); lua_add_string_field ("type", "typing"); break; @@ -487,7 +487,7 @@ void push_service (struct tgl_message *M) { } } -void push_message (struct tgl_message *M) { +void push_message (struct tgl_message *M) { assert (M); my_lua_checkstack (luaState, 10); lua_newtable (luaState); @@ -496,7 +496,7 @@ void push_message (struct tgl_message *M) { lua_add_num_field ("temp_id", (M->temp_id)); if (!(M->flags & TGLMF_CREATED)) { return; } lua_add_num_field ("flags", M->flags); - + if (tgl_get_peer_type (M->fwd_from_id)) { lua_pushstring (luaState, "fwd_from"); push_peer (M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id)); @@ -508,55 +508,55 @@ void push_message (struct tgl_message *M) { if (M->reply_id) { tgl_message_id_t msg_id = M->permanent_id; msg_id.id = M->reply_id; - + lua_add_string_field ("reply_id", print_permanent_msg_id (msg_id)); } if (M->flags & TGLMF_MENTION) { lua_pushstring (luaState, "mention"); lua_pushboolean (luaState, 1); - lua_settable (luaState, -3); + lua_settable (luaState, -3); } - + lua_pushstring (luaState, "from"); push_peer (M->from_id, tgl_peer_get (TLS, M->from_id)); - lua_settable (luaState, -3); - + lua_settable (luaState, -3); + lua_pushstring (luaState, "to"); push_peer (M->to_id, tgl_peer_get (TLS, M->to_id)); - lua_settable (luaState, -3); - + lua_settable (luaState, -3); + lua_pushstring (luaState, "out"); lua_pushboolean (luaState, (M->flags & TGLMF_OUT) != 0); - lua_settable (luaState, -3); - + lua_settable (luaState, -3); + lua_pushstring (luaState, "unread"); lua_pushboolean (luaState, (M->flags & TGLMF_UNREAD) != 0); - lua_settable (luaState, -3); - + lua_settable (luaState, -3); + lua_pushstring (luaState, "date"); lua_pushnumber (luaState, M->date); - lua_settable (luaState, -3); - + lua_settable (luaState, -3); + lua_pushstring (luaState, "service"); lua_pushboolean (luaState, (M->flags & TGLMF_SERVICE) != 0); - lua_settable (luaState, -3); + lua_settable (luaState, -3); - if (!(M->flags & TGLMF_SERVICE)) { + if (!(M->flags & TGLMF_SERVICE)) { if (M->message_len && M->message) { lua_pushstring (luaState, "text"); lua_pushlstring (luaState, M->message, M->message_len); - lua_settable (luaState, -3); + lua_settable (luaState, -3); } if (M->media.type && M->media.type != tgl_message_media_none) { lua_pushstring (luaState, "media"); push_media (&M->media); - lua_settable (luaState, -3); + lua_settable (luaState, -3); } } else { lua_pushstring (luaState, "action"); push_service (M); - lua_settable (luaState, -3); + lua_settable (luaState, -3); } } @@ -686,79 +686,96 @@ struct lua_arg lua_ptr[MAX_LUA_COMMANDS]; static int pos; enum lua_query_type { + lq_accept_secret_chat, + lq_add_contact, + lq_block_user, + lq_channel_del_admin, + lq_channel_demote, + lq_channel_get_admins, + lq_channel_get_bots, + lq_channel_get_kicked, + lq_channel_get_users, + lq_channel_info, + lq_channel_invite, + lq_channel_join, + lq_channel_kick, + lq_channel_leave, + lq_channel_list, + lq_channel_set_about, + lq_channel_set_admin, + lq_channel_set_mod, + lq_channel_set_photo, + lq_channel_set_username, + lq_channel_unblock, + lq_channels_dialog_list, + lq_chat_add_user, + lq_chat_del_user, + lq_chat_info, + lq_chat_set_photo, + lq_chat_upgrade, lq_contact_list, + lq_contact_search, + lq_create_channel, + lq_create_group_chat, + lq_create_secret_chat, + lq_del_contact, + lq_delete_msg, lq_dialog_list, - lq_msg, - lq_msg_channel, - lq_send_typing, - lq_send_typing_abort, - lq_rename_chat, - lq_send_photo, - lq_chat_set_photo, - lq_set_profile_photo, - lq_set_profile_name, - lq_set_profile_username, - lq_send_video, - lq_send_text, - lq_reply, + lq_export_channel_link, + lq_export_chat_link, + lq_extf, lq_fwd, lq_fwd_media, + lq_get_message, + lq_global_search, + lq_history, + lq_import_chat_link, + lq_leave_channel, + lq_load_audio, + lq_load_document, + lq_load_document_thumb, lq_load_photo, - lq_load_video_thumb, lq_load_video, - lq_chat_info, - lq_user_info, - lq_history, - lq_chat_add_user, - lq_chat_del_user, - lq_add_contact, - lq_del_contact, + lq_load_video_thumb, + lq_mark_read, + lq_msg, + lq_msg_channel, + lq_post_audio, + lq_post_document, + lq_post_file, + lq_post_location, + lq_post_photo, + lq_post_text, + lq_post_video, + lq_rename_channel, + lq_rename_chat, lq_rename_contact, - lq_search, - lq_global_search, + lq_reply, + lq_reply_audio, + lq_reply_document, + lq_reply_file, + lq_reply_photo, + lq_reply_video, lq_resolve_username, - lq_mark_read, - lq_create_secret_chat, - lq_create_group_chat, + lq_restore_msg, + lq_search, lq_send_audio, + lq_send_contact, lq_send_document, lq_send_file, - lq_load_audio, - lq_load_document, - lq_load_document_thumb, - lq_delete_msg, - lq_restore_msg, - lq_get_message, - lq_accept_secret_chat, - lq_send_contact, - lq_status_online, - lq_status_offline, lq_send_location, - lq_extf, - lq_import_chat_link, - lq_export_chat_link, - lq_channels_dialog_list, - lq_chat_upgrade, - lq_create_channel, - lq_channel_info, - lq_export_channel_link, - lq_channel_invite, - lq_channel_join, - lq_leave_channel, - lq_channel_kick, - lq_channel_get_admins, - lq_channel_get_users, - lq_channel_get_bots, - lq_channel_get_kicked, - lq_channel_unblock, - lq_rename_channel, - lq_channel_set_photo, - lq_channel_set_about, - lq_channel_set_username, - lq_channel_set_admin, - lq_channel_set_mod, - lq_channel_demote, - lq_contact_search + lq_send_photo, + lq_send_text, + lq_send_typing, + lq_send_typing_abort, + lq_send_video, + lq_set_profile_name, + lq_set_profile_photo, + lq_set_profile_username, + lq_status_offline, + lq_status_online, + lq_unblock_user, + lq_user_info }; struct lua_query_extra { @@ -1272,6 +1289,30 @@ void lua_do_all (void) { tgl_do_send_text (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, 0, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; + case lq_post_audio: + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO | TGLMF_POST_AS_CHANNEL, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_post_document: + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGLMF_POST_AS_CHANNEL, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_post_file: + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO | TGLMF_POST_AS_CHANNEL, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_post_photo: + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO | TGLMF_POST_AS_CHANNEL, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_post_text: + tgl_do_send_text (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, 256, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_post_video: + tgl_do_send_document (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO | TGLMF_POST_AS_CHANNEL, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; case lq_chat_set_photo: tgl_do_set_chat_photo (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].str, lua_empty_cb, lua_ptr[p].ptr); p += 3; @@ -1316,6 +1357,26 @@ void lua_do_all (void) { tgl_do_reply_message (TLS, &lua_ptr[p + 1].msg_id, LUA_STR_ARG (p + 2), 0, lua_msg_cb, lua_ptr[p].ptr); p += 3; break; + case lq_reply_audio: + tgl_do_reply_document (TLS, &lua_ptr[p + 1].msg_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_reply_document: + tgl_do_reply_document (TLS, &lua_ptr[p + 1].msg_id, lua_ptr[p + 2].str, NULL, 0, 0, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_reply_file: + tgl_do_reply_document (TLS, &lua_ptr[p + 1].msg_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_reply_photo: + tgl_do_reply_document (TLS, &lua_ptr[p + 1].msg_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_reply_video: + tgl_do_reply_document (TLS, &lua_ptr[p + 1].msg_id, lua_ptr[p + 2].str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, lua_msg_cb, lua_ptr[p].ptr); + p += 3; + break; case lq_fwd: tmp_msg_id = &lua_ptr[p + 2].msg_id; tgl_do_forward_messages (TLS, lua_ptr[p + 1].peer_id, 1, (void *)&tmp_msg_id, 0, lua_one_msg_cb, lua_ptr[p].ptr); @@ -1441,7 +1502,7 @@ void lua_do_all (void) { tgl_do_upgrade_group (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 2; break; - case lq_create_channel: + case lq_create_channel: tgl_do_create_channel (TLS, 1, &lua_ptr[p + 1].peer_id, LUA_STR_ARG (p + 2), LUA_STR_ARG (p + 3), 1,lua_empty_cb, lua_ptr[p].ptr); p += 4; break; @@ -1453,6 +1514,10 @@ void lua_do_all (void) { tgl_do_export_channel_link (TLS, lua_ptr[p + 1].peer_id, lua_str_cb, lua_ptr[p].ptr); p += 2; break; + case lq_post_location: + tgl_do_send_location (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].dnum, lua_ptr[p + 3].dnum, 256, lua_msg_cb, lua_ptr[p].ptr); + p += 4; + break; case lq_channel_invite: tgl_do_channel_invite_user (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 3; @@ -1521,6 +1586,25 @@ void lua_do_all (void) { tgl_do_contact_search (TLS, LUA_STR_ARG (p + 1), lua_contact_search_cb, lua_ptr[p].ptr); p += 2; break; + case lq_block_user: + tgl_do_block_user (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_unblock_user: + tgl_do_unblock_user (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; + case lq_channel_del_admin: + tgl_do_channel_set_admin (TLS, lua_ptr[p + 1].peer_id, lua_ptr[p + 2].peer_id, 0, lua_empty_cb, lua_ptr[p].ptr); + p += 3; + break; + case lq_channel_list: + tgl_do_get_channels_dialog_list (TLS, 100, 0, lua_dialog_list_cb, lua_ptr[p ++].ptr); + break; + case lq_channel_leave: + tgl_do_leave_channel (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); + p += 2; + break; /* lq_delete_msg, lq_restore_msg, @@ -1594,6 +1678,11 @@ struct lua_function functions[] = { {"load_document", lq_load_document, { lfp_msg, lfp_none }}, {"load_document_thumb", lq_load_document_thumb, { lfp_msg, lfp_none }}, {"reply_msg", lq_reply, { lfp_msg, lfp_string, lfp_none }}, + {"reply_file", lq_reply_file, {lfp_msg, lfp_string, lfp_none}}, + {"reply_audio", lq_send_audio, {lfp_msg, lfp_string, lfp_none}}, + {"reply_document", lq_reply_document, {lfp_msg, lfp_string, lfp_none}}, + {"reply_photo", lq_reply_photo, {lfp_msg, lfp_string, lfp_none}}, + {"reply_video", lq_reply_video, {lfp_msg, lfp_string, lfp_none}}, {"fwd_msg", lq_fwd, { lfp_peer, lfp_msg, lfp_none }}, {"fwd_media", lq_fwd_media, { lfp_peer, lfp_msg, lfp_none }}, {"chat_info", lq_chat_info, { lfp_chat, lfp_none }}, @@ -1621,7 +1710,8 @@ struct lua_function functions[] = { {"send_contact", lq_send_contact, { lfp_peer, lfp_string, lfp_string, lfp_string, lfp_none }}, {"status_online", lq_status_online, { lfp_none }}, {"status_offline", lq_status_offline, { lfp_none }}, - {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, + {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, + {"post_location", lq_post_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, {"ext_function", lq_extf, { lfp_string, lfp_none }}, {"import_chat_link", lq_import_chat_link, { lfp_string, lfp_none }}, {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, @@ -1647,6 +1737,23 @@ struct lua_function functions[] = { {"channel_set_mod", lq_channel_set_mod, { lfp_channel, lfp_peer, lfp_none }}, {"channel_demote", lq_channel_demote, { lfp_channel, lfp_peer, lfp_none }}, {"resolve_username", lq_contact_search, { lfp_string, lfp_none }}, + {"block_user", lq_block_user, { lfp_user, lfp_none }}, + {"unblock_user", lq_unblock_user, { lfp_user, lfp_none }}, + {"import_channel_link", lq_import_chat_link, { lfp_string, lfp_none }}, + {"resolve_username", lq_contact_search, { lfp_string, lfp_none }}, + {"create_channel", lq_create_channel, { lfp_peer, lfp_string, lfp_string, lfp_none }}, + {"channel_set_mod", lq_channel_set_mod, { lfp_channel, lfp_peer, lfp_none }}, + {"channel_del_admin", lq_channel_del_admin, { lfp_channel, lfp_user,lfp_none }}, + {"channel_del_mod", lq_channel_del_admin, { lfp_channel, lfp_user,lfp_none }}, + {"chat_upgrade", lq_chat_upgrade, { lfp_peer, lfp_none }}, + {"channel_leave", lq_channel_leave, { lfp_channel, lfp_none }}, + {"get_channel_list", lq_channel_list, { lfp_none }}, + {"post_audio", lq_post_audio, { lfp_peer, lfp_string, lfp_none }}, + {"post_document", lq_post_document, { lfp_peer, lfp_string, lfp_none }}, + {"post_file", lq_post_file, { lfp_peer, lfp_string, lfp_none }}, + {"post_photo", lq_post_photo, { lfp_peer, lfp_string, lfp_none }}, + {"post_text", lq_post_text, { lfp_peer, lfp_string, lfp_none }}, + {"post_video", lq_post_video, { lfp_peer, lfp_string, lfp_none }}, { 0, 0, { lfp_none}} }; @@ -1657,10 +1764,10 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { lua_pushboolean (L, 0); return 1; } - + int a1 = luaL_ref (L, LUA_REGISTRYINDEX); int a2 = luaL_ref (L, LUA_REGISTRYINDEX); - + struct lua_query_extra *e = malloc (sizeof (*e)); assert (e); e->func = a2; @@ -1697,7 +1804,7 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { ok = 0; break; } - + if (F->params[p] == lfp_user) { peer_id = parse_input_peer_id (s, strlen (s), TGL_PEER_USER); } else if (F->params[p] == lfp_chat) { @@ -1709,12 +1816,12 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { } else { peer_id = parse_input_peer_id (s, strlen (s), 0); } - + if (!peer_id.peer_type) { ok = 0; break; } - + lua_ptr[pos + p].peer_id = peer_id; break; @@ -1730,10 +1837,10 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { case lfp_number: num = lua_tonumber (L, -cc); - + lua_ptr[pos + p].num = num; break; - + case lfp_double: dval = lua_tonumber (L, -cc); lua_ptr[pos + p].dnum = dval; @@ -1751,27 +1858,27 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { break; } break; - + case lfp_positive_number: num = lua_tonumber (L, -cc); if (num <= 0) { ok = 0; break; } - + lua_ptr[pos + p].num = num; break; - + case lfp_nonnegative_number: num = lua_tonumber (L, -cc); if (num < 0) { ok = 0; break; } - + lua_ptr[pos + p].num = num; break; - + default: assert (0); } @@ -1784,7 +1891,7 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { lua_pushboolean (L, 0); return 1; } - + for (p = 0; p < sp; p++) { if (F->params[p] == lfp_string) { lua_ptr[pos + p].str = tstrdup (lua_ptr[pos + p].str); @@ -1799,7 +1906,7 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) { static void lua_postpone_alarm (evutil_socket_t fd, short what, void *arg) { int *t = arg; - + lua_settop (luaState, 0); //lua_checkstack (luaState, 20); my_lua_checkstack (luaState, 20); @@ -1807,7 +1914,7 @@ static void lua_postpone_alarm (evutil_socket_t fd, short what, void *arg) { lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[1]); lua_rawgeti (luaState, LUA_REGISTRYINDEX, t[0]); assert (lua_gettop (luaState) == 2); - + int r = ps_lua_pcall (luaState, 1, 0, 0); luaL_unref (luaState, LUA_REGISTRYINDEX, t[0]); @@ -1843,13 +1950,13 @@ static int postpone_from_lua (lua_State *L) { t[0] = a1; t[1] = a2; *(void **)(t + 2) = ev; - + struct timeval ts= { .tv_sec = (long)timeout, .tv_usec = (timeout - ((long)timeout)) * 1000000 }; event_add (ev, &ts); - + lua_pushboolean (L, 1); return 1; } @@ -1862,7 +1969,7 @@ static int safe_quit_from_lua (lua_State *L) { return 1; } safe_quit = 1; - + lua_pushboolean (L, 1); return 1; } @@ -1939,11 +2046,11 @@ struct command { static void do_interface_from_lua (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { lua_settop (luaState, 0); my_lua_checkstack (luaState, 20); - - struct lua_query_extra *e = command->arg; + + struct lua_query_extra *e = command->arg; lua_rawgeti (luaState, LUA_REGISTRYINDEX, e->func); lua_rawgeti (luaState, LUA_REGISTRYINDEX, e->param); - + int i; for (i = 0; i < arg_num; i ++) { int j = i; @@ -1958,7 +2065,7 @@ static void do_interface_from_lua (struct command *command, int arg_num, struct switch (command->args[j] & 0xff) { case ca_none: case ca_period: - assert (0); + assert (0); break; case ca_user: case ca_chat: @@ -1996,9 +2103,9 @@ static void do_interface_from_lua (struct command *command, int arg_num, struct break; } } - - + + int r = ps_lua_pcall (luaState, 1 + arg_num, 0, 0); if (r) { @@ -2021,7 +2128,7 @@ static int register_interface_from_lua (lua_State *L) { for (i = 0; i < n - 4; i++) { const char *s = lua_tostring (L, -1); lua_pop (L, 1); - + if (!s || !strlen (s)) { lua_pushboolean (L, 0); return 1; @@ -2052,7 +2159,7 @@ static int register_interface_from_lua (lua_State *L) { VARIANT (double) VARIANT (string_end) VARIANT (string) - + #undef VARTIANT if (!ok) { @@ -2060,12 +2167,12 @@ static int register_interface_from_lua (lua_State *L) { return 1; } } - + const char *s = lua_tostring (L, -1); lua_pop (L, 1); - + cmd.desc = s ? tstrdup (s) : tstrdup ("no help provided"); - + int a1 = luaL_ref (L, LUA_REGISTRYINDEX); int a2 = luaL_ref (L, LUA_REGISTRYINDEX); @@ -2075,9 +2182,9 @@ static int register_interface_from_lua (lua_State *L) { e->param = a1; cmd.arg = e; - + cmd.fun = do_interface_from_lua; - + s = lua_tostring (L, -1); lua_pop (L, 1); @@ -2101,7 +2208,7 @@ void lua_init (const char *file) { my_lua_register (luaState, functions[i].name, universal_from_lua); i ++; } - + lua_register (luaState, "postpone", postpone_from_lua); lua_register (luaState, "safe_quit", safe_quit_from_lua); lua_register (luaState, "register_interface_function", register_interface_from_lua); From e2b9d3c2b4086e998924e82b988c00e8c22dbd76 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 04:00:37 +0000 Subject: [PATCH 138/164] Update lua-tg.c --- lua-tg.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index dccccf93..1be7ee13 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -1,19 +1,15 @@ /* 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 */ @@ -1426,7 +1422,7 @@ void lua_do_all (void) { tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, LUA_STR_ARG (p + 1), lua_msg_list_cb, lua_ptr[p].ptr); p += 2; break; - case lq_resolve_username: + case lq_resolve_username: tgl_do_contact_search (TLS, LUA_STR_ARG (p + 1), lua_contact_search_cb, lua_ptr[p].ptr); p += 2; break; @@ -1740,7 +1736,6 @@ struct lua_function functions[] = { {"block_user", lq_block_user, { lfp_user, lfp_none }}, {"unblock_user", lq_unblock_user, { lfp_user, lfp_none }}, {"import_channel_link", lq_import_chat_link, { lfp_string, lfp_none }}, - {"resolve_username", lq_contact_search, { lfp_string, lfp_none }}, {"create_channel", lq_create_channel, { lfp_peer, lfp_string, lfp_string, lfp_none }}, {"channel_set_mod", lq_channel_set_mod, { lfp_channel, lfp_peer, lfp_none }}, {"channel_del_admin", lq_channel_del_admin, { lfp_channel, lfp_user,lfp_none }}, From 2d92ab444ce0ba6f5e3c1ae40690f01c5c74a556 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 04:03:36 +0000 Subject: [PATCH 139/164] Removes duplicate lq_resolve_username, sort lua_function by name --- lua-tg.c | 160 ++++++++++++++++++++++++++----------------------------- 1 file changed, 75 insertions(+), 85 deletions(-) diff --git a/lua-tg.c b/lua-tg.c index 1be7ee13..6bd02196 100644 --- a/lua-tg.c +++ b/lua-tg.c @@ -752,7 +752,6 @@ enum lua_query_type { lq_reply_file, lq_reply_photo, lq_reply_video, - lq_resolve_username, lq_restore_msg, lq_search, lq_send_audio, @@ -1422,10 +1421,6 @@ void lua_do_all (void) { tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, LUA_STR_ARG (p + 1), lua_msg_list_cb, lua_ptr[p].ptr); p += 2; break; - case lq_resolve_username: - tgl_do_contact_search (TLS, LUA_STR_ARG (p + 1), lua_contact_search_cb, lua_ptr[p].ptr); - p += 2; - break; case lq_mark_read: tgl_do_mark_read (TLS, lua_ptr[p + 1].peer_id, lua_empty_cb, lua_ptr[p].ptr); p += 2; @@ -1653,102 +1648,97 @@ struct lua_function { }; struct lua_function functions[] = { - {"get_contact_list", lq_contact_list, { lfp_none }}, - {"get_dialog_list", lq_dialog_list, { lfp_none }}, - {"rename_chat", lq_rename_chat, { lfp_chat, lfp_string, lfp_none }}, - {"send_msg", lq_msg, { lfp_peer, lfp_string, lfp_none }}, - {"post_msg", lq_msg_channel, { lfp_channel, lfp_string, lfp_none }}, - {"send_typing", lq_send_typing, { lfp_peer, lfp_none }}, - {"send_typing_abort", lq_send_typing_abort, { lfp_peer, lfp_none }}, - {"send_photo", lq_send_photo, { lfp_peer, lfp_string, lfp_none }}, - {"send_video", lq_send_video, { lfp_peer, lfp_string, lfp_none }}, - {"send_audio", lq_send_audio, { lfp_peer, lfp_string, lfp_none }}, - {"send_document", lq_send_document, { lfp_peer, lfp_string, lfp_none }}, - {"send_file", lq_send_file, { lfp_peer, lfp_string, lfp_none }}, - {"send_text", lq_send_text, { lfp_peer, lfp_string, lfp_none }}, - {"chat_set_photo", lq_chat_set_photo, { lfp_chat, lfp_string, lfp_none }}, - {"load_photo", lq_load_photo, { lfp_msg, lfp_none }}, - {"load_video", lq_load_video, { lfp_msg, lfp_none }}, - {"load_video_thumb", lq_load_video_thumb, { lfp_msg, lfp_none }}, - {"load_audio", lq_load_audio, { lfp_msg, lfp_none }}, - {"load_document", lq_load_document, { lfp_msg, lfp_none }}, - {"load_document_thumb", lq_load_document_thumb, { lfp_msg, lfp_none }}, - {"reply_msg", lq_reply, { lfp_msg, lfp_string, lfp_none }}, - {"reply_file", lq_reply_file, {lfp_msg, lfp_string, lfp_none}}, - {"reply_audio", lq_send_audio, {lfp_msg, lfp_string, lfp_none}}, - {"reply_document", lq_reply_document, {lfp_msg, lfp_string, lfp_none}}, - {"reply_photo", lq_reply_photo, {lfp_msg, lfp_string, lfp_none}}, - {"reply_video", lq_reply_video, {lfp_msg, lfp_string, lfp_none}}, - {"fwd_msg", lq_fwd, { lfp_peer, lfp_msg, lfp_none }}, - {"fwd_media", lq_fwd_media, { lfp_peer, lfp_msg, lfp_none }}, - {"chat_info", lq_chat_info, { lfp_chat, lfp_none }}, - {"channel_info", lq_channel_info, { lfp_channel, lfp_none }}, - {"user_info", lq_user_info, { lfp_user, lfp_none }}, - {"get_history", lq_history, { lfp_peer, lfp_nonnegative_number, lfp_none }}, - {"chat_add_user", lq_chat_add_user, { lfp_chat, lfp_user, lfp_none }}, - {"chat_del_user", lq_chat_del_user, { lfp_chat, lfp_user, lfp_none }}, - {"add_contact", lq_add_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, - {"del_contact", lq_del_contact, { lfp_user, lfp_none }}, - {"rename_contact", lq_rename_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, - {"msg_search", lq_search, { lfp_peer, lfp_string, lfp_none }}, - {"msg_global_search", lq_global_search, { lfp_string, lfp_none }}, - {"resolve_username", lq_resolve_username, { lfp_string, lfp_none }}, - {"mark_read", lq_mark_read, { lfp_peer, lfp_none }}, - {"set_profile_photo", lq_set_profile_photo, { lfp_string, lfp_none }}, - {"set_profile_name", lq_set_profile_name, { lfp_string,lfp_string, lfp_none }}, - {"set_profile_username", lq_set_profile_username, { lfp_string, lfp_none }}, - {"create_secret_chat", lq_create_secret_chat, { lfp_user, lfp_none }}, - {"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }}, - {"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }}, - {"restore_msg", lq_restore_msg, { lfp_positive_number, lfp_none }}, - {"get_message", lq_get_message, { lfp_msg, lfp_none }}, {"accept_secret_chat", lq_accept_secret_chat, { lfp_secret_chat, lfp_none }}, - {"send_contact", lq_send_contact, { lfp_peer, lfp_string, lfp_string, lfp_string, lfp_none }}, - {"status_online", lq_status_online, { lfp_none }}, - {"status_offline", lq_status_offline, { lfp_none }}, - {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, - {"post_location", lq_post_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, - {"ext_function", lq_extf, { lfp_string, lfp_none }}, - {"import_chat_link", lq_import_chat_link, { lfp_string, lfp_none }}, - {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, - {"get_channels_dialog_list", lq_channels_dialog_list, { lfp_none }}, - {"chat_upgrade", lq_chat_upgrade, { lfp_peer, lfp_none }}, - {"create_channel", lq_create_channel, { lfp_peer, lfp_string, lfp_string, lfp_none }}, + {"add_contact", lq_add_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, + {"block_user", lq_block_user, { lfp_user, lfp_none }}, + {"channel_del_admin", lq_channel_del_admin, { lfp_channel, lfp_user,lfp_none }}, + {"channel_del_mod", lq_channel_del_admin, { lfp_channel, lfp_user,lfp_none }}, + {"channel_demote", lq_channel_demote, { lfp_channel, lfp_peer, lfp_none }}, + {"channel_get_admins", lq_channel_get_admins, { lfp_channel, lfp_none }}, + {"channel_get_bots", lq_channel_get_bots, { lfp_channel, lfp_none }}, + {"channel_get_kicked", lq_channel_get_kicked, { lfp_channel, lfp_none }}, + {"channel_get_users", lq_channel_get_users, { lfp_channel, lfp_none }}, {"channel_info", lq_channel_info, { lfp_channel, lfp_none }}, - {"export_channel_link", lq_export_channel_link, { lfp_channel, lfp_none }}, {"channel_invite", lq_channel_invite, { lfp_channel, lfp_user, lfp_none }}, {"channel_join", lq_channel_join, { lfp_channel, lfp_none }}, - {"leave_channel", lq_leave_channel, { lfp_channel, lfp_none }}, {"channel_kick", lq_channel_kick, { lfp_channel, lfp_user, lfp_none }}, - {"channel_get_admins", lq_channel_get_admins, { lfp_channel, lfp_none }}, - {"channel_get_users", lq_channel_get_users, { lfp_channel, lfp_none }}, - {"channel_get_bots", lq_channel_get_bots, { lfp_channel, lfp_none }}, - {"channel_get_kicked", lq_channel_get_kicked, { lfp_channel, lfp_none }}, - {"channel_unblock", lq_channel_unblock, { lfp_channel, lfp_peer, lfp_none }}, - {"rename_channel", lq_rename_channel, { lfp_channel, lfp_string, lfp_none }}, - {"channel_set_photo", lq_channel_set_photo, { lfp_channel, lfp_string, lfp_none }}, + {"channel_leave", lq_channel_leave, { lfp_channel, lfp_none }}, {"channel_set_about", lq_channel_set_about, { lfp_channel, lfp_string, lfp_none }}, - {"channel_set_username", lq_channel_set_username, { lfp_channel, lfp_string, lfp_none }}, {"channel_set_admin", lq_channel_set_admin, { lfp_channel, lfp_peer, lfp_none }}, {"channel_set_mod", lq_channel_set_mod, { lfp_channel, lfp_peer, lfp_none }}, - {"channel_demote", lq_channel_demote, { lfp_channel, lfp_peer, lfp_none }}, - {"resolve_username", lq_contact_search, { lfp_string, lfp_none }}, - {"block_user", lq_block_user, { lfp_user, lfp_none }}, - {"unblock_user", lq_unblock_user, { lfp_user, lfp_none }}, - {"import_channel_link", lq_import_chat_link, { lfp_string, lfp_none }}, - {"create_channel", lq_create_channel, { lfp_peer, lfp_string, lfp_string, lfp_none }}, - {"channel_set_mod", lq_channel_set_mod, { lfp_channel, lfp_peer, lfp_none }}, - {"channel_del_admin", lq_channel_del_admin, { lfp_channel, lfp_user,lfp_none }}, - {"channel_del_mod", lq_channel_del_admin, { lfp_channel, lfp_user,lfp_none }}, + {"channel_set_photo", lq_channel_set_photo, { lfp_channel, lfp_string, lfp_none }}, + {"channel_set_username", lq_channel_set_username, { lfp_channel, lfp_string, lfp_none }}, + {"channel_unblock", lq_channel_unblock, { lfp_channel, lfp_peer, lfp_none }}, + {"chat_add_user", lq_chat_add_user, { lfp_chat, lfp_user, lfp_none }}, + {"chat_del_user", lq_chat_del_user, { lfp_chat, lfp_user, lfp_none }}, + {"chat_info", lq_chat_info, { lfp_chat, lfp_none }}, + {"chat_set_photo", lq_chat_set_photo, { lfp_chat, lfp_string, lfp_none }}, {"chat_upgrade", lq_chat_upgrade, { lfp_peer, lfp_none }}, - {"channel_leave", lq_channel_leave, { lfp_channel, lfp_none }}, + {"create_channel", lq_create_channel, { lfp_peer, lfp_string, lfp_string, lfp_none }}, + {"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }}, + {"create_secret_chat", lq_create_secret_chat, { lfp_user, lfp_none }}, + {"del_contact", lq_del_contact, { lfp_user, lfp_none }}, + {"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }}, + {"export_channel_link", lq_export_channel_link, { lfp_channel, lfp_none }}, + {"export_chat_link", lq_export_chat_link, { lfp_chat, lfp_none }}, + {"ext_function", lq_extf, { lfp_string, lfp_none }}, + {"fwd_media", lq_fwd_media, { lfp_peer, lfp_msg, lfp_none }}, + {"fwd_msg", lq_fwd, { lfp_peer, lfp_msg, lfp_none }}, {"get_channel_list", lq_channel_list, { lfp_none }}, + {"get_channels_dialog_list", lq_channels_dialog_list, { lfp_none }}, + {"get_contact_list", lq_contact_list, { lfp_none }}, + {"get_dialog_list", lq_dialog_list, { lfp_none }}, + {"get_history", lq_history, { lfp_peer, lfp_nonnegative_number, lfp_none }}, + {"get_message", lq_get_message, { lfp_msg, lfp_none }}, + {"import_channel_link", lq_import_chat_link, { lfp_string, lfp_none }}, + {"import_chat_link", lq_import_chat_link, { lfp_string, lfp_none }}, + {"leave_channel", lq_leave_channel, { lfp_channel, lfp_none }}, + {"load_audio", lq_load_audio, { lfp_msg, lfp_none }}, + {"load_document", lq_load_document, { lfp_msg, lfp_none }}, + {"load_document_thumb", lq_load_document_thumb, { lfp_msg, lfp_none }}, + {"load_photo", lq_load_photo, { lfp_msg, lfp_none }}, + {"load_video", lq_load_video, { lfp_msg, lfp_none }}, + {"load_video_thumb", lq_load_video_thumb, { lfp_msg, lfp_none }}, + {"mark_read", lq_mark_read, { lfp_peer, lfp_none }}, + {"msg_global_search", lq_global_search, { lfp_string, lfp_none }}, + {"msg_search", lq_search, { lfp_peer, lfp_string, lfp_none }}, {"post_audio", lq_post_audio, { lfp_peer, lfp_string, lfp_none }}, {"post_document", lq_post_document, { lfp_peer, lfp_string, lfp_none }}, {"post_file", lq_post_file, { lfp_peer, lfp_string, lfp_none }}, + {"post_location", lq_post_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, + {"post_msg", lq_msg_channel, { lfp_channel, lfp_string, lfp_none }}, {"post_photo", lq_post_photo, { lfp_peer, lfp_string, lfp_none }}, {"post_text", lq_post_text, { lfp_peer, lfp_string, lfp_none }}, {"post_video", lq_post_video, { lfp_peer, lfp_string, lfp_none }}, + {"rename_channel", lq_rename_channel, { lfp_channel, lfp_string, lfp_none }}, + {"rename_chat", lq_rename_chat, { lfp_chat, lfp_string, lfp_none }}, + {"rename_contact", lq_rename_contact, { lfp_string, lfp_string, lfp_string, lfp_none }}, + {"reply_audio", lq_send_audio, {lfp_msg, lfp_string, lfp_none}}, + {"reply_document", lq_reply_document, {lfp_msg, lfp_string, lfp_none}}, + {"reply_file", lq_reply_file, {lfp_msg, lfp_string, lfp_none}}, + {"reply_msg", lq_reply, { lfp_msg, lfp_string, lfp_none }}, + {"reply_photo", lq_reply_photo, {lfp_msg, lfp_string, lfp_none}}, + {"reply_video", lq_reply_video, {lfp_msg, lfp_string, lfp_none}}, + {"resolve_username", lq_contact_search, { lfp_string, lfp_none }}, + {"restore_msg", lq_restore_msg, { lfp_positive_number, lfp_none }}, + {"send_audio", lq_send_audio, { lfp_peer, lfp_string, lfp_none }}, + {"send_contact", lq_send_contact, { lfp_peer, lfp_string, lfp_string, lfp_string, lfp_none }}, + {"send_document", lq_send_document, { lfp_peer, lfp_string, lfp_none }}, + {"send_file", lq_send_file, { lfp_peer, lfp_string, lfp_none }}, + {"send_location", lq_send_location, { lfp_peer, lfp_double, lfp_double, lfp_none }}, + {"send_msg", lq_msg, { lfp_peer, lfp_string, lfp_none }}, + {"send_photo", lq_send_photo, { lfp_peer, lfp_string, lfp_none }}, + {"send_text", lq_send_text, { lfp_peer, lfp_string, lfp_none }}, + {"send_typing", lq_send_typing, { lfp_peer, lfp_none }}, + {"send_typing_abort", lq_send_typing_abort, { lfp_peer, lfp_none }}, + {"send_video", lq_send_video, { lfp_peer, lfp_string, lfp_none }}, + {"set_profile_name", lq_set_profile_name, { lfp_string,lfp_string, lfp_none }}, + {"set_profile_photo", lq_set_profile_photo, { lfp_string, lfp_none }}, + {"set_profile_username", lq_set_profile_username, { lfp_string, lfp_none }}, + {"status_offline", lq_status_offline, { lfp_none }}, + {"status_online", lq_status_online, { lfp_none }}, + {"unblock_user", lq_unblock_user, { lfp_user, lfp_none }}, + {"user_info", lq_user_info, { lfp_user, lfp_none }}, { 0, 0, { lfp_none}} }; From ad538b908b551941b2e70098c4a93d3b73f41e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Navarro=20Fern=C3=A1ndez?= Date: Tue, 1 Mar 2016 17:21:21 +0100 Subject: [PATCH 140/164] Update README.md dnf -> yum libjansson-devel -> jansson-devel --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index fc1c5f9b..cf1f2098 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,10 @@ On Fedora: sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel libgcrypt-devel +On CentOS: + + sudo yum install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel jansson-devel python-devel + On Archlinux: yaourt -S telegram-cli-git From e6f6a2cf509417c8949aa7e420fb4021e2aa8d57 Mon Sep 17 00:00:00 2001 From: Antonio Galea Date: Tue, 27 Oct 2015 09:45:28 +0100 Subject: [PATCH 141/164] fix: null error string breaks json mode --- interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface.c b/interface.c index 80168fcf..a1152f57 100644 --- a/interface.c +++ b/interface.c @@ -2289,7 +2289,7 @@ void print_fail (struct in_ev *ev) { json_t *res = json_object (); assert (json_object_set_new (res, "result", json_string ("FAIL")) >= 0); assert (json_object_set_new (res, "error_code", json_integer (TLS->error_code)) >= 0); - assert (json_object_set_new (res, "error", json_string (TLS->error)) >= 0); + assert (json_object_set_new (res, "error", json_string (TLS->error ? TLS->error : "")) >= 0); char *s = json_dumps (res, 0); mprintf (ev, "%s\n", s); json_decref (res); From 75729e32a1f3c9691f49d6ed49305f250fdc180f Mon Sep 17 00:00:00 2001 From: Behrang Saeedzadeh Date: Wed, 27 Jan 2016 20:09:02 +1100 Subject: [PATCH 142/164] Updated installation instructions using Homebrew --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cf1f2098..48cf773c 100644 --- a/README.md +++ b/README.md @@ -106,11 +106,21 @@ or manually: ./configure -or with OpenSSL: +You might have to manually pass the location of OpenSSL to `configure`: - ./configure --with-openssl=/usr/local/opt/openssl && make CFSUFFIX='-Wno-error=unused' + $ brew info openssl + openssl: stable 1.0.2e (bottled) [keg-only] + Poured from bottle /usr/local/Cellar/openssl/1.0.2e_1 (465 files, 11.9M) -If you get a lua error on Sierra, you can configure without LUA using +so in this case the configure should be run as: + + ./configure --with-openssl=/usr/local/Cellar/openssl/1.0.2e_1 + +in other cases OpenSSL could be found in `/usr/local/opt`, e.g.: + + ./configure --with-openssl=/usr/local/opt/openssl + +If you get a LUA error on Sierra, you can configure without LUA using ./configure --disable-liblua From eb9dc73639806d39bcb57fecc722c4518421da6e Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 15:50:54 +0000 Subject: [PATCH 143/164] Removes conflicted line --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index 4a1fbf6d..8daa5d94 100644 --- a/debian/control +++ b/debian/control @@ -1,6 +1,5 @@ Source: telegram-cli Section: net -<<<<<<< HEAD Priority: optional Maintainer: Cleto Martín Build-Depends: autoconf-archive, From 808271432ba3e80c51e3f38fc2cc302492e7bfd2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 15:52:11 +0000 Subject: [PATCH 144/164] Removes useless file --- DEADJOE | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 DEADJOE diff --git a/DEADJOE b/DEADJOE deleted file mode 100644 index 217d7836..00000000 --- a/DEADJOE +++ /dev/null @@ -1,41 +0,0 @@ - -*** These modified files were found in JOE when it aborted on Mon Mar 7 21:37:19 2016 -*** JOE was aborted by UNIX signal 1 - -*** File '/home/rondoozle/tg/.git/COMMIT_EDITMSG' - -# Please enter the commit message for your changes. Lines starting -# with '#' will be ignored, and an empty message aborts the commit. -# -# Committer: Garemyah Johnson -# -# On branch master -# Your branch is up-to-date with 'origin/master'. -SuperGroups -# Changes to be committed: -# modified: Makefile.in -# modified: Makefile.tgl -# modified: Makefile.tl-parser -# modified: README-LUA -# modified: config.h.in -# modified: config.sample -# modified: configure -# modified: configure.ac -# modified: interface.c -# modified: interface.h -# modified: json-tg.c -# modified: loop.c -# modified: lua-tg.c -# modified: lua-tg.h -# modified: main.c -# modified: telegram.h -# - -*** File '(Unnamed)' -/home/rondoozle/tg/.git/COMMIT_EDITMSG -/home/rondoozle/tg/.git/COMMIT_EDITMSG -/home/rondoozle/tg/.git/COMMIT_EDITMSG -/home/rondoozle/tg/.git/COMMIT_EDITMSG -/home/rondoozle/tg/.git/COMMIT_EDITMSG -/home/rondoozle/tg/.git/COMMIT_EDITMSG -/home/rondoozle/tg/.git/COMMIT_EDITMSG From 21b7501879469ec6b5ba6b4b340215d373b97a94 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 3 Feb 2019 16:29:56 +0000 Subject: [PATCH 145/164] Updates README with table of builds --- README.md | 21 +++++++++++++-------- tgl | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 945bc719..0cdac2e3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,21 @@ ## Telegram messenger CLI -[![Build Status](https://travis-ci.org/kenorb-contrib/tg.png)](https://travis-ci.org/kenorb-contrib/tg) +Command-line interface for [Telegram](http://telegram.org). Uses readline interface. It is client implementation of TGL library. -Command-line interface for [Telegram](http://telegram.org). Uses readline interface. +> Note: This is a fork of [`telegram-cli`](https://github.com/vysheng/tg). -**[ This is a fork of [telegram-cli](https://github.com/vysheng/tg) with history callbacks to use in [ibotg](https://github.com/prsai/ibotg) ]** +Build status: + +| Repository | Status| +| ------------------------------------------------------ | ----- | +| [vysheng](https://github.com/vysheng/tg) (main) |[![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg)| +| [kenorb-contrib](https://github.com/kenorb-contrib/tg) |[![Build Status](https://travis-ci.org/kenorb-contrib/tg.png)](https://travis-ci.org/kenorb-contrib/tg)| ### API, Protocol documentation -Documentation for Telegram API is available here: http://core.telegram.org/api +Documentation for Telegram API is available here: -Documentation for MTproto protocol is available here: http://core.telegram.org/mtproto +Documentation for MTproto protocol is available here: ### Upgrading to version 1.0 @@ -24,9 +29,9 @@ Fourth, in `peer_name` '#' are substitued to '@'. (Not applied to appending of ' ### Installation -Clone GitHub Repository +Clone this GitHub repository with `--recursive` parameter to clone submodules. - git clone --recursive https://github.com/kenorb-contrib/tg.git && cd tg + git clone --recursive https://github.com/CHANGETHIS/tg.git && cd tg ### Python Support @@ -253,4 +258,4 @@ If two or more peers have same name, number is appended to the name. (for #### Other * **quit** - quit -* **safe_quit** - wait for all queries to end then quit +* **safe_quit** - wait for all queries to end then quit \ No newline at end of file diff --git a/tgl b/tgl index 09a32d9c..57f1bc41 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 09a32d9c75980e0ba06c158d9ca9ec5100eaf79b +Subproject commit 57f1bc41ae13297e6c3e23ac465fd45ec6659f50 From bba2ac5c2cc24a64e3906114cb6ac92bf8b74637 Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 14 Mar 2019 20:07:16 +0000 Subject: [PATCH 146/164] libssl1.0-dev works, but not libssl-dev Ref: https://github.com/kenorb-contrib/tg/commit/f3fe47ff6b9eb91de2026f7ab86db77be6562ffb#commitcomment-32747153 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0cdac2e3..14feb474 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ If you do not want to use them pass options --disable-libconfig, --disable-liblu On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev libpython3-dev libgcrypt-dev zlib1g-dev lua-lgi make + sudo apt-get install libreadline-dev libconfig-dev libssl1.0-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev libpython3-dev libgcrypt-dev zlib1g-dev lua-lgi make To build and install the packaege, run: dpkg-buildpackage -b @@ -258,4 +258,4 @@ If two or more peers have same name, number is appended to the name. (for #### Other * **quit** - quit -* **safe_quit** - wait for all queries to end then quit \ No newline at end of file +* **safe_quit** - wait for all queries to end then quit From 67fa951edfe876d4f72e3cc6e197b265a3c8f2e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tun=C3=A7=20Y=C4=B1ld=C4=B1r=C4=B1m?= Date: Mon, 13 May 2019 14:52:53 +0300 Subject: [PATCH 147/164] Added timestamps to typing indicators. --- interface.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/interface.c b/interface.c index f18ab8e8..266978ca 100644 --- a/interface.c +++ b/interface.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef READLINE_GNU #include @@ -3015,39 +3016,43 @@ void mark_read_upd (struct tgl_state *TLSR, int num, struct tgl_message *list[]) } void print_typing (struct in_ev *ev, enum tgl_typing_status status) { + + time_t t = time(NULL); + struct tm tm = *localtime(&t); + switch (status) { case tgl_typing_none: mprintf (ev, "doing nothing"); break; case tgl_typing_typing: - mprintf (ev, "typing"); + mprintf (ev, "typing -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_cancel: - mprintf (ev, "deleting typed message"); + mprintf (ev, "deleting typed message -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_record_video: - mprintf (ev, "recording video"); + mprintf (ev, "recording video -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_upload_video: - mprintf (ev, "uploading video"); + mprintf (ev, "uploading video -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_record_audio: - mprintf (ev, "recording audio"); + mprintf (ev, "recording audio -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_upload_audio: - mprintf (ev, "uploading audio"); + mprintf (ev, "uploading audio -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_upload_photo: - mprintf (ev, "uploading photo"); + mprintf (ev, "uploading photo -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_upload_document: - mprintf (ev, "uploading document"); + mprintf (ev, "uploading document -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_geo: - mprintf (ev, "choosing location"); + mprintf (ev, "choosing location -- [%d:%d]", tm.tm_hour, tm.tm_min); break; case tgl_typing_choose_contact: - mprintf (ev, "choosing contact"); + mprintf (ev, "choosing contact -- [%d:%d]", tm.tm_hour, tm.tm_min); break; } } From e4eb11ce5dfca7eef210406e1e0fcd741130381f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tun=C3=A7=20Y=C4=B1ld=C4=B1r=C4=B1m?= Date: Mon, 13 May 2019 15:15:27 +0300 Subject: [PATCH 148/164] Added dates to typing indicators. --- interface.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/interface.c b/interface.c index 266978ca..22db9fba 100644 --- a/interface.c +++ b/interface.c @@ -3025,34 +3025,34 @@ void print_typing (struct in_ev *ev, enum tgl_typing_status status) { mprintf (ev, "doing nothing"); break; case tgl_typing_typing: - mprintf (ev, "typing -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "typing -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_cancel: - mprintf (ev, "deleting typed message -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "deleting typed message -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_record_video: - mprintf (ev, "recording video -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "recording video -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_upload_video: - mprintf (ev, "uploading video -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "uploading video -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_record_audio: - mprintf (ev, "recording audio -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "recording audio -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_upload_audio: - mprintf (ev, "uploading audio -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "uploading audio -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_upload_photo: - mprintf (ev, "uploading photo -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "uploading photo -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_upload_document: - mprintf (ev, "uploading document -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "uploading document -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_geo: - mprintf (ev, "choosing location -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "choosing location -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; case tgl_typing_choose_contact: - mprintf (ev, "choosing contact -- [%d:%d]", tm.tm_hour, tm.tm_min); + mprintf (ev, "choosing contact -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); break; } } From bac16a425ff53c79619f386e4396f2b73704a585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tun=C3=A7=20Y=C4=B1ld=C4=B1r=C4=B1m?= Date: Mon, 13 May 2019 15:30:36 +0300 Subject: [PATCH 149/164] Added date/timestamps to 'marked read' status. --- interface.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/interface.c b/interface.c index 22db9fba..36036323 100644 --- a/interface.c +++ b/interface.c @@ -2918,6 +2918,8 @@ struct event *unread_message_event; void print_read_list (int num, struct tgl_message *list[]) { + time_t t = time(NULL); + struct tm tm = *localtime(&t); struct in_ev *ev = notify_ev; int i; mprint_start (ev); @@ -2976,7 +2978,7 @@ void print_read_list (int num, struct tgl_message *list[]) { default: assert (0); } - mprintf (ev, " marked read %d outbox and %d inbox messages\n", c1, c2); + mprintf (ev, " marked read %d outbox and %d inbox messages -- [%d:%d] -- [%d/%d/%d]\n", c1, c2, tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); mpop_color (ev); } } @@ -3017,8 +3019,8 @@ void mark_read_upd (struct tgl_state *TLSR, int num, struct tgl_message *list[]) void print_typing (struct in_ev *ev, enum tgl_typing_status status) { - time_t t = time(NULL); - struct tm tm = *localtime(&t); + time_t t = time(NULL); + struct tm tm = *localtime(&t); switch (status) { case tgl_typing_none: From 0bc121a82c4bbeee91c7284950d249acde21f5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tun=C3=A7=20Y=C4=B1ld=C4=B1r=C4=B1m?= Date: Mon, 13 May 2019 15:49:38 +0300 Subject: [PATCH 150/164] Changed formatting of date/timestamps on 'read' and 'typing' indicators. --- interface.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/interface.c b/interface.c index 36036323..12408d72 100644 --- a/interface.c +++ b/interface.c @@ -2978,7 +2978,7 @@ void print_read_list (int num, struct tgl_message *list[]) { default: assert (0); } - mprintf (ev, " marked read %d outbox and %d inbox messages -- [%d:%d] -- [%d/%d/%d]\n", c1, c2, tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, " marked read %d outbox and %d inbox messages -- [%d/%d/%d %d:%d:%d]\n", c1, c2, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); mpop_color (ev); } } @@ -3027,34 +3027,34 @@ void print_typing (struct in_ev *ev, enum tgl_typing_status status) { mprintf (ev, "doing nothing"); break; case tgl_typing_typing: - mprintf (ev, "typing -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "typing -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_cancel: - mprintf (ev, "deleting typed message -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "deleting typed message -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_record_video: - mprintf (ev, "recording video -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "recording video -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_video: - mprintf (ev, "uploading video -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "uploading video -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_record_audio: - mprintf (ev, "recording audio -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "recording audio -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_audio: - mprintf (ev, "uploading audio -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "uploading audio -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_photo: - mprintf (ev, "uploading photo -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "uploading photo -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_document: - mprintf (ev, "uploading document -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "uploading document -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_geo: - mprintf (ev, "choosing location -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "choosing location -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_choose_contact: - mprintf (ev, "choosing contact -- [%d:%d] -- [%d/%d/%d]", tm.tm_hour, tm.tm_min, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + mprintf (ev, "choosing contact -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; } } From 3ffa1770f47cc7e6eed7c3c811ebb3cfa22905dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tun=C3=A7=20Y=C4=B1ld=C4=B1r=C4=B1m?= Date: Mon, 13 May 2019 16:32:51 +0300 Subject: [PATCH 151/164] Changed formatting of date/timestamps on 'read' and 'typing' indicators to have 2 digits. --- interface.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/interface.c b/interface.c index 12408d72..be8899d2 100644 --- a/interface.c +++ b/interface.c @@ -2978,7 +2978,7 @@ void print_read_list (int num, struct tgl_message *list[]) { default: assert (0); } - mprintf (ev, " marked read %d outbox and %d inbox messages -- [%d/%d/%d %d:%d:%d]\n", c1, c2, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, " marked read %d outbox and %d inbox messages -- [%d/%02d/%02d %02d:%02d:%02d]\n", c1, c2, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); mpop_color (ev); } } @@ -3027,34 +3027,34 @@ void print_typing (struct in_ev *ev, enum tgl_typing_status status) { mprintf (ev, "doing nothing"); break; case tgl_typing_typing: - mprintf (ev, "typing -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "typing -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_cancel: - mprintf (ev, "deleting typed message -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "deleting typed message -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_record_video: - mprintf (ev, "recording video -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "recording video -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_video: - mprintf (ev, "uploading video -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "uploading video -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_record_audio: - mprintf (ev, "recording audio -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "recording audio -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_audio: - mprintf (ev, "uploading audio -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "uploading audio -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_photo: - mprintf (ev, "uploading photo -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "uploading photo -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_upload_document: - mprintf (ev, "uploading document -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "uploading document -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_geo: - mprintf (ev, "choosing location -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "choosing location -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case tgl_typing_choose_contact: - mprintf (ev, "choosing contact -- [%d/%d/%d %d:%d:%d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + mprintf (ev, "choosing contact -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; } } From 8ae323c1dc399bf3b7bf02b178746a98ff17d1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tun=C3=A7=20Y=C4=B1ld=C4=B1r=C4=B1m?= Date: Sun, 28 Jul 2019 11:18:04 +0300 Subject: [PATCH 152/164] Added timestamps to status updates and fixed a typo --- interface.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/interface.c b/interface.c index be8899d2..9116ebed 100644 --- a/interface.c +++ b/interface.c @@ -3137,47 +3137,50 @@ void our_id_gw (struct tgl_state *TLSR, tgl_peer_id_t id) { } void print_peer_updates (struct in_ev *ev, int flags) { + time_t t = time(NULL); + struct tm tm = *localtime(&t); + if (flags & TGL_UPDATE_PHONE) { - mprintf (ev, " phone"); + mprintf (ev, " phone -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_CONTACT) { - mprintf (ev, " contact"); + mprintf (ev, " contact -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_PHOTO) { - mprintf (ev, " photo"); + mprintf (ev, " photo -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_BLOCKED) { - mprintf (ev, " blocked"); + mprintf (ev, " blocked -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_REAL_NAME) { - mprintf (ev, " name"); + mprintf (ev, " name -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_NAME) { - mprintf (ev, " contact_name"); + mprintf (ev, " contact_name -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_REQUESTED) { - mprintf (ev, " status"); + mprintf (ev, " status -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_WORKING) { - mprintf (ev, " status"); + mprintf (ev, " status -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_FLAGS) { - mprintf (ev, " flags"); + mprintf (ev, " flags -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_TITLE) { - mprintf (ev, " title"); + mprintf (ev, " title -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_ADMIN) { - mprintf (ev, " admin"); + mprintf (ev, " admin -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_MEMBERS) { - mprintf (ev, " members"); + mprintf (ev, " members -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_ACCESS_HASH) { - mprintf (ev, " access_hash"); + mprintf (ev, " access_hash -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (flags & TGL_UPDATE_USERNAME) { - mprintf (ev, " username"); + mprintf (ev, " username -- [%d/%02d/%02d %02d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } } @@ -4360,7 +4363,7 @@ void print_message (struct in_ev *ev, struct tgl_message *M) { last_to_id = M->to_id; //print_start (); - + // Sending to a USER if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) { if (M->flags & TGLMF_OUT) { From 17e4c3912f45d98c8718cfdc23c47b197a61735a Mon Sep 17 00:00:00 2001 From: Fyodor Date: Sun, 29 Dec 2019 04:56:57 +0300 Subject: [PATCH 153/164] add info about logout --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 14feb474..d232a78d 100644 --- a/README.md +++ b/README.md @@ -259,3 +259,4 @@ If two or more peers have same name, number is appended to the name. (for #### Other * **quit** - quit * **safe_quit** - wait for all queries to end then quit +* run `telegram-cli -q` to logout from account From bde835a19aa68032fc555cfc78cdf3fe1f84a19d Mon Sep 17 00:00:00 2001 From: Fyodor Date: Sun, 29 Dec 2019 04:59:34 +0300 Subject: [PATCH 154/164] add info about usernames resolving --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d232a78d..648909fe 100644 --- a/README.md +++ b/README.md @@ -260,3 +260,6 @@ If two or more peers have same name, number is appended to the name. (for * **quit** - quit * **safe_quit** - wait for all queries to end then quit * run `telegram-cli -q` to logout from account + +#### Troubleshooting +* if you got error: `get error FAIL: 38: can not parse arg #1` it maybe be unresolved username. You should use `resolve_username channel/group/user_name` before running action with it. [See this issue for more info](https://github.com/vysheng/tg/issues/823) From e63c9ddcf391de7f131c5d0849713b2fe14fef11 Mon Sep 17 00:00:00 2001 From: Rafal W Date: Mon, 6 Jan 2020 10:43:44 +0000 Subject: [PATCH 155/164] Change address to new forked repository --- debian/watch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/watch b/debian/watch index 2148331b..9f6e1d9c 100644 --- a/debian/watch +++ b/debian/watch @@ -1,4 +1,4 @@ version=3 opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/tg-$1\.tar\.gz/ \ - https://github.com/vysheng/tg/tags .*/v?(\d\S*)\.tar\.gz + https://github.com/kenorb-contrib/tg/tags .*/v?(\d\S*)\.tar\.gz From c00f352b926c37a3ae7f79ee7ce66398a668faec Mon Sep 17 00:00:00 2001 From: Jorge Gonzalez Date: Sat, 1 Feb 2020 13:06:52 +0100 Subject: [PATCH 156/164] Fix debian libssl dependency --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 648909fe..858ff086 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ If you do not want to use them pass options --disable-libconfig, --disable-liblu On Ubuntu/Debian use: - sudo apt-get install libreadline-dev libconfig-dev libssl1.0-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev libpython3-dev libgcrypt-dev zlib1g-dev lua-lgi make + sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev libpython3-dev libgcrypt-dev zlib1g-dev lua-lgi make To build and install the packaege, run: dpkg-buildpackage -b From 783f6985aa452a42f253b25f8d9e215657cb9ae8 Mon Sep 17 00:00:00 2001 From: Olivier Kaloudoff Date: Mon, 30 Mar 2020 14:38:11 +0200 Subject: [PATCH 157/164] debian/control: add missing dependency libgcrypt-dev --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 8daa5d94..e71f80b4 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,7 @@ Build-Depends: autoconf-archive, libjansson-dev, libpython-dev, liblua5.2-dev, + libgcrypt-dev, lua-lgi, lua5.2 Standards-Version: 3.9.5 From 66bcf7d07f12e8cb16ef6b8575b92f32e526f2bd Mon Sep 17 00:00:00 2001 From: Olivier Kaloudoff Date: Mon, 30 Mar 2020 14:39:05 +0200 Subject: [PATCH 158/164] debian/rules: configure using prefix=/usr --- debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index b82afaac..e29b4d17 100755 --- a/debian/rules +++ b/debian/rules @@ -12,7 +12,7 @@ export DH_VERBOSE=1 VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') override_dh_auto_configure: - ./configure --disable-openssl + ./configure --disable-openssl --prefix=/usr %: cp tg-server.pub server.pub dh $@ --with autotools-dev From dd912f1ed8518ddb691c34a536034f3b9ef63745 Mon Sep 17 00:00:00 2001 From: Olivier Kaloudoff Date: Mon, 30 Mar 2020 14:39:40 +0200 Subject: [PATCH 159/164] fix install step (telegram -> bin/telegram-cli) --- Makefile.in | 4 ++-- debian/install | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index f0bfc76d..ffcce82b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -66,6 +66,6 @@ distclean: rm -rf ${DIR_LIST} config.h config.log config.status install: all - @mkdir -p $(INSTALL_BIN) - $(INSTALL) telegram $(INSTALL_BIN) + @mkdir -p $(DESTDIR)/$(INSTALL_BIN) + $(INSTALL) bin/telegram-cli $(DESTDIR)/$(INSTALL_BIN) rm -rf ${DIR_LIST} config.log config.status > /dev/null || echo "all clean" diff --git a/debian/install b/debian/install index 8fa667d1..ab1b228e 100644 --- a/debian/install +++ b/debian/install @@ -1,4 +1,4 @@ -bin/telegram-cli usr/bin +#bin/telegram-cli usr/bin server.pub etc/telegram-cli #bin/telegram-cli usr/share/telegram-daemon/bin From a3832eeec6ba4b3ebf182fd567b046a3169b7435 Mon Sep 17 00:00:00 2001 From: Olivier Kaloudoff Date: Mon, 30 Mar 2020 16:43:43 +0200 Subject: [PATCH 160/164] debian/rules: prevent run of dh_usrlocal --- debian/rules | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debian/rules b/debian/rules index e29b4d17..43febf23 100755 --- a/debian/rules +++ b/debian/rules @@ -11,8 +11,13 @@ export DH_VERBOSE=1 VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') + override_dh_auto_configure: ./configure --disable-openssl --prefix=/usr + +override_dh_usrlocal: + + %: cp tg-server.pub server.pub dh $@ --with autotools-dev From 49c4afe01ef5fc0797a65debb95500c740106abe Mon Sep 17 00:00:00 2001 From: Sebastian Elisa Pfeifer Date: Sun, 20 Sep 2020 18:17:31 +0200 Subject: [PATCH 161/164] Update Readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 858ff086..c287b538 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Fourth, in `peer_name` '#' are substitued to '@'. (Not applied to appending of ' Clone this GitHub repository with `--recursive` parameter to clone submodules. - git clone --recursive https://github.com/CHANGETHIS/tg.git && cd tg + git clone --recursive https://github.com/kenorb-contrib/tg.git && cd tg ### Python Support @@ -47,6 +47,7 @@ On Ubuntu/Debian use: sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev libpython3-dev libgcrypt-dev zlib1g-dev lua-lgi make To build and install the packaege, run: + dpkg-buildpackage -b sudo dpkg -i ../telegram-cli_x.x.x-x_amd64.deb From e8052fa0939c739c18ada4b4198b5e16eb34c049 Mon Sep 17 00:00:00 2001 From: Mateusz Piotrowski <0mp@FreeBSD.org> Date: Tue, 6 Oct 2020 00:59:20 +0200 Subject: [PATCH 162/164] Update FreeBSD installation instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 858ff086..0f9e7e5f 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ On Milislinux: On FreeBSD: - pkg install libconfig libexecinfo lua52 python jansson + pkg install telegram-cli On OpenBSD: From c048e44651ac342bd4252d46de8a395ab5c2524a Mon Sep 17 00:00:00 2001 From: Franklin Souza Date: Mon, 15 Feb 2021 21:10:41 -0300 Subject: [PATCH 163/164] README.md updating --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 858ff086..0f2df388 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ On CentOS: On Archlinux: - yaourt -S telegram-cli-git + yay -S telegram-cli-git On Milislinux: From aad2e644fffa16066b227741d54de31bddb04ff8 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Sun, 29 May 2022 21:56:13 +0100 Subject: [PATCH 164/164] tg: fix build on gcc-10 (-fno-common) gcc-10 changed the default from -fcommon to fno-common: https://gcc.gnu.org/PR85678 As a result build fails as: ld: objs/loop.o:/build/tg/loop.c:77: multiple definition of `verbosity'; objs/main.o:/build/tg/main.c:93: first defined here --- interface.c | 3 +-- loop.c | 2 -- main.c | 15 +++++++-------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/interface.c b/interface.c index 9116ebed..d916b760 100644 --- a/interface.c +++ b/interface.c @@ -132,7 +132,7 @@ int do_html; int safe_quit; int in_readline; -int readline_active; +static int readline_active; int log_level; @@ -3759,7 +3759,6 @@ void interpreter (char *line) { interpreter_ex (line, 0); } -int readline_active; /*void rprintf (const char *format, ...) { mprint_start (ev); va_list ap; diff --git a/loop.c b/loop.c index b11399b0..32e7f6ea 100644 --- a/loop.c +++ b/loop.c @@ -87,7 +87,6 @@ extern int binlog_enabled; extern int unknown_user_list_pos; extern int unknown_user_list[]; -int register_mode; extern int safe_quit; extern int sync_from_start; @@ -387,7 +386,6 @@ int all_authorized (void) { int zero[512]; -int readline_active; int new_dc_num; int wait_dialog_list; diff --git a/main.c b/main.c index 7ae6941a..03e89466 100644 --- a/main.c +++ b/main.c @@ -90,8 +90,8 @@ "# Feel free to put something here\n" int bot_mode; -int verbosity; -int msg_num_mode; +extern int verbosity; +extern int msg_num_mode; char *default_username; char *config_filename; char *prefix; @@ -108,7 +108,7 @@ int binlog_enabled; extern int log_level; int sync_from_start; int allow_weak_random; -int disable_colors; +extern int disable_colors; int readline_disabled; int disable_output; int reset_authorization; @@ -121,8 +121,8 @@ int enable_json; int alert_sound; int auto_mark_read; int exit_code; -int permanent_msg_id_mode; -int permanent_peer_id_mode; +extern int permanent_msg_id_mode; +extern int permanent_peer_id_mode; char *home_directory; struct tgl_state *TLS; @@ -517,9 +517,8 @@ void usage (void) { char *log_net_file; FILE *log_net_f; -int register_mode; -int disable_auto_accept; -int wait_dialog_list; +extern int disable_auto_accept; +extern int wait_dialog_list; char *logname; int daemonize=0;