Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
T
tg
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
tg
Commits
06dee8bd
Commit
06dee8bd
authored
Nov 21, 2013
by
Vysheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sometimes new binlog works
parent
fe0e4fed
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1010 additions
and
421 deletions
+1010
-421
binlog.c
binlog.c
+609
-27
binlog.h
binlog.h
+49
-0
interface.c
interface.c
+12
-4
loop.c
loop.c
+3
-8
main.c
main.c
+5
-1
mtproto-client.c
mtproto-client.c
+23
-53
queries.c
queries.c
+46
-114
queries.h
queries.h
+1
-1
structures.c
structures.c
+256
-212
structures.h
structures.h
+6
-1
No files found.
binlog.c
View file @
06dee8bd
This diff is collapsed.
Click to expand it.
binlog.h
View file @
06dee8bd
#ifndef __BINLOG_H__
#ifndef __BINLOG_H__
#define __BINLOG_H__
#define __BINLOG_H__
#include "structures.h"
#define LOG_START 0x8948329a
#define LOG_START 0x8948329a
#define LOG_AUTH_KEY 0x984932aa
#define LOG_AUTH_KEY 0x984932aa
#define LOG_DEFAULT_DC 0x95382908
#define LOG_DEFAULT_DC 0x95382908
...
@@ -16,8 +18,55 @@
...
@@ -16,8 +18,55 @@
#define LOG_ENCR_CHAT_REQUESTED 0x9011011a
#define LOG_ENCR_CHAT_REQUESTED 0x9011011a
#define LOG_ENCR_CHAT_OK 0x7612ce13
#define LOG_ENCR_CHAT_OK 0x7612ce13
#define CODE_binlog_new_user 0xe04f30de
#define CODE_binlog_user_delete 0xf7a27c79
#define CODE_binlog_set_user_access_token 0x1349f615
#define CODE_binlog_set_user_phone 0x5d3afde2
#define CODE_binlog_set_user_friend 0x75a7ec5a
#define CODE_binlog_dc_option 0x08c0ef19
#define CODE_binlog_user_full_photo 0xfaa35824
#define CODE_binlog_user_blocked 0xb2dea7cd
#define CODE_binlog_set_user_full_name 0x4ceb4cf0
#define CODE_binlog_encr_chat_delete 0xb9d33f87
#define CODE_binlog_encr_chat_requested 0xf57d1ea2
#define CODE_binlog_set_encr_chat_access_hash 0xe5612bb3
#define CODE_binlog_set_encr_chat_date 0x54f16911
#define CODE_binlog_set_encr_chat_state 0x76a6e45b
#define CODE_binlog_encr_chat_accepted 0x4627e926
#define CODE_binlog_set_encr_chat_key 0x179df2d4
#define CODE_binlog_set_dh_params 0x20ba46bc
#define CODE_binlog_encr_chat_init 0x939cd1c7
void
*
alloc_log_event
(
int
l
);
void
*
alloc_log_event
(
int
l
);
void
replay_log
(
void
);
void
replay_log
(
void
);
void
add_log_event
(
const
int
*
data
,
int
l
);
void
add_log_event
(
const
int
*
data
,
int
l
);
void
write_binlog
(
void
);
void
write_binlog
(
void
);
void
bl_do_set_auth_key_id
(
int
num
,
unsigned
char
*
buf
);
void
bl_do_dc_option
(
int
id
,
int
l1
,
const
char
*
name
,
int
l2
,
const
char
*
ip
,
int
port
);
void
bl_do_set_our_id
(
int
id
);
void
bl_do_new_user
(
int
id
,
const
char
*
f
,
int
fl
,
const
char
*
l
,
int
ll
,
long
long
access_token
,
const
char
*
p
,
int
pl
,
int
contact
);
void
bl_do_user_delete
(
struct
user
*
U
);
void
bl_do_set_user_profile_photo
(
struct
user
*
U
,
long
long
photo_id
,
struct
file_location
*
big
,
struct
file_location
*
small
);
void
bl_do_set_user_name
(
struct
user
*
U
,
const
char
*
f
,
int
fl
,
const
char
*
l
,
int
ll
);
void
bl_do_set_user_access_token
(
struct
user
*
U
,
long
long
access_token
);
void
bl_do_set_user_phone
(
struct
user
*
U
,
const
char
*
p
,
int
pl
);
void
bl_do_set_user_friend
(
struct
user
*
U
,
int
friend
);
void
bl_do_set_user_full_photo
(
struct
user
*
U
,
const
int
*
start
,
int
len
);
void
bl_do_set_user_blocked
(
struct
user
*
U
,
int
blocked
);
void
bl_do_set_user_real_name
(
struct
user
*
U
,
const
char
*
f
,
int
fl
,
const
char
*
l
,
int
ll
);
void
bl_do_encr_chat_delete
(
struct
secret_chat
*
U
);
void
bl_do_encr_chat_requested
(
struct
secret_chat
*
U
,
long
long
access_hash
,
int
date
,
int
admin_id
,
int
user_id
,
unsigned
char
g_key
[],
unsigned
char
nonce
[]);
void
bl_do_set_encr_chat_access_hash
(
struct
secret_chat
*
U
,
long
long
access_hash
);
void
bl_do_set_encr_chat_date
(
struct
secret_chat
*
U
,
int
date
);
void
bl_do_set_encr_chat_state
(
struct
secret_chat
*
U
,
enum
secret_chat_state
state
);
void
bl_do_encr_chat_accepted
(
struct
secret_chat
*
U
,
const
unsigned
char
g_key
[],
const
unsigned
char
nonce
[],
long
long
key_fingerprint
);
void
bl_do_set_encr_chat_key
(
struct
secret_chat
*
E
,
unsigned
char
key
[],
long
long
key_fingerprint
);
void
bl_do_encr_chat_init
(
int
id
,
int
user_id
,
unsigned
char
random
[],
unsigned
char
g_a
[]);
void
bl_do_dc_signed
(
int
id
);
void
bl_do_set_working_dc
(
int
num
);
void
bl_do_set_dh_params
(
int
root
,
unsigned
char
prime
[],
int
version
);
#endif
#endif
interface.c
View file @
06dee8bd
...
@@ -916,14 +916,20 @@ void hexdump (int *in_ptr, int *in_end) {
...
@@ -916,14 +916,20 @@ void hexdump (int *in_ptr, int *in_end) {
}
}
void
logprintf
(
const
char
*
format
,
...)
{
void
logprintf
(
const
char
*
format
,
...)
{
print_start
();
int
x
=
0
;
if
(
!
prompt_was
)
{
x
=
1
;
print_start
();
}
printf
(
COLOR_GREY
" *** "
);
printf
(
COLOR_GREY
" *** "
);
va_list
ap
;
va_list
ap
;
va_start
(
ap
,
format
);
va_start
(
ap
,
format
);
vfprintf
(
stdout
,
format
,
ap
);
vfprintf
(
stdout
,
format
,
ap
);
va_end
(
ap
);
va_end
(
ap
);
printf
(
COLOR_NORMAL
);
printf
(
COLOR_NORMAL
);
print_end
();
if
(
x
)
{
print_end
();
}
}
}
int
color_stack_pos
;
int
color_stack_pos
;
...
@@ -1007,8 +1013,10 @@ void print_user_name (peer_id_t id, peer_t *U) {
...
@@ -1007,8 +1013,10 @@ void print_user_name (peer_id_t id, peer_t *U) {
if
(
U
->
flags
&
(
FLAG_USER_SELF
|
FLAG_USER_CONTACT
))
{
if
(
U
->
flags
&
(
FLAG_USER_SELF
|
FLAG_USER_CONTACT
))
{
push_color
(
COLOR_REDB
);
push_color
(
COLOR_REDB
);
}
}
if
((
U
->
flags
&
FLAG_DELETED
)
||
(
U
->
flags
&
FLAG_EMPTY
)
)
{
if
((
U
->
flags
&
FLAG_DELETED
))
{
printf
(
"deleted user#%d"
,
get_peer_id
(
id
));
printf
(
"deleted user#%d"
,
get_peer_id
(
id
));
}
else
if
(
!
(
U
->
flags
&
FLAG_CREATED
))
{
printf
(
"empty user#%d"
,
get_peer_id
(
id
));
}
else
if
(
!
U
->
user
.
first_name
||
!
strlen
(
U
->
user
.
first_name
))
{
}
else
if
(
!
U
->
user
.
first_name
||
!
strlen
(
U
->
user
.
first_name
))
{
printf
(
"%s"
,
U
->
user
.
last_name
);
printf
(
"%s"
,
U
->
user
.
last_name
);
}
else
if
(
!
U
->
user
.
last_name
||
!
strlen
(
U
->
user
.
last_name
))
{
}
else
if
(
!
U
->
user
.
last_name
||
!
strlen
(
U
->
user
.
last_name
))
{
...
@@ -1123,7 +1131,7 @@ peer_id_t last_from_id;
...
@@ -1123,7 +1131,7 @@ peer_id_t last_from_id;
peer_id_t
last_to_id
;
peer_id_t
last_to_id
;
void
print_message
(
struct
message
*
M
)
{
void
print_message
(
struct
message
*
M
)
{
if
(
M
->
flags
&
(
FLAG_EMPTY
|
FLAG_DELETED
))
{
if
(
M
->
flags
&
(
FLAG_
MESSAGE_
EMPTY
|
FLAG_DELETED
))
{
return
;
return
;
}
}
if
(
M
->
service
)
{
if
(
M
->
service
)
{
...
...
loop.c
View file @
06dee8bd
...
@@ -57,6 +57,7 @@ extern int binlog_enabled;
...
@@ -57,6 +57,7 @@ extern int binlog_enabled;
extern
int
unknown_user_list_pos
;
extern
int
unknown_user_list_pos
;
extern
int
unknown_user_list
[];
extern
int
unknown_user_list
[];
int
register_mode
;
int
unread_messages
;
int
unread_messages
;
void
got_it
(
char
*
line
,
int
len
);
void
got_it
(
char
*
line
,
int
len
);
...
@@ -483,7 +484,7 @@ int loop (void) {
...
@@ -483,7 +484,7 @@ int loop (void) {
int
res
=
do_auth_check_phone
(
default_username
);
int
res
=
do_auth_check_phone
(
default_username
);
assert
(
res
>=
0
);
assert
(
res
>=
0
);
logprintf
(
"%s
\n
"
,
res
>
0
?
"phone registered"
:
"phone not registered"
);
logprintf
(
"%s
\n
"
,
res
>
0
?
"phone registered"
:
"phone not registered"
);
if
(
res
>
0
)
{
if
(
res
>
0
&&
!
register_mode
)
{
do_send_code
(
default_username
);
do_send_code
(
default_username
);
char
*
code
=
0
;
char
*
code
=
0
;
size_t
size
=
0
;
size_t
size
=
0
;
...
@@ -552,13 +553,7 @@ int loop (void) {
...
@@ -552,13 +553,7 @@ int loop (void) {
for
(
i
=
0
;
i
<=
MAX_DC_NUM
;
i
++
)
if
(
DC_list
[
i
]
&&
!
DC_list
[
i
]
->
has_auth
)
{
for
(
i
=
0
;
i
<=
MAX_DC_NUM
;
i
++
)
if
(
DC_list
[
i
]
&&
!
DC_list
[
i
]
->
has_auth
)
{
do_export_auth
(
i
);
do_export_auth
(
i
);
do_import_auth
(
i
);
do_import_auth
(
i
);
DC_list
[
i
]
->
has_auth
=
1
;
bl_do_dc_signed
(
i
);
if
(
binlog_enabled
)
{
int
*
ev
=
alloc_log_event
(
8
);
ev
[
0
]
=
LOG_DC_SIGNED
;
ev
[
1
]
=
i
;
add_log_event
(
ev
,
8
);
}
write_auth_file
();
write_auth_file
();
}
}
write_auth_file
();
write_auth_file
();
...
...
main.c
View file @
06dee8bd
...
@@ -312,9 +312,10 @@ extern char *rsa_public_key_name;
...
@@ -312,9 +312,10 @@ extern char *rsa_public_key_name;
extern
int
verbosity
;
extern
int
verbosity
;
extern
int
default_dc_num
;
extern
int
default_dc_num
;
int
register_mode
;
void
args_parse
(
int
argc
,
char
**
argv
)
{
void
args_parse
(
int
argc
,
char
**
argv
)
{
int
opt
=
0
;
int
opt
=
0
;
while
((
opt
=
getopt
(
argc
,
argv
,
"u:hk:vn:Nc:p:l:"
))
!=
-
1
)
{
while
((
opt
=
getopt
(
argc
,
argv
,
"u:hk:vn:Nc:p:l:
R
"
))
!=
-
1
)
{
switch
(
opt
)
{
switch
(
opt
)
{
case
'u'
:
case
'u'
:
set_default_username
(
optarg
);
set_default_username
(
optarg
);
...
@@ -338,6 +339,9 @@ void args_parse (int argc, char **argv) {
...
@@ -338,6 +339,9 @@ void args_parse (int argc, char **argv) {
case
'l'
:
case
'l'
:
log_level
=
atoi
(
optarg
);
log_level
=
atoi
(
optarg
);
break
;
break
;
case
'R'
:
register_mode
=
1
;
break
;
case
'h'
:
case
'h'
:
default:
default:
usage
();
usage
();
...
...
mtproto-client.c
View file @
06dee8bd
...
@@ -61,6 +61,11 @@ char new_nonce[256];
...
@@ -61,6 +61,11 @@ char new_nonce[256];
char
server_nonce
[
256
];
char
server_nonce
[
256
];
extern
int
binlog_enabled
;
extern
int
binlog_enabled
;
int
total_packets_sent
;
long
long
total_data_sent
;
int
rpc_execute
(
struct
connection
*
c
,
int
op
,
int
len
);
int
rpc_execute
(
struct
connection
*
c
,
int
op
,
int
len
);
int
rpc_becomes_ready
(
struct
connection
*
c
);
int
rpc_becomes_ready
(
struct
connection
*
c
);
int
rpc_close
(
struct
connection
*
c
);
int
rpc_close
(
struct
connection
*
c
);
...
@@ -183,6 +188,9 @@ int rpc_send_packet (struct connection *c) {
...
@@ -183,6 +188,9 @@ int rpc_send_packet (struct connection *c) {
write_out
(
c
,
&
unenc_msg_header
,
20
);
write_out
(
c
,
&
unenc_msg_header
,
20
);
write_out
(
c
,
packet_buffer
,
len
);
write_out
(
c
,
packet_buffer
,
len
);
flush_out
(
c
);
flush_out
(
c
);
total_packets_sent
++
;
total_data_sent
+=
total_len
;
return
1
;
return
1
;
}
}
...
@@ -198,6 +206,9 @@ int rpc_send_message (struct connection *c, void *data, int len) {
...
@@ -198,6 +206,9 @@ int rpc_send_message (struct connection *c, void *data, int len) {
c
->
out_packet_num
++
;
c
->
out_packet_num
++
;
write_out
(
c
,
data
,
len
);
write_out
(
c
,
data
,
len
);
flush_out
(
c
);
flush_out
(
c
);
total_packets_sent
++
;
total_data_sent
+=
total_len
;
return
1
;
return
1
;
}
}
...
@@ -506,19 +517,16 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) {
...
@@ -506,19 +517,16 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) {
static
unsigned
char
tmp
[
44
],
sha1_buffer
[
20
];
static
unsigned
char
tmp
[
44
],
sha1_buffer
[
20
];
memcpy
(
tmp
,
new_nonce
,
32
);
memcpy
(
tmp
,
new_nonce
,
32
);
tmp
[
32
]
=
1
;
tmp
[
32
]
=
1
;
//GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12);
bl_do_set_auth_key_id
(
GET_DC
(
c
)
->
id
,
(
unsigned
char
*
)
GET_DC
(
c
)
->
auth_key
);
sha1
((
unsigned
char
*
)
GET_DC
(
c
)
->
auth_key
,
256
,
sha1_buffer
);
sha1
((
unsigned
char
*
)
GET_DC
(
c
)
->
auth_key
,
256
,
sha1_buffer
);
GET_DC
(
c
)
->
auth_key_id
=
*
(
long
long
*
)(
sha1_buffer
+
12
);
memcpy
(
tmp
+
33
,
sha1_buffer
,
8
);
memcpy
(
tmp
+
33
,
sha1_buffer
,
8
);
sha1
(
tmp
,
41
,
sha1_buffer
);
sha1
(
tmp
,
41
,
sha1_buffer
);
assert
(
!
memcmp
(
packet
+
56
,
sha1_buffer
+
4
,
16
));
assert
(
!
memcmp
(
packet
+
56
,
sha1_buffer
+
4
,
16
));
GET_DC
(
c
)
->
server_salt
=
*
(
long
long
*
)
server_nonce
^
*
(
long
long
*
)
new_nonce
;
GET_DC
(
c
)
->
server_salt
=
*
(
long
long
*
)
server_nonce
^
*
(
long
long
*
)
new_nonce
;
/* if (binlog_enabled) {
int *ev = alloc_log_event (16);
ev[0] = LOG_DC_SALT;
ev[1] = GET_DC(c)->id;
*(long long *)(ev + 2) = GET_DC(c)->server_salt;
add_log_event (ev, 16);
}*/
if
(
verbosity
>=
3
)
{
if
(
verbosity
>=
3
)
{
logprintf
(
"auth_key_id=%016llx
\n
"
,
GET_DC
(
c
)
->
auth_key_id
);
logprintf
(
"auth_key_id=%016llx
\n
"
,
GET_DC
(
c
)
->
auth_key_id
);
}
}
...
@@ -535,14 +543,6 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) {
...
@@ -535,14 +543,6 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) {
auth_success
++
;
auth_success
++
;
GET_DC
(
c
)
->
flags
|=
1
;
GET_DC
(
c
)
->
flags
|=
1
;
write_auth_file
();
write_auth_file
();
if
(
binlog_enabled
)
{
int
*
ev
=
alloc_log_event
(
8
+
8
+
256
);
ev
[
0
]
=
LOG_AUTH_KEY
;
ev
[
1
]
=
GET_DC
(
c
)
->
id
;
*
(
long
long
*
)(
ev
+
2
)
=
GET_DC
(
c
)
->
auth_key_id
;
memcpy
(
ev
+
4
,
GET_DC
(
c
)
->
auth_key
,
256
);
add_log_event
(
ev
,
8
+
8
+
256
);
}
return
1
;
return
1
;
}
}
...
@@ -825,25 +825,12 @@ void work_update (struct connection *c UU, long long msg_id UU) {
...
@@ -825,25 +825,12 @@ void work_update (struct connection *c UU, long long msg_id UU) {
if
(
U
->
print_name
)
{
free
(
U
->
print_name
);
}
if
(
U
->
print_name
)
{
free
(
U
->
print_name
);
}
U
->
first_name
=
fetch_str_dup
();
U
->
first_name
=
fetch_str_dup
();
U
->
last_name
=
fetch_str_dup
();
U
->
last_name
=
fetch_str_dup
();
U
->
print_name
=
create_print_name
(
U
->
id
,
U
->
first_name
,
U
->
last_name
,
0
,
0
);
printf
(
" changed name to "
);
printf
(
" changed name to "
);
print_user_name
(
user_id
,
UC
);
print_user_name
(
user_id
,
UC
);
printf
(
"
\n
"
);
printf
(
"
\n
"
);
pop_color
();
pop_color
();
print_end
();
print_end
();
if
(
!
strlen
(
U
->
first_name
))
{
if
(
!
strlen
(
U
->
last_name
))
{
U
->
print_name
=
strdup
(
"none"
);
}
else
{
U
->
print_name
=
strdup
(
U
->
last_name
);
}
}
else
{
if
(
!
strlen
(
U
->
last_name
))
{
U
->
print_name
=
strdup
(
U
->
first_name
);
}
else
{
U
->
print_name
=
malloc
(
strlen
(
U
->
first_name
)
+
strlen
(
U
->
last_name
)
+
2
);
sprintf
(
U
->
print_name
,
"%s_%s"
,
U
->
first_name
,
U
->
last_name
);
}
}
}
else
{
}
else
{
int
l
;
int
l
;
l
=
prefetch_strlen
();
l
=
prefetch_strlen
();
...
@@ -871,11 +858,12 @@ void work_update (struct connection *c UU, long long msg_id UU) {
...
@@ -871,11 +858,12 @@ void work_update (struct connection *c UU, long long msg_id UU) {
print_end
();
print_end
();
unsigned
y
=
fetch_int
();
unsigned
y
=
fetch_int
();
if
(
y
==
CODE_user_profile_photo_empty
)
{
if
(
y
==
CODE_user_profile_photo_empty
)
{
U
->
photo_id
=
0
;
U
->
photo_big
.
dc
=
-
2
;
U
->
photo_big
.
dc
=
-
2
;
U
->
photo_small
.
dc
=
-
2
;
U
->
photo_small
.
dc
=
-
2
;
}
else
{
}
else
{
assert
(
y
==
CODE_user_profile_photo
);
assert
(
y
==
CODE_user_profile_photo
);
fetch_long
();
// photo_id
U
->
photo_id
=
fetch_long
();
fetch_file_location
(
&
U
->
photo_small
);
fetch_file_location
(
&
U
->
photo_small
);
fetch_file_location
(
&
U
->
photo_big
);
fetch_file_location
(
&
U
->
photo_big
);
}
}
...
@@ -1031,12 +1019,14 @@ void work_update (struct connection *c UU, long long msg_id UU) {
...
@@ -1031,12 +1019,14 @@ void work_update (struct connection *c UU, long long msg_id UU) {
case
CODE_update_encryption
:
case
CODE_update_encryption
:
{
{
struct
secret_chat
*
E
=
fetch_alloc_encrypted_chat
();
struct
secret_chat
*
E
=
fetch_alloc_encrypted_chat
();
if
(
verbosity
>=
2
)
{
logprintf
(
"Secret chat state = %d
\n
"
,
E
->
state
);
}
print_start
();
print_start
();
push_color
(
COLOR_YELLOW
);
push_color
(
COLOR_YELLOW
);
print_date
(
time
(
0
));
print_date
(
time
(
0
));
switch
(
E
->
state
)
{
switch
(
E
->
state
)
{
case
sc_none
:
case
sc_none
:
assert
(
0
);
break
;
break
;
case
sc_waiting
:
case
sc_waiting
:
printf
(
" Encrypted chat "
);
printf
(
" Encrypted chat "
);
...
@@ -1159,6 +1149,7 @@ void work_update (struct connection *c UU, long long msg_id UU) {
...
@@ -1159,6 +1149,7 @@ void work_update (struct connection *c UU, long long msg_id UU) {
break
;
break
;
default:
default:
logprintf
(
"Unknown update type %08x
\n
"
,
op
);
logprintf
(
"Unknown update type %08x
\n
"
,
op
);
;
}
}
}
}
...
@@ -1244,13 +1235,6 @@ void work_new_session_created (struct connection *c, long long msg_id UU) {
...
@@ -1244,13 +1235,6 @@ void work_new_session_created (struct connection *c, long long msg_id UU) {
fetch_long
();
// unique_id
fetch_long
();
// unique_id
GET_DC
(
c
)
->
server_salt
=
fetch_long
();
GET_DC
(
c
)
->
server_salt
=
fetch_long
();
/* if (binlog_enabled) {
int *ev = alloc_log_event (16);
ev[0] = LOG_DC_SALT;
ev[1] = GET_DC(c)->id;
*(long long *)(ev + 2) = GET_DC(c)->server_salt;
add_log_event (ev, 16);
}*/
}
}
void
work_msgs_ack
(
struct
connection
*
c
UU
,
long
long
msg_id
UU
)
{
void
work_msgs_ack
(
struct
connection
*
c
UU
,
long
long
msg_id
UU
)
{
...
@@ -1332,13 +1316,6 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) {
...
@@ -1332,13 +1316,6 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) {
fetch_int
();
// error_code
fetch_int
();
// error_code
long
long
new_server_salt
=
fetch_long
();
long
long
new_server_salt
=
fetch_long
();
GET_DC
(
c
)
->
server_salt
=
new_server_salt
;
GET_DC
(
c
)
->
server_salt
=
new_server_salt
;
/* if (binlog_enabled) {
int *ev = alloc_log_event (16);
ev[0] = LOG_DC_SALT;
ev[1] = GET_DC(c)->id;
*(long long *)(ev + 2) = GET_DC(c)->server_salt;
add_log_event (ev, 16);
}*/
}
}
void
work_pong
(
struct
connection
*
c
UU
,
long
long
msg_id
UU
)
{
void
work_pong
(
struct
connection
*
c
UU
,
long
long
msg_id
UU
)
{
...
@@ -1434,13 +1411,6 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc,
...
@@ -1434,13 +1411,6 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc,
if
(
DC
->
server_salt
!=
enc
->
server_salt
)
{
if
(
DC
->
server_salt
!=
enc
->
server_salt
)
{
DC
->
server_salt
=
enc
->
server_salt
;
DC
->
server_salt
=
enc
->
server_salt
;
write_auth_file
();
write_auth_file
();
/* if (binlog_enabled) {
int *ev = alloc_log_event (16);
ev[0] = LOG_DC_SALT;
ev[1] = DC->id;
*(long long *)(ev + 2) = DC->server_salt;
add_log_event (ev, 16);
}*/
}
}
int
this_server_time
=
enc
->
msg_id
>>
32LL
;
int
this_server_time
=
enc
->
msg_id
>>
32LL
;
...
...
queries.c
View file @
06dee8bd
...
@@ -328,7 +328,6 @@ void do_insert_header (void) {
...
@@ -328,7 +328,6 @@ void do_insert_header (void) {
/* {{{ Get config */
/* {{{ Get config */
void
fetch_dc_option
(
void
)
{
void
fetch_dc_option
(
void
)
{
int
*
start
=
in_ptr
;
assert
(
fetch_int
()
==
CODE_dc_option
);
assert
(
fetch_int
()
==
CODE_dc_option
);
int
id
=
fetch_int
();
int
id
=
fetch_int
();
int
l1
=
prefetch_strlen
();
int
l1
=
prefetch_strlen
();
...
@@ -339,13 +338,8 @@ void fetch_dc_option (void) {
...
@@ -339,13 +338,8 @@ void fetch_dc_option (void) {
if
(
verbosity
)
{
if
(
verbosity
)
{
logprintf
(
"id = %d, name = %.*s ip = %.*s port = %d
\n
"
,
id
,
l1
,
name
,
l2
,
ip
,
port
);
logprintf
(
"id = %d, name = %.*s ip = %.*s port = %d
\n
"
,
id
,
l1
,
name
,
l2
,
ip
,
port
);
}
}
if
(
!
DC_list
[
id
])
{
alloc_dc
(
id
,
strndup
(
ip
,
l2
),
port
);
bl_do_dc_option
(
id
,
l1
,
name
,
l2
,
ip
,
port
);
new_dc_num
++
;
if
(
binlog_enabled
)
{
add_log_event
(
start
,
4
*
(
in_ptr
-
start
));
}
}
}
}
int
help_get_config_on_answer
(
struct
query
*
q
UU
)
{
int
help_get_config_on_answer
(
struct
query
*
q
UU
)
{
...
@@ -453,12 +447,8 @@ void do_send_code (const char *user) {
...
@@ -453,12 +447,8 @@ void do_send_code (const char *user) {
dc_create_session
(
DC_working
);
dc_create_session
(
DC_working
);
}
}
dc_working_num
=
want_dc_num
;
dc_working_num
=
want_dc_num
;
if
(
binlog_enabled
)
{
int
*
ev
=
alloc_log_event
(
8
);
bl_do_set_working_dc
(
dc_working_num
);
ev
[
0
]
=
LOG_DEFAULT_DC
;
ev
[
1
]
=
dc_working_num
;
add_log_event
(
ev
,
8
);
}
logprintf
(
"send_code: dc_num = %d
\n
"
,
dc_working_num
);
logprintf
(
"send_code: dc_num = %d
\n
"
,
dc_working_num
);
want_dc_num
=
0
;
want_dc_num
=
0
;
...
@@ -496,16 +486,12 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error
...
@@ -496,16 +486,12 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error
if
(
l
>=
s
&&
!
memcmp
(
error
,
"PHONE_MIGRATE_"
,
s
))
{
if
(
l
>=
s
&&
!
memcmp
(
error
,
"PHONE_MIGRATE_"
,
s
))
{
int
i
=
error
[
s
]
-
'0'
;
int
i
=
error
[
s
]
-
'0'
;
assert
(
DC_list
[
i
]);
assert
(
DC_list
[
i
]);
dc_working_num
=
i
;
dc_working_num
=
i
;
DC_working
=
DC_list
[
i
];
DC_working
=
DC_list
[
i
];
write_auth_file
();
write_auth_file
();
if
(
binlog_enabled
)
{
bl_do_set_working_dc
(
i
);
int
*
ev
=
alloc_log_event
(
8
);
ev
[
0
]
=
LOG_DEFAULT_DC
;
ev
[
1
]
=
i
;
add_log_event
(
ev
,
8
);
}
check_phone_result
=
1
;
check_phone_result
=
1
;
}
else
if
(
l
>=
s2
&&
!
memcmp
(
error
,
"NETWORK_MIGRATE_"
,
s2
))
{
}
else
if
(
l
>=
s2
&&
!
memcmp
(
error
,
"NETWORK_MIGRATE_"
,
s2
))
{
...
@@ -513,12 +499,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error
...
@@ -513,12 +499,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error
assert
(
DC_list
[
i
]);
assert
(
DC_list
[
i
]);
dc_working_num
=
i
;
dc_working_num
=
i
;
if
(
binlog_enabled
)
{
bl_do_set_working_dc
(
i
);
int
*
ev
=
alloc_log_event
(
8
);
ev
[
0
]
=
LOG_DEFAULT_DC
;
ev
[
1
]
=
i
;
add_log_event
(
ev
,
8
);
}
DC_working
=
DC_list
[
i
];
DC_working
=
DC_list
[
i
];
write_auth_file
();
write_auth_file
();
...
@@ -602,24 +583,15 @@ int sign_in_on_answer (struct query *q UU) {
...
@@ -602,24 +583,15 @@ int sign_in_on_answer (struct query *q UU) {
if
(
!
our_id
)
{
if
(
!
our_id
)
{
our_id
=
get_peer_id
(
User
.
id
);
our_id
=
get_peer_id
(
User
.
id
);
if
(
binlog_enabled
)
{
bl_do_set_our_id
(
our_id
);
int
*
ev
=
alloc_log_event
(
8
);
ev
[
0
]
=
LOG_OUR_ID
;
ev
[
1
]
=
our_id
;
add_log_event
(
ev
,
8
);
}
}
}
sign_in_ok
=
1
;
sign_in_ok
=
1
;
if
(
verbosity
)
{
if
(
verbosity
)
{
logprintf
(
"authorized successfully: name = '%s %s', phone = '%s', expires = %d
\n
"
,
User
.
first_name
,
User
.
last_name
,
User
.
phone
,
(
int
)(
expires
-
get_double_time
()));
logprintf
(
"authorized successfully: name = '%s %s', phone = '%s', expires = %d
\n
"
,
User
.
first_name
,
User
.
last_name
,
User
.
phone
,
(
int
)(
expires
-
get_double_time
()));
}
}
DC_working
->
has_auth
=
1
;
DC_working
->
has_auth
=
1
;
if
(
binlog_enabled
)
{
int
*
ev
=
alloc_log_event
(
8
);
bl_do_dc_signed
(
DC_working
->
id
);
ev
[
0
]
=
LOG_DC_SIGNED
;
ev
[
1
]
=
DC_working
->
id
;
add_log_event
(
ev
,
8
);
}
return
0
;
return
0
;
}
}
...
@@ -2219,23 +2191,16 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
...
@@ -2219,23 +2191,16 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
BIGNUM
*
r
=
BN_new
();
BIGNUM
*
r
=
BN_new
();
BN_init
(
r
);
BN_init
(
r
);
BN_mod_exp
(
r
,
g_a
,
b
,
p
,
ctx
);
BN_mod_exp
(
r
,
g_a
,
b
,
p
,
ctx
);
memset
(
E
->
key
,
0
,
sizeof
(
E
->
key
));
static
unsigned
char
kk
[
256
];
BN_bn2bin
(
r
,
(
void
*
)
E
->
key
);
memset
(
kk
,
0
,
sizeof
(
kk
));
for
(
i
=
0
;
i
<
64
;
i
++
)
{
BN_bn2bin
(
r
,
kk
);
E
->
key
[
i
]
^=
*
(((
int
*
)
E
->
nonce
)
+
i
);
for
(
i
=
0
;
i
<
256
;
i
++
)
{
kk
[
i
]
^=
E
->
nonce
[
i
];
}
}
static
unsigned
char
sha_buffer
[
20
];
static
unsigned
char
sha_buffer
[
20
];
sha1
((
void
*
)
E
->
key
,
256
,
sha_buffer
);
sha1
(
kk
,
256
,
sha_buffer
);
E
->
key_fingerprint
=
*
(
long
long
*
)(
sha_buffer
+
12
);
if
(
binlog_enabled
)
{
bl_do_set_encr_chat_key
(
E
,
kk
,
*
(
long
long
*
)(
sha_buffer
+
12
));
int
*
ev
=
alloc_log_event
(
8
+
8
+
256
);
ev
[
0
]
=
LOG_ENCR_CHAT_KEY
;
ev
[
1
]
=
get_peer_id
(
E
->
id
);
*
(
long
long
*
)(
ev
+
2
)
=
E
->
key_fingerprint
;
memcpy
(
ev
+
4
,
E
->
key
,
256
);
add_log_event
(
ev
,
8
+
8
+
256
);
}
clear_packet
();
clear_packet
();
out_int
(
CODE_messages_accept_encryption
);
out_int
(
CODE_messages_accept_encryption
);
...
@@ -2256,16 +2221,6 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
...
@@ -2256,16 +2221,6 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
BN_clear_free
(
p
);
BN_clear_free
(
p
);
BN_clear_free
(
r
);
BN_clear_free
(
r
);
if
(
binlog_enabled
)
{
int
*
ev
=
alloc_log_event
(
16
+
512
);
ev
[
0
]
=
LOG_ENCR_CHAT_SEND_ACCEPT
;
ev
[
1
]
=
get_peer_id
(
E
->
id
);
*
(
long
long
*
)(
ev
+
2
)
=
E
->
key_fingerprint
;
memcpy
(
ev
+
4
,
E
->
key
,
256
);
memcpy
(
ev
+
68
,
buf
,
256
);
add_log_event
(
ev
,
16
+
512
);
}
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
send_encr_accept_methods
,
E
);
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
send_encr_accept_methods
,
E
);
}
}
...
@@ -2299,18 +2254,10 @@ void do_create_keys_end (struct secret_chat *U) {
...
@@ -2299,18 +2254,10 @@ void do_create_keys_end (struct secret_chat *U) {
BN_clear_free
(
g_b
);
BN_clear_free
(
g_b
);
BN_clear_free
(
r
);
BN_clear_free
(
r
);
BN_clear_free
(
a
);
BN_clear_free
(
a
);
if
(
binlog_enabled
)
{
int
*
ev
=
alloc_log_event
(
8
+
8
+
256
);
ev
[
0
]
=
LOG_ENCR_CHAT_KEY
;
ev
[
1
]
=
get_peer_id
(
U
->
id
);
*
(
long
long
*
)(
ev
+
2
)
=
U
->
key_fingerprint
;
memcpy
(
ev
+
4
,
U
->
key
,
256
);
add_log_event
(
ev
,
8
+
8
+
256
);
}
}
}
void
do_send_create_encr_chat
(
struct
secret_chat
*
E
,
unsigned
char
*
random
)
{
void
do_send_create_encr_chat
(
void
*
x
,
unsigned
char
*
random
)
{
int
user_id
=
(
long
)
x
;
int
i
;
int
i
;
for
(
i
=
0
;
i
<
64
;
i
++
)
{
for
(
i
=
0
;
i
<
64
;
i
++
)
{
*
(((
int
*
)
random
)
+
i
)
^=
mrand48
();
*
(((
int
*
)
random
)
+
i
)
^=
mrand48
();
...
@@ -2333,13 +2280,21 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) {
...
@@ -2333,13 +2280,21 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) {
BN_mod_exp
(
r
,
g
,
a
,
p
,
ctx
);
BN_mod_exp
(
r
,
g
,
a
,
p
,
ctx
);
memcpy
(
E
->
key
,
random
,
256
);
static
char
g_a
[
256
];
static
char
g_a
[
256
];
memset
(
g_a
,
0
,
256
);
memset
(
g_a
,
0
,
256
);
BN_bn2bin
(
r
,
(
void
*
)
g_a
);
BN_bn2bin
(
r
,
(
void
*
)
g_a
);
int
t
=
lrand48
();
while
(
user_chat_get
(
MK_ENCR_CHAT
(
t
)))
{
t
=
lrand48
();
}
bl_do_encr_chat_init
(
t
,
user_id
,
(
void
*
)
random
,
(
void
*
)
g_a
);
peer_t
*
_E
=
user_chat_get
(
MK_ENCR_CHAT
(
t
));
assert
(
_E
);
struct
secret_chat
*
E
=
&
_E
->
encr_chat
;
clear_packet
();
clear_packet
();
out_int
(
CODE_messages_request_encryption
);
out_int
(
CODE_messages_request_encryption
);
peer_t
*
U
=
user_chat_get
(
MK_USER
(
E
->
user_id
));
peer_t
*
U
=
user_chat_get
(
MK_USER
(
E
->
user_id
));
...
@@ -2360,46 +2315,28 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) {
...
@@ -2360,46 +2315,28 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) {
BN_clear_free
(
p
);
BN_clear_free
(
p
);
BN_clear_free
(
r
);
BN_clear_free
(
r
);
if
(
binlog_enabled
)
{
int
*
ev
=
alloc_log_event
(
12
+
256
);
ev
[
0
]
=
LOG_ENCR_CHAT_SEND_CREATE
;
ev
[
1
]
=
get_peer_id
(
E
->
id
);
ev
[
2
]
=
E
->
user_id
;
memcpy
(
ev
+
3
,
E
->
key
,
256
);
add_log_event
(
ev
,
12
+
256
);
}
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
send_encr_request_methods
,
E
);
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
send_encr_request_methods
,
E
);
}
}
int
get_dh_config_on_answer
(
struct
query
*
q
UU
)
{
int
get_dh_config_on_answer
(
struct
query
*
q
UU
)
{
int
*
start
=
in_ptr
;
unsigned
x
=
fetch_int
();
unsigned
x
=
fetch_int
();
assert
(
x
==
CODE_messages_dh_config
||
x
==
CODE_messages_dh_config_not_modified
||
LOG_DH_CONFIG
);
assert
(
x
==
CODE_messages_dh_config
||
x
==
CODE_messages_dh_config_not_modified
||
LOG_DH_CONFIG
);
if
(
x
==
CODE_messages_dh_config
||
x
==
LOG_DH_CONFIG
)
{
if
(
x
==
CODE_messages_dh_config
||
x
==
LOG_DH_CONFIG
)
{
encr_root
=
fetch_int
();
int
a
=
fetch_int
();
if
(
encr_prime
)
{
free
(
encr_prime
);
}
int
l
=
prefetch_strlen
();
int
l
=
prefetch_strlen
();
assert
(
l
==
256
);
assert
(
l
==
256
);
encr_prime
=
(
void
*
)
fetch_str_dup
();
char
*
s
=
fetch_str
(
l
);
encr_param_version
=
fetch_int
();
int
v
=
fetch_int
();
if
(
binlog_enabled
)
{
bl_do_set_dh_params
(
a
,
(
void
*
)
s
,
v
);
*
start
=
LOG_DH_CONFIG
;
add_log_event
(
start
,
4
*
(
in_ptr
-
start
));
*
start
=
CODE_messages_dh_config
;
}
}
}
if
(
x
==
LOG_DH_CONFIG
)
{
return
0
;
}
if
(
x
==
LOG_DH_CONFIG
)
{
return
0
;
}
int
l
=
prefetch_strlen
();
int
l
=
prefetch_strlen
();
assert
(
l
==
256
);
assert
(
l
==
256
);
unsigned
char
*
random
=
(
void
*
)
fetch_str_dup
();
unsigned
char
*
random
=
(
void
*
)
fetch_str_dup
();
if
(
q
->
extra
)
{
if
(
q
->
extra
)
{
struct
secret_chat
*
E
=
q
->
extra
;
void
**
x
=
q
->
extra
;
if
(
E
->
state
==
sc_request
)
{
((
void
(
*
)(
void
*
,
void
*
))(
*
x
))(
x
[
1
],
random
);
do_send_accept_encr_chat
(
q
->
extra
,
random
);
free
(
x
);
}
else
if
(
E
->
state
==
sc_none
)
{
do_send_create_encr_chat
(
q
->
extra
,
random
);
}
free
(
random
);
free
(
random
);
}
else
{
}
else
{
free
(
random
);
free
(
random
);
...
@@ -2418,17 +2355,21 @@ void do_accept_encr_chat_request (struct secret_chat *E) {
...
@@ -2418,17 +2355,21 @@ void do_accept_encr_chat_request (struct secret_chat *E) {
out_int
(
CODE_messages_get_dh_config
);
out_int
(
CODE_messages_get_dh_config
);
out_int
(
encr_param_version
);
out_int
(
encr_param_version
);
out_int
(
256
);
out_int
(
256
);
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
get_dh_config_methods
,
E
);
void
**
x
=
malloc
(
2
*
sizeof
(
void
*
));
x
[
0
]
=
do_send_accept_encr_chat
;
x
[
1
]
=
E
;
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
get_dh_config_methods
,
x
);
}
}
void
do_create_encr_chat_request
(
struct
secret_chat
*
E
)
{
void
do_create_encr_chat_request
(
int
user_id
)
{
assert
(
E
->
state
==
sc_none
);
clear_packet
();
clear_packet
();
out_int
(
CODE_messages_get_dh_config
);
out_int
(
CODE_messages_get_dh_config
);
out_int
(
encr_param_version
);
out_int
(
encr_param_version
);
out_int
(
256
);
out_int
(
256
);
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
get_dh_config_methods
,
E
);
void
**
x
=
malloc
(
2
*
sizeof
(
void
*
));
x
[
0
]
=
do_send_create_encr_chat
;
x
[
1
]
=
(
void
*
)(
long
)(
user_id
);
send_query
(
DC_working
,
packet_ptr
-
packet_buffer
,
packet_buffer
,
&
get_dh_config_methods
,
x
);
}
}
/* }}} */
/* }}} */
...
@@ -2666,16 +2607,7 @@ void do_create_secret_chat (peer_id_t id) {
...
@@ -2666,16 +2607,7 @@ void do_create_secret_chat (peer_id_t id) {
return
;
return
;
}
}
peer_t
*
P
=
malloc
(
sizeof
(
*
P
));
do_create_encr_chat_request
(
get_peer_id
(
id
));
memset
(
P
,
0
,
sizeof
(
*
P
));
P
->
id
=
MK_ENCR_CHAT
(
lrand48
());
P
->
encr_chat
.
user_id
=
get_peer_id
(
id
);
insert_encrypted_chat
(
P
);
P
->
print_name
=
create_print_name
(
P
->
id
,
"!"
,
U
->
user
.
first_name
,
U
->
user
.
last_name
,
0
);
do_create_encr_chat_request
(
&
P
->
encr_chat
);
}
}
/* }}} */
/* }}} */
...
...
queries.h
View file @
06dee8bd
...
@@ -81,7 +81,7 @@ void do_get_user_info (peer_id_t id);
...
@@ -81,7 +81,7 @@ void do_get_user_info (peer_id_t id);
void
do_forward_message
(
peer_id_t
id
,
int
n
);
void
do_forward_message
(
peer_id_t
id
,
int
n
);
void
do_rename_chat
(
peer_id_t
id
,
char
*
name
);
void
do_rename_chat
(
peer_id_t
id
,
char
*
name
);
void
do_load_encr_video
(
struct
encr_video
*
V
,
int
next
);
void
do_load_encr_video
(
struct
encr_video
*
V
,
int
next
);
void
do_create_encr_chat_request
(
struct
secret_chat
*
E
);
void
do_create_encr_chat_request
(
int
user_id
);
void
do_create_secret_chat
(
peer_id_t
id
);
void
do_create_secret_chat
(
peer_id_t
id
);
void
do_get_suggested
(
void
);
void
do_get_suggested
(
void
);
...
...
structures.c
View file @
06dee8bd
This diff is collapsed.
Click to expand it.
structures.h
View file @
06dee8bd
...
@@ -22,7 +22,8 @@
...
@@ -22,7 +22,8 @@
#include <assert.h>
#include <assert.h>
typedef
struct
{
int
type
;
int
id
;
}
peer_id_t
;
typedef
struct
{
int
type
;
int
id
;
}
peer_id_t
;
#define FLAG_EMPTY 1
//#define FLAG_EMPTY 1
#define FLAG_MESSAGE_EMPTY 1
#define FLAG_DELETED 2
#define FLAG_DELETED 2
#define FLAG_FORBIDDEN 4
#define FLAG_FORBIDDEN 4
#define FLAG_HAS_PHOTO 8
#define FLAG_HAS_PHOTO 8
...
@@ -117,6 +118,7 @@ struct user {
...
@@ -117,6 +118,7 @@ struct user {
int
structure_version
;
int
structure_version
;
struct
file_location
photo_big
;
struct
file_location
photo_big
;
struct
file_location
photo_small
;
struct
file_location
photo_small
;
long
long
photo_id
;
struct
photo
photo
;
struct
photo
photo
;
char
*
first_name
;
char
*
first_name
;
char
*
last_name
;
char
*
last_name
;
...
@@ -296,6 +298,9 @@ void message_insert (struct message *M);
...
@@ -296,6 +298,9 @@ void message_insert (struct message *M);
void
free_photo
(
struct
photo
*
P
);
void
free_photo
(
struct
photo
*
P
);
void
fetch_photo
(
struct
photo
*
P
);
void
fetch_photo
(
struct
photo
*
P
);
void
insert_encrypted_chat
(
peer_t
*
P
);
void
insert_encrypted_chat
(
peer_t
*
P
);
void
insert_user
(
peer_t
*
P
);
void
fetch_photo
(
struct
photo
*
P
);
void
free_photo
(
struct
photo
*
P
);
#define PEER_USER 1
#define PEER_USER 1
#define PEER_CHAT 2
#define PEER_CHAT 2
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment