tg/interface.c

3532 lines
108 KiB
C
Raw Normal View History

2013-10-23 10:26:17 -04:00
/*
This file is part of telegram-cli.
2013-10-23 10:26:17 -04:00
Telegram-cli is free software: you can redistribute it and/or modify
2013-10-23 10:26:17 -04:00
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Telegram-cli is distributed in the hope that it will be useful,
2013-10-23 10:26:17 -04:00
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this telegram-cli. If not, see <http://www.gnu.org/licenses/>.
2013-10-23 10:26:17 -04:00
2015-01-11 16:52:40 -05:00
Copyright Vitaly Valtman 2013-2015
2013-10-23 10:26:17 -04:00
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2013-10-03 08:38:25 -04:00
#define _GNU_SOURCE
2013-10-03 08:38:25 -04:00
#include <assert.h>
#include <stdio.h>
2013-10-11 16:52:20 -04:00
#include <stdarg.h>
2013-10-03 08:38:25 -04:00
#include <stdlib.h>
#include <string.h>
2013-10-18 14:00:19 -04:00
#ifdef READLINE_GNU
2013-10-18 14:00:19 -04:00
#include <readline/readline.h>
#include <readline/history.h>
#else
2013-11-11 06:34:45 -05:00
#include <readline/readline.h>
#include <readline/history.h>
#endif
2014-09-22 18:23:40 -04:00
#include <unistd.h>
2013-10-18 14:00:19 -04:00
2014-08-13 11:55:16 -04:00
//#include "queries.h"
#include "interface.h"
#include "telegram.h"
2014-09-07 15:12:39 -04:00
#ifdef EVENT_V2
2014-08-21 16:35:27 -04:00
#include <event2/event.h>
2014-09-20 18:22:35 -04:00
#include <event2/bufferevent.h>
#include <event2/buffer.h>
2014-09-07 15:12:39 -04:00
#else
#include <event.h>
#include "event-old.h"
#endif
2014-08-18 12:39:04 -04:00
//#include "auto/constants.h"
2014-08-14 18:16:01 -04:00
//#include "tools.h"
2014-08-13 11:55:16 -04:00
//#include "structures.h"
2014-08-21 11:38:51 -04:00
#ifdef USE_LUA
# include "lua-tg.h"
#endif
2015-05-02 07:49:21 -04:00
#ifdef USE_PYTHON
# include "python-tg.h"
#endif
2014-08-13 11:55:16 -04:00
//#include "mtproto-common.h"
2013-11-25 12:16:34 -05:00
2014-11-12 09:38:44 -05:00
#include <tgl/tgl.h>
#include "loop.h"
2014-08-13 08:56:55 -04:00
2014-08-14 18:16:01 -04:00
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#ifdef __APPLE__
#define OPEN_BIN "open %s"
#else
#define OPEN_BIN "xdg-open %s"
#endif
2015-05-11 07:20:34 -04:00
#ifdef USE_JSON
2015-05-11 10:14:58 -04:00
# include <jansson.h>
2015-05-11 07:20:34 -04:00
# include "json-tg.h"
#endif
2014-01-24 10:05:41 -05:00
#define ALLOW_MULT 1
2013-10-24 11:44:54 -04:00
char *default_prompt = "> ";
2015-01-11 16:52:40 -05:00
extern int read_one_string;
extern char one_string[];
extern int one_string_len;
extern char *one_string_prompt;
extern int one_string_flags;
2015-05-11 07:20:34 -04:00
extern int enable_json;
2014-08-26 12:06:30 -04:00
int disable_auto_accept;
2013-10-25 15:50:10 -04:00
int msg_num_mode;
2014-08-24 20:11:41 -04:00
int disable_colors;
2014-02-27 03:48:05 -05:00
int alert_sound;
2014-08-21 11:38:51 -04:00
extern int binlog_read;
2013-10-03 08:38:25 -04:00
int safe_quit;
2013-10-29 20:08:30 -04:00
int in_readline;
2013-11-11 06:34:45 -05:00
int readline_active;
2013-10-29 20:08:30 -04:00
2013-11-15 11:14:25 -05:00
int log_level;
2013-10-29 20:08:30 -04:00
char *line_ptr;
2013-12-06 12:14:41 -05:00
int in_chat_mode;
2014-08-13 11:55:16 -04:00
tgl_peer_id_t chat_mode_id;
extern int readline_disabled;
2014-09-09 13:05:36 -04:00
extern int disable_output;
2014-09-20 18:22:35 -04:00
struct in_ev *notify_ev;
2014-09-22 18:23:40 -04:00
extern int usfd;
extern int sfd;
extern int use_ids;
2014-09-22 18:23:40 -04:00
extern int daemonize;
extern struct tgl_state *TLS;
2015-01-11 16:52:40 -05:00
int readline_deactivated;
void event_incoming (struct bufferevent *bev, short what, void *_arg);
2013-10-29 20:08:30 -04:00
int is_same_word (const char *s, size_t l, const char *word) {
return s && word && strlen (word) == l && !memcmp (s, word, l);
}
2014-09-17 17:03:20 -04:00
static void skip_wspc (void) {
while (*line_ptr && ((unsigned char)*line_ptr) <= ' ') {
line_ptr ++;
2014-08-12 21:22:15 -04:00
}
}
2014-08-13 11:55:16 -04:00
2014-09-17 17:03:20 -04:00
static char *cur_token;
static int cur_token_len;
static int cur_token_end_str;
static int cur_token_quoted;
2014-09-20 18:22:35 -04:00
#define SOCKET_ANSWER_MAX_SIZE (1 << 25)
static char socket_answer[SOCKET_ANSWER_MAX_SIZE + 1];
static int socket_answer_pos = -1;
void socket_answer_start (void) {
socket_answer_pos = 0;
}
static void socket_answer_add_printf (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void socket_answer_add_printf (const char *format, ...) {
if (socket_answer_pos < 0) { return; }
va_list ap;
va_start (ap, format);
socket_answer_pos += vsnprintf (socket_answer + socket_answer_pos, SOCKET_ANSWER_MAX_SIZE - socket_answer_pos, format, ap);
va_end (ap);
if (socket_answer_pos > SOCKET_ANSWER_MAX_SIZE) { socket_answer_pos = -1; }
}
void socket_answer_end (struct in_ev *ev) {
if (ev->bev && socket_answer_pos > 0) {
static char s[100];
sprintf (s, "ANSWER %d\n", socket_answer_pos);
bufferevent_write (ev->bev, s, strlen (s));
bufferevent_write (ev->bev, socket_answer, socket_answer_pos);
bufferevent_write (ev->bev, "\n", 1);
}
socket_answer_pos = -1;
}
#define mprintf(ev,...) \
if (ev) { socket_answer_add_printf (__VA_ARGS__); } \
else { printf (__VA_ARGS__); }
#define mprint_start(ev,...) \
if (!ev) { print_start (__VA_ARGS__); } \
else { socket_answer_start (); }
#define mprint_end(ev,...) \
if (!ev) { print_end (__VA_ARGS__); } \
else { socket_answer_end (ev); }
#define mpush_color(ev,...) \
if (!ev) { push_color (__VA_ARGS__); }
#define mpop_color(ev,...) \
if (!ev) { pop_color (__VA_ARGS__); }
2014-09-17 17:03:20 -04:00
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 ++;
}
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);
2013-10-29 20:08:30 -04:00
}
2014-09-17 17:03:20 -04:00
}
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 ();
}
2013-10-29 20:08:30 -04:00
}
}
#define NOT_FOUND (int)0x80000000
2014-08-13 11:55:16 -04:00
tgl_peer_id_t TGL_PEER_NOT_FOUND = {.id = NOT_FOUND};
2014-09-17 17:03:20 -04:00
long long cur_token_int (void) {
if (cur_token_len <= 0) {
2013-10-29 20:08:30 -04:00
return NOT_FOUND;
2014-09-17 17:03:20 -04:00
} 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;
}
2013-10-29 20:08:30 -04:00
}
}
2014-10-03 05:35:02 -04:00
double cur_token_double (void) {
if (cur_token_len <= 0) {
return NOT_FOUND;
} else {
char c = cur_token[cur_token_len];
cur_token[cur_token_len] = 0;
char *end = 0;
double x = strtod (cur_token, &end);
cur_token[cur_token_len] = c;
if (end != cur_token + cur_token_len) {
return NOT_FOUND;
} else {
return x;
}
}
}
2014-09-17 17:03:20 -04:00
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;
2013-10-29 20:08:30 -04:00
2014-10-01 06:34:55 -04:00
if (l >= 8 && !memcmp (s, "user#id", 7)) {
s += 7;
l -= 7;
int r = atoi (s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-08-13 11:55:16 -04:00
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); }
else { return TGL_PEER_NOT_FOUND; }
2013-10-29 20:08:30 -04:00
}
2014-10-01 06:34:55 -04:00
if (l >= 6 && !memcmp (s, "user#", 5)) {
s += 5;
l -= 5;
2014-09-03 11:54:50 -04:00
int r = atoi (s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-09-03 11:54:50 -04:00
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); }
else { return TGL_PEER_NOT_FOUND; }
}
tgl_peer_t *P = tgl_peer_get_by_name (TLS, s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-08-13 08:56:55 -04:00
2014-08-13 11:55:16 -04:00
if (P && tgl_get_peer_type (P->id) == TGL_PEER_USER) {
2014-08-13 08:56:55 -04:00
return P->id;
2013-10-29 20:08:30 -04:00
} else {
2014-08-13 11:55:16 -04:00
return TGL_PEER_NOT_FOUND;
2013-10-29 20:08:30 -04:00
}
}
2014-09-17 17:03:20 -04:00
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;
2014-10-01 06:34:55 -04:00
if (l >= 8 && !memcmp (s, "chat#id", 7)) {
s += 7;
l -= 7;
int r = atoi (s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-08-13 11:55:16 -04:00
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); }
else { return TGL_PEER_NOT_FOUND; }
2013-10-29 20:08:30 -04:00
}
2014-10-01 06:34:55 -04:00
if (l >= 6 && !memcmp (s, "chat#", 5)) {
s += 5;
l -= 5;
2014-09-03 11:54:50 -04:00
int r = atoi (s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-09-03 11:54:50 -04:00
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); }
else { return TGL_PEER_NOT_FOUND; }
}
tgl_peer_t *P = tgl_peer_get_by_name (TLS, s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-08-13 08:56:55 -04:00
2014-08-13 11:55:16 -04:00
if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) {
2014-08-13 08:56:55 -04:00
return P->id;
2013-10-29 20:08:30 -04:00
} else {
2014-08-13 11:55:16 -04:00
return TGL_PEER_NOT_FOUND;
2013-10-29 20:08:30 -04:00
}
}
2014-09-17 17:03:20 -04:00
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;
tgl_peer_t *P = tgl_peer_get_by_name (TLS, s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-08-13 08:56:55 -04:00
2014-08-13 11:55:16 -04:00
if (P && tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) {
2014-08-13 08:56:55 -04:00
return P->id;
} else {
2014-08-13 11:55:16 -04:00
return TGL_PEER_NOT_FOUND;
}
}
2014-09-17 17:03:20 -04:00
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;
2014-10-01 06:34:55 -04:00
if (l >= 8 && !memcmp (s, "user#id", 7)) {
s += 7;
l -= 7;
int r = atoi (s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-08-13 11:55:16 -04:00
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_USER, r); }
else { return TGL_PEER_NOT_FOUND; }
}
2014-10-01 06:34:55 -04:00
if (l >= 8 && !memcmp (s, "chat#id", 7)) {
s += 7;
l -= 7;
int r = atoi (s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); }
else { return TGL_PEER_NOT_FOUND; }
}
2014-10-01 06:34:55 -04:00
if (l >= 6 && !memcmp (s, "user#", 5)) {
s += 5;
l -= 5;
2014-09-17 17:03:20 -04:00
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; }
}
2014-10-01 06:34:55 -04:00
if (l >= 6 && !memcmp (s, "chat#", 5)) {
s += 5;
l -= 5;
2014-09-17 17:03:20 -04:00
int r = atoi (s);
cur_token[cur_token_len] = c;
2014-08-13 11:55:16 -04:00
if (r >= 0) { return tgl_set_peer_id (TGL_PEER_CHAT, r); }
else { return TGL_PEER_NOT_FOUND; }
2013-10-29 20:08:30 -04:00
}
2014-08-13 08:56:55 -04:00
tgl_peer_t *P = tgl_peer_get_by_name (TLS, s);
2014-09-17 17:03:20 -04:00
cur_token[cur_token_len] = c;
2014-08-13 08:56:55 -04:00
if (P) {
return P->id;
2013-10-29 20:08:30 -04:00
} else {
2014-08-13 11:55:16 -04:00
return TGL_PEER_NOT_FOUND;
2013-10-29 20:08:30 -04:00
}
}
2014-09-17 17:03:20 -04:00
static tgl_peer_t *mk_peer (tgl_peer_id_t id) {
if (tgl_get_peer_type (id) == NOT_FOUND) { return 0; }
tgl_peer_t *P = tgl_peer_get (TLS, id);
2014-10-01 06:34:55 -04:00
if (!P) {
if (tgl_get_peer_type (id) == TGL_PEER_USER) {
tgl_insert_empty_user (TLS, tgl_get_peer_id (id));
2014-10-01 06:34:55 -04:00
}
if (tgl_get_peer_type (id) == TGL_PEER_CHAT) {
tgl_insert_empty_chat (TLS, tgl_get_peer_id (id));
2014-10-01 06:34:55 -04:00
}
P = tgl_peer_get (TLS, id);
2014-10-01 06:34:55 -04:00
}
2014-09-17 17:03:20 -04:00
return P;
}
2013-10-03 08:38:25 -04:00
char *get_default_prompt (void) {
2013-12-06 12:14:41 -05:00
static char buf[1000];
int l = 0;
if (in_chat_mode) {
tgl_peer_t *U = tgl_peer_get (TLS, chat_mode_id);
2013-12-06 12:14:41 -05:00
assert (U && U->print_name);
2014-08-14 18:16:01 -04:00
l += snprintf (buf + l, 999 - l, COLOR_RED "%.*s " COLOR_NORMAL, 100, U->print_name);
2013-12-06 12:14:41 -05:00
}
if (TLS->unread_messages || TLS->cur_uploading_bytes || TLS->cur_downloading_bytes) {
2014-08-14 18:16:01 -04:00
l += snprintf (buf + l, 999 - l, COLOR_RED "[");
int ok = 0;
if (TLS->unread_messages) {
l += snprintf (buf + l, 999 - l, "%d unread", TLS->unread_messages);
ok = 1;
}
if (TLS->cur_uploading_bytes) {
if (ok) { *(buf + l) = ' '; l ++; }
ok = 1;
l += snprintf (buf + l, 999 - l, "%lld%%Up", 100 * TLS->cur_uploaded_bytes / TLS->cur_uploading_bytes);
}
if (TLS->cur_downloading_bytes) {
if (ok) { *(buf + l) = ' '; l ++; }
ok = 1;
l += snprintf (buf + l, 999 - l, "%lld%%Down", 100 * TLS->cur_downloaded_bytes / TLS->cur_downloading_bytes);
}
2014-08-14 18:16:01 -04:00
l += snprintf (buf + l, 999 - l, "]" COLOR_NORMAL);
2014-08-21 16:35:27 -04:00
l += snprintf (buf + l, 999 - l, "%s", default_prompt);
2013-10-24 11:44:54 -04:00
return buf;
2013-12-06 12:14:41 -05:00
}
2014-08-14 18:16:01 -04:00
l += snprintf (buf + l, 999 - l, "%s", default_prompt);
2013-12-06 12:14:41 -05:00
return buf;
2013-10-03 08:38:25 -04:00
}
2014-11-12 09:38:44 -05:00
char *complete_none (const char *text, int state) {
2013-10-03 08:38:25 -04:00
return 0;
}
void set_prompt (const char *s) {
if (readline_disabled) { return; }
rl_set_prompt (s);
}
void update_prompt (void) {
if (readline_disabled) { return; }
2015-01-11 16:52:40 -05:00
if (read_one_string) { return; }
print_start ();
set_prompt (get_default_prompt ());
2013-11-11 06:34:45 -05:00
if (readline_active) {
rl_redisplay ();
}
print_end ();
}
char *modifiers[] = {
"[offline]",
2015-05-14 08:48:20 -04:00
"[enable_preview]",
"[disable_preview]",
"[reply=",
0
};
2013-12-06 12:14:41 -05:00
char *in_chat_commands[] = {
"/exit",
"/quit",
"/history",
"/read",
2013-12-06 12:14:41 -05:00
0
};
enum command_argument {
ca_none,
ca_user,
ca_chat,
ca_secret_chat,
ca_peer,
ca_file_name,
ca_file_name_end,
ca_period,
ca_number,
2014-10-03 05:35:02 -04:00
ca_double,
ca_string_end,
ca_string,
ca_modifier,
2014-09-10 07:52:42 -04:00
ca_command,
2014-09-17 17:03:20 -04:00
ca_extf,
ca_optional = 256
};
struct arg {
int flags;
struct {
tgl_peer_t *P;
struct tgl_message *M;
char *str;
long long num;
2014-10-03 05:35:02 -04:00
double dval;
2014-09-17 17:03:20 -04:00
};
2013-10-03 08:38:25 -04:00
};
2013-10-03 12:09:06 -04:00
struct command {
char *name;
enum command_argument args[10];
2015-05-06 07:39:45 -04:00
void (*fun)(struct command *command, int arg_num, struct arg args[], struct in_ev *ev);
2014-09-18 09:10:42 -04:00
char *desc;
2015-05-06 07:39:45 -04:00
void *arg;
};
2014-09-17 17:03:20 -04:00
int offline_mode;
2015-05-14 08:48:20 -04:00
int reply_id;
int disable_msg_preview;
void print_user_list_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_user *UL[]);
void print_msg_list_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]);
void print_msg_list_success_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]);
void print_dialog_list_gw (struct tgl_state *TLS, void *extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]);
void print_chat_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C);
void print_user_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_user *C);
2015-05-14 08:48:20 -04:00
void print_filename_gw (struct tgl_state *TLS, void *extra, int success, const char *name);
2015-05-01 13:19:12 -04:00
void print_string_gw (struct tgl_state *TLS, void *extra, int success, const char *name);
2015-05-14 08:48:20 -04:00
void open_filename_gw (struct tgl_state *TLS, void *extra, int success, const char *name);
void print_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E);
void print_card_gw (struct tgl_state *TLS, void *extra, int success, int size, int *card);
void print_user_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U);
void print_msg_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M);
void print_msg_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M);
void print_encr_chat_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E);;
void print_success_gw (struct tgl_state *TLS, void *extra, int success);
2014-09-17 17:03:20 -04:00
2014-09-18 09:10:42 -04:00
struct command commands[];
2015-05-14 08:48:20 -04:00
/* {{{ client methods */
2015-05-06 07:39:45 -04:00
void do_help (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (!arg_num);
2014-09-20 18:22:35 -04:00
if (ev) { mprint_start (ev); }
mpush_color (ev, COLOR_YELLOW);
2014-09-18 09:10:42 -04:00
struct command *cmd = commands;
while (cmd->name) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s\n", cmd->desc);
2014-09-18 09:10:42 -04:00
cmd ++;
}
2014-09-20 18:22:35 -04:00
mpop_color (ev);
if (ev) { mprint_end (ev); }
if (!ev) {
fflush (stdout);
}
2014-09-17 17:03:20 -04:00
}
2015-05-06 07:39:45 -04:00
void do_stats (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (!arg_num);
static char stat_buf[1 << 15];
tgl_print_stat (TLS, stat_buf, (1 << 15) - 1);
2014-09-20 18:22:35 -04:00
if (ev) { mprint_start (ev); }
mprintf (ev, "%s\n", stat_buf);
if (ev) { mprint_end (ev); }
if (!ev) {
fflush (stdout);
}
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_show_license (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (!arg_num);
static char *b =
#include "LICENSE.h"
;
if (ev) { mprint_start (ev); }
mprintf (ev, "%s", b);
if (ev) { mprint_end (ev); }
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_quit (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
if (daemonize) {
event_incoming (ev->bev, BEV_EVENT_EOF, ev);
}
do_halt (0);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_safe_quit (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
if (daemonize) {
event_incoming (ev->bev, BEV_EVENT_EOF, ev);
}
safe_quit = 1;
2015-01-11 16:52:40 -05:00
}
2015-05-14 08:48:20 -04:00
void do_set (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
int num = args[1].num;
if (!strcmp (args[0].str, "debug_verbosity")) {
tgl_set_verbosity (TLS, num);
} 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;
}
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_chat_with_peer (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
if (!ev) {
in_chat_mode = 1;
chat_mode_id = args[0].P->id;
}
}
void do_main_session (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
if (notify_ev && !--notify_ev->refcnt) {
free (notify_ev);
}
notify_ev = ev;
if (ev) { ev->refcnt ++; }
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
2014-09-17 17:03:20 -04:00
2015-05-14 08:48:20 -04:00
#define ARG2STR_DEF(n,def) args[n].str ? args[n].str : def, args[n].str ? strlen (args[n].str) : strlen (def)
#define ARG2STR(n) args[n].str, args[n].str ? strlen (args[n].str) : 0
/* {{{ WORK WITH ACCOUNT */
void do_set_password (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_set_password (TLS, ARG2STR_DEF(0, "empty"), print_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
2014-09-17 17:03:20 -04:00
2015-05-14 08:48:20 -04:00
/* {{{ SENDING MESSAGES */
void do_msg (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
vlogprintf (E_ERROR, "reply_id=%d, disable=%d\n", reply_id, disable_msg_preview);
tgl_do_send_message (TLS, args[0].P->id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview, print_msg_success_gw, ev);
2015-04-27 10:52:19 -04:00
}
2015-05-14 08:48:20 -04:00
void do_reply (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
2015-04-27 10:52:19 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_reply_message (TLS, args[0].num, ARG2STR(1), disable_msg_preview, print_msg_success_gw, ev);
2015-04-27 10:52:19 -04:00
}
2015-05-14 08:48:20 -04:00
void do_send_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
2015-04-27 10:52:19 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_send_text (TLS, args[0].P->id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview, print_msg_success_gw, ev);
2015-04-27 10:52:19 -04:00
}
2015-05-14 08:48:20 -04:00
void do_reply_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
2015-04-27 10:52:19 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_reply_text (TLS, args[0].num, args[1].str, disable_msg_preview, print_msg_success_gw, ev);
2015-04-27 10:52:19 -04:00
}
2015-05-14 08:48:20 -04:00
static void _do_send_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev, unsigned long long flags) {
2015-05-05 05:48:58 -04:00
assert (arg_num >= 2);
2015-04-27 10:52:19 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_send_document (TLS, args[0].P->id, args[1].str, arg_num == 2 ? NULL : args[2].str, arg_num == 2 ? 0 : strlen (args[2].str), flags | TGL_SEND_MSG_FLAG_REPLY (reply_id), print_msg_success_gw, ev);
2015-04-27 10:52:19 -04:00
}
2015-05-14 08:48:20 -04:00
void do_send_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO);
}
void do_send_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO);
}
void do_send_audio (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO);
}
void do_send_video (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO);
}
void do_send_document (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_send_file (command, arg_num, args, ev, 0);
}
void _do_reply_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev, unsigned long long flags) {
2015-05-05 05:48:58 -04:00
assert (arg_num >= 2);
2015-04-27 10:52:19 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_reply_document (TLS, args[0].num, args[1].str, arg_num == 2 ? NULL : args[2].str, arg_num == 2 ? 0 : strlen (args[2].str), flags, print_msg_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_reply_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_reply_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_reply_audio (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO);
}
void do_reply_video (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO);
}
void do_reply_document (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
_do_reply_file (command, arg_num, args, ev, 0);
2014-09-17 17:03:20 -04:00
}
2015-05-06 07:39:45 -04:00
void do_fwd (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2015-04-24 09:19:13 -04:00
assert (arg_num >= 2);
if (ev) { ev->refcnt ++; }
2015-04-24 09:19:13 -04:00
assert (arg_num <= 1000);
if (arg_num == 2) {
2015-05-14 08:48:20 -04:00
tgl_do_forward_message (TLS, args[0].P->id, args[1].num, 0, print_msg_success_gw, ev);
2015-04-24 09:19:13 -04:00
} else {
static int list[1000];
int i;
for (i = 0; i < arg_num - 1; i++) {
list[i] = args[i + 1].num;
}
2015-05-14 08:48:20 -04:00
tgl_do_forward_messages (TLS, args[0].P->id, arg_num - 1, list, 0, print_msg_list_success_gw, ev);
2015-04-24 09:19:13 -04:00
}
2014-09-17 17:03:20 -04:00
}
2015-05-06 07:39:45 -04:00
void do_fwd_media (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 2);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_forward_media (TLS, args[0].P->id, args[1].num, 0, print_msg_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_send_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 4);
2015-04-27 06:43:31 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_send_contact (TLS, args[0].P->id, ARG2STR (1), ARG2STR (2), ARG2STR (3), TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev);
2015-04-27 06:43:31 -04:00
}
2015-05-14 08:48:20 -04:00
void do_reply_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 4);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_reply_contact (TLS, args[0].num, ARG2STR (1), ARG2STR (2), ARG2STR (3), 0, print_msg_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_send_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 3);
2015-04-24 07:08:01 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_send_location (TLS, args[0].P->id, args[1].dval, args[2].dval, TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev);
2015-04-24 07:08:01 -04:00
}
2015-05-14 08:48:20 -04:00
void do_reply_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 3);
if (ev) { ev->refcnt ++; }
tgl_do_reply_location (TLS, args[0].num, args[1].dval, args[2].dval, 0, print_msg_success_gw, ev);
}
void do_broadcast (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num >= 1 && arg_num <= 1000);
static tgl_peer_id_t ids[1000];
int i;
for (i = 0; i < arg_num - 1; i++) {
ids[i] = args[i].P->id;
}
if (ev) { ev->refcnt ++; }
tgl_do_send_broadcast (TLS, arg_num - 1, ids, args[arg_num - 1].str, strlen (args[arg_num - 1].str), disable_msg_preview, print_msg_list_success_gw, ev);
}
/* }}} */
/* {{{ EDITING SELF PROFILE */
void do_set_profile_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_set_profile_photo (TLS, args[0].str, print_success_gw, ev);
}
2015-05-14 08:48:20 -04:00
void do_set_profile_name (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
if (ev) { ev->refcnt ++; }
tgl_do_set_profile_name (TLS, ARG2STR (0), ARG2STR (1), print_user_gw, ev);
}
void do_set_username (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_set_username (TLS, ARG2STR (0), print_user_gw, ev);
}
void do_status_online (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (!arg_num);
if (ev) { ev->refcnt ++; }
tgl_do_update_status (TLS, 1, print_success_gw, ev);
}
void do_status_offline (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (!arg_num);
if (ev) { ev->refcnt ++; }
tgl_do_update_status (TLS, 0, print_success_gw, ev);
}
void do_export_card (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (!arg_num);
if (ev) { ev->refcnt ++; }
tgl_do_export_card (TLS, print_card_gw, ev);
}
/* }}} */
/* {{{ WORKING WITH GROUP CHATS */
void do_chat_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
if (ev) { ev->refcnt ++; }
tgl_do_set_chat_photo (TLS, args[0].P->id, args[1].str, print_success_gw, ev);
}
2015-05-06 07:39:45 -04:00
void do_rename_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 2);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_rename_chat (TLS, args[0].P->id, ARG2STR (1), print_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_chat_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2015-05-01 13:19:12 -04:00
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_get_chat_info (TLS, args[0].P->id, offline_mode, print_chat_info_gw, ev);
2015-05-01 13:19:12 -04:00
}
2015-05-14 08:48:20 -04:00
void do_chat_add_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 3);
if (ev) { ev->refcnt ++; }
tgl_do_add_user_to_chat (TLS, args[0].P->id, args[1].P->id, args[2].num != NOT_FOUND ? args[2].num : 100, print_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_chat_del_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
if (ev) { ev->refcnt ++; }
tgl_do_del_user_from_chat (TLS, args[0].P->id, args[1].P->id, print_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_create_group_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num >= 1 && arg_num <= 1000);
static tgl_peer_id_t ids[1000];
int i;
for (i = 0; i < arg_num - 1; i++) {
ids[i] = args[i + 1].P->id;
}
2014-09-17 17:03:20 -04:00
2015-05-14 08:48:20 -04:00
if (ev) { ev->refcnt ++; }
tgl_do_create_group_chat (TLS, arg_num - 1, ids, ARG2STR (0), print_success_gw, ev);
}
2014-09-17 17:03:20 -04:00
2015-05-14 08:48:20 -04:00
void do_export_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
2014-09-20 18:22:35 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_export_chat_link (TLS, args[0].P->id, print_string_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_import_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_import_chat_link (TLS, ARG2STR (0), print_success_gw, ev);
}
/* }}} */
/* {{{ WORKING WITH USERS */
void do_user_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
tgl_do_get_user_info (TLS, args[0].P->id, offline_mode, print_user_info_gw, ev);
}
void do_add_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 3);
if (ev) { ev->refcnt ++; }
tgl_do_add_contact (TLS, ARG2STR (0), ARG2STR (1), ARG2STR (2), 0, print_user_list_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-06 07:39:45 -04:00
void do_rename_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 3);
if (args[0].P->user.phone) {
2014-09-20 18:22:35 -04:00
if (ev) { ev->refcnt ++; }
tgl_do_add_contact (TLS, args[0].P->user.phone, strlen (args[0].P->user.phone), args[1].str, strlen (args[1].str), args[2].str, strlen (args[2].str), 0, print_user_list_gw, ev);
} else {
if (ev) { ev->refcnt ++; }
print_success_gw (TLS, ev, 0);
2014-09-17 17:03:20 -04:00
}
}
2015-05-14 08:48:20 -04:00
void do_del_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
tgl_do_del_contact (TLS, args[0].P->id, print_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_import_card (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
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;
if (ev) { ev->refcnt ++; }
tgl_do_import_card (TLS, pp, p, print_user_gw, ev);
}
2014-09-18 11:14:24 -04:00
}
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
/* {{{ WORKING WITH SECRET CHATS */
void do_accept_secret_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_accept_encr_chat_request (TLS, &args[0].P->encr_chat, print_encr_chat_success_gw, ev);
}
void do_set_ttl (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 2);
if (args[0].P->encr_chat.state == sc_ok) {
if (ev) { ev->refcnt ++; }
tgl_do_set_encr_chat_ttl (TLS, &args[0].P->encr_chat, args[1].num, print_msg_success_gw, ev);
} else {
if (ev) { ev->refcnt ++; }
print_success_gw (TLS, ev, 0);
}
2014-09-17 17:03:20 -04:00
}
2015-05-06 07:39:45 -04:00
void do_visualize_key (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
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 (TLS, id, buf);
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2014-09-17 17:03:20 -04:00
int i;
for (i = 0; i < 16; i++) {
int x = buf[i];
int j;
for (j = 0; j < 4; j ++) {
2014-09-20 18:22:35 -04:00
if (!ev) {
mpush_color (ev, colors[x & 3]);
mpush_color (ev, COLOR_INVERSE);
2015-05-14 08:48:20 -04:00
}
if (!disable_colors && !ev) {
mprintf (ev, " ");
} else {
switch (x & 3) {
case 0:
mprintf (ev, " ");
break;
case 1:
mprintf (ev, "--");
break;
case 2:
mprintf (ev, "==");
break;
case 3:
mprintf (ev, "||");
break;
}
}
if (!ev) {
mpop_color (ev);
mpop_color (ev);
}
x = x >> 2;
}
if (i & 1) {
mprintf (ev, "\n");
}
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
mprint_end (ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_create_secret_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_create_secret_chat (TLS, args[0].P->id, print_secret_chat_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
2014-09-17 17:03:20 -04:00
2015-05-14 08:48:20 -04:00
/* {{{ WORKING WITH DIALOG LIST */
void do_dialog_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num <= 2);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_get_dialog_list (TLS, args[0].num != NOT_FOUND ? args[0].num : 100, args[1].num != NOT_FOUND ? args[1].num : 0, print_dialog_list_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_contact_search (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 2);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_contact_search (TLS, args[0].str, strlen (args[0].str), args[1].num == NOT_FOUND ? args[1].num : 10, print_user_list_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_contact_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (!arg_num);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_update_contact_list (TLS, print_user_list_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
2014-10-09 13:38:45 -04:00
2015-05-14 08:48:20 -04:00
/* {{{ WORKING WITH ONE DIALOG */
2014-10-12 11:53:57 -04:00
2015-05-14 08:48:20 -04:00
void do_mark_read (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_mark_read (TLS, args[0].P->id, print_success_gw, ev);
}
2015-05-14 08:48:20 -04:00
void do_history (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 3);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_get_history (TLS, args[0].P->id, args[2].num != NOT_FOUND ? args[2].num : 0, args[1].num != NOT_FOUND ? args[1].num : 40, offline_mode, print_msg_list_gw, ev);
}
2015-05-14 08:48:20 -04:00
void do_send_typing (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_send_typing (TLS, args[0].P->id, tgl_typing_typing, print_success_gw, ev);
2014-10-12 11:53:57 -04:00
}
2015-05-14 08:48:20 -04:00
void do_send_typing_abort (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_send_typing (TLS, args[0].P->id, tgl_typing_cancel, print_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
/* {{{ WORKING WITH MEDIA */
#define DO_LOAD_PHOTO(tp,act,actf) \
void do_ ## act ## _ ## tp (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \
assert (arg_num == 1);\
struct tgl_message *M = tgl_message_get (TLS, args[0].num);\
if (M && !(M->flags & TGLMF_SERVICE)) {\
if (ev) { ev->refcnt ++; } \
if (M->media.type == tgl_message_media_photo) { \
tgl_do_load_photo (TLS, M->media.photo, actf, ev);\
} else if (M->media.type == tgl_message_media_document) {\
tgl_do_load_document (TLS, M->media.document, actf, ev);\
} else if (M->media.type == tgl_message_media_document_encr) {\
tgl_do_load_encr_document (TLS, M->media.encr_document, actf, ev); \
} else if (M->media.type == tgl_message_media_webpage) {\
actf (TLS, ev, 1, M->media.webpage->url);\
} else if (M->media.type == tgl_message_media_geo || M->media.type == tgl_message_media_venue) { \
static char s[1000]; \
sprintf (s, "https://maps.google.com/?q=%.6lf,%.6lf", M->media.geo.latitude, M->media.geo.longitude);\
actf (TLS, ev, 1, s);\
}\
}\
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
#define DO_LOAD_PHOTO_THUMB(tp,act,actf) \
void do_ ## act ## _ ## tp ## _thumb (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \
assert (arg_num == 1);\
struct tgl_message *M = tgl_message_get (TLS, args[0].num);\
if (M && !(M->flags & TGLMF_SERVICE)) {\
if (M->media.type == tgl_message_media_document) {\
if (ev) { ev->refcnt ++; } \
tgl_do_load_document_thumb (TLS, M->media.document, actf, ev);\
}\
}\
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
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(file, 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_THUMB(file, 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(file, open, open_filename_gw)
DO_LOAD_PHOTO_THUMB(video, open, open_filename_gw)
DO_LOAD_PHOTO_THUMB(document, open, open_filename_gw)
DO_LOAD_PHOTO_THUMB(file, open, open_filename_gw)
DO_LOAD_PHOTO(any, open, open_filename_gw)
void do_load_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2015-05-01 13:19:12 -04:00
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_load_file_location (TLS, &args[0].P->user.photo_big, print_filename_gw, ev);
2015-05-01 13:19:12 -04:00
}
2015-05-14 08:48:20 -04:00
void do_view_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-17 17:03:20 -04:00
assert (arg_num == 1);
2014-09-20 18:22:35 -04:00
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_load_file_location (TLS, &args[0].P->user.photo_big, open_filename_gw, ev);
2015-04-27 10:52:19 -04:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
2014-09-20 18:22:35 -04:00
2015-05-14 08:48:20 -04:00
/* {{{ ANOTHER MESSAGES FUNCTIONS */
void do_search (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
assert (arg_num == 6);
tgl_peer_id_t id;
if (args[0].P) {
id = args[0].P->id;
} else {
id = TGL_PEER_NOT_FOUND;
}
int limit;
if (args[1].num != NOT_FOUND) {
limit = args[1].num;
} 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;
}
int offset;
if (args[4].num != NOT_FOUND) {
offset = args[4].num;
} else {
offset = 0;
2014-09-20 18:22:35 -04:00
}
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_msg_search (TLS, id, from, to, limit, offset, args[5].str, strlen (args[5].str), print_msg_list_gw, ev);
}
2015-05-14 08:48:20 -04:00
void do_delete_msg (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_delete_msg (TLS, args[0].num, print_success_gw, ev);
2014-09-17 17:03:20 -04:00
}
2015-05-14 08:48:20 -04:00
void do_get_message (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2015-01-11 16:52:40 -05:00
assert (arg_num == 1);
if (ev) { ev->refcnt ++; }
2015-05-14 08:48:20 -04:00
tgl_do_get_message (TLS, args[0].num, print_msg_gw, ev);
2015-01-11 16:52:40 -05:00
}
2015-05-14 08:48:20 -04:00
/* }}} */
extern char *default_username;
extern char *config_filename;
extern char *prefix;
extern char *auth_file_name;
extern char *state_file_name;
extern char *secret_chat_file_name;
extern char *downloads_directory;
extern char *config_directory;
extern char *binlog_file_name;
extern char *lua_file;
2015-05-02 07:49:21 -04:00
extern char *python_file;
2014-09-23 09:18:42 -04:00
extern struct event *term_ev;
2015-05-06 07:39:45 -04:00
void do_clear (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
2014-09-23 10:39:28 -04:00
logprintf ("Do_clear\n");
free (default_username);
free (config_filename);
//free (prefix);
free (auth_file_name);
free (state_file_name);
free (secret_chat_file_name);
free (downloads_directory);
free (config_directory);
free (binlog_file_name);
free (lua_file);
2015-05-02 07:49:21 -04:00
free (python_file);
2014-09-23 09:18:42 -04:00
clear_history ();
event_free (term_ev);
struct event_base *ev_base = TLS->ev_base;
2014-11-11 12:13:41 -05:00
tgl_free_all (TLS);
event_base_free (ev_base);
do_halt (0);
}
2015-05-06 07:39:45 -04:00
#define MAX_COMMANDS_SIZE 1000
struct command commands[MAX_COMMANDS_SIZE] = {
{"accept_secret_chat", {ca_secret_chat, ca_none}, do_accept_secret_chat, "accept_secret_chat <secret chat>\tAccepts secret chat. Only useful with -E option", NULL},
{"add_contact", {ca_string, ca_string, ca_string, ca_none}, do_add_contact, "add_contact <phone> <first name> <last name>\tTries to add user to contact list", NULL},
{"broadcast", {ca_user, ca_period, ca_string_end, ca_none}, do_broadcast, "broadcast <user>+ <text>\tSends text to several users at once", NULL},
{"chat_add_user", {ca_chat, ca_user, ca_number | ca_optional, ca_none}, do_chat_add_user, "chat_add_user <chat> <user> [msgs-to-forward]\tAdds user to chat. Sends him last msgs-to-forward message from this chat. Default 100", NULL},
{"chat_del_user", {ca_chat, ca_user, ca_none}, do_chat_del_user, "chat_del_user <chat> <user>\tDeletes user from chat", NULL},
{"chat_info", {ca_chat, ca_none}, do_chat_info, "chat_info <chat>\tPrints info about chat (id, members, admin, etc.)", NULL},
{"chat_set_photo", {ca_chat, ca_file_name_end, ca_none}, do_chat_set_photo, "chat_set_photo <chat> <filename>\tSets chat photo. Photo will be cropped to square", NULL},
{"chat_with_peer", {ca_peer, ca_none}, do_chat_with_peer, "chat_with_peer <peer>\tInterface option. All input will be treated as messages to this peer. Type /quit to end this mode", NULL},
{"clear", {ca_none}, do_clear, "clear\tClears all data and exits. For debug.", NULL},
{"contact_list", {ca_none}, do_contact_list, "contact_list\tPrints contact list", NULL},
{"contact_search", {ca_string, ca_number | ca_optional, ca_none}, do_contact_search, "contact_search username [limit]\tSearches contacts by username", NULL},
{"create_group_chat", {ca_string, ca_user, ca_period, ca_none}, do_create_group_chat, "create_group_chat <name> <user>+\tCreates group chat with users", NULL},
{"create_secret_chat", {ca_user, ca_none}, do_create_secret_chat, "create_secret_chat <user>\tStarts creation of secret chat", NULL},
{"del_contact", {ca_user, ca_none}, do_del_contact, "del_contact <user>\tDeletes contact from contact list", NULL},
{"delete_msg", {ca_number, ca_none}, do_delete_msg, "delete_msg <msg-id>\tDeletes message", NULL},
{"dialog_list", {ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_dialog_list, "dialog_list [limit=100] [offset=0]\tList of last conversations", NULL},
{"export_card", {ca_none}, do_export_card, "export_card\tPrints card that can be imported by another user with import_card method", NULL},
{"export_chat_link", {ca_chat, ca_none}, do_export_chat_link, "export_chat_link\tPrints chat link that can be used to join to chat", NULL},
{"fwd", {ca_peer, ca_number, ca_period, ca_none}, do_fwd, "fwd <peer> <msg-id>+\tForwards message to peer. Forward to secret chats is forbidden", NULL},
{"fwd_media", {ca_peer, ca_number, ca_none}, do_fwd_media, "fwd <peer> <msg-id>\tForwards message media to peer. Forward to secret chats is forbidden. Result slightly differs from fwd", NULL},
{"get_message", {ca_number, ca_none}, do_get_message, "get_message <msg-id>\tGet message by id", NULL},
{"help", {ca_none}, do_help, "help\tPrints this help", NULL},
{"history", {ca_peer, ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_history, "history <peer> [limit] [offset]\tPrints messages with this peer (most recent message lower). Also marks messages as read", NULL},
{"import_card", {ca_string, ca_none}, do_import_card, "import_card <card>\tGets user by card and prints it name. You can then send messages to him as usual", NULL},
{"import_chat_link", {ca_string, ca_none}, do_import_chat_link, "impoty_chat_link <hash>\tJoins to chat by link", NULL},
{"load_audio", {ca_number, ca_none}, do_load_audio, "load_audio <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_chat_photo", {ca_chat, ca_none}, do_load_user_photo, "load_chat_photo <chat>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_document", {ca_number, ca_none}, do_load_document, "load_document <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_document_thumb", {ca_number, ca_none}, do_load_document_thumb, "load_document_thumb <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_file", {ca_number, ca_none}, do_load_file, "load_file <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_file_thumb", {ca_number, ca_none}, do_load_file_thumb, "load_file_thumb <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_photo", {ca_number, ca_none}, do_load_photo, "load_photo <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_user_photo", {ca_user, ca_none}, do_load_user_photo, "load_user_photo <user>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_video", {ca_number, ca_none}, do_load_video, "load_video <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"load_video_thumb", {ca_number, ca_none}, do_load_video_thumb, "load_video_thumb <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
{"main_session", {ca_none}, do_main_session, "main_session\tSends updates to this connection (or terminal). Useful only with listening socket", NULL},
{"mark_read", {ca_peer, ca_none}, do_mark_read, "mark_read <peer>\tMarks messages with peer as read", NULL},
{"msg", {ca_peer, ca_string_end, ca_none}, do_msg, "msg <peer> <text>\tSends text message to peer", NULL},
{"quit", {ca_none}, do_quit, "quit\tQuits immediately", NULL},
{"rename_chat", {ca_chat, ca_string_end, ca_none}, do_rename_chat, "rename_chat <chat> <new name>\tRenames chat", NULL},
{"rename_contact", {ca_user, ca_string, ca_string, ca_none}, do_rename_contact, "rename_contact <user> <first name> <last name>\tRenames contact", NULL},
{"reply", {ca_number, ca_string_end, ca_none}, do_reply, "msg <msg-id> <text>\tSends text reply to message", NULL},
{"reply_audio", {ca_number, ca_file_name, ca_none}, do_send_audio, "reply_audio <msg-id> <file>\tSends audio to peer", NULL},
{"reply_contact", {ca_number, ca_string, ca_string, ca_string, ca_none}, do_reply_contact, "reply_contact <msg-id> <phone> <first-name> <last-name>\tSends contact (not necessary telegram user)", NULL},
{"reply_document", {ca_number, ca_file_name, ca_none}, do_reply_document, "reply_document <msg-id> <file>\tSends document to peer", NULL},
{"reply_file", {ca_number, ca_file_name, ca_none}, do_reply_file, "reply_file <msg-id> <file>\tSends document to peer", NULL},
{"reply_location", {ca_number, ca_double, ca_double, ca_none}, do_reply_location, "reply_location <msg-id> <latitude> <longitude>\tSends geo location", NULL},
{"reply_photo", {ca_number, ca_file_name, ca_string_end | ca_optional, ca_none}, do_reply_photo, "reply_photo <msg-id> <file> [caption]\tSends photo to peer", NULL},
//{"reply_text", {ca_number, ca_file_name_end, ca_none}, do_reply_text, "reply_text <msg-id> <file>\tSends contents of text file as plain text message", NULL},
{"reply_video", {ca_number, ca_file_name, ca_none}, do_reply_video, "reply_video <msg-id> <file>\tSends video to peer", NULL},
// {"restore_msg", {ca_number, ca_none}, do_restore_msg, "restore_msg <msg-id>\tRestores message. Only available shortly (one hour?) after deletion", NULL},
{"safe_quit", {ca_none}, do_safe_quit, "safe_quit\tWaits for all queries to end, then quits", NULL},
{"search", {ca_peer | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_number | ca_optional, ca_string_end}, do_search, "search [peer] [limit] [from] [to] [offset] pattern\tSearch for pattern in messages from date from to date to (unixtime) in messages with peer (if peer not present, in all messages)", NULL},
2015-05-14 08:48:20 -04:00
//{"secret_chat_rekey", { ca_secret_chat, ca_none}, do_secret_chat_rekey, "generate new key for active secret chat", NULL},
2015-05-06 07:39:45 -04:00
{"send_audio", {ca_peer, ca_file_name, ca_none}, do_send_audio, "send_audio <peer> <file>\tSends audio to peer", NULL},
{"send_contact", {ca_peer, ca_string, ca_string, ca_string, ca_none}, do_send_contact, "send_contact <peer> <phone> <first-name> <last-name>\tSends contact (not necessary telegram user)", NULL},
{"send_document", {ca_peer, ca_file_name, ca_none}, do_send_document, "send_document <peer> <file>\tSends document to peer", NULL},
{"send_file", {ca_peer, ca_file_name, ca_none}, do_send_file, "send_file <peer> <file>\tSends document to peer", NULL},
{"send_location", {ca_peer, ca_double, ca_double, ca_none}, do_send_location, "send_location <peer> <latitude> <longitude>\tSends geo location", NULL},
{"send_photo", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_photo, "send_photo <peer> <file> [caption]\tSends photo to peer", NULL},
{"send_text", {ca_peer, ca_file_name_end, ca_none}, do_send_text, "send_text <peer> <file>\tSends contents of text file as plain text message", NULL},
{"send_typing", {ca_peer, ca_none}, do_send_typing, "send_typing <peer>\tSends typing notification", NULL},
{"send_typing_abort", {ca_peer, ca_none}, do_send_typing_abort, "send_typing <peer>\tSends typing notification abort", NULL},
{"send_video", {ca_peer, ca_file_name, ca_string | ca_optional, ca_none}, do_send_video, "send_video <peer> <file> [caption]\tSends video to peer", NULL},
{"set", {ca_string, ca_number, ca_none}, do_set, "set <param> <value>\tSets value of param. Currently available: log_level, debug_verbosity, alarm, msg_num", NULL},
{"set_password", {ca_string | ca_optional, ca_none}, do_set_password, "set_password <hint>\tSets password", NULL},
{"set_profile_name", {ca_string, ca_string, ca_none}, do_set_profile_name, "set_profile_name <first-name> <last-name>\tSets profile name.", NULL},
{"set_profile_photo", {ca_file_name_end, ca_none}, do_set_profile_photo, "set_profile_photo <filename>\tSets profile photo. Photo will be cropped to square", NULL},
{"set_ttl", {ca_secret_chat, ca_number, ca_none}, do_set_ttl, "set_ttl <secret chat>\tSets secret chat ttl. Client itself ignores ttl", NULL},
{"set_username", {ca_string, ca_none}, do_set_username, "set_username <name>\tSets username.", NULL},
{"show_license", {ca_none}, do_show_license, "show_license\tPrints contents of GPL license", NULL},
{"stats", {ca_none}, do_stats, "stats\tFor debug purpose", NULL},
{"status_online", {ca_none}, do_status_online, "status_online\tSets status as online", NULL},
{"status_offline", {ca_none}, do_status_offline, "status_offline\tSets status as offline", NULL},
{"user_info", {ca_user, ca_none}, do_user_info, "user_info <user>\tPrints info about user (id, last online, phone)", NULL},
{"view_audio", {ca_number, ca_none}, do_open_audio, "view_audio <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_chat_photo", {ca_chat, ca_none}, do_view_user_photo, "view_chat_photo <chat>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_document", {ca_number, ca_none}, do_open_document, "view_document <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_document_thumb", {ca_number, ca_none}, do_open_document_thumb, "view_document_thumb <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_file", {ca_number, ca_none}, do_open_file, "view_file <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_file_thumb", {ca_number, ca_none}, do_open_file_thumb, "view_file_thumb <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_photo", {ca_number, ca_none}, do_open_photo, "view_photo <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_user_photo", {ca_user, ca_none}, do_view_user_photo, "view_user_photo <user>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_video", {ca_number, ca_none}, do_open_video, "view_video <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view_video_thumb", {ca_number, ca_none}, do_open_video_thumb, "view_video_thumb <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
{"view", {ca_number, ca_none}, do_open_any, "view <msg-id>\tTries to view message contents", NULL},
{"visualize_key", {ca_secret_chat, ca_none}, do_visualize_key, "visualize_key <secret chat>\tPrints visualization of encryption key (first 16 bytes sha1 of it in fact}", NULL}
};
2015-05-06 07:39:45 -04:00
void register_new_command (struct command *cmd) {
int i = 0;
while (commands[i].name) {
i ++;
}
assert (i < MAX_COMMANDS_SIZE - 1);
commands[i] = *cmd;
}
enum command_argument get_complete_mode (void) {
2014-09-17 17:03:20 -04:00
force_end_mode = 0;
2013-10-29 20:08:30 -04:00
line_ptr = rl_line_buffer;
2014-09-17 17:03:20 -04:00
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;
}
2014-09-17 17:03:20 -04:00
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;
2013-10-03 08:38:25 -04:00
int n = 0;
struct tgl_command;
while (command->name) {
2014-09-17 17:03:20 -04:00
if (is_same_word (cur_token, cur_token_len, command->name)) {
2013-10-03 08:38:25 -04:00
break;
}
n ++;
command ++;
}
2014-09-17 17:03:20 -04:00
if (!command->name) {
return ca_none;
}
enum command_argument *flags = command->args;
2013-10-03 08:38:25 -04:00
while (1) {
int period = 0;
2014-09-17 17:03:20 -04:00
if (*flags == ca_period) {
flags --;
period = 1;
}
2014-09-17 17:03:20 -04:00
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;
}
}
2014-09-17 17:03:20 -04:00
char *save = line_ptr;
next_token ();
2014-10-03 05:35:02 -04:00
if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double) {
2014-09-17 17:03:20 -04:00
if (cur_token_quoted) {
if (opt) {
line_ptr = save;
flags ++;
continue;
} else if (period) {
line_ptr = save;
flags += 2;
continue;
2014-09-17 17:03:20 -04:00
} 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;
2014-10-03 05:35:02 -04:00
case ca_double:
ok = (cur_token_double () != NOT_FOUND);
break;
2014-09-17 17:03:20 -04:00
default:
assert (0);
}
if (opt && !ok) {
line_ptr = save;
flags ++;
continue;
}
if (period && !ok) {
line_ptr = save;
flags += 2;
continue;
}
2014-09-17 17:03:20 -04:00
if (!ok) {
return ca_none;
}
flags ++;
continue;
}
}
2014-09-17 17:03:20 -04:00
if (op == ca_string || op == ca_file_name) {
if (cur_token_end_str) {
return op;
} else {
flags ++;
continue;
}
2013-10-29 20:08:30 -04:00
}
2014-09-17 17:03:20 -04:00
assert (0);
2013-10-03 08:38:25 -04:00
}
}
int complete_string_list (char **list, int index, const char *text, int len, char **R) {
index ++;
2013-10-03 12:09:06 -04:00
while (list[index] && strncmp (list[index], text, len)) {
2013-10-03 08:38:25 -04:00
index ++;
}
2013-10-03 12:09:06 -04:00
if (list[index]) {
*R = strdup (list[index]);
assert (*R);
2013-10-03 08:38:25 -04:00
return index;
} else {
*R = 0;
return -1;
}
}
void print_msg_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M);
void print_encr_chat_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E);;
void print_success_gw (struct tgl_state *TLS, void *extra, int success);
int complete_command_list (int index, const char *text, int len, char **R) {
index ++;
while (commands[index].name && strncmp (commands[index].name, text, len)) {
index ++;
}
if (commands[index].name) {
*R = strdup (commands[index].name);
assert (*R);
return index;
} else {
*R = 0;
return -1;
}
}
2013-10-03 08:38:25 -04:00
char *command_generator (const char *text, int state) {
#ifndef DISABLE_EXTF
static int len;
#endif
static int index;
static enum command_argument mode;
2014-09-17 17:03:20 -04:00
static char *command_pos;
static int command_len;
2013-12-06 12:14:41 -05:00
if (in_chat_mode) {
char *R = 0;
index = complete_string_list (in_chat_commands, index, text, rl_point, &R);
return R;
}
2013-10-03 12:09:06 -04:00
2013-10-28 17:56:17 -04:00
char c = 0;
2014-09-17 17:03:20 -04:00
c = rl_line_buffer[rl_point];
rl_line_buffer[rl_point] = 0;
2013-10-03 08:38:25 -04:00
if (!state) {
#ifndef DISABLE_EXTF
2013-10-03 08:38:25 -04:00
len = strlen (text);
#endif
2013-10-03 08:38:25 -04:00
index = -1;
2013-10-28 17:56:17 -04:00
2013-10-03 08:38:25 -04:00
mode = get_complete_mode ();
2014-09-17 17:03:20 -04:00
command_pos = cur_token;
command_len = cur_token_len;
2013-10-03 08:38:25 -04:00
} else {
if (mode != ca_file_name && mode != ca_file_name_end && index == -1) { return 0; }
2013-10-03 08:38:25 -04:00
}
2014-10-03 05:35:02 -04:00
if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double) {
2013-10-28 17:57:22 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
return 0;
}
2014-09-17 17:03:20 -04:00
assert (command_len >= 0);
2013-10-03 08:38:25 -04:00
char *R = 0;
2014-09-17 17:03:20 -04:00
switch (mode & 255) {
case ca_command:
2014-09-17 17:03:20 -04:00
index = complete_command_list (index, command_pos, command_len, &R);
2013-10-28 17:56:17 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
2013-10-03 08:38:25 -04:00
return R;
case ca_user:
index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R);
2013-10-28 17:56:17 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
2013-10-03 08:38:25 -04:00
return R;
case ca_peer:
index = tgl_complete_peer_list (TLS, index, command_pos, command_len, &R);
2013-10-28 17:56:17 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
2013-10-03 08:38:25 -04:00
return R;
case ca_file_name:
case ca_file_name_end:
2013-10-28 17:56:17 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
2014-09-20 18:22:35 -04:00
R = rl_filename_completion_function (command_pos, state);
2013-10-28 17:56:17 -04:00
return R;
case ca_chat:
index = tgl_complete_chat_list (TLS, index, command_pos, command_len, &R);
2013-10-28 17:56:17 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
2013-10-23 06:24:59 -04:00
return R;
case ca_secret_chat:
index = tgl_complete_encr_chat_list (TLS, index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_modifier:
2014-09-17 17:03:20 -04:00
index = complete_string_list (modifiers, index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
#ifndef DISABLE_EXTF
2014-09-10 07:52:42 -04:00
case ca_extf:
index = tglf_extf_autocomplete (TLS, text, len, index, &R, rl_line_buffer, rl_point);
2014-09-17 17:03:20 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
2014-09-10 07:52:42 -04:00
return R;
#endif
2013-10-03 08:38:25 -04:00
default:
2013-10-28 17:56:17 -04:00
if (c) { rl_line_buffer[rl_point] = c; }
2013-10-03 08:38:25 -04:00
return 0;
}
}
2013-11-25 12:16:34 -05:00
int count = 1;
void work_modifier (const char *s, int l) {
if (is_same_word (s, l, "[offline]")) {
offline_mode = 1;
}
2015-05-14 08:48:20 -04:00
if (sscanf (s, "[reply=%d]", &reply_id) >= 1) {
}
if (is_same_word (s, l, "[disable_preview]")) {
disable_msg_preview = TGL_SEND_MSG_FLAG_DISABLE_PREVIEW;
}
if (is_same_word (s, l, "[enable_preview]")) {
disable_msg_preview = TGL_SEND_MSG_FLAG_ENABLE_PREVIEW;
}
2013-11-25 12:16:34 -05:00
#ifdef ALLOW_MULT
if (sscanf (s, "[x%d]", &count) >= 1) {
}
#endif
2013-10-29 20:08:30 -04:00
}
void print_fail (struct in_ev *ev) {
2015-04-28 08:21:50 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
2015-05-14 08:48:20 -04:00
mprintf (ev, "FAIL: %d: %s\n", TLS->error_code, TLS->error);
2015-05-11 07:20:34 -04:00
} else {
#ifdef USE_JSON
json_t *res = json_object ();
assert (json_object_set (res, "result", json_string ("FAIL")) >= 0);
2015-05-14 08:48:20 -04:00
assert (json_object_set (res, "error_code", json_integer (TLS->error_code)) >= 0);
assert (json_object_set (res, "error", json_string (TLS->error)) >= 0);
2015-05-11 07:20:34 -04:00
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2015-04-28 08:21:50 -04:00
mprint_end (ev);
}
2015-05-15 06:31:38 -04:00
void fail_interface (struct tgl_state *TLS, struct in_ev *ev, int error_code, const char *format, ...) __attribute__ (( format (printf, 4, 5)));
void fail_interface (struct tgl_state *TLS, struct in_ev *ev, int error_code, const char *format, ...) {
static char error[1001];
va_list ap;
va_start (ap, format);
int error_len = vsnprintf (error, 1000, format, ap);
va_end (ap);
if (error_len > 1000) { error_len = 1000; }
error[error_len] = 0;
mprint_start (ev);
if (!enable_json) {
mprintf (ev, "FAIL: %d: %s\n", error_code, error);
} else {
#ifdef USE_JSON
json_t *res = json_object ();
assert (json_object_set (res, "result", json_string ("FAIL")) >= 0);
assert (json_object_set (res, "error_code", json_integer (error_code)) >= 0);
assert (json_object_set (res, "error", json_string (error)) >= 0);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
mprint_end (ev);
}
void print_success (struct in_ev *ev) {
2015-05-11 07:20:34 -04:00
if (ev || enable_json) {
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mprintf (ev, "SUCCESS\n");
} else {
#ifdef USE_JSON
json_t *res = json_object ();
assert (json_object_set (res, "result", json_string ("SUCCESS")) >= 0);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
mprint_end (ev);
}
}
2015-05-11 07:20:34 -04:00
void print_success_gw (struct tgl_state *TLSR, void *extra, int success) {
assert (TLS == TLSR);
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
else { print_success (ev); return; }
}
void print_msg_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M) {
2014-11-10 06:02:14 -05:00
write_secret_chat_file ();
print_success_gw (TLS, extra, success);
}
void print_msg_list_success_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_message *ML[]) {
assert (TLS == TLSR);
print_success_gw (TLSR, extra, success);
}
void print_encr_chat_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E) {
2014-11-10 06:02:14 -05:00
write_secret_chat_file ();
print_success_gw (TLS, extra, success);
}
void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_message *ML[]) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2015-05-11 07:20:34 -04:00
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
int i;
for (i = num - 1; i >= 0; i--) {
print_message (ev, ML[i]);
}
} else {
#ifdef USE_JSON
json_t *res = json_array ();
int i;
for (i = num - 1; i >= 0; i--) {
json_t *a = json_pack_message (ML[i]);
assert (json_array_append (res, a) >= 0);
}
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
2014-08-14 18:16:01 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
void print_msg_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_message *M) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
print_message (ev, M);
} else {
#ifdef USE_JSON
json_t *res = json_pack_message (M);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
void print_user_list_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_user *UL[]) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
int i;
for (i = num - 1; i >= 0; i--) {
print_user_name (ev, UL[i]->id, (void *)UL[i]);
mprintf (ev, "\n");
}
} else {
#ifdef USE_JSON
json_t *res = json_array ();
int i;
for (i = num - 1; i >= 0; i--) {
json_t *a = json_pack_peer (UL[i]->id, (void *)UL[i]);
assert (json_array_append (res, a) >= 0);
}
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
2014-08-14 18:16:01 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
void print_user_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_user *U) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
print_user_name (ev, U->id, (void *)U);
mprintf (ev, "\n");
} else {
#ifdef USE_JSON
json_t *res = json_pack_peer (U->id, (void *)U);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-29 11:46:04 -04:00
}
2015-05-14 08:48:20 -04:00
void print_filename_gw (struct tgl_state *TLSR, void *extra, int success, const char *name) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mprintf (ev, "Saved to %s\n", name);
} else {
#ifdef USE_JSON
json_t *res = json_object ();
assert (json_object_set (res, "result", json_string (name)) >= 0);
assert (json_object_set (res, "event", json_string ("download")) >= 0);
2015-05-11 07:20:34 -04:00
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
2015-05-01 13:19:12 -04:00
void print_string_gw (struct tgl_state *TLSR, void *extra, int success, const char *name) {
assert (TLS == TLSR);
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
mprint_start (ev);
2015-05-11 07:20:34 -04:00
mprint_start (ev);
if (!enable_json) {
mprintf (ev, "%s\n", name);
} else {
#ifdef USE_JSON
json_t *res = json_object ();
assert (json_object_set (res, "result", json_string (name)) >= 0);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2015-05-01 13:19:12 -04:00
mprint_end (ev);
}
2015-05-14 08:48:20 -04:00
void open_filename_gw (struct tgl_state *TLSR, void *extra, int success, const char *name) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (ev) { return; }
if (!success) { print_fail (ev); return; }
2014-08-14 18:16:01 -04:00
static char buf[PATH_MAX];
if (snprintf (buf, sizeof (buf), OPEN_BIN, name) >= (int) sizeof (buf)) {
logprintf ("Open image command buffer overflow\n");
} else {
2015-04-22 13:09:53 -04:00
int pid = fork ();
if (!pid) {
execl("/bin/sh", "sh", "-c", buf, (char *) 0);
exit (0);
2014-08-14 18:16:01 -04:00
}
}
}
void print_chat_info_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_chat *C) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
tgl_peer_t *U = (void *)C;
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "Chat ");
print_chat_name (ev, U->id, U);
mprintf (ev, " (id %d) members:\n", tgl_get_peer_id (U->id));
int i;
for (i = 0; i < C->user_list_size; i++) {
mprintf (ev, "\t\t");
print_user_name (ev, TGL_MK_USER (C->user_list[i].user_id), tgl_peer_get (TLS, TGL_MK_USER (C->user_list[i].user_id)));
mprintf (ev, " invited by ");
print_user_name (ev, TGL_MK_USER (C->user_list[i].inviter_id), tgl_peer_get (TLS, TGL_MK_USER (C->user_list[i].inviter_id)));
mprintf (ev, " at ");
print_date_full (ev, C->user_list[i].date);
if (C->user_list[i].user_id == C->admin_id) {
mprintf (ev, " admin");
}
mprintf (ev, "\n");
2014-08-14 18:16:01 -04:00
}
2015-05-11 07:20:34 -04:00
mpop_color (ev);
} else {
#ifdef USE_JSON
json_t *res = json_pack_peer (C->id, (void *)C);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
2014-08-14 18:16:01 -04:00
}
2015-05-11 07:20:34 -04:00
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
2014-11-15 06:45:37 -05:00
void print_user_status (struct tgl_user_status *S, struct in_ev *ev) {
2015-05-11 07:20:34 -04:00
if (enable_json) { return; }
2014-11-15 06:45:37 -05:00
if (S->online > 0) {
2015-01-09 06:54:46 -05:00
mprintf (ev, "online (was online ");
print_date_full (ev, S->when);
mprintf (ev, ")");
2014-11-15 06:45:37 -05:00
} else {
if (S->online == 0) {
mprintf (ev, "offline");
} else if (S->online == -1) {
mprintf (ev, "offline (was online ");
print_date_full (ev, S->when);
mprintf (ev, ")");
} else if (S->online == -2) {
mprintf (ev, "offline (was online recently)");
} else if (S->online == -3) {
mprintf (ev, "offline (was online last week)");
} else if (S->online == -4) {
mprintf (ev, "offline (was online last month)");
}
}
}
void print_user_info_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_user *U) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
tgl_peer_t *C = (void *)U;
if (!enable_json) {
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "User ");
print_user_name (ev, U->id, C);
if (U->username) {
mprintf (ev, " @%s", U->username);
}
mprintf (ev, " (#%d):\n", tgl_get_peer_id (U->id));
mprintf (ev, "\treal name: %s %s\n", U->real_first_name, U->real_last_name);
mprintf (ev, "\tphone: %s\n", U->phone);
mprintf (ev, "\t");
print_user_status (&U->status, ev);
mprintf (ev, "\n");
mpop_color (ev);
} else {
#ifdef USE_JSON
json_t *res = json_pack_peer (U->id, (void *)U);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
void print_secret_chat_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_secret_chat *E) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, " Encrypted chat ");
print_encr_chat_name (ev, E->id, (void *)E);
mprintf (ev, " is now in wait state\n");
mpop_color (ev);
} else {
#ifdef USE_JSON
json_t *res = json_pack_peer (E->id, (void *)E);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
2013-12-06 12:14:41 -05:00
void print_dialog_list_gw (struct tgl_state *TLSR, void *extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) {
assert (TLS == TLSR);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mpush_color (ev, COLOR_YELLOW);
int i;
for (i = size - 1; i >= 0; i--) {
tgl_peer_t *UC;
switch (tgl_get_peer_type (peers[i])) {
case TGL_PEER_USER:
UC = tgl_peer_get (TLS, peers[i]);
mprintf (ev, "User ");
print_user_name (ev, peers[i], UC);
mprintf (ev, ": %d unread\n", unread_count[i]);
break;
case TGL_PEER_CHAT:
UC = tgl_peer_get (TLS, peers[i]);
mprintf (ev, "Chat ");
print_chat_name (ev, peers[i], UC);
mprintf (ev, ": %d unread\n", unread_count[i]);
break;
}
2014-08-14 18:16:01 -04:00
}
2015-05-11 07:20:34 -04:00
mpop_color (ev);
} else {
#ifdef USE_JSON
json_t *res = json_array ();
int i;
for (i = size - 1; i >= 0; i--) {
json_t *a = json_pack_peer (peers[i], tgl_peer_get (TLS, peers[i]));
assert (json_array_append (res, a) >= 0);
}
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
2014-08-14 18:16:01 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
2013-12-06 12:14:41 -05:00
void interpreter_chat_mode (char *line) {
if (line == NULL || /* EOF received */
!strncmp (line, "/exit", 5) || !strncmp (line, "/quit", 5)) {
2013-12-06 12:14:41 -05:00
in_chat_mode = 0;
update_prompt ();
return;
}
if (!strncmp (line, "/history", 8)) {
int limit = 40;
sscanf (line, "/history %99d", &limit);
if (limit < 0 || limit > 1000) { limit = 40; }
2015-05-14 08:48:20 -04:00
tgl_do_get_history (TLS, chat_mode_id, 0, limit, offline_mode, print_msg_list_gw, 0);
return;
}
if (!strncmp (line, "/read", 5)) {
tgl_do_mark_read (TLS, chat_mode_id, 0, 0);
return;
}
if (strlen (line) > 0) {
2015-05-14 08:48:20 -04:00
tgl_do_send_message (TLS, chat_mode_id, line, strlen (line), 0, 0, 0);
}
2013-12-06 12:14:41 -05:00
}
2014-08-21 16:35:27 -04:00
#define MAX_UNREAD_MESSAGE_COUNT 10000
struct tgl_message *unread_message_list[MAX_UNREAD_MESSAGE_COUNT];
int unread_message_count;
struct event *unread_message_event;
2014-09-20 18:22:35 -04:00
2014-08-21 16:35:27 -04:00
void print_read_list (int num, struct tgl_message *list[]) {
2014-09-20 18:22:35 -04:00
struct in_ev *ev = notify_ev;
2014-08-21 16:35:27 -04:00
int i;
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2014-08-21 16:35:27 -04:00
for (i = 0; i < num; i++) if (list[i]) {
if (enable_json) {
#ifdef USE_JSON
json_t *res = json_pack_read (list[i]);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-08-21 16:35:27 -04:00
tgl_peer_id_t to_id;
if (tgl_get_peer_type (list[i]->to_id) == TGL_PEER_USER && tgl_get_peer_id (list[i]->to_id) == TLS->our_id) {
2014-08-21 16:35:27 -04:00
to_id = list[i]->from_id;
} else {
to_id = list[i]->to_id;
}
int j;
int c1 = 0;
int c2 = 0;
for (j = i; j < num; j++) if (list[j]) {
tgl_peer_id_t end_id;
if (tgl_get_peer_type (list[j]->to_id) == TGL_PEER_USER && tgl_get_peer_id (list[j]->to_id) == TLS->our_id) {
2014-08-21 16:35:27 -04:00
end_id = list[j]->from_id;
} else {
end_id = list[j]->to_id;
}
if (!tgl_cmp_peer_id (to_id, end_id)) {
2015-04-22 13:09:53 -04:00
if (list[j]->flags & TGLMF_OUT) {
2014-08-21 16:35:27 -04:00
c1 ++;
} else {
c2 ++;
}
list[j] = 0;
}
}
assert (c1 + c2 > 0);
if (!enable_json) {
mpush_color (ev, COLOR_YELLOW);
switch (tgl_get_peer_type (to_id)) {
case TGL_PEER_USER:
mprintf (ev, "User ");
print_user_name (ev, to_id, tgl_peer_get (TLS, to_id));
break;
case TGL_PEER_CHAT:
mprintf (ev, "Chat ");
print_chat_name (ev, to_id, tgl_peer_get (TLS, to_id));
break;
case TGL_PEER_ENCR_CHAT:
mprintf (ev, "Secret chat ");
print_encr_chat_name (ev, to_id, tgl_peer_get (TLS, to_id));
break;
default:
assert (0);
}
mprintf (ev, " marked read %d outbox and %d inbox messages\n", c1, c2);
mpop_color (ev);
2015-05-15 10:50:07 -04:00
}
2014-08-21 16:35:27 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-21 16:35:27 -04:00
}
void unread_message_alarm (evutil_socket_t fd, short what, void *arg) {
print_read_list (unread_message_count, unread_message_list);
unread_message_count = 0;
event_free (unread_message_event);
unread_message_event = 0;
}
void mark_read_upd (struct tgl_state *TLSR, int num, struct tgl_message *list[]) {
assert (TLSR == TLS);
2014-08-21 11:38:51 -04:00
if (!binlog_read) { return; }
2014-08-14 18:16:01 -04:00
if (log_level < 1) { return; }
2014-08-21 11:38:51 -04:00
2014-08-21 16:35:27 -04:00
if (unread_message_count + num <= MAX_UNREAD_MESSAGE_COUNT) {
memcpy (unread_message_list + unread_message_count, list, num * sizeof (void *));
unread_message_count += num;
if (!unread_message_event) {
unread_message_event = evtimer_new (TLS->ev_base, unread_message_alarm, 0);
2014-08-21 16:35:27 -04:00
static struct timeval ptimeout = { 1, 0};
event_add (unread_message_event, &ptimeout);
}
} else {
print_read_list (unread_message_count, unread_message_list);
print_read_list (num, list);
unread_message_count = 0;
if (unread_message_event) {
event_free (unread_message_event);
unread_message_event = 0;
}
}
2014-08-14 18:16:01 -04:00
}
void print_typing (struct in_ev *ev, enum tgl_typing_status status) {
switch (status) {
case tgl_typing_none:
mprintf (ev, "doing nothing");
break;
case tgl_typing_typing:
mprintf (ev, "typing");
break;
case tgl_typing_cancel:
mprintf (ev, "deleting typed message");
break;
case tgl_typing_record_video:
mprintf (ev, "recording video");
break;
case tgl_typing_upload_video:
mprintf (ev, "uploading video");
break;
case tgl_typing_record_audio:
mprintf (ev, "recording audio");
break;
case tgl_typing_upload_audio:
mprintf (ev, "uploading audio");
break;
case tgl_typing_upload_photo:
mprintf (ev, "uploading photo");
break;
case tgl_typing_upload_document:
mprintf (ev, "uploading document");
break;
case tgl_typing_geo:
mprintf (ev, "choosing location");
break;
case tgl_typing_choose_contact:
mprintf (ev, "choosing contact");
break;
}
}
void type_notification_upd (struct tgl_state *TLSR, struct tgl_user *U, enum tgl_typing_status status) {
assert (TLSR == TLS);
2014-09-20 18:22:35 -04:00
if (log_level < 2 || (disable_output && !notify_ev)) { return; }
2015-05-11 07:20:34 -04:00
if (enable_json) { return; }
2014-09-20 18:22:35 -04:00
struct in_ev *ev = notify_ev;
mprint_start (ev);
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "User ");
print_user_name (ev, U->id, (void *)U);
mprintf (ev, " is ");
print_typing (ev, status);
mprintf (ev, "\n");
2014-09-20 18:22:35 -04:00
mpop_color (ev);
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
void type_in_chat_notification_upd (struct tgl_state *TLSR, struct tgl_user *U, struct tgl_chat *C, enum tgl_typing_status status) {
assert (TLSR == TLS);
2014-09-20 18:22:35 -04:00
if (log_level < 2 || (disable_output && !notify_ev)) { return; }
2015-05-11 07:20:34 -04:00
if (enable_json) { return; }
2014-09-20 18:22:35 -04:00
struct in_ev *ev = notify_ev;
mprint_start (ev);
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "User ");
print_user_name (ev, U->id, (void *)U);
mprintf (ev, " is ");
print_typing (ev, status);
mprintf (ev, " in chat ");
2014-09-20 18:22:35 -04:00
print_chat_name (ev, C->id, (void *)C);
mprintf (ev, "\n");
mpop_color (ev);
mprint_end (ev);
2014-08-14 18:16:01 -04:00
}
void print_message_gw (struct tgl_state *TLSR, struct tgl_message *M) {
assert (TLSR == TLS);
2014-08-21 11:38:51 -04:00
#ifdef USE_LUA
lua_new_msg (M);
#endif
2015-05-02 07:49:21 -04:00
#ifdef USE_PYTHON
py_new_msg (M);
#endif
2014-08-21 11:38:51 -04:00
if (!binlog_read) { return; }
if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) {
write_secret_chat_file ();
}
2014-09-20 18:22:35 -04:00
if (alert_sound) {
play_sound ();
}
if (disable_output && !notify_ev) { return; }
struct in_ev *ev = notify_ev;
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
print_message (ev, M);
} else {
#ifdef USE_JSON
json_t *res = json_pack_message (M);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-18 12:39:04 -04:00
}
void our_id_gw (struct tgl_state *TLSR, int id) {
assert (TLSR == TLS);
2014-08-21 11:38:51 -04:00
#ifdef USE_LUA
lua_our_id (id);
#endif
2015-05-02 07:49:21 -04:00
#ifdef USE_PYTHON
py_our_id (id);
#endif
2014-08-21 11:38:51 -04:00
}
2014-09-20 18:22:35 -04:00
void print_peer_updates (struct in_ev *ev, int flags) {
2014-08-21 11:38:51 -04:00
if (flags & TGL_UPDATE_PHONE) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " phone");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_CONTACT) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " contact");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_PHOTO) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " photo");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_BLOCKED) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " blocked");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_REAL_NAME) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " name");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_NAME) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " contact_name");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_REQUESTED) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " status");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_WORKING) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " status");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_FLAGS) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " flags");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_TITLE) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " title");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_ADMIN) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " admin");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_MEMBERS) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " members");
2014-08-21 11:38:51 -04:00
}
if (flags & TGL_UPDATE_ACCESS_HASH) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " access_hash");
2014-08-21 11:38:51 -04:00
}
2014-10-12 11:53:57 -04:00
if (flags & TGL_UPDATE_USERNAME) {
mprintf (ev, " username");
}
2014-08-21 11:38:51 -04:00
}
2015-05-15 10:50:07 -04:00
void json_peer_update (struct in_ev *ev, tgl_peer_t *P, unsigned flags) {
2015-05-11 07:20:34 -04:00
#ifdef USE_JSON
json_t *res = json_object ();
assert (json_object_set (res, "event", json_string ("updates")) >= 0);
2015-05-11 07:20:34 -04:00
assert (json_object_set (res, "peer", json_pack_peer (P->id, P)) >= 0);
assert (json_object_set (res, "updates", json_pack_updates (flags)) >= 0);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
void user_update_gw (struct tgl_state *TLSR, struct tgl_user *U, unsigned flags) {
assert (TLSR == TLS);
2014-08-21 11:38:51 -04:00
#ifdef USE_LUA
lua_user_update (U, flags);
#endif
2015-05-02 07:49:21 -04:00
#ifdef USE_PYTHON
py_user_update (U, flags);
#endif
2014-09-20 18:22:35 -04:00
if (disable_output && !notify_ev) { return; }
2014-08-21 11:38:51 -04:00
if (!binlog_read) { return; }
2014-09-20 18:22:35 -04:00
struct in_ev *ev = notify_ev;
2014-08-21 11:38:51 -04:00
if (!(flags & TGL_UPDATE_CREATED)) {
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "User ");
print_user_name (ev, U->id, (void *)U);
if (!(flags & TGL_UPDATE_DELETED)) {
mprintf (ev, " updated");
print_peer_updates (ev, flags);
} else {
mprintf (ev, " deleted");
}
mprintf (ev, "\n");
mpop_color (ev);
2014-08-21 11:38:51 -04:00
} else {
2015-05-11 07:20:34 -04:00
json_peer_update (ev, (void *)U, flags);
2014-08-21 11:38:51 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-21 11:38:51 -04:00
}
}
void chat_update_gw (struct tgl_state *TLSR, struct tgl_chat *U, unsigned flags) {
assert (TLSR == TLS);
2014-08-21 11:38:51 -04:00
#ifdef USE_LUA
lua_chat_update (U, flags);
#endif
2015-05-02 07:49:21 -04:00
#ifdef USE_PYTHON
py_chat_update (U, flags);
#endif
2014-09-20 18:22:35 -04:00
if (disable_output && !notify_ev) { return; }
2014-08-21 11:38:51 -04:00
if (!binlog_read) { return; }
2014-09-20 18:22:35 -04:00
struct in_ev *ev = notify_ev;
2014-08-21 11:38:51 -04:00
if (!(flags & TGL_UPDATE_CREATED)) {
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "Chat ");
print_chat_name (ev, U->id, (void *)U);
if (!(flags & TGL_UPDATE_DELETED)) {
mprintf (ev, " updated");
print_peer_updates (ev, flags);
} else {
mprintf (ev, " deleted");
}
mprintf (ev, "\n");
mpop_color (ev);
2014-08-21 11:38:51 -04:00
} else {
2015-05-11 07:20:34 -04:00
json_peer_update (ev, (void *)U, flags);
2014-08-21 11:38:51 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-21 11:38:51 -04:00
}
}
void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, unsigned flags) {
assert (TLSR == TLS);
2014-08-21 11:38:51 -04:00
#ifdef USE_LUA
lua_secret_chat_update (U, flags);
#endif
2015-05-02 07:49:21 -04:00
#ifdef USE_PYTHON
py_secret_chat_update (U, flags);
#endif
2014-08-21 11:38:51 -04:00
2015-05-02 07:49:21 -04:00
if ((flags & TGL_UPDATE_WORKING) || (flags & TGL_UPDATE_DELETED)) {
write_secret_chat_file ();
}
2014-09-20 18:22:35 -04:00
2014-09-21 17:00:46 -04:00
if (!binlog_read) { return; }
2014-08-26 12:06:30 -04:00
if ((flags & TGL_UPDATE_REQUESTED) && !disable_auto_accept) {
//tgl_do_accept_encr_chat_request (TLS, U, 0, 0);
tgl_do_accept_encr_chat_request (TLS, U, print_encr_chat_success_gw, 0);
2014-08-26 12:06:30 -04:00
}
2014-09-20 18:22:35 -04:00
if (disable_output && !notify_ev) { return; }
struct in_ev *ev = notify_ev;
2014-08-26 12:06:30 -04:00
2014-08-21 11:38:51 -04:00
if (!(flags & TGL_UPDATE_CREATED)) {
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "Secret chat ");
print_encr_chat_name (ev, U->id, (void *)U);
if (!(flags & TGL_UPDATE_DELETED)) {
mprintf (ev, " updated");
print_peer_updates (ev, flags);
} else {
mprintf (ev, " deleted");
}
mprintf (ev, "\n");
mpop_color (ev);
2014-08-21 11:38:51 -04:00
} else {
2015-05-11 07:20:34 -04:00
json_peer_update (ev, (void *)U, flags);
2014-08-21 11:38:51 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-21 11:38:51 -04:00
}
}
void print_card_gw (struct tgl_state *TLSR, void *extra, int success, int size, int *card) {
assert (TLSR == TLS);
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
2014-09-21 04:58:57 -04:00
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mprintf (ev, "Card: ");
int i;
for (i = 0; i < size; i++) {
mprintf (ev, "%08x%c", card[i], i == size - 1 ? '\n' : ':');
}
} else {
#ifdef USE_JSON
static char q[1000];
int pos = 0;
int i;
for (i = 0; i < size; i++) {
pos += sprintf (q + pos, "%08x%s", card[i], i == size - 1 ? "" : ":");
}
json_t *res = json_object ();
assert (json_object_set (res, "result", json_string (q)) >= 0);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
2014-08-29 11:46:04 -04:00
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-08-29 11:46:04 -04:00
}
2015-05-14 08:48:20 -04:00
void callback_extf (struct tgl_state *TLS, void *extra, int success, const char *buf) {
2014-09-20 18:22:35 -04:00
struct in_ev *ev = extra;
2014-09-21 04:58:57 -04:00
if (ev && !--ev->refcnt) {
free (ev);
return;
}
if (!success) { print_fail (ev); return; }
2014-09-20 18:22:35 -04:00
mprint_start (ev);
2015-05-11 07:20:34 -04:00
if (!enable_json) {
mprintf (ev, "%s\n", buf);
} else {
#ifdef USE_JSON
json_t *res = json_object ();
assert (json_object_set (res, "result", json_string (buf)) >= 0);
char *s = json_dumps (res, 0);
mprintf (ev, "%s\n", s);
json_decref (res);
free (s);
#endif
}
2014-09-20 18:22:35 -04:00
mprint_end (ev);
2014-09-10 07:52:42 -04:00
}
2014-11-11 13:10:03 -05:00
void user_status_upd (struct tgl_state *TLS, struct tgl_user *U) {
if (disable_output && !notify_ev) { return; }
if (!binlog_read) { return; }
2014-11-11 13:12:03 -05:00
if (log_level < 3) { return; }
2015-05-11 07:20:34 -04:00
if (enable_json) { return; }
2014-11-11 13:10:03 -05:00
struct in_ev *ev = notify_ev;
mprint_start (ev);
mpush_color (ev, COLOR_YELLOW);
mprintf (ev, "User ");
print_user_name (ev, U->id, (void *)U);
2014-11-15 06:45:37 -05:00
mprintf (ev, " ");
print_user_status (&U->status, ev);
2014-11-11 13:10:03 -05:00
mprintf (ev, "\n");
mpop_color (ev);
mprint_end (ev);
}
2015-01-11 16:52:40 -05:00
void on_login (struct tgl_state *TLS);
void on_started (struct tgl_state *TLS);
2015-05-14 08:48:20 -04:00
void do_get_string (struct tgl_state *TLS, const char *prompt, int flags, void (*cb)(struct tgl_state *, const char *, void *), void *arg);
2015-01-11 16:52:40 -05:00
2014-08-14 18:16:01 -04:00
struct tgl_update_callback upd_cb = {
2014-08-18 12:39:04 -04:00
.new_msg = print_message_gw,
2014-08-14 18:16:01 -04:00
.marked_read = mark_read_upd,
.logprintf = logprintf,
2015-01-11 16:52:40 -05:00
.get_string = do_get_string,
.logged_in = on_login,
.started = on_started,
2014-08-14 18:16:01 -04:00
.type_notification = type_notification_upd,
.type_in_chat_notification = type_in_chat_notification_upd,
.type_in_secret_chat_notification = 0,
.status_notification = 0,
.user_registered = 0,
.user_activated = 0,
.new_authorization = 0,
2014-08-21 11:38:51 -04:00
.user_update = user_update_gw,
.chat_update = chat_update_gw,
.secret_chat_update = secret_chat_update_gw,
.msg_receive = print_message_gw,
2014-11-11 13:10:03 -05:00
.our_id = our_id_gw,
.user_status_update = user_status_upd
2014-08-14 18:16:01 -04:00
};
2014-11-12 09:38:44 -05:00
void interpreter_ex (char *line, void *ex) {
2014-09-17 17:03:20 -04:00
force_end_mode = 1;
2013-10-29 20:08:30 -04:00
assert (!in_readline);
in_readline = 1;
2013-12-06 12:14:41 -05:00
if (in_chat_mode) {
interpreter_chat_mode (line);
in_readline = 0;
return;
}
line_ptr = line;
2013-11-25 12:16:34 -05:00
offline_mode = 0;
2015-05-14 08:48:20 -04:00
reply_id = 0;
disable_msg_preview = 0;
2013-11-25 12:16:34 -05:00
count = 1;
2013-10-29 20:08:30 -04:00
if (!line) {
2015-05-06 07:39:45 -04:00
do_safe_quit (NULL, 0, NULL, NULL);
2013-10-29 20:08:30 -04:00
in_readline = 0;
return;
}
if (line && *line) {
add_history (line);
}
2014-09-17 17:03:20 -04:00
if (*line == '(') {
2014-09-21 04:58:57 -04:00
struct in_ev *ev = ex;
if (ev) { ev->refcnt ++; }
tgl_do_send_extf (TLS, line, strlen (line), callback_extf, ev);
2014-09-17 17:03:20 -04:00
in_readline = 0;
return;
}
2013-10-29 20:08:30 -04:00
while (1) {
2014-09-17 17:03:20 -04:00
next_token ();
if (cur_token_quoted) {
in_readline = 0;
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
2014-09-17 17:03:20 -04:00
return;
2013-10-29 20:08:30 -04:00
}
2014-09-17 17:03:20 -04:00
if (cur_token_len <= 0) {
in_readline = 0;
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
2014-09-17 17:03:20 -04:00
return;
2013-10-29 20:08:30 -04:00
}
2014-09-17 17:03:20 -04:00
if (*cur_token == '[') {
if (cur_token_end_str) {
in_readline = 0;
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
2014-09-17 17:03:20 -04:00
return;
}
if (cur_token[cur_token_len - 1] != ']') {
in_readline = 0;
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
2014-09-17 17:03:20 -04:00
return;
}
work_modifier (cur_token, cur_token_len);
continue;
}
2014-09-17 17:03:20 -04:00
break;
}
if (cur_token_quoted || cur_token_end_str) {
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse command name");
2014-09-17 17:03:20 -04:00
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;
}
2014-09-17 17:03:20 -04:00
n ++;
command ++;
}
if (!command->name) {
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not find comamnd '%.*s'", cur_token_len, cur_token);
2014-09-17 17:03:20 -04:00
in_readline = 0;
return;
}
enum command_argument *flags = command->args;
2015-05-06 07:39:45 -04:00
void (*fun)(struct command *, int, struct arg[], struct in_ev *) = command->fun;
2014-09-17 17:03:20 -04:00
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) {
flags --;
period = 1;
}
2014-09-17 17:03:20 -04:00
enum command_argument op = (*flags) & 255;
int opt = (*flags) & ca_optional;
if (op == ca_none) {
next_token ();
if (cur_token_end_str) {
2014-09-29 12:48:27 -04:00
int z;
for (z = 0; z < count; z ++) {
2015-05-06 07:39:45 -04:00
fun (command, args_num, args, ex);
2014-09-29 12:48:27 -04:00
}
2015-05-15 06:31:38 -04:00
} else {
fail_interface (TLS, ex, ENOSYS, "too many args #%d", args_num);
2014-09-17 17:03:20 -04:00
}
break;
}
2014-09-17 17:03:20 -04:00
if (op == ca_string_end || op == ca_file_name_end) {
next_token_end ();
if (cur_token_len < 0) {
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse string_end arg #%d", args_num);
2014-09-17 17:03:20 -04:00
break;
} else {
args[args_num].flags = 1;
args[args_num ++].str = strndup (cur_token, cur_token_len);
2014-09-29 12:48:27 -04:00
int z;
for (z = 0; z < count; z ++) {
2015-05-06 07:39:45 -04:00
fun (command, args_num, args, ex);
2014-09-29 12:48:27 -04:00
}
2014-09-17 17:03:20 -04:00
break;
}
}
2014-09-17 17:03:20 -04:00
char *save = line_ptr;
next_token ();
if (period && cur_token_end_str) {
2014-09-29 12:48:27 -04:00
int z;
for (z = 0; z < count; z ++) {
2015-05-06 07:39:45 -04:00
fun (command, args_num, args, ex);
2014-09-29 12:48:27 -04:00
}
2014-09-17 17:03:20 -04:00
break;
2013-11-06 18:12:40 -05:00
}
2014-09-17 17:03:20 -04:00
2014-10-03 05:35:02 -04:00
if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double) {
2014-09-17 17:03:20 -04:00
if (cur_token_quoted) {
if (opt) {
2014-10-03 05:35:02 -04:00
if (op != ca_number && op != ca_double) {
2014-09-17 17:03:20 -04:00
args[args_num ++].P = 0;
} else {
2014-10-03 05:35:02 -04:00
if (op == ca_number) {
args[args_num ++].num = NOT_FOUND;
} else {
args[args_num ++].dval = NOT_FOUND;
}
2014-09-17 17:03:20 -04:00
}
line_ptr = save;
flags ++;
continue;
} else if (period) {
line_ptr = save;
flags += 2;
continue;
} else {
2014-09-17 17:03:20 -04:00
break;
}
} else {
if (cur_token_end_str) {
if (opt) {
2014-10-03 05:35:02 -04:00
if (op != ca_number && op != ca_double) {
2014-09-17 17:03:20 -04:00
args[args_num ++].P = 0;
} else {
2014-10-03 05:35:02 -04:00
if (op == ca_number) {
args[args_num ++].num = NOT_FOUND;
} else {
args[args_num ++].dval = NOT_FOUND;
}
2014-09-17 17:03:20 -04:00
}
line_ptr = save;
flags ++;
continue;
} else if (period) {
line_ptr = save;
flags += 2;
continue;
2014-09-17 17:03:20 -04:00
} else {
break;
}
}
2014-09-17 17:03:20 -04:00
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;
2014-10-03 05:35:02 -04:00
case ca_double:
args[args_num ++].dval = cur_token_double ();
ok = (args[args_num - 1].dval != NOT_FOUND);
break;
2014-09-17 17:03:20 -04:00
default:
assert (0);
}
if (opt && !ok) {
line_ptr = save;
flags ++;
continue;
2014-08-29 11:46:04 -04:00
}
if (period && !ok) {
line_ptr = save;
flags += 2;
args_num --;
continue;
}
2014-09-17 17:03:20 -04:00
if (!ok) {
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse arg #%d", args_num);
2014-09-17 17:03:20 -04:00
break;
}
flags ++;
continue;
2014-08-29 11:46:04 -04:00
}
}
2014-09-17 17:03:20 -04:00
if (op == ca_string || op == ca_file_name) {
if (cur_token_end_str || cur_token_len < 0) {
2015-05-15 06:31:38 -04:00
fail_interface (TLS, ex, ENOSYS, "can not parse string arg #%d", args_num);
2014-09-17 17:03:20 -04:00
break;
} else {
args[args_num].flags = 1;
args[args_num ++].str = strndup (cur_token, cur_token_len);
flags ++;
continue;
}
2014-09-11 07:04:04 -04:00
}
2014-09-17 17:03:20 -04:00
assert (0);
2013-10-11 16:52:20 -04:00
}
2014-09-17 17:03:20 -04:00
int i;
for (i = 0; i < args_num; i++) {
if (args[i].flags & 1) {
free (args[i].str);
}
2013-11-25 12:16:34 -05:00
}
2014-09-17 17:03:20 -04:00
2013-11-15 07:59:06 -05:00
update_prompt ();
2013-10-29 20:08:30 -04:00
in_readline = 0;
2013-10-11 16:52:20 -04:00
}
2014-11-12 09:38:44 -05:00
void interpreter (char *line) {
2014-09-20 18:22:35 -04:00
interpreter_ex (line, 0);
}
int readline_active;
2014-09-20 18:22:35 -04:00
/*void rprintf (const char *format, ...) {
mprint_start (ev);
va_list ap;
va_start (ap, format);
vfprintf (stdout, format, ap);
va_end (ap);
print_end();
2014-09-20 18:22:35 -04:00
}*/
2013-10-18 15:30:24 -04:00
int saved_point;
char *saved_line;
int prompt_was;
2015-01-11 16:52:40 -05:00
void deactivate_readline (void) {
if (read_one_string) {
printf ("\033[2K\r");
fflush (stdout);
} else {
2013-10-18 15:30:24 -04:00
saved_point = rl_point;
2014-08-14 18:16:01 -04:00
saved_line = malloc (rl_end + 1);
assert (saved_line);
saved_line[rl_end] = 0;
memcpy (saved_line, rl_line_buffer, rl_end);
2013-10-18 15:30:24 -04:00
rl_save_prompt();
rl_replace_line("", 0);
rl_redisplay();
}
2015-01-11 16:52:40 -05:00
}
void reactivate_readline (void) {
if (read_one_string) {
printf ("%s ", one_string_prompt);
if (!(one_string_flags & 1)) {
printf ("%.*s", one_string_len, one_string);
}
fflush (stdout);
} else {
set_prompt (get_default_prompt ());
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
free (saved_line);
}
}
void print_start (void) {
if (in_readline) { return; }
if (readline_disabled) { return; }
assert (!prompt_was);
if (readline_active) {
deactivate_readline ();
}
2013-10-18 15:30:24 -04:00
prompt_was = 1;
}
2013-10-18 15:30:24 -04:00
void print_end (void) {
2013-10-29 20:08:30 -04:00
if (in_readline) { return; }
if (readline_disabled) {
fflush (stdout);
return;
}
2013-10-18 15:30:24 -04:00
assert (prompt_was);
if (readline_active) {
2015-01-11 16:52:40 -05:00
reactivate_readline ();
2013-10-18 15:30:24 -04:00
}
prompt_was = 0;
}
2014-08-20 21:56:53 -04:00
/*void hexdump (int *in_ptr, int *in_end) {
2014-09-20 18:22:35 -04:00
mprint_start (ev);
int *ptr = in_ptr;
2014-09-20 18:22:35 -04:00
while (ptr < in_end) { mprintf (ev, " %08x", *(ptr ++)); }
mprintf (ev, "\n");
mprint_end (ev);
2014-08-20 21:56:53 -04:00
}*/
void logprintf (const char *format, ...) {
2013-11-21 14:35:49 -05:00
int x = 0;
if (!prompt_was) {
x = 1;
print_start ();
}
if (!disable_colors) {
printf (COLOR_GREY);
}
printf (" *** ");
2013-10-11 16:52:20 -04:00
va_list ap;
va_start (ap, format);
vfprintf (stdout, format, ap);
va_end (ap);
if (!disable_colors) {
printf (COLOR_NORMAL);
}
2013-11-21 14:35:49 -05:00
if (x) {
print_end ();
}
2013-10-03 08:38:25 -04:00
}
2013-10-16 15:19:39 -04:00
2013-10-18 15:30:24 -04:00
int color_stack_pos;
const char *color_stack[10];
void push_color (const char *color) {
2014-08-24 20:11:41 -04:00
if (disable_colors) { return; }
2013-10-18 15:30:24 -04:00
assert (color_stack_pos < 10);
color_stack[color_stack_pos ++] = color;
printf ("%s", color);
}
void pop_color (void) {
2014-08-24 20:11:41 -04:00
if (disable_colors) { return; }
2013-10-18 15:30:24 -04:00
assert (color_stack_pos > 0);
color_stack_pos --;
if (color_stack_pos >= 1) {
printf ("%s", color_stack[color_stack_pos - 1]);
2013-10-18 15:30:24 -04:00
} else {
printf ("%s", COLOR_NORMAL);
}
}
2014-09-20 18:22:35 -04:00
void print_media (struct in_ev *ev, struct tgl_message_media *M) {
assert (M);
2013-10-18 15:30:24 -04:00
switch (M->type) {
2014-08-18 12:39:04 -04:00
case tgl_message_media_none:
2013-10-18 15:30:24 -04:00
return;
2014-08-18 12:39:04 -04:00
case tgl_message_media_photo:
assert (M->photo);
if (M->photo->caption && strlen (M->photo->caption)) {
mprintf (ev, "[photo %s]", M->photo->caption);
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, "[photo]");
}
2015-05-05 05:48:58 -04:00
if (M->caption) {
mprintf (ev, " %s", M->caption);
}
2013-10-18 15:30:24 -04:00
return;
2015-01-11 16:52:40 -05:00
case tgl_message_media_document:
mprintf (ev, "[");
assert (M->document);
2015-05-14 08:48:20 -04:00
if (M->document->flags & TGLDF_IMAGE) {
2015-01-11 16:52:40 -05:00
mprintf (ev, "image");
2015-05-14 08:48:20 -04:00
} else if (M->document->flags & TGLDF_AUDIO) {
2015-01-11 16:52:40 -05:00
mprintf (ev, "audio");
2015-05-14 08:48:20 -04:00
} else if (M->document->flags & TGLDF_VIDEO) {
2015-01-11 16:52:40 -05:00
mprintf (ev, "video");
2015-05-14 08:48:20 -04:00
} else if (M->document->flags & TGLDF_STICKER) {
2015-01-11 16:52:40 -05:00
mprintf (ev, "sticker");
2014-08-12 21:22:15 -04:00
} else {
2015-01-11 16:52:40 -05:00
mprintf (ev, "document");
2014-08-12 21:22:15 -04:00
}
2015-01-11 16:52:40 -05:00
if (M->document->caption && strlen (M->document->caption)) {
mprintf (ev, " %s:", M->document->caption);
2014-08-12 21:22:15 -04:00
} else {
2015-01-11 16:52:40 -05:00
mprintf (ev, ":");
2014-08-12 21:22:15 -04:00
}
2015-01-11 16:52:40 -05:00
if (M->document->mime_type) {
mprintf (ev, " type=%s", M->document->mime_type);
2015-01-11 16:52:40 -05:00
}
if (M->document->w && M->document->h) {
mprintf (ev, " size=%dx%d", M->document->w, M->document->h);
2015-01-11 16:52:40 -05:00
}
if (M->document->duration) {
mprintf (ev, " duration=%d", M->document->duration);
2015-01-11 16:52:40 -05:00
}
mprintf (ev, " size=");
if (M->document->size < (1 << 10)) {
mprintf (ev, "%dB", M->document->size);
} else if (M->document->size < (1 << 20)) {
mprintf (ev, "%dKiB", M->document->size >> 10);
} else if (M->document->size < (1 << 30)) {
mprintf (ev, "%dMiB", M->document->size >> 20);
2013-11-15 05:37:14 -05:00
} else {
mprintf (ev, "%dGiB", M->document->size >> 30);
2013-11-15 05:37:14 -05:00
}
2015-01-11 16:52:40 -05:00
mprintf (ev, "]");
2015-05-05 05:48:58 -04:00
if (M->caption) {
mprintf (ev, " %s", M->caption);
}
2015-01-11 16:52:40 -05:00
2013-11-04 12:34:27 -05:00
return;
2015-01-11 16:52:40 -05:00
case tgl_message_media_document_encr:
mprintf (ev, "[");
2015-05-14 08:48:20 -04:00
if (M->encr_document->flags & TGLDF_IMAGE) {
mprintf (ev, "image");
2015-05-14 08:48:20 -04:00
} else if (M->encr_document->flags & TGLDF_AUDIO) {
mprintf (ev, "audio");
2015-05-14 08:48:20 -04:00
} else if (M->encr_document->flags & TGLDF_VIDEO) {
mprintf (ev, "video");
2015-05-14 08:48:20 -04:00
} else if (M->encr_document->flags & TGLDF_STICKER) {
mprintf (ev, "sticker");
2014-08-18 12:39:04 -04:00
} else {
mprintf (ev, "document");
2014-08-18 12:39:04 -04:00
}
2015-01-11 16:52:40 -05:00
2015-04-30 06:43:48 -04:00
if (M->encr_document->caption && strlen (M->encr_document->caption)) {
mprintf (ev, " %s:", M->encr_document->caption);
2014-08-18 12:39:04 -04:00
} else {
2015-01-11 16:52:40 -05:00
mprintf (ev, ":");
2014-08-18 12:39:04 -04:00
}
2015-01-11 16:52:40 -05:00
2015-04-30 06:43:48 -04:00
if (M->encr_document->mime_type) {
mprintf (ev, " type=%s", M->encr_document->mime_type);
2015-01-11 16:52:40 -05:00
}
2015-04-30 06:43:48 -04:00
if (M->encr_document->w && M->encr_document->h) {
mprintf (ev, " size=%dx%d", M->encr_document->w, M->encr_document->h);
2014-08-18 12:39:04 -04:00
}
2015-01-11 16:52:40 -05:00
2015-04-30 06:43:48 -04:00
if (M->encr_document->duration) {
mprintf (ev, " duration=%d", M->encr_document->duration);
}
mprintf (ev, " size=");
2015-04-30 06:43:48 -04:00
if (M->encr_document->size < (1 << 10)) {
mprintf (ev, "%dB", M->encr_document->size);
} else if (M->encr_document->size < (1 << 20)) {
mprintf (ev, "%dKiB", M->encr_document->size >> 10);
} else if (M->encr_document->size < (1 << 30)) {
mprintf (ev, "%dMiB", M->encr_document->size >> 20);
} else {
2015-04-30 06:43:48 -04:00
mprintf (ev, "%dGiB", M->encr_document->size >> 30);
2015-01-11 16:52:40 -05:00
}
mprintf (ev, "]");
2013-11-15 05:37:14 -05:00
return;
2014-08-18 12:39:04 -04:00
case tgl_message_media_geo:
2015-05-01 13:26:47 -04:00
mprintf (ev, "[geo https://maps.google.com/?q=%.6lf,%.6lf]", M->geo.latitude, M->geo.longitude);
2013-10-18 15:30:24 -04:00
return;
2014-08-18 12:39:04 -04:00
case tgl_message_media_contact:
2014-09-20 18:22:35 -04:00
mprintf (ev, "[contact] ");
mpush_color (ev, COLOR_RED);
mprintf (ev, "%s %s ", M->first_name, M->last_name);
mpop_color (ev);
mprintf (ev, "%s", M->phone);
2013-10-18 15:30:24 -04:00
return;
2014-08-18 12:39:04 -04:00
case tgl_message_media_unsupported:
2014-09-20 18:22:35 -04:00
mprintf (ev, "[unsupported]");
2013-10-18 15:30:24 -04:00
return;
2015-04-22 13:09:53 -04:00
case tgl_message_media_webpage:
mprintf (ev, "[webpage:");
2015-05-01 11:12:07 -04:00
assert (M->webpage);
2015-04-30 06:43:48 -04:00
if (M->webpage->url) {
mprintf (ev, " url:'%s'", M->webpage->url);
2015-04-22 13:09:53 -04:00
}
2015-04-30 06:43:48 -04:00
if (M->webpage->title) {
mprintf (ev, " title:'%s'", M->webpage->title);
2015-04-22 13:09:53 -04:00
}
2015-04-30 06:43:48 -04:00
if (M->webpage->description) {
mprintf (ev, " description:'%s'", M->webpage->description);
2015-04-22 13:09:53 -04:00
}
2015-04-30 06:43:48 -04:00
if (M->webpage->author) {
mprintf (ev, " author:'%s'", M->webpage->author);
2015-04-22 13:09:53 -04:00
}
mprintf (ev, "]");
break;
2015-05-01 13:26:47 -04:00
case tgl_message_media_venue:
mprintf (ev, "[geo https://maps.google.com/?q=%.6lf,%.6lf", M->venue.geo.latitude, M->venue.geo.longitude);
if (M->venue.title) {
mprintf (ev, " title:'%s'", M->venue.title);
}
if (M->venue.address) {
mprintf (ev, " address:'%s'", M->venue.address);
}
if (M->venue.provider) {
mprintf (ev, " provider:'%s'", M->venue.provider);
}
if (M->venue.venue_id) {
mprintf (ev, " id:'%s'", M->venue.venue_id);
}
mprintf (ev, "]");
return;
2013-10-18 15:30:24 -04:00
default:
2014-09-20 18:22:35 -04:00
mprintf (ev, "x = %d\n", M->type);
2013-10-18 15:30:24 -04:00
assert (0);
}
}
2013-10-23 06:24:59 -04:00
int unknown_user_list_pos;
int unknown_user_list[1000];
2014-09-20 18:22:35 -04:00
void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U) {
2014-08-13 11:55:16 -04:00
assert (tgl_get_peer_type (id) == TGL_PEER_USER);
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_RED);
2014-10-13 05:46:24 -04:00
if (!U) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "user#%d", tgl_get_peer_id (id));
2013-10-23 06:24:59 -04:00
int i;
int ok = 1;
2013-10-23 06:24:59 -04:00
for (i = 0; i < unknown_user_list_pos; i++) {
2014-08-13 11:55:16 -04:00
if (unknown_user_list[i] == tgl_get_peer_id (id)) {
ok = 0;
2013-10-23 06:24:59 -04:00
break;
}
}
if (ok) {
2013-10-23 06:24:59 -04:00
assert (unknown_user_list_pos < 1000);
2014-08-13 11:55:16 -04:00
unknown_user_list[unknown_user_list_pos ++] = tgl_get_peer_id (id);
2013-10-23 06:24:59 -04:00
}
2013-10-18 15:30:24 -04:00
} else {
2015-04-22 13:09:53 -04:00
if (U->flags & (TGLUF_SELF | TGLUF_CONTACT)) {
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_REDB);
2013-10-23 06:24:59 -04:00
}
2015-04-22 13:09:53 -04:00
if ((U->flags & TGLUF_DELETED)) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "deleted user#%d", tgl_get_peer_id (id));
2015-04-22 13:09:53 -04:00
} else if (!(U->flags & TGLUF_CREATED)) {
2014-10-13 05:46:24 -04:00
mprintf (ev, "user#%d", tgl_get_peer_id (id));
} else if (use_ids) {
mprintf (ev, "user#%d", tgl_get_peer_id (id));
2013-11-06 18:12:40 -05:00
} else if (!U->user.first_name || !strlen (U->user.first_name)) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s", U->user.last_name);
2013-11-06 18:12:40 -05:00
} else if (!U->user.last_name || !strlen (U->user.last_name)) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s", U->user.first_name);
2013-10-23 06:24:59 -04:00
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s %s", U->user.first_name, U->user.last_name);
2013-10-23 06:24:59 -04:00
}
2015-04-22 13:09:53 -04:00
if (U->flags & (TGLUF_SELF | TGLUF_CONTACT)) {
2014-09-20 18:22:35 -04:00
mpop_color (ev);
2013-10-23 06:24:59 -04:00
}
2013-10-18 15:30:24 -04:00
}
2014-09-20 18:22:35 -04:00
mpop_color (ev);
2013-10-18 15:30:24 -04:00
}
2014-09-20 18:22:35 -04:00
void print_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) {
2014-08-13 11:55:16 -04:00
assert (tgl_get_peer_type (id) == TGL_PEER_CHAT);
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_MAGENTA);
if (!C || use_ids) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "chat#%d", tgl_get_peer_id (id));
2013-10-18 15:30:24 -04:00
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s", C->chat.title);
2013-10-18 15:30:24 -04:00
}
2014-09-20 18:22:35 -04:00
mpop_color (ev);
2013-10-18 15:30:24 -04:00
}
2014-09-20 18:22:35 -04:00
void print_encr_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) {
2014-08-13 11:55:16 -04:00
assert (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT);
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_MAGENTA);
if (!C || use_ids) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "encr_chat#%d", tgl_get_peer_id (id));
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s", C->print_name);
}
2014-09-20 18:22:35 -04:00
mpop_color (ev);
}
2014-09-20 18:22:35 -04:00
void print_encr_chat_name_full (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) {
2014-08-13 11:55:16 -04:00
assert (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT);
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_MAGENTA);
if (!C || use_ids) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "encr_chat#%d", tgl_get_peer_id (id));
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s", C->print_name);
}
2014-09-20 18:22:35 -04:00
mpop_color (ev);
}
2013-10-18 15:30:24 -04:00
static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
2014-09-20 18:22:35 -04:00
void print_date (struct in_ev *ev, long t) {
2014-02-18 13:06:00 -05:00
struct tm *tm = localtime ((void *)&t);
2013-10-18 15:30:24 -04:00
if (time (0) - t < 12 * 60 * 60) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "[%02d:%02d] ", tm->tm_hour, tm->tm_min);
2015-04-24 07:08:01 -04:00
} else if (time (0) - t < 24 * 60 * 60 * 180) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "[%02d %s]", tm->tm_mday, monthes[tm->tm_mon]);
2015-04-24 07:08:01 -04:00
} else {
mprintf (ev, "[%02d %s %d]", tm->tm_mday, monthes[tm->tm_mon], tm->tm_year + 1900);
2013-10-18 15:30:24 -04:00
}
}
2014-09-20 18:22:35 -04:00
void print_date_full (struct in_ev *ev, long t) {
2014-02-18 13:06:00 -05:00
struct tm *tm = localtime ((void *)&t);
2014-09-20 18:22:35 -04:00
mprintf (ev, "[%04d/%02d/%02d %02d:%02d:%02d]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
2013-10-24 03:38:32 -04:00
}
2014-09-20 18:22:35 -04:00
void print_service_message (struct in_ev *ev, struct tgl_message *M) {
assert (M);
2014-08-18 12:39:04 -04:00
//print_start ();
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_GREY);
2013-10-24 18:21:52 -04:00
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_MAGENTA);
if (msg_num_mode) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%lld ", M->id);
}
2014-09-20 18:22:35 -04:00
print_date (ev, M->date);
mpop_color (ev);
mprintf (ev, " ");
2014-08-13 11:55:16 -04:00
if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) {
print_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
2013-11-15 05:37:14 -05:00
} else {
2014-08-13 11:55:16 -04:00
assert (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT);
print_encr_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
2013-11-15 05:37:14 -05:00
}
2014-09-20 18:22:35 -04:00
mprintf (ev, " ");
print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id));
switch (M->action.type) {
2014-08-18 12:39:04 -04:00
case tgl_message_action_none:
2014-09-20 18:22:35 -04:00
mprintf (ev, "\n");
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_geo_chat_create:
2014-09-20 18:22:35 -04:00
mprintf (ev, "Created geo chat\n");
2013-11-22 18:26:35 -05:00
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_geo_chat_checkin:
2014-09-20 18:22:35 -04:00
mprintf (ev, "Checkin in geochat\n");
2013-11-22 18:26:35 -05:00
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_chat_create:
2014-09-20 18:22:35 -04:00
mprintf (ev, " created chat %s. %d users\n", M->action.title, M->action.user_num);
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_chat_edit_title:
2014-09-20 18:22:35 -04:00
mprintf (ev, " changed title to %s\n",
M->action.new_title);
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_chat_edit_photo:
2014-09-20 18:22:35 -04:00
mprintf (ev, " changed photo\n");
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_chat_delete_photo:
2014-09-20 18:22:35 -04:00
mprintf (ev, " deleted photo\n");
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_chat_add_user:
2014-09-20 18:22:35 -04:00
mprintf (ev, " added user ");
print_user_name (ev, tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user)));
2014-09-20 18:22:35 -04:00
mprintf (ev, "\n");
break;
2015-05-01 12:32:06 -04:00
case tgl_message_action_chat_add_user_by_link:
mprintf (ev, " added by link from ");
print_user_name (ev, tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user)));
mprintf (ev, "\n");
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_chat_delete_user:
2014-09-20 18:22:35 -04:00
mprintf (ev, " deleted user ");
print_user_name (ev, tgl_set_peer_id (TGL_PEER_USER, M->action.user), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.user)));
2014-09-20 18:22:35 -04:00
mprintf (ev, "\n");
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_set_message_ttl:
2014-09-20 18:22:35 -04:00
mprintf (ev, " set ttl to %d seconds. Unsupported yet\n", M->action.ttl);
2013-11-15 05:37:14 -05:00
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_read_messages:
2014-09-20 18:22:35 -04:00
mprintf (ev, " %d messages marked read\n", M->action.read_cnt);
2014-08-12 21:22:15 -04:00
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_delete_messages:
2014-09-20 18:22:35 -04:00
mprintf (ev, " %d messages deleted\n", M->action.delete_cnt);
2014-08-12 21:22:15 -04:00
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_screenshot_messages:
2014-09-20 18:22:35 -04:00
mprintf (ev, " %d messages screenshoted\n", M->action.screenshot_cnt);
2014-08-12 21:22:15 -04:00
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_flush_history:
2014-09-20 18:22:35 -04:00
mprintf (ev, " cleared history\n");
break;
case tgl_message_action_resend:
mprintf (ev, " resend query\n");
2014-08-12 21:22:15 -04:00
break;
2014-08-18 12:39:04 -04:00
case tgl_message_action_notify_layer:
2014-09-20 18:22:35 -04:00
mprintf (ev, " updated layer to %d\n", M->action.layer);
2014-08-12 21:22:15 -04:00
break;
case tgl_message_action_typing:
mprintf (ev, " is ");
print_typing (ev, M->action.typing);
break;
2014-11-13 11:22:12 -05:00
case tgl_message_action_noop:
mprintf (ev, " noop\n");
break;
case tgl_message_action_request_key:
mprintf (ev, " request rekey #%016llx\n", M->action.exchange_id);
break;
case tgl_message_action_accept_key:
mprintf (ev, " accept rekey #%016llx\n", M->action.exchange_id);
break;
case tgl_message_action_commit_key:
mprintf (ev, " commit rekey #%016llx\n", M->action.exchange_id);
break;
case tgl_message_action_abort_key:
mprintf (ev, " abort rekey #%016llx\n", M->action.exchange_id);
break;
}
2014-09-20 18:22:35 -04:00
mpop_color (ev);
2014-08-18 12:39:04 -04:00
//print_end ();
}
2014-08-13 11:55:16 -04:00
tgl_peer_id_t last_from_id;
tgl_peer_id_t last_to_id;
2014-09-20 18:22:35 -04:00
void print_message (struct in_ev *ev, struct tgl_message *M) {
assert (M);
2015-04-22 13:09:53 -04:00
if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) {
2013-11-04 12:34:27 -05:00
return;
}
2015-04-22 13:09:53 -04:00
if (!(M->flags & TGLMF_CREATED)) { return; }
if (M->flags & TGLMF_SERVICE) {
2014-09-20 18:22:35 -04:00
print_service_message (ev, M);
return;
}
2014-08-13 11:55:16 -04:00
if (!tgl_get_peer_type (M->to_id)) {
2013-12-18 10:21:49 -05:00
logprintf ("Bad msg\n");
return;
}
2013-10-18 15:30:24 -04:00
last_from_id = M->from_id;
last_to_id = M->to_id;
2013-10-18 15:30:24 -04:00
2014-08-18 12:39:04 -04:00
//print_start ();
2014-08-13 11:55:16 -04:00
if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) {
2015-04-22 13:09:53 -04:00
if (M->flags & TGLMF_OUT) {
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_GREEN);
2013-10-25 15:50:10 -04:00
if (msg_num_mode) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%lld ", M->id);
2013-10-25 15:50:10 -04:00
}
2014-09-20 18:22:35 -04:00
print_date (ev, M->date);
mpop_color (ev);
mprintf (ev, " ");
print_user_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_GREEN);
2015-04-22 13:09:53 -04:00
if (M->flags & TGLMF_UNREAD) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " <<< ");
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, " ««« ");
}
2013-10-16 15:19:39 -04:00
} else {
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_BLUE);
2013-10-25 15:50:10 -04:00
if (msg_num_mode) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%lld ", M->id);
2013-10-25 15:50:10 -04:00
}
2014-09-20 18:22:35 -04:00
print_date (ev, M->date);
mpop_color (ev);
mprintf (ev, " ");
print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id));
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_BLUE);
2015-04-22 13:09:53 -04:00
if (M->flags & TGLMF_UNREAD) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " >>> ");
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, " »»» ");
2014-02-27 03:48:05 -05:00
}
}
2014-08-13 11:55:16 -04:00
} else if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) {
tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
2013-11-04 12:34:27 -05:00
assert (P);
2015-04-22 13:09:53 -04:00
if (M->flags & TGLMF_UNREAD) {
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_GREEN);
2013-11-04 12:34:27 -05:00
if (msg_num_mode) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%lld ", M->id);
2013-11-04 12:34:27 -05:00
}
2014-09-20 18:22:35 -04:00
print_date (ev, M->date);
mprintf (ev, " ");
mpush_color (ev, COLOR_CYAN);
mprintf (ev, " %s", P->print_name);
mpop_color (ev);
2015-04-22 13:09:53 -04:00
if (M->flags & TGLMF_UNREAD) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " <<< ");
2013-11-04 12:34:27 -05:00
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, " ««« ");
2013-11-04 12:34:27 -05:00
}
} else {
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_BLUE);
2013-11-04 12:34:27 -05:00
if (msg_num_mode) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%lld ", M->id);
2013-11-04 12:34:27 -05:00
}
2014-09-20 18:22:35 -04:00
print_date (ev, M->date);
mpush_color (ev, COLOR_CYAN);
mprintf (ev, " %s", P->print_name);
mpop_color (ev);
2015-04-22 13:09:53 -04:00
if (M->flags & TGLMF_UNREAD) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " >>> ");
2013-11-04 12:34:27 -05:00
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, " »»» ");
2014-02-27 03:48:05 -05:00
}
2013-11-04 12:34:27 -05:00
}
} else {
2014-08-13 11:55:16 -04:00
assert (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT);
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_MAGENTA);
2013-10-25 15:50:10 -04:00
if (msg_num_mode) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%lld ", M->id);
2013-10-25 15:50:10 -04:00
}
2014-09-20 18:22:35 -04:00
print_date (ev, M->date);
mpop_color (ev);
mprintf (ev, " ");
print_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
2014-09-20 18:22:35 -04:00
mprintf (ev, " ");
print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id));
if ((tgl_get_peer_type (M->from_id) == TGL_PEER_USER) && (tgl_get_peer_id (M->from_id) == TLS->our_id)) {
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_GREEN);
2013-10-18 15:30:24 -04:00
} else {
2014-09-20 18:22:35 -04:00
mpush_color (ev, COLOR_BLUE);
2013-10-16 15:19:39 -04:00
}
2015-04-22 13:09:53 -04:00
if (M->flags & TGLMF_UNREAD) {
2014-09-20 18:22:35 -04:00
mprintf (ev, " >>> ");
} else {
2014-09-20 18:22:35 -04:00
mprintf (ev, " »»» ");
}
2013-10-18 15:30:24 -04:00
}
2014-08-13 11:55:16 -04:00
if (tgl_get_peer_type (M->fwd_from_id) == TGL_PEER_USER) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "[fwd from ");
print_user_name (ev, M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id));
2014-09-20 18:22:35 -04:00
mprintf (ev, "] ");
2013-10-24 18:21:52 -04:00
}
2015-04-23 11:22:11 -04:00
if (M->reply_id) {
mprintf (ev, "[reply to %d] ", M->reply_id);
}
2015-04-27 10:52:19 -04:00
if (M->flags & TGLMF_MENTION) {
mprintf (ev, "[mention] ");
}
2013-10-18 15:30:24 -04:00
if (M->message && strlen (M->message)) {
2014-09-20 18:22:35 -04:00
mprintf (ev, "%s", M->message);
2013-10-18 15:30:24 -04:00
}
2014-08-18 12:39:04 -04:00
if (M->media.type != tgl_message_media_none) {
2015-04-22 13:09:53 -04:00
if (M->message && strlen (M->message)) {
mprintf (ev, " ");
}
2014-09-20 18:22:35 -04:00
print_media (ev, &M->media);
2013-10-16 15:19:39 -04:00
}
2014-09-20 18:22:35 -04:00
mpop_color (ev);
2013-10-18 15:30:24 -04:00
assert (!color_stack_pos);
2014-09-20 18:22:35 -04:00
mprintf (ev, "\n");
2014-08-18 12:39:04 -04:00
//print_end();
2013-10-16 15:19:39 -04:00
}
2014-02-27 03:48:05 -05:00
void play_sound (void) {
printf ("\a");
}
void set_interface_callbacks (void) {
if (readline_disabled) { return; }
readline_active = 1;
rl_filename_quote_characters = strdup (" ");
rl_basic_word_break_characters = strdup (" ");
rl_callback_handler_install (get_default_prompt (), interpreter);
rl_completion_entry_function = command_generator;
}