This commit is contained in:
Oleg Davydov 2014-10-06 02:08:35 +04:00
commit 2867d3733b
34 changed files with 1788 additions and 165 deletions

View File

@ -23,10 +23,11 @@ LIB_LIST=${LIB}/libtgl.a
TG_OBJECTS=${OBJ}/main.o ${OBJ}/loop.o ${OBJ}/interface.o ${OBJ}/lua-tg.o
TGL_OBJECTS=${OBJ}/net.o ${OBJ}/mtproto-common.o ${OBJ}/mtproto-client.o ${OBJ}/queries.o ${OBJ}/structures.o ${OBJ}/binlog.o ${OBJ}/auto/auto.o ${OBJ}/tgl.o ${OBJ}/updates.o
TLC_OBJECTS=${OBJ}/tlc.o ${OBJ}/tl-parser.o ${OBJ}/crc32.o
TLD_OBJECTS=${OBJ}/dump-tl-file.o
GENERATE_OBJECTS=${OBJ}/generate.o
COMMON_OBJECTS=${OBJ}/tools.o
OBJ_LIST=${TG_OBJECTS} ${TLC_OBJECTS} ${GENERATE_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS}
OBJ_C=${TLC_OBJECTS} ${GENERATE_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS}
OBJ_LIST=${TG_OBJECTS} ${TLC_OBJECTS} ${GENERATE_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS} ${TLD_OBJECTS}
OBJ_C=${TLC_OBJECTS} ${GENERATE_OBJECTS} ${COMMON_OBJECTS} ${TGL_OBJECTS} ${TLD_OBJECTS}
DEPENDENCE=$(subst ${OBJ}/,${DEP}/,$(patsubst %.o,%.d,${OBJ_LIST}))
DEPENDENCE_LIST=${DEPENDENCE}
@ -41,6 +42,7 @@ CC=@CC@
all: ${EXE_LIST} ${DIR_LIST} ${LIB_LIST}
create_dirs_and_headers: ${DIR_LIST} ${AUTO}/auto.c ${AUTO}/auto-header.h ${AUTO}/constants.h
create_dirs: ${DIR_LIST}
dump-tl: ${EXE}/dump-tl-file
${DIR_LIST}:
@test -d $@ || mkdir -p $@
@ -85,6 +87,9 @@ ${AUTO}/auto-header.h: ${AUTO}/scheme.tlo ${EXE}/generate
${AUTO}/constants.h: ${AUTO}/scheme2.tl ${srcdir}/gen_constants_h.awk
awk -f ${srcdir}/gen_constants_h.awk < $< > $@
${EXE}/dump-tl-file: ${OBJ}/auto/auto.o ${TLD_OBJECTS}
${CC} ${OBJ}/auto/auto.o ${TLD_OBJECTS} ${LINK_FLAGS} -o $@
clean:
rm -rf ${DIR_LIST} config.log config.status > /dev/null || echo "all clean"

View File

@ -74,5 +74,7 @@ Function_list (arguments are listed aside from cb_function and cb_extra, :
status_online ()
status_offline ()
send_location (peer, latitude, longitude)
Also, you have function
postpone (cb_function, cb_extra, timeout). It will call your cb_function in specified number of seconds (number of seconds may be double).

461
auto-static-print.c Normal file
View File

@ -0,0 +1,461 @@
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2014
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static int cur_token_len;
static char *cur_token;
static int cur_token_real_len;
static int cur_token_quoted;
static int multiline_output = 1;
static int multiline_offset;
static int multiline_offset_size = 2;
static int *in_ptr, *in_end;
static inline int fetch_int (void) {
return *(in_ptr ++);
}
static inline int fetch_long (void) {
long long r = *(long long *)in_ptr;
in_ptr += 2;
return r;
}
static inline int fetch_long (void) {
long long r = *(long long *)in_ptr;
in_ptr += 2;
return r;
}
static inline void out_int (int a) {}
static inline void out_double (double a) {}
static inline void out_string (char *s, int l) {}
static inline void out_long (long long a) {}
static int disable_field_names;
#define expect_token(token,len) \
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \
local_next_token ();
#define expect_token_ptr(token,len) \
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \
local_next_token ();
#define expect_token_autocomplete(token,len) \
if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return -1; }\
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return -1; } \
local_next_token ();
#define expect_token_ptr_autocomplete(token,len) \
if (cur_token_len == -3 && len >= cur_token_real_len && !memcmp (cur_token, token, cur_token_real_len)) { set_autocomplete_string (token); return 0; }\
if (len != cur_token_len || memcmp (cur_token, token, cur_token_len)) { return 0; } \
local_next_token ();
static int autocomplete_mode;
static char *autocomplete_string;
static int (*autocomplete_fun)(const char *, int, int, char **);
static void set_autocomplete_string (const char *s) {
if (autocomplete_string) { free (autocomplete_string); }
autocomplete_string = strdup (s);
assert (autocomplete_string);
autocomplete_mode = 1;
}
static void set_autocomplete_type (int (*f)(const char *, int, int, char **)) {
autocomplete_fun = f;
autocomplete_mode = 2;
}
static int is_int (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
if (strtoll (cur_token, &p, 10)) {}
cur_token[cur_token_len] = c;
return p == cur_token + cur_token_len;
}
static long long get_int (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
long long val = strtoll (cur_token, &p, 0);
cur_token[cur_token_len] = c;
return val;
}
static int is_double (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
if (strtod (cur_token, &p)) {}
cur_token[cur_token_len] = c;
return p == cur_token + cur_token_len;
}
static double get_double (void) {
if (cur_token_len <= 0) { return 0; }
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *p = 0;
double val = strtod (cur_token, &p);
cur_token[cur_token_len] = c;
return val;
}
static struct paramed_type *paramed_type_dup (struct paramed_type *P) {
if (ODDP (P)) { return P; }
struct paramed_type *R = malloc (sizeof (*R));
assert (R);
R->type = malloc (sizeof (*R->type));
assert (R->type);
memcpy (R->type, P->type, sizeof (*P->type));
R->type->id = strdup (P->type->id);
assert (R->type->id);
if (P->type->params_num) {
R->params = malloc (sizeof (void *) * P->type->params_num);
assert (R->params);
int i;
for (i = 0; i < P->type->params_num; i++) {
R->params[i] = paramed_type_dup (P->params[i]);
}
}
return R;
}
void tgl_paramed_type_free (struct paramed_type *P) {
if (ODDP (P)) { return; }
if (P->type->params_num) {
int i;
for (i = 0; i < P->type->params_num; i++) {
tgl_paramed_type_free (P->params[i]);
}
free (P->params);
}
free (P->type->id);
free (P->type);
free (P);
}
static char *buffer_pos, *buffer_end;
static int is_wspc (char c) {
return c <= 32 && c > 0;
}
static void skip_wspc (void) {
while (buffer_pos < buffer_end && is_wspc (*buffer_pos)) {
buffer_pos ++;
}
}
static int is_letter (char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-';
}
static char exp_buffer[1 << 25];;
static int exp_buffer_pos;
static inline int is_hex (char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
}
static inline int hex2dec (char c) {
if (c >= '0' && c <= '9') { return c - '0'; }
else { return c - 'a' + 10; }
}
static void expand_backslashed (char *s, int len) {
int backslashed = 0;
exp_buffer_pos = 0;
int i = 0;
while (i < len) {
assert (i + 3 <= (1 << 25));
if (backslashed) {
backslashed = 0;
switch (s[i ++]) {
case 'n':
exp_buffer[exp_buffer_pos ++] = '\n';
break;
case 'r':
exp_buffer[exp_buffer_pos ++] = '\r';
break;
case 't':
exp_buffer[exp_buffer_pos ++] = '\t';
break;
case 'b':
exp_buffer[exp_buffer_pos ++] = '\b';
break;
case 'a':
exp_buffer[exp_buffer_pos ++] = '\a';
break;
case '\\':
exp_buffer[exp_buffer_pos ++] = '\\';
break;
case 'x':
if (i + 2 > len || !is_hex (s[i]) || !is_hex (s[i + 1])) {
exp_buffer_pos = -1;
return;
}
exp_buffer[exp_buffer_pos ++] = hex2dec (s[i]) * 16 + hex2dec (s[i + 1]);
i += 2;
break;
default:
break;
}
} else {
if (s[i] == '\\') {
backslashed = 1;
i ++;
} else {
exp_buffer[exp_buffer_pos ++] = s[i ++];
}
}
}
}
static void local_next_token (void) {
skip_wspc ();
cur_token_quoted = 0;
if (buffer_pos >= buffer_end) {
cur_token_len = -3;
cur_token_real_len = 0;
return;
}
char c = *buffer_pos;
if (is_letter (c)) {
cur_token = buffer_pos;
while (buffer_pos < buffer_end && is_letter (*buffer_pos)) {
buffer_pos ++;
}
if (buffer_pos < buffer_end) {
cur_token_len = buffer_pos - cur_token;
} else {
cur_token_real_len = buffer_pos - cur_token;
cur_token_len = -3;
}
return;
} else if (c == '"') {
cur_token_quoted = 1;
cur_token = buffer_pos ++;
int backslashed = 0;
while (buffer_pos < buffer_end && (*buffer_pos != '"' || backslashed)) {
if (*buffer_pos == '\\') {
backslashed ^= 1;
} else {
backslashed = 0;
}
buffer_pos ++;
}
if (*buffer_pos == '"') {
buffer_pos ++;
expand_backslashed (cur_token + 1, buffer_pos - cur_token - 2);
if (exp_buffer_pos < 0) {
cur_token_len = -2;
} else {
cur_token_len = exp_buffer_pos;
cur_token = exp_buffer;
}
} else {
cur_token_len = -2;
}
return;
} else {
if (c) {
cur_token = buffer_pos ++;
cur_token_len = 1;
} else {
cur_token_len = -3;
cur_token_real_len = 0;
}
}
}
#define MAX_FVARS 100
static struct paramed_type *fvars[MAX_FVARS];
static int fvars_pos;
static void add_var_to_be_freed (struct paramed_type *P) {
assert (fvars_pos < MAX_FVARS);
fvars[fvars_pos ++] = P;
}
static void free_vars_to_be_freed (void) {
int i;
for (i = 0; i < fvars_pos; i++) {
tgl_paramed_type_free (fvars[i]);
}
fvars_pos = 0;
}
int tglf_extf_autocomplete (const char *text, int text_len, int index, char **R, char *data, int data_len) {
if (index == -1) {
buffer_pos = data;
buffer_end = data + data_len;
autocomplete_mode = 0;
local_next_token ();
struct paramed_type *P = autocomplete_function_any ();
free_vars_to_be_freed ();
if (P) { tgl_paramed_type_free (P); }
}
if (autocomplete_mode == 0) { return -1; }
int len = strlen (text);
if (autocomplete_mode == 1) {
if (index >= 0) { return -1; }
index = 0;
if (!strncmp (text, autocomplete_string, len)) {
*R = strdup (autocomplete_string);
assert (*R);
return index;
} else {
return -1;
}
} else {
return autocomplete_fun (text, len, index, R);
}
}
struct paramed_type *tglf_extf_store (const char *data, int data_len) {
buffer_pos = (char *)data;
buffer_end = (char *)(data + data_len);
local_next_token ();
return store_function_any ();
}
#define OUT_BUF_SIZE (1 << 25)
static char out_buf[OUT_BUF_SIZE];
static int out_buf_pos;
#define eprintf(...) \
do { \
out_buf_pos += snprintf (out_buf + out_buf_pos, OUT_BUF_SIZE - out_buf_pos, __VA_ARGS__);\
assert (out_buf_pos < OUT_BUF_SIZE);\
} while (0)\
static int valid_utf8_char (const char *str) {
unsigned char c = (unsigned char) *str;
int n = 0;
if ((c & 0x80) == 0x00) {
n = 0;
} else if ((c & 0xe0) == 0xc0) {
n = 1;
} else if ((c & 0xf0) == 0xe0) {
n = 2;
} else if ((c & 0xf8) == 0xf0) {
n = 3;
} else if ((c & 0xfc) == 0xf8) {
n = 4;
} else if ((c & 0xfe) == 0xfc) {
n = 5;
} else {
return -1;
}
int i;
for (i = 0; i < n; i ++) {
if ((((unsigned char)(str[i + 1])) & 0xc0) != 0x80) {
return -1;
}
}
return n + 1;
}
static void print_escaped_string (const char *str, int len) {
eprintf ("\"");
const char *end = str + len;
while (str < end) {
int n = valid_utf8_char (str);
if (n < 0) {
eprintf ("\\x%02x", (int)(unsigned char)*str);
str ++;
} else if (n >= 2) {
int i;
for (i = 0; i < n; i++) {
eprintf ("%c", *(str ++));
}
} else if (((unsigned char)*str) >= ' ' && *str != '"' && *str != '\\') {
eprintf ("%c", *str);
str ++;
} else {
switch (*str) {
case '\n':
eprintf("\\n");
break;
case '\r':
eprintf("\\r");
break;
case '\t':
eprintf("\\t");
break;
case '\b':
eprintf("\\b");
break;
case '\a':
eprintf("\\a");
break;
case '\\':
eprintf ("\\\\");
break;
case '"':
eprintf ("\\\"");
break;
default:
eprintf ("\\x%02x", (int)(unsigned char)*str);
break;
}
str ++;
}
}
eprintf ("\"");
}
static void print_offset (void) {
int i;
for (i = 0; i < multiline_offset; i++) {
eprintf (" ");
}
}
char *tglf_extf_fetch (struct paramed_type *T) {
out_buf_pos = 0;
fetch_type_any (T);
return out_buf;
}

View File

@ -432,6 +432,6 @@ static void print_offset (void) {
char *tglf_extf_fetch (struct paramed_type *T) {
out_buf_pos = 0;
fetch_type_any (T);
if (fetch_type_any (T) < 0) { return 0; }
return out_buf;
}

View File

@ -782,6 +782,12 @@ static int fetch_comb_binlog_send_message_text (void *extra) {
}
M->to_id = tgl_set_peer_id (t, fetch_int ());
if (t == TGL_PEER_ENCR_CHAT) {
tgl_peer_t *P = tgl_peer_get (M->to_id);
if (P) {
P->encr_chat.out_seq_no ++;
}
}
M->date = fetch_int ();
int l = prefetch_strlen ();
@ -824,6 +830,11 @@ static int fetch_comb_binlog_send_message_action_encr (void *extra) {
M->media.type = tgl_message_media_none;
tglf_fetch_message_action_encrypted (&M->action);
tgl_peer_t *P = tgl_peer_get (M->to_id);
if (P) {
P->encr_chat.out_seq_no ++;
}
M->unread = 1;
M->out = tgl_get_peer_id (M->from_id) == tgl_state.our_id;
@ -952,6 +963,11 @@ static int fetch_comb_binlog_create_message_media_encr_pending (void *extra) {
int t = fetch_int ();
M->to_id = tgl_set_peer_id (t, fetch_int ());
M->date = fetch_int ();
tgl_peer_t *P = tgl_peer_get (M->to_id);
if (P) {
P->encr_chat.out_seq_no ++;
}
int l = prefetch_strlen ();
M->message = talloc (l + 1);
@ -1316,13 +1332,53 @@ static void create_new_binlog (void) {
static int s[1000];
packet_ptr = s;
out_int (CODE_binlog_start);
out_int (CODE_binlog_dc_option);
out_int (tgl_state.test_mode ? TG_SERVER_TEST_DC : TG_SERVER_DC);
out_string ("");
out_string (tgl_state.test_mode ? TG_SERVER_TEST : TG_SERVER);
out_int (443);
out_int (CODE_binlog_default_dc);
out_int (tgl_state.test_mode ? TG_SERVER_TEST_DC : TG_SERVER_DC);
if (tgl_state.test_mode) {
out_int (CODE_binlog_dc_option);
out_int (1);
out_string ("");
out_string (TG_SERVER_TEST_1);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (2);
out_string ("");
out_string (TG_SERVER_TEST_2);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (3);
out_string ("");
out_string (TG_SERVER_TEST_3);
out_int (443);
out_int (CODE_binlog_default_dc);
out_int (2);
} else {
out_int (CODE_binlog_dc_option);
out_int (1);
out_string ("");
out_string (TG_SERVER_1);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (2);
out_string ("");
out_string (TG_SERVER_2);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (3);
out_string ("");
out_string (TG_SERVER_3);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (4);
out_string ("");
out_string (TG_SERVER_4);
out_int (443);
out_int (CODE_binlog_dc_option);
out_int (5);
out_string ("");
out_string (TG_SERVER_5);
out_int (443);
out_int (CODE_binlog_default_dc);
out_int (2);
}
int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL | O_CREAT, 0600);
if (fd < 0) {
@ -1542,7 +1598,7 @@ void bl_do_user_set_friend (struct tgl_user *U, int friend) {
void bl_do_dc_option (int id, int l1, const char *name, int l2, const char *ip, int port) {
struct tgl_dc *DC = tgl_state.DC_list[id];
if (DC) { return; }
if (DC && !strncmp (ip, DC->ip, l2)) { return; }
clear_packet ();
out_int (CODE_binlog_dc_option);
@ -1717,7 +1773,7 @@ void bl_do_encr_chat_init (int id, int user_id, unsigned char random[], unsigned
void bl_do_set_pts (int pts) {
if (tgl_state.locks & TGL_LOCK_DIFF) { return; }
if (pts == tgl_state.pts) { return; }
if (pts <= tgl_state.pts) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_set_pts;
ev[1] = pts;
@ -1726,7 +1782,7 @@ void bl_do_set_pts (int pts) {
void bl_do_set_qts (int qts) {
if (tgl_state.locks & TGL_LOCK_DIFF) { return; }
if (qts == tgl_state.qts) { return; }
if (qts <= tgl_state.qts) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_set_qts;
ev[1] = qts;
@ -1735,7 +1791,7 @@ void bl_do_set_qts (int qts) {
void bl_do_set_date (int date) {
if (tgl_state.locks & TGL_LOCK_DIFF) { return; }
if (date == tgl_state.date) { return; }
if (date <= tgl_state.date) { return; }
int *ev = alloc_log_event (8);
ev[0] = CODE_binlog_set_date;
ev[1] = date;

6
debian/changelog vendored
View File

@ -1,5 +1,5 @@
telegram-cli (0.1-1) unstable; urgency=low
telegram-cli (1.0.5.1-1) unstable; urgency=low
* Initial release (Closes #737563)
* Initial release
-- Cleto Martín <cleto@debian.org> Mon, 03 Feb 2014 20:00:03 +0000
-- Steve Illichevsky <still.ru@gmail.com> Wed, 01 Oct 2014 21:06:28 +0400

2
debian/compat vendored
View File

@ -1 +1 @@
9
8

24
debian/control vendored
View File

@ -1,16 +1,16 @@
Source: telegram-cli
Section: net
Priority: optional
Maintainer: Cleto Martín <cleto@debian.org>
Build-Depends: debhelper (>= 8.0.0),
autotools-dev,
autoconf-archive,
libreadline-dev,
libconfig-dev,
libssl-dev,
lua5.2,
liblua5.2-dev
Standards-Version: 3.9.4
Priority: extra
Maintainer: Steve Illichevsky <still.ru@gmail.com>
Build-Depends: debhelper (>= 8.0.0),
autotools-dev,
autoconf-archive,
libreadline-dev,
libconfig-dev,
libssl-dev,
lua5.1,
liblua5.1-dev
Standards-Version: 3.9.2
Homepage: https://github.com/vysheng/tg
Vcs-Git: git://github.com/vysheng/tg.git
Vcs-Browser: https://github.com/vysheng/tg
@ -33,4 +33,4 @@ Description: Command-line interface for Telegram messenger
* Group chat: create and manage groups.
* Secret chat: secured and encrypted conversations.
* Contact management: add/edit/remove contacts.
* Multimedia support: send/load photos and videos.
* Multimedia support: send/load photos and videos.

23
debian/copyright vendored
View File

@ -1,19 +1,19 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Format: http://dep.debian.net/deps/dep5
Upstream-Name: telegram-cli
Source: https://github.com/vysheng/tg
Files: *
Copyright: 2013 Vitaly Valtman
License: GPL-2.0+
Copyright: 2013-2014 Vitaly Valtman <https://github.com/vysheng>
License: GPL-3.0+
Files: debian/*
Copyright: 2014 Cleto Martín <cleto@debian.org>
License: GPL-2.0+
Copyright: 2014 Steve Illichevsky <still.ru@gmail.com>
License: GPL-3.0+
License: GPL-2.0+
This package is free software; you can redistribute it and/or modify
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
@ -22,7 +22,10 @@ License: GPL-2.0+
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
along with this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.

3
debian/docs vendored
View File

@ -1 +1,4 @@
README.es
README-LUA
README.md
#telegram-cli.8

1
debian/files vendored Normal file
View File

@ -0,0 +1 @@
telegram-cli_1.0.5.1-1_i386.deb net extra

4
debian/install vendored
View File

@ -1 +1,3 @@
telegram usr/bin
bin/telegram-cli usr/bin
bin/tlc usr/bin
server.pub etc/telegram-cli

26
debian/rules vendored
View File

@ -1,17 +1,23 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# 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')
%:
dh $@ --with autotools-dev
dh $@ --with autotools-dev
build-orig:
mkdir -p $(PACKAGE_NAME)-$(VERSION)
tar --exclude=ax_lua.m4 --exclude=debian --exclude=\.pc \
--exclude=$(PACKAGE_NAME)-$(VERSION) -cf - . \
| ( cd $(PACKAGE_NAME)-$(VERSION) && tar xf - )
tar -cf ../$(PACKAGE_NAME)_$(VERSION).orig.tar $(PACKAGE_NAME)-$(VERSION)
$(RM) -r $(PACKAGE_NAME)-$(VERSION)
xz ../$(PACKAGE_NAME)_$(VERSION).orig.tar
mkdir -p $(PACKAGE_NAME)-$(VERSION)
tar --exclude=ax_lua.m4 --exclude=debian --exclude=\.pc \
--exclude=$(PACKAGE_NAME)-$(VERSION) -cf - . \
| ( cd $(PACKAGE_NAME)-$(VERSION) && tar xf - )
tar -cf ../$(PACKAGE_NAME)_$(VERSION).orig.tar $(PACKAGE_NAME)-$(VERSION)
$(RM) -r $(PACKAGE_NAME)-$(VERSION)
xz ../$(PACKAGE_NAME)_$(VERSION).orig.tar

48
debian/telegram-cli.8 vendored Normal file
View File

@ -0,0 +1,48 @@
.TH man 8 "02 October 2014" "1.0.5.1" "telegram-cli man page"
.SH NAME
telegram-cli \- Command-line interface for Telegram messenger
.SH SYNOPSIS
telegram-cli -k [keyfile]
.SH DESCRIPTION
Telegram messenger is a cloud-based instant messaging designed for
smart phones and similar to Whatsapp but more flexible, and
powerful. You can send messages, photos, videos and documents to
people who are in your phone contacts (and have Telegram). Telegram
also supports secret chats whose provide a private (encrypted) way of
communication.
.
This package contains a command-line based client for Telegram with
the following features:
* Colored terminal messages.
* Message management: history, stats, etc.
* Group chat: create and manage groups.
* Secret chat: secured and encrypted conversations.
* Contact management: add/edit/remove contacts.
* Multimedia support: send/load photos and videos.
.SH OPTIONS
Telegram-cli Usage
-u specify username (would not be asked during authorization)
-k specify location of public key (possible multiple entries)
-v increase verbosity (0-ERROR 1-WARNIN 2-NOTICE 3+-DEBUG-levels)
-N message num mode
-c config file name
-p use specified profile
-l log level
-f during authorization fetch all messages since registration
-E diable 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
-R disable readline
-d daemon mode
-L <log-name> log file name
-U <user-name> change uid after start
-G <group-name> change gid after start
-D disable output
-P <port> port to listen for input commands
-S <socket-name> unix socket to create
.SH SEE ALSO
.SH BUGS
No known bugs.
.SH AUTHOR
Vitaliy Vatman (-@-)

1
debian/telegram-cli.manpages vendored Normal file
View File

@ -0,0 +1 @@
debian/telegram-cli.8

73
dump-tl-file.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include "auto.h"
int *tgl_in_ptr, *tgl_in_end;
int tgl_packet_buffer[0];
int *tgl_packet_ptr;
char *tgl_strdup (char *s) {
return strdup (s);
}
void tgl_out_cstring (const char *str, long len) {}
char *tglf_extf_fetch (struct paramed_type *T);
#define LEN (1 << 28)
static int x[LEN / 4];
int main (int argc, char **argv) {
int i;
int dump_binlog = 0;
while ((i = getopt (argc, argv, "b")) != -1) {
switch (i) {
case 'b':
dump_binlog = 1;
break;
default:
printf ("unknown option '%c'\n", (char)i);
exit (1);
}
}
if (!dump_binlog) {
exit (1);
}
if (optind + 1 != argc) {
exit (1);
}
int fd = open (argv[optind], O_RDONLY);
if (fd < 0) {
perror ("open");
exit (1);
}
int r = read (fd, x, LEN);
if (r <= 0) {
perror ("read");
exit (1);
}
if (r == LEN) {
printf ("Too long file\n");
exit (1);
}
assert (!(r & 3));
tgl_in_ptr = x;
tgl_in_end = x + (r / 4);
while (tgl_in_ptr < tgl_in_end) {
if (dump_binlog) {
char *R = tglf_extf_fetch (TYPE_TO_PARAM(binlog_update));
if (!R) {
printf ("Can not fetch\n");
exit (1);
}
printf ("%s\n", R);
}
}
return 0;
}

View File

@ -1 +1 @@
encrypted_scheme16.tl
encrypted_scheme17.tl

30
encrypted_scheme17.tl Normal file
View File

@ -0,0 +1,30 @@
---types---
decryptedMessageLayer#99a438cf layer:int message:DecryptedMessage = DecryptedMessageLayer;
decryptedMessage_l16#1f814f1f random_id:long random_bytes:bytes message:string media:DecryptedMessageMedia = DecryptedMessage;
decryptedMessageService_l16#aa48327d random_id:long random_bytes:bytes action:DecryptedMessageAction = DecryptedMessage;
decryptedMessage#20a6d4e2 in_seq_no:int out_seq_no:int ttl:int random_id:long random_bytes:bytes message:string media:DecryptedMessageMedia = DecryptedMessage;
decryptedMessageService#9bb84a4e in_seq_no:int out_seq_no:int random_id:long random_bytes:bytes action:DecryptedMessageAction = DecryptedMessage;
decryptedMessageMediaEmpty#89f5c4a = DecryptedMessageMedia;
decryptedMessageMediaPhoto#32798a8c thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
//decryptedMessageMediaVideo#4cee6ef3 thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaGeoPoint#35480a59 lat:double long:double = DecryptedMessageMedia;
decryptedMessageMediaContact#588a0a97 phone_number:string first_name:string last_name:string user_id:int = DecryptedMessageMedia;
decryptedMessageActionSetMessageTTL#a1733aec ttl_seconds:int = DecryptedMessageAction;
decryptedMessageMediaDocument#b095434b thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia;
//decryptedMessageMediaAudio#6080758f duration:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaVideo#524a415d thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaAudio#57e0a9cb duration:int mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageActionReadMessages#c4f40be random_ids:Vector<long> = DecryptedMessageAction;
decryptedMessageActionDeleteMessages#65614304 random_ids:Vector<long> = DecryptedMessageAction;
decryptedMessageActionScreenshotMessages#8ac1f475 random_ids:Vector<long> = DecryptedMessageAction;
decryptedMessageActionFlushHistory#6719e45c = DecryptedMessageAction;
decryptedMessageActionNotifyLayer#f3048883 layer:int = DecryptedMessageAction;
decryptedMessageActionTyping#ccb27641 action:SendMessageAction = DecryptedMessageAction;
---functions---

View File

@ -292,6 +292,23 @@ long long cur_token_int (void) {
}
}
double cur_token_double (void) {
if (cur_token_len <= 0) {
return NOT_FOUND;
} else {
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *end = 0;
double x = strtod (cur_token, &end);
cur_token[cur_token_len] = c;
if (end != cur_token + cur_token_len) {
return NOT_FOUND;
} else {
return x;
}
}
}
tgl_peer_id_t cur_token_user (void) {
if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; }
int l = cur_token_len;
@ -300,17 +317,17 @@ tgl_peer_id_t cur_token_user (void) {
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
if (l >= 6 && !memcmp (s, "user#", 5)) {
s += 5;
l -= 5;
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, "user#id", 7)) {
s += 7;
l -= 7;
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); }
@ -335,18 +352,17 @@ tgl_peer_id_t cur_token_chat (void) {
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
if (l >= 6 && !memcmp (s, "chat#", 5)) {
s += 5;
l -= 5;
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 >= 8 && !memcmp (s, "chat#id", 7)) {
s += 7;
l -= 7;
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); }
@ -386,22 +402,6 @@ tgl_peer_id_t cur_token_peer (void) {
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
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; }
}
if (l >= 8 && !memcmp (s, "user#id", 7)) {
s += 7;
l -= 7;
@ -418,6 +418,22 @@ tgl_peer_id_t cur_token_peer (void) {
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 (s);
cur_token[cur_token_len] = c;
@ -432,6 +448,15 @@ tgl_peer_id_t cur_token_peer (void) {
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 (id);
if (!P) {
if (tgl_get_peer_type (id) == TGL_PEER_USER) {
tgl_insert_empty_user (tgl_get_peer_id (id));
}
if (tgl_get_peer_type (id) == TGL_PEER_CHAT) {
tgl_insert_empty_chat (tgl_get_peer_id (id));
}
P = tgl_peer_get (id);
}
return P;
}
@ -511,6 +536,7 @@ enum command_argument {
ca_file_name_end,
ca_period,
ca_number,
ca_double,
ca_string_end,
ca_string,
ca_modifier,
@ -528,6 +554,7 @@ struct arg {
struct tgl_message *M;
char *str;
long long num;
double dval;
};
};
@ -988,6 +1015,11 @@ void do_clear (int arg_num, struct arg args[], struct in_ev *ev) {
do_halt (0);
}
void do_send_location (int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 3);
tgl_do_send_location (args[0].P->id, args[1].dval, args[2].dval, 0, 0);
}
struct command commands[] = {
{"help", {ca_none}, do_help, "help\tPrints this help"},
@ -1030,7 +1062,7 @@ struct command commands[] = {
{"chat_del_user", {ca_chat, ca_user, ca_none}, do_chat_del_user, "chat_del_user <chat> <user>\tDeletes user from chat"},
{"status_online", {ca_none}, do_status_online, "status_online\tSets status as online"},
{"status_offline", {ca_none}, do_status_offline, "status_offline\tSets status as offline"},
{"quit", {ca_none}, do_quit, "quit\tQuits immideatly"},
{"quit", {ca_none}, do_quit, "quit\tQuits immediately"},
{"safe_quit", {ca_none}, do_safe_quit, "safe_quit\tWaits for all queries to end, then quits"},
{"set", {ca_string, ca_number, ca_none}, do_set, "set <param> <value>\tSets value of param. Currently available: log_level, debug_verbosity, alarm, msg_num"},
{"chat_with_peer", {ca_peer, ca_none}, do_chat_with_peer, "chat_with_peer <peer>\tInterface option. All input will be treated as messages to this peer. Type /quit to end this mode"},
@ -1046,6 +1078,7 @@ struct command commands[] = {
{"send_contact", {ca_peer, ca_string, ca_string, ca_string, ca_none}, do_send_contact, "send_contact <peer> <phone> <first-name> <last-name>\tSends contact (not necessary telegram user)"},
{"main_session", {ca_none}, do_main_session, "main_session\tSends updates to this connection (or terminal). Useful only with listening socket"},
{"clear", {ca_none}, do_clear, "clear\tClears all data and exits. For debug."},
{"send_location", {ca_peer, ca_double, ca_double, ca_none}, do_send_location, "send_location <peer> <latitude> <longitude>\tSends geo location"},
{0, {ca_none}, 0, ""}
};
@ -1108,7 +1141,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) {
if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double) {
if (cur_token_quoted) {
if (opt) {
line_ptr = save;
@ -1137,6 +1170,9 @@ enum command_argument get_complete_mode (void) {
case ca_number:
ok = (cur_token_int () != NOT_FOUND);
break;
case ca_double:
ok = (cur_token_double () != NOT_FOUND);
break;
default:
assert (0);
}
@ -1222,7 +1258,7 @@ char *command_generator (const char *text, int state) {
if (index == -1) { return 0; }
}
if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number) {
if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double) {
if (c) { rl_line_buffer[rl_point] = c; }
return 0;
}
@ -1594,26 +1630,68 @@ void mark_read_upd (int num, struct tgl_message *list[]) {
}
}
void type_notification_upd (struct tgl_user *U) {
void print_typing (struct in_ev *ev, enum tgl_typing_status status) {
switch (status) {
case tgl_typing_none:
mprintf (ev, "doing nothing");
break;
case tgl_typing_typing:
mprintf (ev, "typing");
break;
case tgl_typing_cancel:
mprintf (ev, "deleting typed message");
break;
case tgl_typing_record_video:
mprintf (ev, "recording video");
break;
case tgl_typing_upload_video:
mprintf (ev, "uploading video");
break;
case tgl_typing_record_audio:
mprintf (ev, "recording audio");
break;
case tgl_typing_upload_audio:
mprintf (ev, "uploading audio");
break;
case tgl_typing_upload_photo:
mprintf (ev, "uploading photo");
break;
case tgl_typing_upload_document:
mprintf (ev, "uploading document");
break;
case tgl_typing_geo:
mprintf (ev, "choosing location");
break;
case tgl_typing_choose_contact:
mprintf (ev, "choosing contact");
break;
}
}
void type_notification_upd (struct tgl_user *U, enum tgl_typing_status status) {
if (log_level < 2 || (disable_output && !notify_ev)) { return; }
struct in_ev *ev = notify_ev;
mprint_start (ev);
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "User ");
print_user_name (ev, U->id, (void *)U);
mprintf (ev, " is typing\n");
mprintf (ev, " is ");
print_typing (ev, status);
mprintf (ev, "\n");
mpop_color (ev);
mprint_end (ev);
}
void type_in_chat_notification_upd (struct tgl_user *U, struct tgl_chat *C) {
void type_in_chat_notification_upd (struct tgl_user *U, struct tgl_chat *C, enum tgl_typing_status status) {
if (log_level < 2 || (disable_output && !notify_ev)) { return; }
struct in_ev *ev = notify_ev;
mprint_start (ev);
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "User ");
print_user_name (ev, U->id, (void *)U);
mprintf (ev, " is typing in chat ");
mprintf (ev, " is ");
print_typing (ev, status);
mprintf (ev, " in chat ");
print_chat_name (ev, C->id, (void *)C);
mprintf (ev, "\n");
mpop_color (ev);
@ -1916,7 +1994,10 @@ void interpreter_ex (char *line UU, void *ex) {
if (op == ca_none) {
next_token ();
if (cur_token_end_str) {
fun (args_num, args, ex);
int z;
for (z = 0; z < count; z ++) {
fun (args_num, args, ex);
}
}
break;
}
@ -1928,7 +2009,10 @@ void interpreter_ex (char *line UU, void *ex) {
} else {
args[args_num].flags = 1;
args[args_num ++].str = strndup (cur_token, cur_token_len);
fun (args_num, args, ex);
int z;
for (z = 0; z < count; z ++) {
fun (args_num, args, ex);
}
break;
}
}
@ -1937,17 +2021,24 @@ void interpreter_ex (char *line UU, void *ex) {
next_token ();
if (period && cur_token_end_str) {
fun (args_num, args, ex);
int z;
for (z = 0; z < count; z ++) {
fun (args_num, args, ex);
}
break;
}
if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number) {
if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double) {
if (cur_token_quoted) {
if (opt) {
if (op != ca_number) {
if (op != ca_number && op != ca_double) {
args[args_num ++].P = 0;
} else {
args[args_num ++].num = NOT_FOUND;
if (op == ca_number) {
args[args_num ++].num = NOT_FOUND;
} else {
args[args_num ++].dval = NOT_FOUND;
}
}
line_ptr = save;
flags ++;
@ -1958,10 +2049,14 @@ void interpreter_ex (char *line UU, void *ex) {
} else {
if (cur_token_end_str) {
if (opt) {
if (op != ca_number) {
if (op != ca_number && op != ca_double) {
args[args_num ++].P = 0;
} else {
args[args_num ++].num = NOT_FOUND;
if (op == ca_number) {
args[args_num ++].num = NOT_FOUND;
} else {
args[args_num ++].dval = NOT_FOUND;
}
}
line_ptr = save;
flags ++;
@ -1992,6 +2087,10 @@ void interpreter_ex (char *line UU, void *ex) {
args[args_num ++].num = cur_token_int ();
ok = (args[args_num - 1].num != NOT_FOUND);
break;
case ca_double:
args[args_num ++].dval = cur_token_double ();
ok = (args[args_num - 1].dval != NOT_FOUND);
break;
default:
assert (0);
}
@ -2386,6 +2485,10 @@ void print_service_message (struct in_ev *ev, struct tgl_message *M) {
case tgl_message_action_notify_layer:
mprintf (ev, " updated layer to %d\n", M->action.layer);
break;
case tgl_message_action_typing:
mprintf (ev, " is ");
print_typing (ev, M->action.typing);
break;
default:
assert (0);
}

32
loop.c
View File

@ -91,6 +91,8 @@ static int delete_stdin_event;
extern volatile int sigterm_cnt;
extern char *start_command;
static void stdin_read_callback_all (int arg, short what, struct event *self) {
if (!readline_disabled) {
if (((long)arg) & 1) {
@ -500,9 +502,19 @@ void read_dc (int auth_file_fd, int id, unsigned ver) {
}
void empty_auth_file (void) {
char *ip = tgl_state.test_mode ? TG_SERVER_TEST : TG_SERVER;
bl_do_dc_option (tgl_state.test_mode ? TG_SERVER_TEST_DC : TG_SERVER_DC, 0, "", strlen (ip), ip, 443);
bl_do_set_working_dc (tgl_state.test_mode ? TG_SERVER_TEST_DC : TG_SERVER_DC);
if (tgl_state.test_mode) {
bl_do_dc_option (1, 0, "", strlen (TG_SERVER_TEST_1), TG_SERVER_TEST_1, 443);
bl_do_dc_option (2, 0, "", strlen (TG_SERVER_TEST_2), TG_SERVER_TEST_2, 443);
bl_do_dc_option (3, 0, "", strlen (TG_SERVER_TEST_3), TG_SERVER_TEST_3, 443);
bl_do_set_working_dc (2);
} else {
bl_do_dc_option (1, 0, "", strlen (TG_SERVER_1), TG_SERVER_1, 443);
bl_do_dc_option (2, 0, "", strlen (TG_SERVER_2), TG_SERVER_2, 443);
bl_do_dc_option (3, 0, "", strlen (TG_SERVER_3), TG_SERVER_3, 443);
bl_do_dc_option (4, 0, "", strlen (TG_SERVER_4), TG_SERVER_4, 443);
bl_do_dc_option (5, 0, "", strlen (TG_SERVER_5), TG_SERVER_5, 443);
bl_do_set_working_dc (2);
}
}
int need_dc_list_update;
@ -842,6 +854,20 @@ int loop (void) {
lua_diff_end ();
#endif
if (start_command) {
safe_quit = 1;
while (*start_command) {
char *start = start_command;
while (*start_command && *start_command != '\n') {
start_command ++;
}
if (*start_command) {
*start_command = 0;
start_command ++;
}
interpreter_ex (start, 0);
}
}
/*tgl_do_get_dialog_list (get_dialogs_callback, 0);
if (wait_dialog_list) {

View File

@ -495,6 +495,7 @@ enum lua_query_type {
lq_send_contact,
lq_status_online,
lq_status_offline,
lq_send_location,
lq_extf
};
@ -1086,6 +1087,14 @@ void lua_do_all (void) {
free (s);
p += 2;
break;
case lq_send_location:
if (sizeof (void *) == 4) {
tgl_do_send_location (((tgl_peer_t *)lua_ptr[p + 1])->id , *(float *)(lua_ptr + p + 2), *(float *)(lua_ptr + p + 3), lua_msg_cb, lua_ptr[p]);
} else {
tgl_do_send_location (((tgl_peer_t *)lua_ptr[p + 1])->id , *(double *)(lua_ptr + p + 2), *(double *)(lua_ptr + p + 3), lua_msg_cb, lua_ptr[p]);
}
p += 4;
break;
/*
lq_delete_msg,
lq_restore_msg,
@ -1120,7 +1129,8 @@ enum lua_function_param {
lfp_number,
lfp_positive_number,
lfp_nonnegative_number,
lfp_msg
lfp_msg,
lfp_double
};
struct lua_function {
@ -1168,6 +1178,7 @@ 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 }},
{"ext_function", lq_extf, { lfp_string, lfp_none }},
{ 0, 0, { lfp_none}}
};
@ -1203,6 +1214,7 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) {
const char *s;
tgl_peer_t *P;
long long num;
double dval;
struct tgl_message *M;
switch (F->params[p]) {
case lfp_none:
@ -1256,6 +1268,17 @@ static int parse_lua_function (lua_State *L, struct lua_function *F) {
lua_ptr[pos + p] = (void *)(long)num;
break;
case lfp_double:
dval = lua_tonumber (L, -cc);
if (sizeof (void *) == 4) {
*(float *)(lua_ptr + pos + p) = dval;
} else {
assert (sizeof (void *) >= 8);
*(double *)(lua_ptr + pos + p) = dval;
}
break;
case lfp_positive_number:
num = lua_tonumber (L, -cc);
if (num <= 0) {

17
main.c
View File

@ -59,6 +59,7 @@
#include <grp.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "telegram.h"
#include "loop.h"
@ -110,6 +111,7 @@ int readline_disabled;
int disable_output;
int reset_authorization;
int port;
char *start_command;
void set_default_username (const char *s) {
if (default_username) {
@ -283,7 +285,7 @@ void parse_config_val (config_t *conf, char **s, char *param_name, const char *d
strcpy (buf + l, param_name);
config_lookup_string (conf, buf, &r);
if (r) {
if (path) {
if (path && *r != '/') {
tasprintf (s, "%s/%s", path, r);
} else {
*s = tstrdup (r);
@ -399,6 +401,11 @@ void parse_config (void) {
tasprintf (&secret_chat_file_name, "%s/%s/%s", get_home_directory (), CONFIG_DIRECTORY, SECRET_CHAT_FILE);
}
tgl_set_download_directory (downloads_directory);
if (!mkdir (downloads_directory, CONFIG_DIRECTORY_MODE)) {
if (!disable_output) {
printf ("[%s] created\n", downloads_directory);
}
}
}
#endif
@ -421,7 +428,7 @@ void usage (void) {
#endif
printf (" -l log level\n");
printf (" -f during authorization fetch all messages since registration\n");
printf (" -E diable auto accept of encrypted chats\n");
printf (" -E disable auto accept of encrypted chats\n");
#ifdef USE_LUA
printf (" -s lua script file\n");
#endif
@ -435,6 +442,7 @@ void usage (void) {
printf (" -D disable output\n");
printf (" -P <port> port to listen for input commands\n");
printf (" -S <socket-name> unix socket to create\n");
printf (" -e <commands> make commands end exit\n");
exit (1);
}
@ -537,7 +545,7 @@ char *unix_socket;
void args_parse (int argc, char **argv) {
int opt = 0;
while ((opt = getopt (argc, argv, "u:hk:vNl:fEwWCRdL:DU:G:qP:S:"
while ((opt = getopt (argc, argv, "u:hk:vNl:fEwWCRdL:DU:G:qP:S:e:"
#ifdef HAVE_LIBCONFIG
"c:p:"
#else
@ -626,6 +634,9 @@ void args_parse (int argc, char **argv) {
case 'S':
unix_socket = optarg;
break;
case 'e':
start_command = optarg;
break;
case 'h':
default:
usage ();

View File

@ -80,7 +80,7 @@
#define MAX_NET_RES (1L << 16)
//extern int log_level;
#ifndef HAVE___BUILTIN_BSWAP32
#if !defined(HAVE___BUILTIN_BSWAP32) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
static inline unsigned __builtin_bswap32(unsigned x) {
return ((x << 24) & 0xff000000 ) |
((x << 8) & 0x00ff0000 ) |
@ -284,6 +284,13 @@ static int process_respq_answer (struct connection *c, char *packet, int len, in
unsigned long long what;
unsigned p1, p2;
int i;
long long packet_auth_key_id = *(long long *)packet;
if (packet_auth_key_id) {
assert (temp_key);
vlogprintf (E_WARNING, "received packet during creation of temp auth key. Probably answer on old query. Drop\n");
return 0;
}
vlogprintf (E_DEBUG, "process_respq_answer(), len=%d, op=0x%08x\n", len, *(int *)(packet + 20));
assert (len >= 76);
assert (!*(long long *) packet);
@ -552,6 +559,12 @@ static int process_dh_answer (struct connection *c, char *packet, int len, int t
//if (len < 116) {
// vlogprintf (E_ERROR, "%u * %u = %llu", p1, p2, what);
//}
long long packet_auth_key_id = *(long long *)packet;
if (packet_auth_key_id) {
assert (temp_key);
vlogprintf (E_WARNING, "received packet during creation of temp auth key. Probably answer on old query. Drop\n");
return 0;
}
assert (len >= 116);
assert (!*(long long *) packet);
assert (*(int *) (packet + 16) == len - 20);
@ -660,6 +673,13 @@ static void mpc_on_get_config (void *extra, int success);
static int process_auth_complete (struct connection *c UU, char *packet, int len, int temp_key) {
struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
vlogprintf (E_DEBUG - 1, "process_dh_answer(), len=%d\n", len);
long long packet_auth_key_id = *(long long *)packet;
if (packet_auth_key_id) {
assert (temp_key);
vlogprintf (E_WARNING, "received packet during creation of temp auth key. Probably answer on old query. Drop\n");
return 0;
}
assert (len == 72);
assert (!*(long long *) packet);
assert (*(int *) (packet + 16) == len - 20);
@ -1058,8 +1078,9 @@ static int process_rpc_message (struct connection *c UU, struct encrypted_messag
assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15));
struct tgl_dc *DC = tgl_state.net_methods->get_dc (c);
if (enc->auth_key_id != DC->temp_auth_key_id && enc->auth_key_id != DC->auth_key_id) {
vlogprintf (E_ERROR, "received msg from dc %d with auth_key_id %lld (perm_auth_key_id %lld temp_auth_key_id %lld)\n",
vlogprintf (E_WARNING, "received msg from dc %d with auth_key_id %lld (perm_auth_key_id %lld temp_auth_key_id %lld). Dropping\n",
DC->id, enc->auth_key_id, DC->auth_key_id, DC->temp_auth_key_id);
return 0;
}
if (enc->auth_key_id == DC->temp_auth_key_id) {
assert (enc->auth_key_id == DC->temp_auth_key_id);
@ -1280,7 +1301,7 @@ void tglmp_on_start (void) {
}
if (!ok) {
vlogprintf (E_ERROR, "No pubic keys found\n");
vlogprintf (E_ERROR, "No public keys found\n");
exit (1);
}
@ -1341,19 +1362,26 @@ static void regen_temp_key_gw (evutil_socket_t fd, short what, void *arg) {
}
struct tgl_dc *tglmp_alloc_dc (int id, char *ip, int port UU) {
assert (!tgl_state.DC_list[id]);
struct tgl_dc *DC = talloc0 (sizeof (*DC));
DC->id = id;
DC->ip = ip;
DC->port = port;
tgl_state.DC_list[id] = DC;
if (id > tgl_state.max_dc_num) {
tgl_state.max_dc_num = id;
//assert (!tgl_state.DC_list[id]);
if (!tgl_state.DC_list[id]) {
struct tgl_dc *DC = talloc0 (sizeof (*DC));
DC->id = id;
DC->ip = ip;
DC->port = port;
tgl_state.DC_list[id] = DC;
if (id > tgl_state.max_dc_num) {
tgl_state.max_dc_num = id;
}
DC->ev = evtimer_new (tgl_state.ev_base, regen_temp_key_gw, DC);
static struct timeval p;
event_add (DC->ev, &p);
return DC;
} else {
struct tgl_dc *DC = tgl_state.DC_list[id];
tfree_str (DC->ip);
DC->ip = tstrdup (ip);
return DC;
}
DC->ev = evtimer_new (tgl_state.ev_base, regen_temp_key_gw, DC);
static struct timeval p;
event_add (DC->ev, &p);
return DC;
}
static struct mtproto_methods mtproto_methods = {

View File

@ -201,7 +201,6 @@ static inline int prefetch_strlen (void) {
static inline char *fetch_str (int len) {
assert (len >= 0);
vlogprintf (E_DEBUG + 3, "fetch_string: len = %d\n", len);
if (len < 254) {
char *str = (char *) in_ptr + 1;
in_ptr += 1 + (len >> 2);
@ -294,12 +293,10 @@ int tgl_fetch_bignum (BIGNUM *x);
static inline int fetch_int (void) {
assert (in_ptr + 1 <= in_end);
vlogprintf (E_DEBUG + 3, "fetch_int: 0x%08x (%d)\n", *in_ptr, *in_ptr);
return *(in_ptr ++);
}
static inline int fetch_bool (void) {
vlogprintf (E_DEBUG + 3, "fetch_bool: 0x%08x (%d)\n", *in_ptr, *in_ptr);
assert (in_ptr + 1 <= in_end);
assert (*(in_ptr) == (int)CODE_bool_true || *(in_ptr) == (int)CODE_bool_false);
return *(in_ptr ++) == (int)CODE_bool_true;

6
net.c
View File

@ -26,11 +26,11 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
@ -345,6 +345,10 @@ static void restart_connection (struct connection *c) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (c->port);
if (strcmp (c->ip, c->dc->ip)) {
tfree_str (c->ip);
c->ip = tstrdup (c->dc->ip);
}
addr.sin_addr.s_addr = inet_addr (c->ip);

153
queries.c
View File

@ -94,7 +94,7 @@ struct query *tglq_query_get (long long id) {
static int alarm_query (struct query *q) {
assert (q);
vlogprintf (E_DEBUG, "Alarm query %lld\n", q->msg_id);
vlogprintf (E_DEBUG - 1, "Alarm query %lld\n", q->msg_id);
//q->ev.timeout = get_double_time () + QUERY_TIMEOUT;
//insert_event_timer (&q->ev);
@ -118,7 +118,9 @@ static int alarm_query (struct query *q) {
tglmp_encrypt_send_message (q->session->c, packet_buffer, packet_ptr - packet_buffer, q->flags & QUERY_FORCE_SEND);
} else {
q->flags &= ~QUERY_ACK_RECEIVED;
queries_tree = tree_delete_query (queries_tree, q);
if (tree_lookup_query (queries_tree, q)) {
queries_tree = tree_delete_query (queries_tree, q);
}
q->msg_id = tglmp_encrypt_send_message (q->session->c, q->data, q->data_len, (q->flags & QUERY_FORCE_SEND) | 1);
queries_tree = tree_insert_query (queries_tree, q, lrand48 ());
q->session_id = q->session->session_id;
@ -219,14 +221,35 @@ void tglq_query_error (long long id) {
event_del (q->ev);
}
queries_tree = tree_delete_query (queries_tree, q);
if (q->methods && q->methods->on_error) {
q->methods->on_error (q, error_code, error_len, error);
int res = 0;
if (q->methods && q->methods->on_error && error_code != 500) {
res = q->methods->on_error (q, error_code, error_len, error);
} else {
vlogprintf ( E_WARNING, "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, error);
if (error_code == 420 || error_code == 500) {
int wait;
if (error_code == 420) {
if (strncmp (error, "FLOOD_WAIT_", 11)) {
vlogprintf (E_ERROR, "error = '%s'\n", error);
wait = 10;
} else {
wait = atoll (error + 11);
}
} else {
wait = 10;
}
q->flags &= ~QUERY_ACK_RECEIVED;
static struct timeval ptimeout;
ptimeout.tv_sec = wait;
event_add (q->ev, &ptimeout);
q->session_id = 0;
res = 1;
}
}
if (res <= 0) {
tfree (q->data, q->data_len * 4);
event_free (q->ev);
tfree (q, sizeof (*q));
}
tfree (q->data, q->data_len * 4);
event_free (q->ev);
tfree (q, sizeof (*q));
}
tgl_state.active_queries --;
}
@ -314,7 +337,7 @@ static void out_random (int n) {
int allow_send_linux_version;
void tgl_do_insert_header (void) {
out_int (CODE_invoke_with_layer16);
out_int (CODE_invoke_with_layer17);
out_int (CODE_init_connection);
out_int (TG_APP_ID);
if (allow_send_linux_version) {
@ -914,7 +937,17 @@ static int msg_send_on_answer (struct query *q UU) {
}
static int msg_send_on_error (struct query *q, int error_code, int error_len, char *error) {
vlogprintf (E_WARNING, "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error);
//vlogprintf (E_WARNING, "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error);
if (error_code == 420) {
assert (!strncmp (error, "FLOOD_WAIT_", 11));
int wait = atoll (error + 11);
q->flags &= ~QUERY_ACK_RECEIVED;
static struct timeval ptimeout;
ptimeout.tv_sec = wait;
event_add (q->ev, &ptimeout);
q->session_id = 0;
return 1;
}
long long x = *(long long *)q->extra;
tfree (q->extra, 8);
struct tgl_message *M = tgl_message_get (x);
@ -957,7 +990,13 @@ void tgl_do_send_encr_msg_action (struct tgl_message *M, void (*callback)(void *
out_long (P->encr_chat.access_hash);
out_long (M->id);
encr_start ();
out_int (CODE_decrypted_message_service);
if (P->encr_chat.layer <= 16) {
out_int (CODE_decrypted_message_service_l16);
} else {
out_int (CODE_decrypted_message_service);
out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != tgl_state.our_id));
out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == tgl_state.our_id));
}
out_long (M->id);
static int buf[4];
tglt_secure_random (buf, 16);
@ -1001,7 +1040,14 @@ void tgl_do_send_encr_msg (struct tgl_message *M, void (*callback)(void *callbac
out_long (P->encr_chat.access_hash);
out_long (M->id);
encr_start ();
out_int (CODE_decrypted_message);
if (P->encr_chat.layer <= 16) {
out_int (CODE_decrypted_message_l16);
} else {
out_int (CODE_decrypted_message);
out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != tgl_state.our_id));
out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == tgl_state.our_id));
out_int (0);
}
out_long (M->id);
static int buf[4];
tglt_secure_random (buf, 16);
@ -1141,6 +1187,7 @@ void tgl_do_messages_mark_read (tgl_peer_id_t id, int max_id, int offset, void (
out_peer_id (id);
out_int (max_id);
out_int (offset);
out_int (CODE_bool_true);
int *t = talloc (12);
t[0] = tgl_get_peer_type (id);
t[1] = tgl_get_peer_id (id);
@ -1738,7 +1785,14 @@ static void send_part (struct send_file *f, void *callback, void *callback_extra
tglt_secure_random (&r, 8);
out_long (r);
encr_start ();
out_int (CODE_decrypted_message);
if (P->encr_chat.layer <= 16) {
out_int (CODE_decrypted_message_l16);
} else {
out_int (CODE_decrypted_message);
out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != tgl_state.our_id));
out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == tgl_state.our_id) + 2);
out_int (0);
}
out_long (r);
out_random (15 + 4 * (lrand48 () % 3));
out_string ("");
@ -1783,9 +1837,7 @@ static void send_part (struct send_file *f, void *callback, void *callback_extra
out_cstring ((void *)f->key, 32);
out_cstring ((void *)f->init_iv, 32);
long long msg_id;
tglt_secure_random (&msg_id, 8);
bl_do_create_message_media_encr_pending (msg_id, tgl_state.our_id, tgl_get_peer_type (f->to_id), tgl_get_peer_id (f->to_id), time (0), 0, 0, save_ptr, packet_ptr - save_ptr);
bl_do_create_message_media_encr_pending (r, tgl_state.our_id, tgl_get_peer_type (f->to_id), tgl_get_peer_id (f->to_id), time (0), 0, 0, save_ptr, packet_ptr - save_ptr);
encr_finish (&P->encr_chat);
if (f->size < (16 << 20)) {
@ -1807,7 +1859,7 @@ static void send_part (struct send_file *f, void *callback, void *callback_extra
out_int ((*(int *)md5) ^ (*(int *)(md5 + 4)));
tfree_secure (f->iv, 32);
struct tgl_message *M = tgl_message_get (msg_id);
struct tgl_message *M = tgl_message_get (r);
assert (M);
//M->media.encr_photo.key = f->key;
@ -1943,6 +1995,7 @@ void tgl_do_set_profile_photo (char *file_name, void (*callback)(void *callback_
}
/* }}} */
/* {{{ Forward */
static int fwd_msg_on_answer (struct query *q UU) {
assert (fetch_int () == (int)CODE_messages_stated_message);
@ -2093,6 +2146,65 @@ void tgl_do_forward_media (tgl_peer_id_t id, int n, void (*callback)(void *callb
}
/* }}} */
/* {{{ Send location */
void tgl_do_send_location(tgl_peer_id_t id, double latitude, double longitude, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra) {
if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT) {
clear_packet ();
out_int (CODE_messages_send_encrypted);
out_int (CODE_input_encrypted_chat);
out_int (tgl_get_peer_id (id));
tgl_peer_t *P = tgl_peer_get (id);
assert (P);
out_long (P->encr_chat.access_hash);
long long r;
tglt_secure_random (&r, 8);
out_long (r);
encr_start ();
if (P->encr_chat.layer <= 16) {
out_int (CODE_decrypted_message_l16);
} else {
out_int (CODE_decrypted_message);
out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != tgl_state.our_id));
out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == tgl_state.our_id) + 2);
out_int (0);
}
out_long (r);
out_random (15 + 4 * (lrand48 () % 3));
out_string ("");
int *save_ptr = packet_ptr;
out_int (CODE_decrypted_message_media_geo_point);
out_double (latitude);
out_double (longitude);
bl_do_create_message_media_encr_pending (r, tgl_state.our_id, tgl_get_peer_type (id), tgl_get_peer_id (id), time (0), 0, 0, save_ptr, packet_ptr - save_ptr);
encr_finish (&P->encr_chat);
struct tgl_message *M = tgl_message_get (r);
assert (M);
tglq_send_query (tgl_state.DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M, callback, callback_extra);
} else {
long long t;
tglt_secure_random (&t, 8);
vlogprintf (E_DEBUG, "t = %lld\n", t);
clear_packet ();
out_int (CODE_messages_send_media);
out_peer_id (id);
out_int (CODE_input_media_geo_point);
out_int (CODE_input_geo_point);
out_double (latitude);
out_double (longitude);
out_long (t);
tglq_send_query (tgl_state.DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, 0, callback, callback_extra);
}
}
/* }}} */
/* {{{ Rename chat */
static int rename_chat_on_answer (struct query *q UU) {
assert (fetch_int () == (int)CODE_messages_stated_message);
@ -2361,6 +2473,10 @@ static int download_on_answer (struct query *q) {
struct download *D = q->extra;
if (D->fd == -1) {
D->fd = open (D->name, O_CREAT | O_WRONLY, 0640);
if (D->fd < 0) {
vlogprintf (E_ERROR, "Can not open for writing: %m\n");
assert (D->fd >= 0);
}
}
fetch_int (); // mtime
int len = prefetch_strlen ();
@ -2906,6 +3022,9 @@ static int send_encr_accept_on_answer (struct query *q UU) {
print_end ();
}*/
if (E->state == sc_ok) {
tgl_do_send_encr_chat_layer (E);
}
if (q->callback) {
((void (*)(void *, int, struct tgl_secret_chat *))q->callback) (q->callback_extra, E->state == sc_ok, E);
}

View File

@ -1 +1 @@
scheme16.tl
scheme17.tl

528
scheme17.tl Normal file
View File

@ -0,0 +1,528 @@
int ?= Int;
long ?= Long;
double ?= Double;
string ?= String;
bytes string = Bytes;
boolFalse#bc799737 = Bool;
boolTrue#997275b5 = Bool;
vector#1cb5c415 {t:Type} # [ t ] = Vector t;
error#c4b9f9bb code:int text:string = Error;
null#56730bcc = Null;
inputPeerEmpty#7f3b18ea = InputPeer;
inputPeerSelf#7da07ec9 = InputPeer;
inputPeerContact#1023dbe8 user_id:int = InputPeer;
inputPeerForeign#9b447325 user_id:int access_hash:long = InputPeer;
inputPeerChat#179be863 chat_id:int = InputPeer;
inputUserEmpty#b98886cf = InputUser;
inputUserSelf#f7c1b13f = InputUser;
inputUserContact#86e94f65 user_id:int = InputUser;
inputUserForeign#655e74ff user_id:int access_hash:long = InputUser;
inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact;
inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;
inputMediaEmpty#9664f57f = InputMedia;
inputMediaUploadedPhoto#2dc53a7d file:InputFile = InputMedia;
inputMediaPhoto#8f2ab2ec id:InputPhoto = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
inputMediaUploadedVideo#133ad6f6 file:InputFile duration:int w:int h:int mime_type:string = InputMedia;
inputMediaUploadedThumbVideo#9912dabf file:InputFile thumb:InputFile duration:int w:int h:int mime_type:string = InputMedia;
inputMediaVideo#7f023ae6 id:InputVideo = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#94254732 file:InputFile crop:InputPhotoCrop = InputChatPhoto;
inputChatPhoto#b2e1bf08 id:InputPhoto crop:InputPhotoCrop = InputChatPhoto;
inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint;
inputPhotoEmpty#1cd7bf0d = InputPhoto;
inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto;
inputVideoEmpty#5508ec75 = InputVideo;
inputVideo#ee579652 id:long access_hash:long = InputVideo;
inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation;
inputVideoFileLocation#3d0364ec id:long access_hash:long = InputFileLocation;
inputPhotoCropAuto#ade6b004 = InputPhotoCrop;
inputPhotoCrop#d9915325 crop_left:double crop_top:double crop_width:double = InputPhotoCrop;
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_id:int = Peer;
storage.fileUnknown#aa963b05 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
userEmpty#200250ba id:int = User;
userSelf#720535ec id:int first_name:string last_name:string phone:string photo:UserProfilePhoto status:UserStatus inactive:Bool = User;
userContact#f2fb8319 id:int first_name:string last_name:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User;
userRequest#22e8ceb0 id:int first_name:string last_name:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User;
userForeign#5214c89d id:int first_name:string last_name:string access_hash:long photo:UserProfilePhoto status:UserStatus = User;
userDeleted#b29ad7cc id:int first_name:string last_name:string = User;
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
userStatusEmpty#9d05049 = UserStatus;
userStatusOnline#edb93949 expires:int = UserStatus;
userStatusOffline#8c703f was_online:int = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#6e9c9bc7 id:int title:string photo:ChatPhoto participants_count:int date:int left:Bool version:int = Chat;
chatForbidden#fb0ccc41 id:int title:string date:int = Chat;
chatFull#630e61be id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantsForbidden#fd2bb8a chat_id:int = ChatParticipants;
chatParticipants#7841b415 chat_id:int admin_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
//message#22eb6aba id:int from_id:int to_id:Peer out:Bool unread:Bool date:int message:string media:MessageMedia = Message;
//messageForwarded#5f46804 id:int fwd_from_id:int fwd_date:int from_id:int to_id:Peer out:Bool unread:Bool date:int message:string media:MessageMedia = Message;
//messageService#9f8d60bb id:int from_id:int to_id:Peer out:Bool unread:Bool date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#c8c45a2a photo:Photo = MessageMedia;
messageMediaVideo#a2d24290 video:Video = MessageMedia;
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
messageMediaUnsupported#29632a36 bytes:bytes = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction;
messageActionChatDeletePhoto#95e3fbef = MessageAction;
messageActionChatAddUser#5e3cfc4b user_id:int = MessageAction;
messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
dialog#ab3a99ac peer:Peer top_message:int unread_count:int notify_settings:PeerNotifySettings = Dialog;
photoEmpty#2331b22d id:long = Photo;
photo#22b56751 id:long access_hash:long user_id:int date:int caption:string geo:GeoPoint sizes:Vector<PhotoSize> = Photo;
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
videoEmpty#c10658a8 id:long = Video;
video#388fa391 id:long access_hash:long user_id:int date:int caption:string duration:int mime_type:string size:int thumb:PhotoSize dc_id:int w:int h:int = Video;
geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#2049d70c long:double lat:double = GeoPoint;
auth.checkedPhone#e300cc3b phone_registered:Bool phone_invited:Bool = auth.CheckedPhone;
auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode;
auth.authorization#f6b673a4 expires:int user:User = auth.Authorization;
auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
inputNotifyUsers#193b4417 = InputNotifyPeer;
inputNotifyChats#4a95e84e = InputNotifyPeer;
inputNotifyAll#a429b886 = InputNotifyPeer;
inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents;
inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents;
inputPeerNotifySettings#46a2ce98 mute_until:int sound:string show_previews:Bool events_mask:int = InputPeerNotifySettings;
peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
peerNotifySettingsEmpty#70a68512 = PeerNotifySettings;
peerNotifySettings#8d5e11ee mute_until:int sound:string show_previews:Bool events_mask:int = PeerNotifySettings;
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
userFull#771095da user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool real_first_name:string real_last_name:string = UserFull;
contact#f911c994 user_id:int mutual:Bool = Contact;
importedContact#d0028438 user_id:int client_id:long = ImportedContact;
contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
contactFound#ea879f95 user_id:int = ContactFound;
contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested;
contactStatus#aa77b873 user_id:int expires:int = ContactStatus;
chatLocated#3631cf4c chat_id:int distance:int = ChatLocated;
contacts.foreignLinkUnknown#133421f8 = contacts.ForeignLink;
contacts.foreignLinkRequested#a7801f47 has_phone:Bool = contacts.ForeignLink;
contacts.foreignLinkMutual#1bea8ce1 = contacts.ForeignLink;
contacts.myLinkEmpty#d22a1c60 = contacts.MyLink;
contacts.myLinkRequested#6c69efee contact:Bool = contacts.MyLink;
contacts.myLinkContact#c240ebd9 = contacts.MyLink;
contacts.link#eccea3f5 my_link:contacts.MyLink foreign_link:contacts.ForeignLink user:User = contacts.Link;
contacts.contacts#6f8b8cb2 contacts:Vector<Contact> users:Vector<User> = contacts.Contacts;
contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
contacts.importedContacts#ad524315 imported:Vector<ImportedContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;
contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.found#566000e results:Vector<ContactFound> users:Vector<User> = contacts.Found;
contacts.suggested#5649dcc5 results:Vector<ContactSuggested> users:Vector<User> = contacts.Suggested;
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messageEmpty#3f4e0648 = messages.Message;
messages.message#ff90c417 message:Message chats:Vector<Chat> users:Vector<User> = messages.Message;
messages.statedMessages#969478bb messages:Vector<Message> chats:Vector<Chat> users:Vector<User> pts:int seq:int = messages.StatedMessages;
messages.statedMessage#d07ae726 message:Message chats:Vector<Chat> users:Vector<User> pts:int seq:int = messages.StatedMessage;
messages.sentMessage#d1f4d35c id:int date:int pts:int seq:int = messages.SentMessage;
messages.chat#40e9002a chat:Chat users:Vector<User> = messages.Chat;
messages.chats#8150cbd8 chats:Vector<Chat> users:Vector<User> = messages.Chats;
messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull;
messages.affectedHistory#b7de36f2 pts:int seq:int offset:int = messages.AffectedHistory;
inputMessagesFilterEmpty#57e2f66c = MessagesFilter;
inputMessagesFilterPhotos#9609a51c = MessagesFilter;
inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterAudio#cfc87522 = MessagesFilter;
updateNewMessage#13abdb3 message:Message pts:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;
updateReadMessages#c6649e31 messages:Vector<int> pts:int = Update;
updateDeleteMessages#a92bfe26 messages:Vector<int> pts:int = Update;
updateRestoreMessages#d15de04d messages:Vector<int> pts:int = Update;
//updateUserTyping#6baa8508 user_id:int = Update;
//updateChatUserTyping#3c46cfe6 chat_id:int user_id:int = Update;
updateChatParticipants#7761198 participants:ChatParticipants = Update;
updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
updateUserName#da22d9ad user_id:int first_name:string last_name:string = Update;
updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update;
updateContactRegistered#2575bbb9 user_id:int date:int = Update;
updateContactLink#51a48a9a user_id:int my_link:contacts.MyLink foreign_link:contacts.ForeignLink = Update;
updateActivation#6f690963 user_id:int = Update;
updateNewAuthorization#8f06529a auth_key_id:long date:int device:string location:string = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference;
updatesTooLong#e317af7e = Updates;
updateShortMessage#d3f45784 id:int from_id:int message:string pts:int date:int seq:int = Updates;
updateShortChatMessage#2b2fbd4e id:int from_id:int chat_id:int message:string pts:int date:int seq:int = Updates;
updateShort#78d4dec1 update:Update date:int = Updates;
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
dcOption#2ec2a43c id:int hostname:string ip_address:string port:int = DcOption;
config#2e54dd74 date:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int broadcast_size_max:int = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate;
help.noAppUpdate#c45a6536 = help.AppUpdate;
help.inviteText#18cb9f78 message:string = help.InviteText;
messages.statedMessagesLinks#3e74f5c6 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> links:Vector<contacts.Link> pts:int seq:int = messages.StatedMessages;
messages.statedMessageLink#a9af2881 message:Message chats:Vector<Chat> users:Vector<User> links:Vector<contacts.Link> pts:int seq:int = messages.StatedMessage;
messages.sentMessageLink#e9db4a3f id:int date:int pts:int seq:int links:Vector<contacts.Link> = messages.SentMessage;
inputGeoChat#74d456fa chat_id:int access_hash:long = InputGeoChat;
inputNotifyGeoChatPeer#4d8ddec8 peer:InputGeoChat = InputNotifyPeer;
geoChat#75eaea5a id:int access_hash:long title:string address:string venue:string geo:GeoPoint photo:ChatPhoto participants_count:int date:int checked_in:Bool version:int = Chat;
geoChatMessageEmpty#60311a9b chat_id:int id:int = GeoChatMessage;
geoChatMessage#4505f8e1 chat_id:int id:int from_id:int date:int message:string media:MessageMedia = GeoChatMessage;
geoChatMessageService#d34fa24e chat_id:int id:int from_id:int date:int action:MessageAction = GeoChatMessage;
geochats.statedMessage#17b1578b message:GeoChatMessage chats:Vector<Chat> users:Vector<User> seq:int = geochats.StatedMessage;
geochats.located#48feb267 results:Vector<ChatLocated> messages:Vector<GeoChatMessage> chats:Vector<Chat> users:Vector<User> = geochats.Located;
geochats.messages#d1526db1 messages:Vector<GeoChatMessage> chats:Vector<Chat> users:Vector<User> = geochats.Messages;
geochats.messagesSlice#bc5863e8 count:int messages:Vector<GeoChatMessage> chats:Vector<Chat> users:Vector<User> = geochats.Messages;
messageActionGeoChatCreate#6f038ebc title:string address:string = MessageAction;
messageActionGeoChatCheckin#c7d53de = MessageAction;
updateNewGeoChatMessage#5a68e3f7 message:GeoChatMessage = Update;
wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper;
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat;
encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat;
encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat;
encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat;
encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat;
inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat;
encryptedFileEmpty#c21f497e = EncryptedFile;
encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile;
inputEncryptedFileEmpty#1837c364 = InputEncryptedFile;
inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile;
inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage;
encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage;
messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig;
messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig;
messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage;
messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage;
inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile;
updateChatParticipantAdd#3a0eeb22 chat_id:int user_id:int inviter_id:int version:int = Update;
updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
inputMediaUploadedAudio#4e498cab file:InputFile duration:int mime_type:string = InputMedia;
inputMediaAudio#89938781 id:InputAudio = InputMedia;
inputMediaUploadedDocument#34e794bd file:InputFile file_name:string mime_type:string = InputMedia;
inputMediaUploadedThumbDocument#3e46de5d file:InputFile thumb:InputFile file_name:string mime_type:string = InputMedia;
inputMediaDocument#d184e841 id:InputDocument = InputMedia;
messageMediaDocument#2fda2204 document:Document = MessageMedia;
messageMediaAudio#c6b68300 audio:Audio = MessageMedia;
inputAudioEmpty#d95adc84 = InputAudio;
inputAudio#77d440ff id:long access_hash:long = InputAudio;
inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#18798952 id:long access_hash:long = InputDocument;
inputAudioFileLocation#74dc404d id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation;
audioEmpty#586988d8 id:long = Audio;
audio#c7ac6496 id:long access_hash:long user_id:int date:int duration:int mime_type:string size:int dc_id:int = Audio;
documentEmpty#36f8c871 id:long = Document;
document#9efc6326 id:long access_hash:long user_id:int date:int file_name:string mime_type:string size:int thumb:PhotoSize dc_id:int = Document;
help.support#17c6b5f6 phone_number:string user:User = help.Support;
notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
notifyUsers#b4c83b4c = NotifyPeer;
notifyChats#c007cec3 = NotifyPeer;
notifyAll#74d07c60 = NotifyPeer;
updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
auth.sentAppCode#e325edcf phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode;
updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update;
updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update;
message#567699b3 flags:int id:int from_id:int to_id:Peer date:int message:string media:MessageMedia = Message;
messageForwarded#a367e716 flags:int id:int fwd_from_id:int fwd_date:int from_id:int to_id:Peer date:int message:string media:MessageMedia = Message;
messageService#1d86f70e flags:int id:int from_id:int to_id:Peer date:int action:MessageAction = Message;
sendMessageTypingAction#16bf744e = SendMessageAction;
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
sendMessageRecordVideoAction#a187d66f = SendMessageAction;
sendMessageUploadVideoAction#92042ff7 = SendMessageAction;
sendMessageRecordAudioAction#d52f73f7 = SendMessageAction;
sendMessageUploadAudioAction#e6ac8a6f = SendMessageAction;
sendMessageUploadPhotoAction#990a3c1a = SendMessageAction;
sendMessageUploadDocumentAction#8faee98e = SendMessageAction;
sendMessageGeoLocationAction#176f8ba1 = SendMessageAction;
sendMessageChooseContactAction#628cbc6f = SendMessageAction;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone;
auth.sendCode#768d5f4d phone_number:string sms_type:int api_id:int api_hash:string lang_code:string = auth.SentCode;
auth.sendCall#3c51564 phone_number:string phone_code_hash:string = Bool;
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool;
auth.resetAuthorizations#9fab0d1a = Bool;
auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool;
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
account.registerDevice#446c712c token_type:int token:string device_model:string system_version:string app_version:string app_sandbox:Bool lang_code:string = Bool;
account.unregisterDevice#65c55b40 token_type:int token:string = Bool;
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
account.resetNotifySettings#db7e1747 = Bool;
account.updateProfile#f0888d68 first_name:string last_name:string = User;
account.updateStatus#6628562c offline:Bool = Bool;
account.getWallPapers#c04cfac2 = Vector<WallPaper>;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
contacts.getContacts#22c6aa08 hash:string = contacts.Contacts;
contacts.importContacts#da30b32d contacts:Vector<InputContact> replace:Bool = contacts.ImportedContacts;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.getSuggested#cd773428 limit:int = contacts.Suggested;
contacts.deleteContact#8e953744 id:InputUser = contacts.Link;
contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool;
contacts.block#332b49fc id:InputUser = Bool;
contacts.unblock#e54100bd id:InputUser = Bool;
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
contacts.exportCard#84e53737 = Vector<int>;
contacts.importCard#4fe196fe export_card:Vector<int> = User;
messages.getMessages#4222fa74 id:Vector<int> = messages.Messages;
messages.getDialogs#eccf1df6 offset:int max_id:int limit:int = messages.Dialogs;
messages.getHistory#92a1df2f peer:InputPeer offset:int max_id:int limit:int = messages.Messages;
messages.search#7e9f2ab peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages;
messages.readHistory#eed884c6 peer:InputPeer max_id:int offset:int read_contents:Bool = messages.AffectedHistory;
messages.deleteHistory#f4f8fb61 peer:InputPeer offset:int = messages.AffectedHistory;
messages.deleteMessages#14f2dd0a id:Vector<int> = Vector<int>;
messages.restoreMessages#395f9d7e id:Vector<int> = Vector<int>;
messages.receivedMessages#28abcb68 max_id:int = Vector<int>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.sendMessage#4cde0aab peer:InputPeer message:string random_id:long = messages.SentMessage;
messages.sendMedia#a3c85d76 peer:InputPeer media:InputMedia random_id:long = messages.StatedMessage;
messages.forwardMessages#514cd10f peer:InputPeer id:Vector<int> = messages.StatedMessages;
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
messages.editChatTitle#b4bc68b5 chat_id:int title:string = messages.StatedMessage;
messages.editChatPhoto#d881821d chat_id:int photo:InputChatPhoto = messages.StatedMessage;
messages.addChatUser#2ee9ee9e chat_id:int user_id:InputUser fwd_limit:int = messages.StatedMessage;
messages.deleteChatUser#c3c5cd23 chat_id:int user_id:InputUser = messages.StatedMessage;
messages.createChat#419d9aee users:Vector<InputUser> title:string = messages.StatedMessage;
updates.getState#edd4882a = updates.State;
updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference;
photos.updateProfilePhoto#eef579a0 id:InputPhoto crop:InputPhotoCrop = UserProfilePhoto;
photos.uploadProfilePhoto#d50f9c88 file:InputFile caption:string geo_point:InputGeoPoint crop:InputPhotoCrop = photos.Photo;
upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File;
help.getConfig#c4f9186b = Config;
help.getNearestDc#1fb33026 = NearestDc;
help.getAppUpdate#c812ac7e device_model:string system_version:string app_version:string lang_code:string = help.AppUpdate;
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getInviteText#a4a95186 lang_code:string = help.InviteText;
photos.getUserPhotos#b7ee553c user_id:InputUser offset:int max_id:int limit:int = photos.Photos;
messages.forwardMessage#3f3f4f2 peer:InputPeer id:int random_id:long = messages.StatedMessage;
messages.sendBroadcast#41bb0972 contacts:Vector<InputUser> message:string media:InputMedia = messages.StatedMessages;
geochats.getLocated#7f192d8f geo_point:InputGeoPoint radius:int limit:int = geochats.Located;
geochats.getRecents#e1427e6f offset:int limit:int = geochats.Messages;
geochats.checkin#55b3e8fb peer:InputGeoChat = geochats.StatedMessage;
geochats.getFullChat#6722dd6f peer:InputGeoChat = messages.ChatFull;
geochats.editChatTitle#4c8e2273 peer:InputGeoChat title:string address:string = geochats.StatedMessage;
geochats.editChatPhoto#35d81a95 peer:InputGeoChat photo:InputChatPhoto = geochats.StatedMessage;
geochats.search#cfcdc44d peer:InputGeoChat q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = geochats.Messages;
geochats.getHistory#b53f7a68 peer:InputGeoChat offset:int max_id:int limit:int = geochats.Messages;
geochats.setTyping#8b8a729 peer:InputGeoChat typing:Bool = Bool;
geochats.sendMessage#61b0044 peer:InputGeoChat message:string random_id:long = geochats.StatedMessage;
geochats.sendMedia#b8f0deff peer:InputGeoChat media:InputMedia random_id:long = geochats.StatedMessage;
geochats.createGeoChat#e092e16 title:string geo_point:InputGeoPoint address:string venue:string = geochats.StatedMessage;
messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
messages.discardEncryption#edd923c5 chat_id:int = Bool;
messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X;
help.getSupport#9cdf08cd = help.Support;
auth.sendSms#da9f3e8 phone_number:string phone_code_hash:string = Bool;
messages.readMessageContents id:Vector<int> = Vector<int>;
invokeWithLayer17#50858a19 {X:Type} query:!X = X;

8
server.pub Normal file
View File

@ -0,0 +1,8 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
-----END RSA PUBLIC KEY-----

View File

@ -108,6 +108,34 @@ char *tgls_default_create_print_name (tgl_peer_id_t id, const char *a1, const ch
return tstrdup (s);
}
enum tgl_typing_status tglf_fetch_typing (void) {
switch (fetch_int ()) {
case CODE_send_message_typing_action:
return tgl_typing_typing;
case CODE_send_message_cancel_action:
return tgl_typing_cancel;
case CODE_send_message_record_video_action:
return tgl_typing_record_video;
case CODE_send_message_upload_video_action:
return tgl_typing_upload_video;
case CODE_send_message_record_audio_action:
return tgl_typing_record_audio;
case CODE_send_message_upload_audio_action:
return tgl_typing_upload_audio;
case CODE_send_message_upload_photo_action:
return tgl_typing_upload_photo;
case CODE_send_message_upload_document_action:
return tgl_typing_upload_document;
case CODE_send_message_geo_location_action:
return tgl_typing_geo;
case CODE_send_message_choose_contact_action:
return tgl_typing_choose_contact;
default:
assert (0);
return tgl_typing_none;
}
}
/* {{{ Fetch */
int tglf_fetch_file_location (struct tgl_file_location *loc) {
@ -512,8 +540,8 @@ void tglf_fetch_photo_size (struct tgl_photo_size *S) {
void tglf_fetch_geo (struct tgl_geo *G) {
unsigned x = fetch_int ();
if (x == CODE_geo_point) {
G->longitude = fetch_double ();
G->latitude = fetch_double ();
G->longitude = fetch_double ();
} else {
assert (x == CODE_geo_point_empty);
G->longitude = 0;
@ -923,8 +951,8 @@ void tglf_fetch_message_media_encrypted (struct tgl_message_media *M) {
*/
case CODE_decrypted_message_media_geo_point:
M->type = tgl_message_media_geo;
M->geo.longitude = fetch_double ();
M->geo.latitude = fetch_double ();
M->geo.longitude = fetch_double ();
break;
case CODE_decrypted_message_media_contact:
M->type = tgl_message_media_contact;
@ -990,6 +1018,10 @@ void tglf_fetch_message_action_encrypted (struct tgl_message_action *M) {
case CODE_decrypted_message_action_flush_history:
M->type = tgl_message_action_flush_history;
break;
case CODE_decrypted_message_action_typing:
M->type = tgl_message_action_typing;
M->typing = tglf_fetch_typing ();
break;
default:
vlogprintf (E_ERROR, "x = 0x%08x\n", x);
assert (0);
@ -1009,6 +1041,10 @@ tgl_peer_id_t tglf_fetch_peer_id (void) {
void tglf_fetch_message (struct tgl_message *M) {
unsigned x = fetch_int ();
assert (x == CODE_message_empty || x == CODE_message || x == CODE_message_forwarded || x == CODE_message_service);
int flags = 0;
if (x != CODE_message_empty) {
flags = fetch_int ();
}
int id = fetch_int ();
assert (M->id == id);
if (x == CODE_message_empty) {
@ -1024,11 +1060,12 @@ void tglf_fetch_message (struct tgl_message *M) {
int from_id = fetch_int ();
tgl_peer_id_t to_id = tglf_fetch_peer_id ();
fetch_bool (); // out.
//fetch_bool (); // out.
int unread = fetch_bool ();
//int unread = fetch_bool ();
int date = fetch_int ();
int unread = (flags & 1) != 0;
int new = !(M->flags & FLAG_CREATED);
if (x == CODE_message_service) {
@ -1190,12 +1227,30 @@ void tglf_fetch_encrypted_message (struct tgl_message *M) {
assert (layer >= 0);
x = fetch_int ();
}
assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service);
assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service || x == CODE_decrypted_message_l16 || x == CODE_decrypted_message_service_l16);
//assert (id == fetch_long ());
if (x == CODE_decrypted_message || x == CODE_decrypted_message_service) {
int out_seq_no = fetch_int ();
int in_seq_no = fetch_int ();
if (in_seq_no / 2 <= P->encr_chat.in_seq_no) {
vlogprintf (E_WARNING, "Hole in seq in secret chat. in_seq_no = %d, expect_seq_no = %d\n", in_seq_no / 2, P->encr_chat.in_seq_no + 1);
}
if (in_seq_no / 2 > P->encr_chat.in_seq_no + 1) {
vlogprintf (E_WARNING, "Hole in seq in secret chat. in_seq_no = %d, expect_seq_no = %d\n", in_seq_no / 2, P->encr_chat.in_seq_no + 1);
}
//vlogprintf (E_WARNING, "in = %d, out = %d\n", in_seq_no, out_seq_no);
assert (out_seq_no / 2 <= P->encr_chat.out_seq_no);
P->encr_chat.in_seq_no = in_seq_no / 2;
if (x == CODE_decrypted_message) {
fetch_int (); // ttl
}
} else {
P->encr_chat.in_seq_no ++;
}
fetch_long ();
ll = prefetch_strlen ();
fetch_str (ll); // random_bytes
if (x == CODE_decrypted_message) {
if (x == CODE_decrypted_message || x == CODE_decrypted_message_l16) {
l = prefetch_strlen ();
s = fetch_str (l);
start = in_ptr;
@ -1216,9 +1271,9 @@ void tglf_fetch_encrypted_message (struct tgl_message *M) {
if (ok) {
int *start_file = in_ptr;
assert (skip_type_any (TYPE_TO_PARAM (encrypted_file)) >= 0);
if (x == CODE_decrypted_message) {
if (x == CODE_decrypted_message || x == CODE_decrypted_message_l16) {
bl_do_create_message_media_encr (id, P->encr_chat.user_id, TGL_PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, in_ptr - start_file);
} else if (x == CODE_decrypted_message_service) {
} else if (x == CODE_decrypted_message_service || x == CODE_decrypted_message_service_l16) {
bl_do_create_message_service_encr (id, P->encr_chat.user_id, TGL_PEER_ENCR_CHAT, to_id, date, start, end - start);
}
} else {
@ -1226,7 +1281,7 @@ void tglf_fetch_encrypted_message (struct tgl_message *M) {
M->media.type = CODE_message_media_empty;
}
} else {
if (ok && x == CODE_decrypted_message_service) {
if (ok && (x == CODE_decrypted_message_service || x == CODE_decrypted_message_service_l16)) {
bl_do_create_message_service_encr (id, P->encr_chat.user_id, TGL_PEER_ENCR_CHAT, to_id, date, start, end - start);
}
}
@ -1310,12 +1365,12 @@ struct tgl_user *tglf_fetch_alloc_user_full (void) {
}
struct tgl_message *tglf_fetch_alloc_message (void) {
int data[2];
prefetch_data (data, 8);
struct tgl_message *M = tgl_message_get (data[1]);
int data[3];
prefetch_data (data, 12);
struct tgl_message *M = tgl_message_get (data[0] != (int)CODE_message_empty ? data[2] : data[1]);
if (!M) {
M = tglm_message_alloc (data[1]);
M = tglm_message_alloc (data[0] != (int)CODE_message_empty ? data[2] : data[1]);
}
tglf_fetch_message (M);
return M;

View File

@ -51,5 +51,6 @@ void tglp_peer_delete_name (tgl_peer_t *P);
void tglp_insert_encrypted_chat (tgl_peer_t *P);
void tglp_insert_user (tgl_peer_t *P);
void tglp_insert_chat (tgl_peer_t *P);
enum tgl_typing_status tglf_fetch_typing (void);
#endif

View File

@ -120,7 +120,22 @@ enum tgl_message_action_type {
tgl_message_action_delete_messages,
tgl_message_action_screenshot_messages,
tgl_message_action_flush_history,
tgl_message_action_notify_layer
tgl_message_action_notify_layer,
tgl_message_action_typing
};
enum tgl_typing_status {
tgl_typing_none,
tgl_typing_typing,
tgl_typing_cancel,
tgl_typing_record_video,
tgl_typing_upload_video,
tgl_typing_record_audio,
tgl_typing_upload_audio,
tgl_typing_upload_photo,
tgl_typing_upload_document,
tgl_typing_geo,
tgl_typing_choose_contact
};
struct tgl_file_location {
@ -288,6 +303,8 @@ struct tgl_secret_chat {
int date;
int ttl;
int layer;
int in_seq_no;
int out_seq_no;
long long access_hash;
unsigned char *g_key;
unsigned char *nonce;
@ -367,6 +384,7 @@ struct tgl_message_action {
int read_cnt;
int delete_cnt;
int screenshot_cnt;
enum tgl_typing_status typing;
};
};

25
tgl.h
View File

@ -24,16 +24,22 @@
#include <string.h>
#define TGL_MAX_DC_NUM 100
#define TG_SERVER "149.154.167.50"
#define TG_SERVER_TEST "149.154.167.40"
#define TG_SERVER_DC 2
#define TG_SERVER_TEST_DC 2
#define TG_SERVER_1 "173.240.5.1"
#define TG_SERVER_2 "149.154.167.51"
#define TG_SERVER_3 "174.140.142.6"
#define TG_SERVER_4 "149.154.167.91"
#define TG_SERVER_5 "149.154.171.5"
#define TG_SERVER_TEST_1 "173.240.5.253"
#define TG_SERVER_TEST_2 "149.154.167.40"
#define TG_SERVER_TEST_3 "174.140.142.5"
// JUST RANDOM STRING
#define TGL_BUILD "2014"
#define TGL_VERSION "1.0.5"
#define TGL_BUILD "2234"
#define TGL_VERSION "1.0.6"
#define TGL_ENCRYPTED_LAYER 16
#define TGL_ENCRYPTED_LAYER 17
struct connection;
struct mtproto_methods;
@ -70,8 +76,8 @@ struct tgl_update_callback {
void (*new_msg)(struct tgl_message *M);
void (*marked_read)(int num, struct tgl_message *list[]);
void (*logprintf)(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void (*type_notification)(struct tgl_user *U);
void (*type_in_chat_notification)(struct tgl_user *U, struct tgl_chat *C);
void (*type_notification)(struct tgl_user *U, enum tgl_typing_status status);
void (*type_in_chat_notification)(struct tgl_user *U, struct tgl_chat *C, enum tgl_typing_status status);
void (*type_in_secret_chat_notification)(struct tgl_secret_chat *E);
void (*status_notification)(struct tgl_user *U);
void (*user_registered)(struct tgl_user *U);
@ -289,6 +295,7 @@ void tgl_do_send_contact (tgl_peer_id_t id, const char *phone, int phone_len, co
void tgl_do_forward_media (tgl_peer_id_t id, int n, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_del_contact (tgl_peer_id_t id, void (*callback)(void *callback_extra, int success), void *callback_extra);
void tgl_do_set_encr_chat_ttl (struct tgl_secret_chat *E, int ttl, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_send_location(tgl_peer_id_t id, double latitude, double longitude, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_visualize_key (tgl_peer_id_t id, unsigned char buf[16]);

View File

@ -99,24 +99,28 @@ void tglu_work_update (struct connection *c, long long msg_id) {
break;
case CODE_update_user_typing:
{
//vlogprintf (E_ERROR, "user typing\n");
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *U = tgl_peer_get (id);
enum tgl_typing_status status = tglf_fetch_typing ();
if (tgl_state.callback.type_notification && U) {
tgl_state.callback.type_notification ((void *)U);
tgl_state.callback.type_notification ((void *)U, status);
}
}
break;
case CODE_update_chat_user_typing:
{
//vlogprintf (E_ERROR, "chat typing\n");
tgl_peer_id_t chat_id = TGL_MK_CHAT (fetch_int ());
tgl_peer_id_t id = TGL_MK_USER (fetch_int ());
tgl_peer_t *C = tgl_peer_get (chat_id);
tgl_peer_t *U = tgl_peer_get (id);
enum tgl_typing_status status = tglf_fetch_typing ();
if (U && C) {
if (tgl_state.callback.type_in_chat_notification) {
tgl_state.callback.type_in_chat_notification ((void *)U, (void *)C);
tgl_state.callback.type_in_chat_notification ((void *)U, (void *)C, status);
}
}
}