Commit ff97f2a4 authored by vvaltman's avatar vvaltman

rewitten input parse

parent 1789aa3c
1.0.4
* changed create_group_chat format
* rewritten interface code. Support for escaped characters in quotes
1.0.3
* options to help to run telegram-cli as daemon
1.0.2
......
......@@ -100,62 +100,158 @@ int is_same_word (const char *s, size_t l, const char *word) {
return s && word && strlen (word) == l && !memcmp (s, word, l);
}
char *end_string_token (int *l) {
while (*line_ptr == ' ') { line_ptr ++; }
if (!*line_ptr) {
*l = 0;
return 0;
static void skip_wspc (void) {
while (*line_ptr && ((unsigned char)*line_ptr) <= ' ') {
line_ptr ++;
}
char *s = line_ptr;
while (*line_ptr) { line_ptr ++; }
while (*line_ptr == ' ' || !*line_ptr) { line_ptr --; }
line_ptr ++;
*l = line_ptr - s;
return s;
}
char *next_token (int *l) {
while (*line_ptr == ' ') { line_ptr ++; }
if (!*line_ptr) {
*l = 0;
return 0;
static char *cur_token;
static int cur_token_len;
static int cur_token_end_str;
static int cur_token_quoted;
static void unescape_token (char *start, char *end) {
static char cur_token_buff[(1 << 20) + 1];
cur_token_len = 0;
cur_token = cur_token_buff;
while (start < end) {
assert (cur_token_len < (1 << 20));
switch (*start) {
case '\\':
start ++;
switch (*start) {
case 'n':
cur_token[cur_token_len ++] = '\n';
break;
case 'r':
cur_token[cur_token_len ++] = '\r';
break;
case 't':
cur_token[cur_token_len ++] = '\t';
break;
case 'b':
cur_token[cur_token_len ++] = '\b';
break;
case 'a':
cur_token[cur_token_len ++] = '\a';
break;
default:
cur_token[cur_token_len ++] = *start;
break;
}
break;
default:
cur_token[cur_token_len ++] = *start;;
break;
}
start ++;
}
int neg = 0;
char *s = line_ptr;
int in_str = 0;
while (*line_ptr && (*line_ptr != ' ' || neg || in_str)) {
line_ptr++;
cur_token[cur_token_len] = 0;
}
int force_end_mode;
static void next_token (void) {
skip_wspc ();
cur_token_end_str = 0;
cur_token_quoted = 0;
if (!*line_ptr) {
cur_token_len = 0;
cur_token_end_str = 1;
return;
}
char c = *line_ptr;
char *start = line_ptr;
if (c == '"' || c == '\'') {
cur_token_quoted = 1;
line_ptr ++;
int esc = 0;
while (*line_ptr && (esc || *line_ptr != c)) {
if (*line_ptr == '\\') {
esc = 1 - esc;
} else {
esc = 0;
}
line_ptr ++;
}
if (!*line_ptr) {
cur_token_len = -2;
} else {
unescape_token (start + 1, line_ptr);
line_ptr ++;
}
} else {
while (*line_ptr && ((unsigned char)*line_ptr) > ' ') {
line_ptr ++;
}
cur_token = start;
cur_token_len = line_ptr - start;
cur_token_end_str = (!force_end_mode) && (*line_ptr == 0);
}
}
void next_token_end (void) {
skip_wspc ();
if (*line_ptr && *line_ptr != '"' && *line_ptr != '\'') {
cur_token_quoted = 0;
cur_token = line_ptr;
while (*line_ptr) { line_ptr ++; }
cur_token_len = line_ptr - cur_token;
while (((unsigned char)cur_token[cur_token_len - 1]) <= ' ' && cur_token_len >= 0) {
cur_token_len --;
}
assert (cur_token_len > 0);
cur_token_end_str = !force_end_mode;
return;
} else {
if (*line_ptr) {
next_token ();
skip_wspc ();
if (*line_ptr) {
cur_token_len = -1;
}
} else {
next_token ();
}
}
*l = line_ptr - s;
return s;
}
#define NOT_FOUND (int)0x80000000
tgl_peer_id_t TGL_PEER_NOT_FOUND = {.id = NOT_FOUND};
long long next_token_int (void) {
int l;
char *s = next_token (&l);
if (!s) { return NOT_FOUND; }
char *r;
long long x = strtoll (s, &r, 10);
if (r == s + l) {
return x;
} else {
long long cur_token_int (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;
long long x = strtoll (cur_token, &end, 0);
cur_token[cur_token_len] = c;
if (end != cur_token + cur_token_len) {
return NOT_FOUND;
} else {
return x;
}
}
}
tgl_peer_id_t next_token_user (void) {
int l;
char *s = next_token (&l);
if (!s) { return TGL_PEER_NOT_FOUND; }
tgl_peer_id_t cur_token_user (void) {
if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; }
int l = cur_token_len;
char *s = cur_token;
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; }
}
......@@ -163,14 +259,13 @@ tgl_peer_id_t next_token_user (void) {
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; }
}
char c = s[l];
s[l] = 0;
tgl_peer_t *P = tgl_peer_get_by_name (s);
s[l] = c;
cur_token[cur_token_len] = c;
if (P && tgl_get_peer_type (P->id) == TGL_PEER_USER) {
return P->id;
......@@ -179,15 +274,19 @@ tgl_peer_id_t next_token_user (void) {
}
}
tgl_peer_id_t next_token_chat (void) {
int l;
char *s = next_token (&l);
if (!s) { return TGL_PEER_NOT_FOUND; }
tgl_peer_id_t cur_token_chat (void) {
if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; }
int l = cur_token_len;
char *s = cur_token;
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
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; }
}
......@@ -196,14 +295,13 @@ tgl_peer_id_t next_token_chat (void) {
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; }
}
char c = s[l];
s[l] = 0;
tgl_peer_t *P = tgl_peer_get_by_name (s);
s[l] = c;
cur_token[cur_token_len] = c;
if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) {
return P->id;
......@@ -212,15 +310,14 @@ tgl_peer_id_t next_token_chat (void) {
}
}
tgl_peer_id_t next_token_encr_chat (void) {
int l;
char *s = next_token (&l);
if (!s) { return TGL_PEER_NOT_FOUND; }
tgl_peer_id_t cur_token_encr_chat (void) {
if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; }
char *s = cur_token;
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char c = s[l];
s[l] = 0;
tgl_peer_t *P = tgl_peer_get_by_name (s);
s[l] = c;
cur_token[cur_token_len] = c;
if (P && tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) {
return P->id;
......@@ -229,15 +326,18 @@ tgl_peer_id_t next_token_encr_chat (void) {
}
}
tgl_peer_id_t next_token_peer (void) {
int l;
char *s = next_token (&l);
if (!s) { return TGL_PEER_NOT_FOUND; }
tgl_peer_id_t cur_token_peer (void) {
if (cur_token_len <= 0) { return TGL_PEER_NOT_FOUND; }
int l = cur_token_len;
char *s = cur_token;
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
if (l >= 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; }
}
......@@ -245,14 +345,29 @@ tgl_peer_id_t next_token_peer (void) {
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;
int r = atoi (s);
cur_token[cur_token_len] = c;
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); }
else { return TGL_PEER_NOT_FOUND; }
}
if (l >= 8 && !memcmp (s, "chat#id", 7)) {
s += 7;
l -= 7;
int r = atoi (s);
cur_token[cur_token_len] = c;
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); }
else { return TGL_PEER_NOT_FOUND; }
}
char c = s[l];
s[l] = 0;
tgl_peer_t *P = tgl_peer_get_by_name (s);
s[l] = c;
cur_token[cur_token_len] = c;
if (P) {
return P->id;
......@@ -261,6 +376,12 @@ tgl_peer_id_t next_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);
return P;
}
char *get_default_prompt (void) {
static char buf[1000];
int l = 0;
......@@ -341,117 +462,602 @@ enum command_argument {
ca_string,
ca_modifier,
ca_command,
ca_extf
ca_extf,
ca_optional = 256
};
struct arg {
int flags;
struct {
tgl_peer_t *P;
struct tgl_message *M;
char *str;
long long num;
};
};
struct command {
char *name;
enum command_argument args[10];
void (*fun)(int arg_num, struct arg args[]);
};
int offline_mode;
void print_user_list_gw (void *extra, int success, int num, struct tgl_user *UL[]);
void print_msg_list_gw (void *extra, int success, int num, struct tgl_message *ML[]);
void print_dialog_list_gw (void *extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]);
void print_chat_info_gw (void *extra, int success, struct tgl_chat *C);
void print_user_info_gw (void *extra, int success, struct tgl_user *C);
void print_filename_gw (void *extra, int success, char *name);
void open_filename_gw (void *extra, int success, char *name);
void print_secret_chat_gw (void *extra, int success, struct tgl_secret_chat *E);
void print_card_gw (void *extra, int success, int size, int *card);
void print_user_gw (void *extra, int success, struct tgl_user *U);
void print_msg_gw (void *extra, int success, struct tgl_message *M);
void do_help (int arg_num, struct arg args[]) {
assert (!arg_num);
push_color (COLOR_YELLOW);
printf (
"help - prints this help\n"
"msg <peer> Text - sends message to this peer\n"
"contact_list - prints info about users in your contact list\n"
"stats - just for debugging \n"
"history <peer> [limit] - prints history (and marks it as read). Default limit = 40\n"
"dialog_list - prints info about your dialogs\n"
"send_photo <peer> <photo-file-name> - sends photo to peer\n"
"send_video <peer> <video-file-name> - sends video to peer\n"
"send_text <peer> <text-file-name> - sends text file as plain messages\n"
"chat_info <chat> - prints info about chat\n"
"user_info <user> - prints info about user\n"
"fwd <user> <msg-seqno> - forward message to user. You can see message numbers starting client with -N\n"
"rename_chat <chat> <new-name>\n"
"load_photo/load_video/load_video_thumb <msg-seqno> - loads photo/video to download dir. You can see message numbers starting client with -N\n"
"view_photo/view_video/view_video_thumb <msg-seqno> - loads photo/video to download dir and starts system default viewer. You can see message numbers starting client with -N\n"
"show_license - prints contents of GPLv2\n"
"search <peer> pattern - searches pattern in messages with peer\n"
"global_search pattern - searches pattern in all messages\n"
"mark_read <peer> - mark read all received messages with peer\n"
"add_contact <phone-number> <first-name> <last-name> - tries to add contact to contact-list by phone\n"
"create_secret_chat <user> - creates secret chat with this user\n"
"create_group_chat <user> <chat-topic> - creates group chat with this user, add more users with chat_add_user <user>\n"
"rename_contact <user> <first-name> <last-name> - tries to rename contact. If you have another device it will be a fight\n"
"suggested_contacts - print info about contacts, you have max common friends\n"
"visualize_key <secret_chat> - prints visualization of encryption key. You should compare it to your partner's one\n"
"set <param> <param-value>. Possible <param> values are:\n"
"\tdebug_verbosity - just as it sounds. Debug verbosity\n"
"\tlog_level - level of logging of new events. Lower is less verbose:\n"
"\t\tLevel 1: prints info about read messages\n"
"\t\tLevel 2: prints line, when somebody is typing in chat\n"
"\t\tLevel 3: prints line, when somebody changes online status\n"
"\tmsg_num - enables/disables numeration of messages\n"
"\talert - enables/disables alert sound notifications\n"
"chat_with_peer <peer> - starts chat with this peer. Every command after is message to this peer. Type /exit or /quit to end this mode\n"
);
pop_color ();
fflush (stdout);
}
void do_contact_list (int arg_num, struct arg args[]) {
assert (!arg_num);
tgl_do_update_contact_list (print_user_list_gw, 0);
}
void do_stats (int arg_num, struct arg args[]) {
assert (!arg_num);
static char stat_buf[1 << 15];
tgl_print_stat (stat_buf, (1 << 15) - 1);
printf ("%s\n", stat_buf);
fflush (stdout);
}
void do_history (int arg_num, struct arg args[]) {
assert (arg_num == 3);
tgl_do_get_history_ext (args[0].P->id, args[2].num != NOT_FOUND ? args[2].num : 0, args[1].num != NOT_FOUND ? args[1].num : 40, offline_mode, print_msg_list_gw, 0);
}
void do_dialog_list (int arg_num, struct arg args[]) {
assert (arg_num == 0);
tgl_do_get_dialog_list (print_dialog_list_gw, 0);
}
void do_send_photo (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_send_photo (tgl_message_media_photo, args[0].P->id, args[1].str, 0, 0);
}
void do_send_audio (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_send_photo (tgl_message_media_audio, args[0].P->id, args[1].str, 0, 0);
}
void do_send_video (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_send_photo (tgl_message_media_video, args[0].P->id, args[1].str, 0, 0);
}
void do_send_document (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_send_photo (tgl_message_media_document, args[0].P->id, args[1].str, 0, 0);
}
void do_send_text (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_send_text (args[0].P->id, args[1].str, 0, 0);
}
void do_chat_info (int arg_num, struct arg args[]) {
assert (arg_num == 1);
tgl_do_get_chat_info (args[0].P->id, offline_mode, print_chat_info_gw, 0);
}
void do_user_info (int arg_num, struct arg args[]) {
assert (arg_num == 1);
tgl_do_get_user_info (args[0].P->id, offline_mode, print_user_info_gw, 0);
}
void do_fwd (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_forward_message (args[0].P->id, args[1].num, 0, 0);
}
void do_fwd_media (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_forward_message (args[0].P->id, args[1].num, 0, 0);
}
void do_msg (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_send_message (args[0].P->id, args[1].str, strlen (args[1].str), 0, 0);
}
void do_rename_chat (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_rename_chat (args[0].P->id, args[1].str, 0, 0);
}
#define DO_LOAD_PHOTO(tp,act,actf) \
void do_ ## act ## _ ## tp (int arg_num, struct arg args[]) { \
assert (arg_num == 1);\
struct tgl_message *M = tgl_message_get (args[0].num);\
if (M && !M->service && M->media.type == tgl_message_media_ ## tp) {\
tgl_do_load_ ## tp (&M->media.tp, actf, 0); \
} else if (M && !M->service && M->media.type == tgl_message_media_ ## tp ## _encr) { \
tgl_do_load_encr_video (&M->media.encr_video, actf, 0); \
} \
}
#define DO_LOAD_PHOTO_THUMB(tp,act,actf) \
void do_ ## act ## _ ## tp ## _thumb (int arg_num, struct arg args[]) { \
assert (arg_num == 1);\
struct tgl_message *M = tgl_message_get (args[0].num);\
if (M && !M->service && M->media.type == tgl_message_media_ ## tp) { \
tgl_do_load_ ## tp ## _thumb (&M->media.tp, actf, 0); \
}\
}
DO_LOAD_PHOTO(photo, load, print_filename_gw)
DO_LOAD_PHOTO(video, load, print_filename_gw)
DO_LOAD_PHOTO(audio, load, print_filename_gw)
DO_LOAD_PHOTO(document, load, print_filename_gw)
DO_LOAD_PHOTO_THUMB(video, load, print_filename_gw)
DO_LOAD_PHOTO_THUMB(document, load, print_filename_gw)
DO_LOAD_PHOTO(photo, open, open_filename_gw)
DO_LOAD_PHOTO(video, open, open_filename_gw)
DO_LOAD_PHOTO(audio, open, open_filename_gw)
DO_LOAD_PHOTO(document, open, open_filename_gw)
DO_LOAD_PHOTO_THUMB(video, open, open_filename_gw)
DO_LOAD_PHOTO_THUMB(document, open, open_filename_gw)
void do_add_contact (int arg_num, struct arg args[]) {
assert (arg_num == 3);
tgl_do_add_contact (args[0].str, strlen (args[0].str), args[1].str, strlen (args[1].str), args[2].str, strlen (args[2].str), 0, print_user_list_gw, 0);
}
void do_del_contact (int arg_num, struct arg args[]) {
assert (arg_num == 1);
tgl_do_del_contact (args[0].P->id, 0, 0);
}
void do_rename_contact (int arg_num, struct arg args[]) {
assert (arg_num == 3);
if (args[0].P->user.phone) {
tgl_do_add_contact (args[0].P->user.phone, strlen (args[0].P->user.phone), args[1].str, strlen (args[1].str), args[2].str, strlen (args[2].str), 0, print_user_list_gw, 0);
}
}
void do_show_license (int arg_num, struct arg args[]) {
assert (!arg_num);
char *b =
#include "LICENSE.h"
;
printf ("%s", b);
}
void do_search (int arg_num, struct arg args[]) {
assert (arg_num == 5);
tgl_peer_id_t id;
if (args[0].P) {
id = args[0].P->id;
} else {
id = TGL_PEER_NOT_FOUND;
}
int limit;
if (args[1].num != NOT_FOUND) {
limit = args[1].num;
} else {
limit = 40;
}
int from;
if (args[2].num != NOT_FOUND) {
from = args[2].num;
} else {
from = 0;
}
int to;
if (args[3].num != NOT_FOUND) {
to = args[3].num;
} else {
to = 0;
}
tgl_do_msg_search (id, from, to, limit, args[4].str, print_msg_list_gw, 0);
}
void do_mark_read (int arg_num, struct arg args[]) {
assert (arg_num == 1);
tgl_do_mark_read (args[0].P->id, 0, 0);
}
void do_visualize_key (int arg_num, struct arg args[]) {
assert (arg_num == 1);
static char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN};
static unsigned char buf[16];
memset (buf, 0, sizeof (buf));
tgl_peer_id_t id = args[0].P->id;
tgl_do_visualize_key (id, buf);
print_start ();
int i;
for (i = 0; i < 16; i++) {
int x = buf[i];
int j;
for (j = 0; j < 4; j ++) {
push_color (colors[x & 3]);
push_color (COLOR_INVERSE);
if (!disable_colors) {
printf (" ");
} else {
switch (x & 3) {
case 0:
printf (" ");
break;
case 1:
printf ("--");
break;
case 2:
printf ("==");
break;
case 3:
printf ("||");
break;
}
}
pop_color ();
pop_color ();
x = x >> 2;
}
if (i & 1) { printf ("\n"); }
}
print_end ();
}
void do_create_secret_chat (int arg_num, struct arg args[]) {
assert (arg_num == 1);
tgl_do_create_secret_chat (args[0].P->id, print_secret_chat_gw, 0);
}
void do_chat_add_user (int arg_num, struct arg args[]) {
assert (arg_num == 3);
tgl_do_add_user_to_chat (args[0].P->id, args[1].P->id, args[2].num != NOT_FOUND ? args[2].num : 100, 0, 0);
}
void do_chat_del_user (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_del_user_from_chat (args[0].P->id, args[1].P->id, 0, 0);
}
void do_status_online (int arg_num, struct arg args[]) {
assert (!arg_num);
tgl_do_update_status (1, 0, 0);
}
void do_status_offline (int arg_num, struct arg args[]) {
assert (!arg_num);
tgl_do_update_status (0, 0, 0);
}
void do_quit (int arg_num, struct arg args[]) {
exit (0);
}
void do_safe_quit (int arg_num, struct arg args[]) {
safe_quit = 1;
}
void do_set (int arg_num, struct arg args[]) {
int num = args[1].num;
if (!strcmp (args[0].str, "debug_verbosity")) {
tgl_set_verbosity (num);
} else if (!strcmp (args[0].str, "log_level")) {
log_level = num;
} else if (!strcmp (args[0].str, "msg_num")) {
msg_num_mode = num;
} else if (!strcmp (args[0].str, "alert")) {
alert_sound = num;
}
}
void do_chat_with_peer (int arg_num, struct arg args[]) {
in_chat_mode = 1;
chat_mode_id = args[0].P->id;
}
void do_delete_msg (int arg_num, struct arg args[]) {
tgl_do_delete_msg (args[0].num, 0, 0);
}
void do_restore_msg (int arg_num, struct arg args[]) {
tgl_do_restore_msg (args[0].num, 0, 0);
}
void do_create_group_chat (int arg_num, struct arg args[]) {
assert (arg_num >= 1 && arg_num <= 1000);
static tgl_peer_id_t ids[1000];
int i;
for (i = 0; i < arg_num - 1; i++) {
ids[i] = args[i + 1].P->id;
}
tgl_do_create_group_chat_ex (arg_num - 1, ids, args[0].str, 0, 0);
}
void do_chat_set_photo (int arg_num, struct arg args[]) {
assert (arg_num == 2);
tgl_do_set_chat_photo (args[0].P->id, args[1].str, 0, 0);
}
void do_set_profile_photo (int arg_num, struct arg args[]) {
assert (arg_num == 1);
tgl_do_set_profile_photo (args[0].str, 0, 0);
}
void do_accept_secret_chat (int arg_num, struct arg args[]) {
assert (arg_num == 1);
tgl_do_accept_encr_chat_request (&args[0].P->encr_chat, 0, 0);
}
void do_set_ttl (int arg_num, struct arg args[]) {
assert (arg_num == 2);
if (args[0].P->encr_chat.state == sc_ok) {
tgl_do_set_encr_chat_ttl (&args[0].P->encr_chat, args[1].num, 0, 0);
}
}
void do_export_card (int arg_num, struct arg args[]) {
assert (!arg_num);
tgl_do_export_card (print_card_gw, 0);
}
void do_import_card (int arg_num, struct arg args[]) {
assert (arg_num == 1);
char *s = args[0].str;
int l = strlen (s);
if (l > 0) {
int i;
static int p[10];
int pp = 0;
int cur = 0;
int ok = 1;
for (i = 0; i < l; i ++) {
if (s[i] >= '0' && s[i] <= '9') {
cur = cur * 16 + s[i] - '0';
} else if (s[i] >= 'a' && s[i] <= 'f') {
cur = cur * 16 + s[i] - 'a' + 10;
} else if (s[i] == ':') {
if (pp >= 9) {
ok = 0;
break;
}
p[pp ++] = cur;
cur = 0;
}
}
if (ok) {
p[pp ++] = cur;
tgl_do_import_card (pp, p, print_user_gw, 0);
}
}
}
void do_send_contact (int arg_num, struct arg args[]) {
assert (arg_num == 4);
tgl_do_send_contact (args[0].P->id, args[1].str, strlen (args[1].str), args[2].str, strlen (args[2].str), args[3].str, strlen (args[3].str), print_msg_gw, 0);
}
struct command commands[] = {
{"help", {ca_none}},
{"contact_list", {ca_none}},
{"stats", {ca_none}},
{"history", {ca_peer, ca_none, ca_number, ca_number}},
{"dialog_list", {ca_none}},
{"send_photo", {ca_peer, ca_file_name_end}},
{"send_video", {ca_peer, ca_file_name_end}},
{"send_audio", {ca_peer, ca_file_name_end}},
{"send_document", {ca_peer, ca_file_name_end}},
{"send_text", {ca_peer, ca_file_name_end}},
{"chat_info", {ca_chat, ca_none}},
{"user_info", {ca_user, ca_none}},
{"fwd", {ca_peer, ca_number, ca_none}},
{"fwd_media", {ca_peer, ca_number, ca_none}},
{"msg", {ca_peer, ca_string_end}},
{"rename_chat", {ca_peer, ca_string_end}},
{"load_photo", {ca_number, ca_none}},
{"view_photo", {ca_number, ca_none}},
{"load_video_thumb", {ca_number, ca_none}},
{"view_video_thumb", {ca_number, ca_none}},
{"load_video", {ca_number, ca_none}},
{"view_video", {ca_number, ca_none}},
{"load_audio", {ca_number, ca_none}},
{"view_audio", {ca_number, ca_none}},
{"load_document", {ca_number, ca_none}},
{"view_document", {ca_number, ca_none}},
{"load_document_thumb", {ca_number, ca_none}},
{"view_document_thumb", {ca_number, ca_none}},
{"add_contact", {ca_string, ca_string, ca_string, ca_none}},
{"del_contact", {ca_user, ca_none}},
{"rename_contact", {ca_user, ca_string, ca_string, ca_none}},
{"show_license", {ca_none}},
{"search", {ca_peer, ca_string_end}},
{"mark_read", {ca_peer, ca_none}},
{"visualize_key", {ca_secret_chat, ca_none}},
{"create_secret_chat", {ca_user, ca_none}},
{"global_search", {ca_string_end}},
{"chat_add_user", {ca_chat, ca_user, ca_none}},
{"chat_del_user", {ca_chat, ca_user, ca_none}},
{"status_online", {ca_none}},
{"status_offline", {ca_none}},
{"quit", {ca_none}},
{"safe_quit", {ca_none}},
{"set", {ca_string, ca_string, ca_none}},
{"chat_with_peer", {ca_peer, ca_none}},
{"delete_msg", {ca_number, ca_none}},
{"restore_msg", {ca_number, ca_none}},
{"create_group_chat", {ca_user, ca_string_end}},
{"chat_set_photo", {ca_chat, ca_file_name_end}},
{"set_profile_photo", {ca_file_name_end}},
{"accept_secret_chat", {ca_secret_chat, ca_none}},
{"set_ttl", {ca_secret_chat, ca_number, ca_none}},
{"export_card", {ca_none}},
{"import_card", {ca_string, ca_none}},
{"send_contact", {ca_peer, ca_string, ca_string, ca_string}},
{0, {ca_none}}
{"help", {ca_none}, do_help},
{"contact_list", {ca_none}, do_contact_list},
{"stats", {ca_none}, do_stats},
{"history", {ca_peer, ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_history},
{"dialog_list", {ca_none}, do_dialog_list},
{"send_photo", {ca_peer, ca_file_name_end, ca_none}, do_send_photo},
{"send_video", {ca_peer, ca_file_name_end, ca_none}, do_send_video},
{"send_audio", {ca_peer, ca_file_name_end, ca_none}, do_send_audio},
{"send_document", {ca_peer, ca_file_name_end, ca_none}, do_send_document},
{"send_text", {ca_peer, ca_file_name_end, ca_none}, do_send_text},
{"chat_info", {ca_chat, ca_none}, do_chat_info},
{"user_info", {ca_user, ca_none}, do_user_info},
{"fwd", {ca_peer, ca_number, ca_none}, do_fwd},
{"fwd_media", {ca_peer, ca_number, ca_none}, do_fwd_media},
{"msg", {ca_peer, ca_string_end, ca_none}, do_msg},
{"rename_chat", {ca_peer, ca_string_end, ca_none}, do_rename_chat},
{"load_photo", {ca_number, ca_none}, do_load_photo},
{"view_photo", {ca_number, ca_none}, do_open_photo},
{"load_video_thumb", {ca_number, ca_none}, do_load_video_thumb},
{"view_video_thumb", {ca_number, ca_none}, do_open_video_thumb},
{"load_video", {ca_number, ca_none}, do_load_video},
{"view_video", {ca_number, ca_none}, do_open_video},
{"load_audio", {ca_number, ca_none}, do_load_audio},
{"view_audio", {ca_number, ca_none}, do_open_audio},
{"load_document", {ca_number, ca_none}, do_load_document},
{"view_document", {ca_number, ca_none}, do_open_document},
{"load_document_thumb", {ca_number, ca_none}, do_load_document_thumb},
{"view_document_thumb", {ca_number, ca_none}, do_open_document_thumb},
{"add_contact", {ca_string, ca_string, ca_string, ca_none}, do_add_contact},
{"del_contact", {ca_user, ca_none}, do_del_contact},
{"rename_contact", {ca_user, ca_string, ca_string, ca_none}, do_rename_contact},
{"show_license", {ca_none}, do_show_license},
{"search", {ca_peer | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_string_end}, do_search},
{"mark_read", {ca_peer, ca_none}, do_mark_read},
{"visualize_key", {ca_secret_chat, ca_none}, do_visualize_key},
{"create_secret_chat", {ca_user, ca_none}, do_create_secret_chat},
{"chat_add_user", {ca_chat, ca_user, ca_number | ca_optional, ca_none}, do_chat_add_user},
{"chat_del_user", {ca_chat, ca_user, ca_none}, do_chat_del_user},
{"status_online", {ca_none}, do_status_online},
{"status_offline", {ca_none}, do_status_offline},
{"quit", {ca_none}, do_quit},
{"safe_quit", {ca_none}, do_safe_quit},
{"set", {ca_string, ca_number, ca_none}, do_set},
{"chat_with_peer", {ca_peer, ca_none}, do_chat_with_peer},
{"delete_msg", {ca_number, ca_none}, do_delete_msg},
{"restore_msg", {ca_number, ca_none}, do_restore_msg},
{"create_group_chat", {ca_string, ca_user, ca_period, ca_none}, do_create_group_chat},
{"chat_set_photo", {ca_chat, ca_file_name_end, ca_none}, do_chat_set_photo},
{"set_profile_photo", {ca_file_name_end, ca_none}, do_set_profile_photo},
{"accept_secret_chat", {ca_secret_chat, ca_none}, do_accept_secret_chat},
{"set_ttl", {ca_secret_chat, ca_number, ca_none}, do_set_ttl},
{"export_card", {ca_none}, do_export_card},
{"import_card", {ca_string, ca_none}, do_import_card},
{"send_contact", {ca_peer, ca_string, ca_string, ca_string}, do_send_contact},
{0, {ca_none}, 0}
};
enum command_argument get_complete_mode (void) {
force_end_mode = 0;
line_ptr = rl_line_buffer;
int l = 0;
char *r = next_token (&l);
if (!r) { return ca_command; }
if (*r == '(') { return ca_extf; }
while (r && r[0] == '[' && r[l - 1] == ']') {
r = next_token (&l);
if (!r) { return ca_command; }
}
if (*r == '[' && !r[l]) {
return ca_modifier;
while (1) {
next_token ();
if (cur_token_quoted) { return ca_none; }
if (cur_token_len <= 0) { return ca_command; }
if (*cur_token == '[') {
if (cur_token_end_str) {
return ca_modifier;
}
if (cur_token[cur_token_len - 1] != ']') {
return ca_none;
}
continue;
}
break;
}
if (!*line_ptr) { return ca_command; }
if (cur_token_quoted) { return ca_none; }
if (cur_token_end_str) { return ca_command; }
if (*cur_token == '(') { return ca_extf; }
struct command *command = commands;
int n = 0;
struct tgl_command;
while (command->name) {
if (is_same_word (r, l, command->name)) {
if (is_same_word (cur_token, cur_token_len, command->name)) {
break;
}
n ++;
command ++;
}
if (!command->name) {
return ca_none;
}
enum command_argument *flags = command->args;
while (1) {
if (!next_token (&l) || !*line_ptr) {
return *flags;
}
if (*flags == ca_none) {
return ca_none;
if (*flags == ca_period) {
flags --;
}
if (*flags == ca_string_end) {
return ca_string_end;
enum command_argument op = (*flags) & 255;
int opt = (*flags) & ca_optional;
if (op == ca_none) { return ca_none; }
if (op == ca_string_end || op == ca_file_name_end) {
next_token_end ();
if (cur_token_len < 0 || !cur_token_end_str) {
return ca_none;
} else {
return op;
}
}
if (*flags == ca_file_name_end) {
return ca_file_name_end;
char *save = line_ptr;
next_token ();
if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number) {
if (cur_token_quoted) {
if (opt) {
line_ptr = save;
flags ++;
continue;
} else {
return ca_none;
}
} else {
if (cur_token_end_str) { return op; }
int ok = 1;
switch (op) {
case ca_user:
ok = (tgl_get_peer_type (cur_token_user ()) != NOT_FOUND);
break;
case ca_chat:
ok = (tgl_get_peer_type (cur_token_chat ()) != NOT_FOUND);
break;
case ca_secret_chat:
ok = (tgl_get_peer_type (cur_token_encr_chat ()) != NOT_FOUND);
break;
case ca_peer:
ok = (tgl_get_peer_type (cur_token_user ()) != NOT_FOUND);
break;
case ca_number:
ok = (cur_token_int () != NOT_FOUND);
break;
default:
assert (0);
}
if (opt && !ok) {
line_ptr = save;
flags ++;
continue;
}
if (!ok) {
return ca_none;
}
flags ++;
continue;
}
}
flags ++;
if (*flags == ca_period) {
flags --;
if (op == ca_string || op == ca_file_name) {
if (cur_token_end_str) {
return op;
} else {
flags ++;
continue;
}
}
assert (0);
}
}
......@@ -488,6 +1094,8 @@ int complete_command_list (int index, const char *text, int len, char **R) {
char *command_generator (const char *text, int state) {
static int len, index;
static enum command_argument mode;
static char *command_pos;
static int command_len;
if (in_chat_mode) {
char *R = 0;
......@@ -496,13 +1104,15 @@ char *command_generator (const char *text, int state) {
}
char c = 0;
c = rl_line_buffer[rl_point];
rl_line_buffer[rl_point] = 0;
if (!state) {
len = strlen (text);
index = -1;
c = rl_line_buffer[rl_point];
rl_line_buffer[rl_point] = 0;
mode = get_complete_mode ();
command_pos = cur_token;
command_len = cur_token_len;
} else {
if (index == -1) { return 0; }
}
......@@ -511,40 +1121,42 @@ char *command_generator (const char *text, int state) {
if (c) { rl_line_buffer[rl_point] = c; }
return 0;
}
assert (command_len >= 0);
char *R = 0;
switch (mode) {
switch (mode & 255) {
case ca_command:
index = complete_command_list (index, text, len, &R);
index = complete_command_list (index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_user:
index = tgl_complete_user_list (index, text, len, &R);
index = tgl_complete_user_list (index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_peer:
index = tgl_complete_peer_list (index, text, len, &R);
index = tgl_complete_peer_list (index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_file_name:
case ca_file_name_end:
R = rl_filename_completion_function (text, state);
R = rl_filename_completion_function (command_pos, state);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_chat:
index = tgl_complete_chat_list (index, text, len, &R);
index = tgl_complete_chat_list (index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_secret_chat:
index = tgl_complete_encr_chat_list (index, text, len, &R);
index = tgl_complete_encr_chat_list (index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_modifier:
index = complete_string_list (modifiers, index, text, len, &R);
index = complete_string_list (modifiers, index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_extf:
index = tglf_extf_autocomplete (text, len, index, &R, rl_line_buffer, rl_point);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
default:
if (c) { rl_line_buffer[rl_point] = c; }
......@@ -556,7 +1168,6 @@ char **complete_text (char *text, int start UU, int end UU) {
return (char **) rl_completion_matches (text, command_generator);
}
int offline_mode;
int count = 1;
void work_modifier (const char *s, int l) {
if (is_same_word (s, l, "[offline]")) {
......@@ -1061,6 +1672,7 @@ struct tgl_update_callback upd_cb = {
void interpreter (char *line UU) {
force_end_mode = 1;
assert (!in_readline);
in_readline = 1;
if (in_chat_mode) {
......@@ -1079,670 +1691,197 @@ void interpreter (char *line UU) {
if (line && *line) {
add_history (line);
}
if (*line == '(') {
tgl_do_send_extf (line, strlen (line), callback_extf, 0);
in_readline = 0;
return;
}
int l;
char *command;
while (1) {
command = next_token (&l);
if (!command) { in_readline = 0; return; }
if (*command == '[' && command[l - 1] == ']') {
work_modifier (command, l);
} else {
break;
next_token ();
if (cur_token_quoted) {
in_readline = 0;
return;
}
}
int _;
char *save = line_ptr;
int ll = l;
char *cs = command;
for (_ = 0; _ < count; _ ++) {
line_ptr = save;
l = ll;
command = cs;
#define IS_WORD(s) is_same_word (command, l, (s))
#define RET in_readline = 0; return;
tgl_peer_id_t id;
#define GET_PEER \
id = next_token_peer (); \
if (!tgl_cmp_peer_id (id, TGL_PEER_NOT_FOUND)) { \
printf ("Bad user/chat id\n"); \
RET; \
}
#define GET_PEER_USER \
id = next_token_user (); \
if (!tgl_cmp_peer_id (id, TGL_PEER_NOT_FOUND)) { \
printf ("Bad user id\n"); \
RET; \
}
#define GET_PEER_CHAT \
id = next_token_chat (); \
if (!tgl_cmp_peer_id (id, TGL_PEER_NOT_FOUND)) { \
printf ("Bad chat id\n"); \
RET; \
}
#define GET_PEER_ENCR_CHAT \
id = next_token_encr_chat (); \
if (!tgl_cmp_peer_id (id, TGL_PEER_NOT_FOUND)) { \
printf ("Bad encr_chat id\n"); \
RET; \
}
if (command && *command == '(') {
tgl_do_send_extf (line, strlen (line), callback_extf, 0);
} else if (IS_WORD ("contact_list")) {
tgl_do_update_contact_list (print_user_list_gw, 0);
} else if (IS_WORD ("dialog_list")) {
tgl_do_get_dialog_list (print_dialog_list_gw, 0);
} else if (IS_WORD ("stats")) {
static char stat_buf[1 << 15];
tgl_print_stat (stat_buf, (1 << 15) - 1);
printf ("%s\n", stat_buf);
fflush (stdout);
} else if (IS_WORD ("msg")) {
GET_PEER;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty message\n");
RET;
}
tgl_do_send_message (id, s, strlen (s), 0, 0);
} else if (IS_WORD ("rename_chat")) {
GET_PEER_CHAT;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty new name\n");
RET;
}
tgl_do_rename_chat (id, s, 0, 0);
} else if (IS_WORD ("send_photo")) {
GET_PEER;
int t;
char *s = end_string_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
char *d = strndup (s, t);
assert (d);
tgl_do_send_photo (tgl_message_media_photo, id, d, 0, 0);
} else if (IS_WORD ("chat_set_photo")) {
GET_PEER_CHAT;
int t;
char *s = end_string_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
char *d = strndup (s, t);
assert (d);
tgl_do_set_chat_photo (id, d, 0, 0);
} else if (IS_WORD ("set_profile_photo")) {
int t;
char *s = end_string_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
char *d = strndup (s, t);
assert (d);
tgl_do_set_profile_photo (d, 0, 0);
} else if (IS_WORD("send_video")) {
GET_PEER;
int t;
char *s = end_string_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
char *d = strndup (s, t);
assert (d);
tgl_do_send_photo (tgl_message_media_video, id, d, 0, 0);
} else if (IS_WORD ("send_text")) {
GET_PEER;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
char *d = strndup (s, t);
assert (d);
tgl_do_send_text (id, d, 0, 0);
} else if (IS_WORD ("fwd")) {
GET_PEER;
int num = next_token_int ();
if (num == NOT_FOUND || num <= 0) {
printf ("Bad msg id\n");
RET;
}
tgl_do_forward_message (id, num, 0, 0);
} else if (IS_WORD ("fwd_media")) {
GET_PEER;
int num = next_token_int ();
if (num == NOT_FOUND || num <= 0) {
printf ("Bad msg id\n");
RET;
}
tgl_do_forward_media (id, num, 0, 0);
} else if (IS_WORD ("load_photo")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_photo) {
tgl_do_load_photo (&M->media.photo, print_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_photo_encr) {
tgl_do_load_encr_video (&M->media.encr_video, print_filename_gw, 0); // this is not a bug.
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_photo")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_photo) {
tgl_do_load_photo (&M->media.photo, open_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_photo_encr) {
tgl_do_load_encr_video (&M->media.encr_video, open_filename_gw, 0); // this is not a bug.
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_video_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_video) {
tgl_do_load_video_thumb (&M->media.video, print_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_video_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_video) {
tgl_do_load_video_thumb (&M->media.video, open_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_video")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_video) {
tgl_do_load_video (&M->media.video, print_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_video_encr) {
tgl_do_load_encr_video (&M->media.encr_video, print_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_video")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_video) {
tgl_do_load_video (&M->media.video, open_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_video_encr) {
tgl_do_load_encr_video (&M->media.encr_video, open_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("chat_info")) {
GET_PEER_CHAT;
tgl_do_get_chat_info (id, offline_mode, print_chat_info_gw, 0);
} else if (IS_WORD ("user_info")) {
GET_PEER_USER;
tgl_do_get_user_info (id, offline_mode, print_user_info_gw, 0);
} else if (IS_WORD ("history")) {
GET_PEER;
int limit = next_token_int ();
tgl_do_get_history (id, limit > 0 ? limit : 40, offline_mode, print_msg_list_gw, 0);
} else if (IS_WORD ("chat_add_user")) {
GET_PEER_CHAT;
tgl_peer_id_t chat_id = id;
GET_PEER_USER;
tgl_do_add_user_to_chat (chat_id, id, 100, 0, 0);
} else if (IS_WORD ("chat_del_user")) {
GET_PEER_CHAT;
tgl_peer_id_t chat_id = id;
GET_PEER_USER;
tgl_do_del_user_from_chat (chat_id, id, 0, 0);
} else if (IS_WORD ("add_contact")) {
int phone_len, first_name_len, last_name_len;
char *phone, *first_name, *last_name;
phone = next_token (&phone_len);
if (!phone) {
printf ("No phone number found\n");
RET;
}
first_name = next_token (&first_name_len);
if (!first_name_len) {
printf ("No first name found\n");
RET;
if (cur_token_len <= 0) {
in_readline = 0;
return;
}
last_name = next_token (&last_name_len);
if (!last_name_len) {
printf ("No last name found\n");
RET;
}
tgl_do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 0, print_user_list_gw, 0);
} else if (IS_WORD ("del_contact")) {
GET_PEER_USER;
tgl_do_del_contact (id, 0, 0);
} else if (IS_WORD ("send_contact")) {
GET_PEER;
int phone_len, first_name_len, last_name_len;
char *phone, *first_name, *last_name;
phone = next_token (&phone_len);
if (!phone) {
printf ("No phone number found\n");
RET;
}
first_name = next_token (&first_name_len);
if (!first_name_len) {
printf ("No first name found\n");
RET;
}
last_name = next_token (&last_name_len);
if (!last_name_len) {
printf ("No last name found\n");
RET;
}
tgl_do_send_contact (id, phone, phone_len, first_name, first_name_len, last_name, last_name_len, print_msg_gw, 0);
} else if (IS_WORD ("rename_contact")) {
GET_PEER_USER;
tgl_peer_t *U = tgl_peer_get (id);
if (!U) {
printf ("No such user\n");
RET;
if (*cur_token == '[') {
if (cur_token_end_str) {
in_readline = 0;
return;
}
if (cur_token[cur_token_len - 1] != ']') {
in_readline = 0;
return;
}
work_modifier (cur_token, cur_token_len);
continue;
}
if (!U->user.phone || !strlen (U->user.phone)) {
printf ("User has no phone. Can not rename\n");
RET;
break;
}
if (cur_token_quoted || cur_token_end_str) {
in_readline = 0;
return;
}
struct command *command = commands;
int n = 0;
struct tgl_command;
while (command->name) {
if (is_same_word (cur_token, cur_token_len, command->name)) {
break;
}
int phone_len, first_name_len, last_name_len;
char *phone, *first_name, *last_name;
phone_len = strlen (U->user.phone);
phone = U->user.phone;
first_name = next_token (&first_name_len);
if (!first_name_len) {
printf ("No first name found\n");
RET;
n ++;
command ++;
}
if (!command->name) {
in_readline = 0;
return;
}
enum command_argument *flags = command->args;
void (*fun)(int, struct arg[]) = command->fun;
int args_num = 0;
static struct arg args[1000];
while (1) {
assert (args_num < 1000);
args[args_num].flags = 0;
int period = 0;
if (*flags == ca_period) {
period = 1;
flags --;
}
last_name = next_token (&last_name_len);
if (!last_name_len) {
printf ("No last name found\n");
RET;
enum command_argument op = (*flags) & 255;
int opt = (*flags) & ca_optional;
if (op == ca_none) {
next_token ();
if (cur_token_end_str) {
fun (args_num, args);
}
break;
}
tgl_do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 1, print_user_list_gw, 0);
} else if (IS_WORD ("help")) {
//print_start ();
push_color (COLOR_YELLOW);
printf (
"help - prints this help\n"
"msg <peer> Text - sends message to this peer\n"
"contact_list - prints info about users in your contact list\n"
"stats - just for debugging \n"
"history <peer> [limit] - prints history (and marks it as read). Default limit = 40\n"
"dialog_list - prints info about your dialogs\n"
"send_photo <peer> <photo-file-name> - sends photo to peer\n"
"send_video <peer> <video-file-name> - sends video to peer\n"
"send_text <peer> <text-file-name> - sends text file as plain messages\n"
"chat_info <chat> - prints info about chat\n"
"user_info <user> - prints info about user\n"
"fwd <user> <msg-seqno> - forward message to user. You can see message numbers starting client with -N\n"
"rename_chat <chat> <new-name>\n"
"load_photo/load_video/load_video_thumb <msg-seqno> - loads photo/video to download dir. You can see message numbers starting client with -N\n"
"view_photo/view_video/view_video_thumb <msg-seqno> - loads photo/video to download dir and starts system default viewer. You can see message numbers starting client with -N\n"
"show_license - prints contents of GPLv2\n"
"search <peer> pattern - searches pattern in messages with peer\n"
"global_search pattern - searches pattern in all messages\n"
"mark_read <peer> - mark read all received messages with peer\n"
"add_contact <phone-number> <first-name> <last-name> - tries to add contact to contact-list by phone\n"
"create_secret_chat <user> - creates secret chat with this user\n"
"create_group_chat <user> <chat-topic> - creates group chat with this user, add more users with chat_add_user <user>\n"
"rename_contact <user> <first-name> <last-name> - tries to rename contact. If you have another device it will be a fight\n"
"suggested_contacts - print info about contacts, you have max common friends\n"
"visualize_key <secret_chat> - prints visualization of encryption key. You should compare it to your partner's one\n"
"set <param> <param-value>. Possible <param> values are:\n"
"\tdebug_verbosity - just as it sounds. Debug verbosity\n"
"\tlog_level - level of logging of new events. Lower is less verbose:\n"
"\t\tLevel 1: prints info about read messages\n"
"\t\tLevel 2: prints line, when somebody is typing in chat\n"
"\t\tLevel 3: prints line, when somebody changes online status\n"
"\tmsg_num - enables/disables numeration of messages\n"
"\talert - enables/disables alert sound notifications\n"
"chat_with_peer <peer> - starts chat with this peer. Every command after is message to this peer. Type /exit or /quit to end this mode\n"
);
pop_color ();
} else if (IS_WORD ("show_license")) {
char *b =
#include "LICENSE.h"
;
printf ("%s", b);
} else if (IS_WORD ("search")) {
GET_PEER;
int from = 0;
int to = 0;
int limit = 40;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty message\n");
RET;
if (op == ca_string_end || op == ca_file_name_end) {
next_token_end ();
if (cur_token_len < 0) {
break;
} else {
args[args_num].flags = 1;
args[args_num ++].str = strndup (cur_token, cur_token_len);
fun (args_num, args);
break;
}
}
tgl_do_msg_search (id, from, to, limit, s, print_msg_list_gw, 0);
} else if (IS_WORD ("global_search")) {
int from = 0;
int to = 0;
int limit = 40;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty message\n");
RET;
char *save = line_ptr;
next_token ();
if (period && cur_token_end_str) {
fun (args_num, args);
break;
}
tgl_do_msg_search (TGL_PEER_NOT_FOUND, from, to, limit, s, print_msg_list_gw, 0);
} else if (IS_WORD ("mark_read")) {
GET_PEER;
tgl_do_mark_read (id, 0, 0);
} else if (IS_WORD ("visualize_key")) {
static char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN};
GET_PEER_ENCR_CHAT;
static unsigned char buf[16];
memset (buf, 0, sizeof (buf));
tgl_do_visualize_key (id, buf);
print_start ();
int i;
for (i = 0; i < 16; i++) {
int x = buf[i];
int j;
for (j = 0; j < 4; j ++) {
push_color (colors[x & 3]);
push_color (COLOR_INVERSE);
if (!disable_colors) {
printf (" ");
if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number) {
if (cur_token_quoted) {
if (opt) {
if (op != ca_number) {
args[args_num ++].P = 0;
} else {
args[args_num ++].num = NOT_FOUND;
}
line_ptr = save;
flags ++;
continue;
} else {
switch (x & 3) {
case 0:
printf (" ");
break;
case 1:
printf ("--");
break;
case 2:
printf ("==");
break;
case 3:
printf ("||");
break;
}
} else {
if (cur_token_end_str) {
if (opt) {
if (op != ca_number) {
args[args_num ++].P = 0;
} else {
args[args_num ++].num = NOT_FOUND;
}
line_ptr = save;
flags ++;
continue;
} else {
break;
}
}
pop_color ();
pop_color ();
x = x >> 2;
}
if (i & 1) { printf ("\n"); }
}
print_end ();
} else if (IS_WORD ("create_secret_chat")) {
GET_PEER;
tgl_do_create_secret_chat (id, print_secret_chat_gw, 0);
} else if (IS_WORD ("create_group_chat")) {
GET_PEER_USER;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty chat topic\n");
RET;
}
tgl_do_create_group_chat (id, s, 0, 0);
//} else if (IS_WORD ("suggested_contacts")) {
// tgl_do_get_suggested ();
} else if (IS_WORD ("status_online")) {
tgl_do_update_status (1, 0, 0);
} else if (IS_WORD ("status_offline")) {
tgl_do_update_status (0, 0, 0);
} else if (IS_WORD ("contacts_search")) {
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty search query\n");
RET;
}
tgl_do_contacts_search (100, s, print_user_list_gw, 0);
} else if (IS_WORD("send_audio")) {
GET_PEER;
int t;
char *s = end_string_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
char *d = strndup (s, t);
assert (d);
tgl_do_send_photo (tgl_message_media_audio, id, d, 0, 0);
} else if (IS_WORD("send_document")) {
GET_PEER;
int t;
char *s = end_string_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
char *d = strndup (s, t);
assert (d);
tgl_do_send_photo (tgl_message_media_document, id, d, 0, 0);
} else if (IS_WORD ("load_audio")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_audio) {
tgl_do_load_audio (&M->media.audio, print_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_audio_encr) {
tgl_do_load_encr_video (&M->media.encr_video, print_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_audio")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_audio) {
tgl_do_load_audio (&M->media.audio, open_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_audio_encr) {
tgl_do_load_encr_video (&M->media.encr_video, open_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_document_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == (int)tgl_message_media_document) {
tgl_do_load_document_thumb (&M->media.document, print_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_document_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == (int)tgl_message_media_document) {
tgl_do_load_document_thumb (&M->media.document, open_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_document")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_document) {
tgl_do_load_document (&M->media.document, print_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_document_encr) {
tgl_do_load_encr_video (&M->media.encr_video, print_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_document")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct tgl_message *M = tgl_message_get (num);
if (M && !M->service && M->media.type == tgl_message_media_document) {
tgl_do_load_document (&M->media.document, open_filename_gw, 0);
} else if (M && !M->service && M->media.type == tgl_message_media_document_encr) {
tgl_do_load_encr_video (&M->media.encr_video, open_filename_gw, 0);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("set")) {
command = next_token (&l);
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
if (IS_WORD ("debug_verbosity")) {
tgl_set_verbosity (num);
} else if (IS_WORD ("log_level")) {
log_level = num;
} else if (IS_WORD ("msg_num")) {
msg_num_mode = num;
} else if (IS_WORD ("alert")) {
alert_sound = num;
}
} else if (IS_WORD ("chat_with_peer")) {
GET_PEER;
in_chat_mode = 1;
chat_mode_id = id;
} else if (IS_WORD ("delete_msg")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
tgl_do_delete_msg (num, 0, 0);
} else if (IS_WORD ("restore_msg")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
tgl_do_restore_msg (num, 0, 0);
} else if (IS_WORD ("delete_restore_msg")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
tgl_do_delete_msg (num, 0, 0);
tgl_do_restore_msg (num, 0, 0);
} else if (IS_WORD ("export_card")) {
tgl_do_export_card (print_card_gw, 0);
} else if (IS_WORD ("import_card")) {
int l;
char *s = next_token (&l);
if (l > 0) {
int i;
static int p[10];
int pp = 0;
int cur = 0;
int ok = 1;
for (i = 0; i < l; i ++) {
if (s[i] >= '0' && s[i] <= '9') {
cur = cur * 16 + s[i] - '0';
} else if (s[i] >= 'a' && s[i] <= 'f') {
cur = cur * 16 + s[i] - 'a' + 10;
} else if (s[i] == ':') {
if (pp >= 9) {
ok = 0;
break;
int ok = 1;
switch (op) {
case ca_user:
args[args_num ++].P = mk_peer (cur_token_user ());
ok = args[args_num - 1].P != NULL;
break;
case ca_chat:
args[args_num ++].P = mk_peer (cur_token_chat ());
ok = args[args_num - 1].P != NULL;
break;
case ca_secret_chat:
args[args_num ++].P = mk_peer (cur_token_encr_chat ());
ok = args[args_num - 1].P != NULL;
break;
case ca_peer:
args[args_num ++].P = mk_peer (cur_token_peer ());
ok = args[args_num - 1].P != NULL;
break;
case ca_number:
args[args_num ++].num = cur_token_int ();
ok = (args[args_num - 1].num != NOT_FOUND);
break;
default:
assert (0);
}
if (opt && !ok) {
if (op != ca_number) {
args[args_num ++].P = 0;
} else {
args[args_num ++].num = NOT_FOUND;
}
p[pp ++] = cur;
cur = 0;
line_ptr = save;
flags ++;
continue;
}
if (!ok) {
break;
}
flags ++;
continue;
}
if (ok) {
p[pp ++] = cur;
tgl_do_import_card (pp, p, print_user_gw, 0);
}
}
} else if (IS_WORD ("quit")) {
exit (0);
} else if (IS_WORD ("accept_secret_chat")) {
GET_PEER_ENCR_CHAT;
tgl_peer_t *E = tgl_peer_get (id);
assert (E);
tgl_do_accept_encr_chat_request (&E->encr_chat, 0, 0);
} else if (IS_WORD ("set_ttl")) {
GET_PEER_ENCR_CHAT;
tgl_peer_t *E = tgl_peer_get (id);
assert (E);
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
if (E->encr_chat.state == sc_ok) {
tgl_do_set_encr_chat_ttl (&E->encr_chat, num, 0, 0);
if (op == ca_string || op == ca_file_name) {
if (cur_token_end_str || cur_token_len < 0) {
break;
} else {
args[args_num].flags = 1;
args[args_num ++].str = strndup (cur_token, cur_token_len);
flags ++;
continue;
}
}
} else if (IS_WORD ("safe_quit")) {
safe_quit = 1;
assert (0);
}
int i;
for (i = 0; i < args_num; i++) {
if (args[i].flags & 1) {
free (args[i].str);
}
}
#undef IS_WORD
#undef RET
update_prompt ();
in_readline = 0;
}
......
......@@ -659,7 +659,7 @@ static long long msg_id_override;
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, "process_dh_answer(), len=%d\n", len);
vlogprintf (E_DEBUG - 1, "process_dh_answer(), len=%d\n", len);
assert (len == 72);
assert (!*(long long *) packet);
assert (*(int *) (packet + 16) == len - 20);
......
......@@ -1160,7 +1160,7 @@ void tgl_do_messages_mark_read_encr (tgl_peer_id_t id, long long access_hash, in
void tgl_do_mark_read (tgl_peer_id_t id, void (*callback)(void *callback_extra, int success), void *callback_extra) {
if (tgl_get_peer_type (id) == TGL_PEER_USER || tgl_get_peer_type (id) == TGL_PEER_CHAT) {
tgl_do_messages_mark_read (id, tgl_state.max_msg_id, 0, callback, callback_extra);
tgl_do_messages_mark_read (id, 0, 0, callback, callback_extra);
return;
}
tgl_peer_t *P = tgl_peer_get (id);
......@@ -1260,7 +1260,9 @@ static struct query_methods get_history_methods = {
void tgl_do_get_local_history (tgl_peer_id_t id, int limit, void (*callback)(void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) {
tgl_peer_t *P = tgl_peer_get (id);
if (!P || !P->last) {
callback (callback_extra, 0, 0, 0);
if (callback) {
callback (callback_extra, 0, 0, 0);
}
return;
}
struct tgl_message *M = P->last;
......@@ -1279,14 +1281,18 @@ void tgl_do_get_local_history (tgl_peer_id_t id, int limit, void (*callback)(voi
ML[count ++] = M;
}
callback (callback_extra, 1, count, ML);
if (callback) {
callback (callback_extra, 1, count, ML);
}
tfree (ML, sizeof (void *) * count);
}
void tgl_do_get_local_history_ext (tgl_peer_id_t id, int offset, int limit, void (*callback)(void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra) {
tgl_peer_t *P = tgl_peer_get (id);
if (!P || !P->last) {
callback (callback_extra, 0, 0, 0);
if (callback) {
callback (callback_extra, 0, 0, 0);
}
return;
}
struct tgl_message *M = P->last;
......@@ -1297,7 +1303,9 @@ void tgl_do_get_local_history_ext (tgl_peer_id_t id, int offset, int limit, void
count ++;
}
if (count <= offset) {
callback (callback_extra, 1, 0, 0);
if (callback) {
callback (callback_extra, 1, 0, 0);
}
return;
}
struct tgl_message **ML = talloc (sizeof (void *) * (count - offset));
......@@ -1312,7 +1320,9 @@ void tgl_do_get_local_history_ext (tgl_peer_id_t id, int offset, int limit, void
count ++;
}
callback (callback_extra, 1, count - offset, ML);
if (callback) {
callback (callback_extra, 1, count - offset, ML);
}
tfree (ML, sizeof (void *) * (count) - offset);
}
......@@ -1835,7 +1845,9 @@ void _tgl_do_send_photo (enum tgl_message_media_type type, tgl_peer_id_t to_id,
int fd = open (file_name, O_RDONLY);
if (fd < 0) {
vlogprintf (E_WARNING, "No such file '%s'\n", file_name);
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
struct stat buf;
......@@ -1844,7 +1856,9 @@ void _tgl_do_send_photo (enum tgl_message_media_type type, tgl_peer_id_t to_id,
if (size <= 0) {
vlogprintf (E_WARNING, "File has zero length\n");
close (fd);
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
struct send_file *f = talloc0 (sizeof (*f));
......@@ -1863,7 +1877,9 @@ void _tgl_do_send_photo (enum tgl_message_media_type type, tgl_peer_id_t to_id,
close (fd);
vlogprintf (E_WARNING, "Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000);
tfree (f, sizeof (*f));
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
......@@ -1886,7 +1902,9 @@ void _tgl_do_send_photo (enum tgl_message_media_type type, tgl_peer_id_t to_id,
close (fd);
vlogprintf (E_WARNING, "Unknown type %d.\n", type);
tfree (f, sizeof (*f));
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
f->file_name = tstrdup (file_name);
......@@ -1968,7 +1986,9 @@ static struct query_methods fwd_msg_methods = {
void tgl_do_forward_message (tgl_peer_id_t id, int n, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra) {
if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT) {
vlogprintf (E_WARNING, "Can not forward messages from secret chat\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
clear_packet ();
......@@ -2007,23 +2027,31 @@ 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) {
if (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT) {
vlogprintf (E_WARNING, "Can not forward messages from secret chat\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
struct tgl_message *M = tgl_message_get (n);
if (!M) {
vlogprintf (E_WARNING, "No such message\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
if (M->flags & FLAG_ENCRYPTED) {
vlogprintf (E_WARNING, "Can not forward media from encrypted message\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
if (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_video && M->media.type != tgl_message_media_audio && M->media.type != tgl_message_media_document) {
vlogprintf (E_WARNING, "Can only forward photo/audio/video/document\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
clear_packet ();
......@@ -2159,10 +2187,14 @@ void tgl_do_get_chat_info (tgl_peer_id_t id, int offline_mode, void (*callback)(
tgl_peer_t *C = tgl_peer_get (id);
if (!C) {
vlogprintf (E_WARNING, "No such chat\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
} else {
//print_chat_info (&C->chat);
callback (callback_extra, 1, &C->chat);
if (callback) {
callback (callback_extra, 1, &C->chat);
}
}
return;
}
......@@ -2214,9 +2246,13 @@ void tgl_do_get_user_info (tgl_peer_id_t id, int offline_mode, void (*callback)(
tgl_peer_t *C = tgl_peer_get (id);
if (!C) {
vlogprintf (E_WARNING, "No such user\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
} else {
callback (callback_extra, 1, &C->user);
if (callback) {
callback (callback_extra, 1, &C->user);
}
}
return;
}
......@@ -2415,7 +2451,9 @@ static void load_next_part (struct download *D, void *callback, void *callback_e
void tgl_do_load_photo_size (struct tgl_photo_size *P, void (*callback)(void *callback_extra, int success, char *filename), void *callback_extra) {
if (!P->loc.dc) {
vlogprintf (E_WARNING, "Bad video thumb\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
......@@ -2436,7 +2474,9 @@ void tgl_do_load_photo_size (struct tgl_photo_size *P, void (*callback)(void *ca
void tgl_do_load_photo (struct tgl_photo *photo, void (*callback)(void *callback_extra, int success, char *filename), void *callback_extra) {
if (!photo->sizes_num) {
vlogprintf (E_WARNING, "No sizes\n");
callback (callback_extra, 0, 0);
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
int max = -1;
......@@ -2841,7 +2881,9 @@ void tgl_do_send_accept_encr_chat (struct tgl_secret_chat *E, unsigned char *ran
}
}
if (ok) {
callback (callback_extra, 1, E);
if (callback) {
callback (callback_extra, 1, E);
}
return;
} // Already generated key for this chat
unsigned char random_here[256];
......@@ -3378,6 +3420,9 @@ void tgl_do_create_group_chat (tgl_peer_id_t id, char *chat_topic, void (*callba
tgl_peer_t *U = tgl_peer_get (id);
if (!U) {
vlogprintf (E_WARNING, "Can not create chat with unknown user\n");
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
clear_packet ();
......@@ -3395,6 +3440,35 @@ void tgl_do_create_group_chat (tgl_peer_id_t id, char *chat_topic, void (*callba
out_string (chat_topic);
tglq_send_query (tgl_state.DC_working, packet_ptr - packet_buffer, packet_buffer, &create_group_chat_methods, 0, callback, callback_extra);
}
void tgl_do_create_group_chat_ex (int users_num, tgl_peer_id_t ids[], char *chat_topic, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra) {
clear_packet ();
out_int (CODE_messages_create_chat);
out_int (CODE_vector);
out_int (users_num); // Number of users, currently we support only 1 user.
int i;
for (i = 0; i < users_num; i++) {
tgl_peer_id_t id = ids[i];
tgl_peer_t *U = tgl_peer_get (id);
if (!U || tgl_get_peer_type (id) != TGL_PEER_USER) {
vlogprintf (E_WARNING, "Can not create chat with unknown user\n");
if (callback) {
callback (callback_extra, 0, 0);
}
return;
}
if (U && U->user.access_hash) {
out_int (CODE_input_user_foreign);
out_int (tgl_get_peer_id (id));
out_long (U->user.access_hash);
} else {
out_int (CODE_input_user_contact);
out_int (tgl_get_peer_id (id));
}
}
out_string (chat_topic);
tglq_send_query (tgl_state.DC_working, packet_ptr - packet_buffer, packet_buffer, &create_group_chat_methods, 0, callback, callback_extra);
}
/* }}} */
/* {{{ Delete msg */
......
......@@ -87,7 +87,7 @@ char *tgls_default_create_print_name (tgl_peer_id_t id, const char *a1, const ch
}
char *s = buf;
while (*s) {
if (*s == ' ') { *s = '_'; }
if (((unsigned char)*s) <= ' ') { *s = '_'; }
if (*s == '#') { *s = '@'; }
s++;
}
......
......@@ -249,6 +249,7 @@ void tgl_do_send_msg (struct tgl_message *M, void (*callback)(void *callback_ext
void tgl_do_send_text (tgl_peer_id_t id, char *file, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_mark_read (tgl_peer_id_t id, void (*callback)(void *callback_extra, int success), void *callback_extra);
void tgl_do_get_history (tgl_peer_id_t id, int limit, int offline_mode, void (*callback)(void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra);
void tgl_do_get_history_ext (tgl_peer_id_t id, int offset, int limit, int offline_mode, void (*callback)(void *callback_extra, int success, int size, struct tgl_message *list[]), void *callback_extra);
void tgl_do_get_dialog_list (void (*callback)(void *callback_extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]), void *callback_extra);
void tgl_do_send_photo (enum tgl_message_media_type type, tgl_peer_id_t to_id, char *file_name, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_set_chat_photo (tgl_peer_id_t chat_id, char *file_name, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
......@@ -275,6 +276,7 @@ void tgl_do_get_difference (int sync_from_start, void (*callback)(void *callback
void tgl_do_add_user_to_chat (tgl_peer_id_t chat_id, tgl_peer_id_t id, int limit, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_del_user_from_chat (tgl_peer_id_t chat_id, tgl_peer_id_t id, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_create_group_chat (tgl_peer_id_t id, char *chat_topic, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_create_group_chat_ex (int users_num, tgl_peer_id_t ids[], char *chat_topic, void (*callback)(void *callback_extra, int success, struct tgl_message *M), void *callback_extra);
void tgl_do_delete_msg (long long id, void (*callback)(void *callback_extra, int success), void *callback_extra);
void tgl_do_restore_msg (long long id, void (*callback)(void *callback_extra, int success), void *callback_extra);
void tgl_do_update_status (int online, void (*callback)(void *callback_extra, int success), void *callback_extra);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment