tg/interface.c

1526 lines
39 KiB
C
Raw Normal View History

2013-10-23 10:26:17 -04:00
/*
This file is part of telegram-client.
Telegram-client is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Telegram-client is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#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
2013-10-18 14:00:19 -04:00
2013-10-03 08:38:25 -04:00
#include "include.h"
2013-10-11 16:52:20 -04:00
#include "queries.h"
#include "interface.h"
#include "telegram.h"
#include "structures.h"
#include "mtproto-common.h"
2013-11-25 12:16:34 -05:00
2013-12-24 06:29:18 -05:00
//#define ALLOW_MULT 1
2013-10-24 11:44:54 -04:00
char *default_prompt = "> ";
int unread_messages;
2013-10-25 15:50:10 -04:00
int msg_num_mode;
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;
long long cur_uploading_bytes;
long long cur_uploaded_bytes;
long long cur_downloading_bytes;
long long cur_downloaded_bytes;
2013-10-29 20:08:30 -04:00
char *line_ptr;
extern peer_t *Peers[];
2013-11-04 12:34:27 -05:00
extern int peer_num;
2013-10-29 20:08:30 -04:00
2013-12-06 12:14:41 -05:00
int in_chat_mode;
peer_id_t chat_mode_id;
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);
}
char *next_token (int *l) {
while (*line_ptr == ' ') { line_ptr ++; }
if (!*line_ptr) {
*l = 0;
return 0;
}
int neg = 0;
char *s = line_ptr;
int in_str = 0;
while (*line_ptr && (*line_ptr != ' ' || neg || in_str)) {
2013-10-29 20:08:30 -04:00
if (*line_ptr == '\\') {
neg = 1 - neg;
} else {
if (*line_ptr == '"' && !neg) {
in_str = !in_str;
}
2013-10-29 20:08:30 -04:00
neg = 0;
}
line_ptr++;
}
*l = line_ptr - s;
return s;
}
#define NOT_FOUND (int)0x80000000
peer_id_t PEER_NOT_FOUND = {.id = NOT_FOUND};
long long next_token_int (void) {
2013-10-29 20:08:30 -04:00
int l;
char *s = next_token (&l);
if (!s) { return NOT_FOUND; }
char *r;
long long x = strtoll (s, &r, 10);
2013-10-29 20:08:30 -04:00
if (r == s + l) {
return x;
} else {
return NOT_FOUND;
}
}
peer_id_t next_token_user (void) {
2013-10-29 20:08:30 -04:00
int l;
char *s = next_token (&l);
if (!s) { return PEER_NOT_FOUND; }
2013-10-29 20:08:30 -04:00
if (l >= 6 && !memcmp (s, "user#", 5)) {
s += 5;
l -= 5;
int r = atoi (s);
if (r >= 0) { return set_peer_id (PEER_USER, r); }
else { return PEER_NOT_FOUND; }
2013-10-29 20:08:30 -04:00
}
2013-10-29 20:08:30 -04:00
int index = 0;
2013-11-04 12:34:27 -05:00
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) {
2013-10-29 20:08:30 -04:00
index ++;
}
2013-11-04 12:34:27 -05:00
if (index < peer_num) {
2013-10-29 20:08:30 -04:00
return Peers[index]->id;
} else {
return PEER_NOT_FOUND;
2013-10-29 20:08:30 -04:00
}
}
peer_id_t next_token_chat (void) {
2013-10-29 20:08:30 -04:00
int l;
char *s = next_token (&l);
if (!s) { return PEER_NOT_FOUND; }
if (l >= 6 && !memcmp (s, "chat#", 5)) {
s += 5;
l -= 5;
int r = atoi (s);
if (r >= 0) { return set_peer_id (PEER_CHAT, r); }
else { return PEER_NOT_FOUND; }
2013-10-29 20:08:30 -04:00
}
2013-10-29 20:08:30 -04:00
int index = 0;
2013-11-04 12:34:27 -05:00
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
2013-10-29 20:08:30 -04:00
index ++;
}
2013-11-04 12:34:27 -05:00
if (index < peer_num) {
2013-10-29 20:08:30 -04:00
return Peers[index]->id;
} else {
return PEER_NOT_FOUND;
2013-10-29 20:08:30 -04:00
}
}
peer_id_t next_token_encr_chat (void) {
int l;
char *s = next_token (&l);
if (!s) { return PEER_NOT_FOUND; }
int index = 0;
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) {
index ++;
}
if (index < peer_num) {
return Peers[index]->id;
} else {
return PEER_NOT_FOUND;
}
}
peer_id_t next_token_peer (void) {
2013-10-29 20:08:30 -04:00
int l;
char *s = next_token (&l);
if (!s) { return PEER_NOT_FOUND; }
if (l >= 6 && !memcmp (s, "user#", 5)) {
s += 5;
l -= 5;
int r = atoi (s);
if (r >= 0) { return set_peer_id (PEER_USER, r); }
else { return PEER_NOT_FOUND; }
}
if (l >= 6 && !memcmp (s, "chat#", 5)) {
s += 5;
l -= 5;
int r = atoi (s);
if (r >= 0) { return set_peer_id (PEER_CHAT, r); }
else { return PEER_NOT_FOUND; }
2013-10-29 20:08:30 -04:00
}
2013-10-29 20:08:30 -04:00
int index = 0;
2013-11-04 12:34:27 -05:00
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name))) {
2013-10-29 20:08:30 -04:00
index ++;
}
2013-11-04 12:34:27 -05:00
if (index < peer_num) {
2013-10-29 20:08:30 -04:00
return Peers[index]->id;
} else {
return PEER_NOT_FOUND;
2013-10-29 20:08:30 -04:00
}
}
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) {
peer_t *U = user_chat_get (chat_mode_id);
assert (U && U->print_name);
l += tsnprintf (buf + l, 999 - l, COLOR_RED "%.*s " COLOR_NORMAL, 100, U->print_name);
2013-12-06 12:14:41 -05:00
}
if (unread_messages || cur_uploading_bytes || cur_downloading_bytes) {
l += tsnprintf (buf + l, 999 - l, COLOR_RED "[");
int ok = 0;
if (unread_messages) {
l += tsnprintf (buf + l, 999 - l, "%d unread", unread_messages);
ok = 1;
}
if (cur_uploading_bytes) {
if (ok) { *(buf + l) = ' '; l ++; }
ok = 1;
l += tsnprintf (buf + l, 999 - l, "%lld%%Up", 100 * cur_uploaded_bytes / cur_uploading_bytes);
}
if (cur_downloading_bytes) {
if (ok) { *(buf + l) = ' '; l ++; }
ok = 1;
l += tsnprintf (buf + l, 999 - l, "%lld%%Down", 100 * cur_downloaded_bytes / cur_downloading_bytes);
}
l += tsnprintf (buf + l, 999 - l, "]" COLOR_NORMAL);
2013-10-24 11:44:54 -04:00
return buf;
2013-12-06 12:14:41 -05:00
}
l += tsnprintf (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
}
char *complete_none (const char *text UU, int state UU) {
return 0;
}
void set_prompt (const char *s) {
rl_set_prompt (s);
}
void update_prompt (void) {
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]",
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
};
2013-10-03 08:38:25 -04:00
char *commands[] = {
"help",
"msg",
2013-10-11 16:52:20 -04:00
"contact_list",
"stats",
"history",
"dialog_list",
"send_photo",
"send_video",
2013-10-22 04:36:07 -04:00
"send_text",
2013-10-23 06:24:59 -04:00
"chat_info",
2013-10-25 13:29:02 -04:00
"user_info",
2013-10-25 15:50:10 -04:00
"fwd",
2013-10-25 18:33:17 -04:00
"rename_chat",
"load_photo",
"view_photo",
"load_video_thumb",
"view_video_thumb",
"load_video",
"view_video",
"add_contact",
"rename_contact",
2013-10-25 05:28:29 -04:00
"show_license",
"search",
2013-11-04 12:34:27 -05:00
"mark_read",
"visualize_key",
2013-11-05 17:24:26 -05:00
"create_secret_chat",
2013-11-06 17:46:17 -05:00
"suggested_contacts",
2013-11-06 18:12:40 -05:00
"global_search",
"chat_add_user",
"chat_del_user",
"status_online",
"status_offline",
"contacts_search",
2013-11-09 13:23:11 -05:00
"quit",
"safe_quit",
2013-11-15 05:37:14 -05:00
"send_audio",
"load_audio",
"view_audio",
"send_document",
"load_document_thumb",
"view_document_thumb",
"load_document",
"view_document",
2013-11-15 11:14:25 -05:00
"set",
2013-12-06 12:14:41 -05:00
"chat_with_peer",
2013-10-03 08:38:25 -04:00
0 };
int commands_flags[] = {
070,
072,
07,
07,
072,
07,
0732,
0732,
2013-10-22 04:36:07 -04:00
0732,
2013-10-23 06:24:59 -04:00
074,
2013-10-25 15:50:10 -04:00
071,
2013-10-25 13:29:02 -04:00
072,
2013-10-25 18:33:17 -04:00
074,
2013-10-25 05:28:29 -04:00
07,
07,
07,
07,
07,
07,
07,
071,
07,
072,
2013-11-04 12:34:27 -05:00
072,
075,
2013-11-05 17:24:26 -05:00
071,
2013-11-06 17:46:17 -05:00
07,
2013-11-06 18:12:40 -05:00
07,
0724,
0724,
07,
07,
07,
2013-11-09 13:23:11 -05:00
07,
2013-12-24 06:58:31 -05:00
07,
2013-11-15 05:37:14 -05:00
0732,
07,
07,
0732,
07,
07,
07,
07,
2013-11-15 11:14:25 -05:00
07,
2013-12-06 12:14:41 -05:00
072,
2013-10-03 08:38:25 -04:00
};
2013-10-03 12:09:06 -04:00
2013-10-03 08:38:25 -04:00
int get_complete_mode (void) {
2013-10-29 20:08:30 -04:00
line_ptr = rl_line_buffer;
2013-10-03 08:38:25 -04:00
int l = 0;
2013-10-29 20:08:30 -04:00
char *r = next_token (&l);
if (!r) { return 0; }
while (r && r[0] == '[' && r[l - 1] == ']') {
r = next_token (&l);
if (!r) { return 0; }
}
if (*r == '[' && !r[l]) {
return 6;
}
2013-10-29 20:08:30 -04:00
if (!*line_ptr) { return 0; }
2013-10-03 08:38:25 -04:00
char **command = commands;
int n = 0;
int flags = -1;
while (*command) {
2013-10-29 20:08:30 -04:00
if (is_same_word (r, l, *command)) {
2013-10-03 08:38:25 -04:00
flags = commands_flags[n];
break;
}
n ++;
command ++;
}
if (flags == -1) {
2013-10-29 20:08:30 -04:00
return 7;
2013-10-03 08:38:25 -04:00
}
int s = 0;
while (1) {
2013-10-29 20:08:30 -04:00
if (!next_token (&l) || !*line_ptr) {
return flags ? flags & 7 : 7;
}
2013-10-03 08:38:25 -04:00
s ++;
if (s <= 4) { flags >>= 3; }
}
}
int complete_user_list (int index, const char *text, int len, char **R) {
index ++;
2013-11-04 12:34:27 -05:00
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) {
index ++;
}
2013-11-04 12:34:27 -05:00
if (index < peer_num) {
*R = strdup (Peers[index]->print_name);
return index;
} else {
return -1;
}
}
2013-10-23 06:24:59 -04:00
int complete_chat_list (int index, const char *text, int len, char **R) {
index ++;
2013-11-04 12:34:27 -05:00
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
2013-10-23 06:24:59 -04:00
index ++;
}
2013-11-04 12:34:27 -05:00
if (index < peer_num) {
*R = strdup (Peers[index]->print_name);
2013-10-23 06:24:59 -04:00
return index;
} else {
return -1;
}
}
int complete_encr_chat_list (int index, const char *text, int len, char **R) {
index ++;
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) {
index ++;
}
if (index < peer_num) {
*R = strdup (Peers[index]->print_name);
return index;
} else {
return -1;
}
}
int complete_user_chat_list (int index, const char *text, int len, char **R) {
index ++;
2013-11-04 12:34:27 -05:00
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) {
index ++;
}
2013-11-04 12:34:27 -05:00
if (index < peer_num) {
*R = strdup (Peers[index]->print_name);
return index;
} else {
return -1;
}
}
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]);
2013-10-03 08:38:25 -04:00
return index;
} else {
*R = 0;
return -1;
}
}
char *command_generator (const char *text, int state) {
static int len, index, mode;
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;
2013-10-03 08:38:25 -04:00
if (!state) {
len = strlen (text);
index = -1;
2013-10-28 17:56:17 -04:00
c = rl_line_buffer[rl_point];
rl_line_buffer[rl_point] = 0;
2013-10-03 08:38:25 -04:00
mode = get_complete_mode ();
} else {
if (index == -1) { return 0; }
}
2013-10-28 17:57:22 -04:00
if (mode == -1) {
if (c) { rl_line_buffer[rl_point] = c; }
return 0;
}
2013-10-03 08:38:25 -04:00
char *R = 0;
switch (mode & 7) {
case 0:
index = complete_string_list (commands, index, text, 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 1:
index = complete_user_list (index, text, 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 2:
index = complete_user_chat_list (index, text, 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 3:
2013-10-28 17:56:17 -04:00
R = rl_filename_completion_function(text,state);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
2013-10-23 06:24:59 -04:00
case 4:
index = complete_chat_list (index, text, 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 5:
index = complete_encr_chat_list (index, text, len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case 6:
index = complete_string_list (modifiers, index, text, len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
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;
}
}
char **complete_text (char *text, int start UU, int end UU) {
return (char **) rl_completion_matches (text, command_generator);
}
2013-11-25 12:16:34 -05:00
int offline_mode;
int count = 1;
void work_modifier (const char *s, int l) {
if (is_same_word (s, l, "[offline]")) {
offline_mode = 1;
}
#ifdef ALLOW_MULT
if (sscanf (s, "[x%d]", &count) >= 1) {
}
#endif
2013-10-29 20:08:30 -04:00
}
2013-12-06 12:14:41 -05:00
void interpreter_chat_mode (char *line) {
if (!strncmp (line, "/exit", 5) || !strncmp (line, "/quit", 5)) {
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; }
do_get_history (chat_mode_id, limit);
return;
}
if (!strncmp (line, "/read", 5)) {
do_mark_read (chat_mode_id);
return;
}
2013-12-06 12:14:41 -05:00
do_send_message (chat_mode_id, line, strlen (line));
}
2013-10-03 08:38:25 -04:00
void interpreter (char *line UU) {
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;
count = 1;
2013-10-29 20:08:30 -04:00
if (!line) {
in_readline = 0;
return;
}
if (line && *line) {
add_history (line);
}
2013-10-29 20:08:30 -04:00
int l;
char *command;
while (1) {
command = next_token (&l);
2013-11-01 07:27:08 -04:00
if (!command) { in_readline = 0; return; }
2013-10-29 20:08:30 -04:00
if (*command == '[' && command[l - 1] == ']') {
2013-11-25 12:16:34 -05:00
work_modifier (command, l);
2013-10-29 20:08:30 -04:00
} else {
break;
}
}
2013-11-25 12:16:34 -05:00
int _;
char *save = line_ptr;
int ll = l;
char *cs = command;
for (_ = 0; _ < count; _ ++) {
line_ptr = save;
l = ll;
command = cs;
2013-10-29 20:08:30 -04:00
#define IS_WORD(s) is_same_word (command, l, (s))
#define RET in_readline = 0; return;
peer_id_t id;
#define GET_PEER \
id = next_token_peer (); \
if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \
2013-12-06 11:40:52 -05:00
printf ("Bad user/chat id\n"); \
RET; \
}
#define GET_PEER_USER \
id = next_token_user (); \
if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \
printf ("Bad user id\n"); \
RET; \
}
#define GET_PEER_CHAT \
id = next_token_chat (); \
if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \
printf ("Bad chat id\n"); \
RET; \
}
#define GET_PEER_ENCR_CHAT \
id = next_token_encr_chat (); \
if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \
printf ("Bad encr_chat id\n"); \
RET; \
}
2013-10-29 20:08:30 -04:00
if (IS_WORD ("contact_list")) {
2013-10-11 16:52:20 -04:00
do_update_contact_list ();
2013-10-29 20:08:30 -04:00
} else if (IS_WORD ("dialog_list")) {
do_get_dialog_list ();
2013-10-29 20:08:30 -04:00
} else if (IS_WORD ("stats")) {
static char stat_buf[1 << 15];
print_stat (stat_buf, (1 << 15) - 1);
printf ("%s\n", stat_buf);
2013-10-29 20:08:30 -04:00
} else if (IS_WORD ("msg")) {
GET_PEER;
2013-10-29 20:08:30 -04:00
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty message\n");
RET;
}
do_send_message (id, s, strlen (s));
} else if (IS_WORD ("rename_chat")) {
GET_PEER_CHAT;
2013-10-29 20:08:30 -04:00
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty new name\n");
RET;
}
do_rename_chat (id, s);
} else if (IS_WORD ("send_photo")) {
GET_PEER;
2013-10-29 20:08:30 -04:00
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
do_send_photo (CODE_input_media_uploaded_photo, id, tstrndup (s, t));
2013-10-29 20:08:30 -04:00
} else if (IS_WORD("send_video")) {
GET_PEER;
2013-10-29 20:08:30 -04:00
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
do_send_photo (CODE_input_media_uploaded_video, id, tstrndup (s, t));
2013-10-29 20:08:30 -04:00
} else if (IS_WORD ("send_text")) {
GET_PEER;
2013-10-29 20:08:30 -04:00
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
do_send_text (id, tstrndup (s, t));
2013-10-29 20:08:30 -04:00
} else if (IS_WORD ("fwd")) {
GET_PEER;
2013-10-29 20:08:30 -04:00
int num = next_token_int ();
if (num == NOT_FOUND || num <= 0) {
printf ("Bad msg id\n");
RET;
}
do_forward_message (id, num);
} else if (IS_WORD ("load_photo")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
2013-10-29 20:08:30 -04:00
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_photo) {
do_load_photo (&M->media.photo, 1);
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) {
do_load_encr_video (&M->media.encr_video, 1); // this is not a bug.
2013-10-29 20:08:30 -04:00
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_photo")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
2013-10-29 20:08:30 -04:00
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_photo) {
do_load_photo (&M->media.photo, 2);
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) {
do_load_encr_video (&M->media.encr_video, 2); // this is not a bug.
2013-10-29 20:08:30 -04:00
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_video_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
2013-10-29 20:08:30 -04:00
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_video) {
do_load_video_thumb (&M->media.video, 1);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_video_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
2013-10-29 20:08:30 -04:00
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_video) {
do_load_video_thumb (&M->media.video, 2);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_video")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
2013-10-29 20:08:30 -04:00
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_video) {
do_load_video (&M->media.video, 1);
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) {
do_load_encr_video (&M->media.encr_video, 1);
2013-10-29 20:08:30 -04:00
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_video")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
2013-10-29 20:08:30 -04:00
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_video) {
do_load_video (&M->media.video, 2);
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) {
do_load_encr_video (&M->media.encr_video, 2);
2013-10-29 20:08:30 -04:00
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("chat_info")) {
GET_PEER_CHAT;
2013-10-29 20:08:30 -04:00
do_get_chat_info (id);
} else if (IS_WORD ("user_info")) {
GET_PEER_USER;
2013-10-29 20:08:30 -04:00
do_get_user_info (id);
} else if (IS_WORD ("history")) {
GET_PEER;
2013-10-29 20:08:30 -04:00
int limit = next_token_int ();
do_get_history (id, limit > 0 ? limit : 40);
} else if (IS_WORD ("chat_add_user")) {
GET_PEER_CHAT;
peer_id_t chat_id = id;
GET_PEER_USER;
do_add_user_to_chat (chat_id, id, 100);
} else if (IS_WORD ("chat_del_user")) {
GET_PEER_CHAT;
peer_id_t chat_id = id;
GET_PEER_USER;
do_del_user_from_chat (chat_id, id);
} else if (IS_WORD ("add_contact")) {
int phone_len, first_name_len, last_name_len;
char *phone, *first_name, *last_name;
phone = next_token (&phone_len);
if (!phone) {
printf ("No phone number found\n");
RET;
}
first_name = next_token (&first_name_len);
if (!first_name_len) {
printf ("No first name found\n");
RET;
}
last_name = next_token (&last_name_len);
if (!last_name_len) {
printf ("No last name found\n");
RET;
}
do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 0);
} else if (IS_WORD ("rename_contact")) {
GET_PEER_USER;
peer_t *U = user_chat_get (id);
if (!U) {
printf ("No such user\n");
RET;
}
if (!U->user.phone || !strlen (U->user.phone)) {
printf ("User has no phone. Can not rename\n");
RET;
}
int phone_len, first_name_len, last_name_len;
char *phone, *first_name, *last_name;
phone_len = strlen (U->user.phone);
phone = U->user.phone;
first_name = next_token (&first_name_len);
if (!first_name_len) {
printf ("No first name found\n");
RET;
}
last_name = next_token (&last_name_len);
if (!last_name_len) {
printf ("No last name found\n");
RET;
}
do_add_contact (phone, phone_len, first_name, first_name_len, last_name, last_name_len, 1);
2013-10-29 20:08:30 -04:00
} else if (IS_WORD ("help")) {
//print_start ();
2013-10-24 14:22:11 -04:00
push_color (COLOR_YELLOW);
printf (
"help - prints this help\n"
"msg <peer> Text - sends message to this peer\n"
"contact_list - prints info about users in your contact list\n"
"stats - just for debugging \n"
"history <peerd> [limit] - prints history (and marks it as read). Default limit = 40\n"
"dialog_list - prints info about your dialogs\n"
"send_photo <peer> <photo-file-name> - sends photo to peer\n"
"send_video <peer> <video-file-name> - sends video to peer\n"
"send_text <peer> <text-file-name> - sends text file as plain messages\n"
"chat_info <chat> - prints info about chat\n"
2013-10-25 13:29:02 -04:00
"user_info <user> - prints info about user\n"
"fwd <user> <msg-seqno> - forward message to user. You can see message numbers starting client with -N\n"
"rename_chat <char> <new-name>\n"
"load_photo/load_video/load_video_thumb <msg-seqno> - loads photo/video to download dir\n"
"view_photo/view_video/view_video_thumb <msg-seqno> - loads photo/video to download dir and starts system default viewer\n"
"show_license - prints contents of GPLv2\n"
2013-11-04 12:34:27 -05:00
"search <peer> pattern - searches pattern in messages with peer\n"
2013-11-06 18:18:35 -05:00
"global_search pattern - searches pattern in all messages\n"
2013-11-04 12:34:27 -05:00
"mark_read <peer> - mark read all received messages with peer\n"
2013-11-06 18:18:35 -05:00
"add_contact <phone-number> <first-name> <last-name> - tries to add contact to contact-list by phone\n"
"create_secret_chat <user> - creates secret chat with this user\n"
"rename_contact <user> <first-name> <last-name> - tries to rename contact. If you have another device it will be a fight\n"
"suggested_contacts - print info about contacts, you have max common friends\n"
"visualize_key <secret_chat> - prints visualization of encryption key. You should compare it to your partner's one\n"
2013-11-15 11:14:25 -05:00
"set <param> <param-value>. Possible <param> values are:\n"
"\tdebug_verbosity - just as it sounds. Debug verbosity\n"
"\tlog_level - level of logging of new events. Lower is less verbose:\n"
"\t\tLevel 1: prints info about read messages\n"
"\t\tLevel 2: prints line, when somebody is typing in chat\n"
"\t\tLevel 3: prints line, when somebody changes online status\n"
"\tmsg_num - enables/disables numeration of messages\n"
2013-12-06 12:16:17 -05:00
"chat_with_peer <peer> - starts chat with this peer. Every command after is message to this peer. Type /exit or /quit to end this mode\n"
2013-10-24 14:22:11 -04:00
);
pop_color ();
2013-10-29 20:08:30 -04:00
} else if (IS_WORD ("show_license")) {
2013-10-25 05:28:29 -04:00
char *b =
#include "LICENSE.h"
;
printf ("%s", b);
} else if (IS_WORD ("search")) {
GET_PEER;
int from = 0;
int to = 0;
int limit = 40;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty message\n");
RET;
}
do_msg_search (id, from, to, limit, s);
2013-11-06 18:12:40 -05:00
} else if (IS_WORD ("global_search")) {
int from = 0;
int to = 0;
int limit = 40;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty message\n");
RET;
}
do_msg_search (PEER_NOT_FOUND, from, to, limit, s);
2013-11-04 12:34:27 -05:00
} else if (IS_WORD ("mark_read")) {
GET_PEER;
do_mark_read (id);
} else if (IS_WORD ("visualize_key")) {
GET_PEER_ENCR_CHAT;
do_visualize_key (id);
2013-11-05 17:24:26 -05:00
} else if (IS_WORD ("create_secret_chat")) {
GET_PEER;
do_create_secret_chat (id);
2013-11-06 17:46:17 -05:00
} else if (IS_WORD ("suggested_contacts")) {
do_get_suggested ();
} else if (IS_WORD ("status_online")) {
do_update_status (1);
} else if (IS_WORD ("status_offline")) {
do_update_status (0);
} else if (IS_WORD ("contacts_search")) {
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty search query\n");
RET;
}
do_contacts_search (100, s);
2013-11-15 05:37:14 -05:00
} else if (IS_WORD("send_audio")) {
GET_PEER;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
do_send_photo (CODE_input_media_uploaded_audio, id, tstrndup (s, t));
2013-11-15 05:37:14 -05:00
} else if (IS_WORD("send_document")) {
GET_PEER;
int t;
char *s = next_token (&t);
if (!s) {
printf ("Empty file name\n");
RET;
}
do_send_photo (CODE_input_media_uploaded_document, id, tstrndup (s, t));
2013-11-15 05:37:14 -05:00
} else if (IS_WORD ("load_audio")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_audio) {
2014-01-17 09:16:35 -05:00
do_load_audio (&M->media.video, 1);
2013-11-15 05:37:14 -05:00
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) {
do_load_encr_video (&M->media.encr_video, 1);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_audio")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_audio) {
2014-01-17 09:16:35 -05:00
do_load_audio (&M->media.video, 2);
2013-11-15 05:37:14 -05:00
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) {
do_load_encr_video (&M->media.encr_video, 2);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_document_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_document) {
2013-12-20 10:45:59 -05:00
do_load_document_thumb (&M->media.document, 1);
2013-11-15 05:37:14 -05:00
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_document_thumb")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_document) {
2013-12-20 10:45:59 -05:00
do_load_document_thumb (&M->media.document, 2);
2013-11-15 05:37:14 -05:00
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("load_document")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_document) {
2013-12-20 10:45:59 -05:00
do_load_document (&M->media.document, 1);
2013-11-15 05:37:14 -05:00
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) {
do_load_encr_video (&M->media.encr_video, 1);
} else {
printf ("Bad msg id\n");
RET;
}
} else if (IS_WORD ("view_document")) {
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
struct message *M = message_get (num);
if (M && !M->service && M->media.type == (int)CODE_message_media_document) {
2013-12-20 10:45:59 -05:00
do_load_document (&M->media.document, 2);
2013-11-15 05:37:14 -05:00
} else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) {
do_load_encr_video (&M->media.encr_video, 2);
} else {
printf ("Bad msg id\n");
RET;
}
2013-11-15 11:14:25 -05:00
} else if (IS_WORD ("set")) {
command = next_token (&l);
long long num = next_token_int ();
if (num == NOT_FOUND) {
printf ("Bad msg id\n");
RET;
}
if (IS_WORD ("debug_verbosity")) {
verbosity = num;
} else if (IS_WORD ("log_level")) {
log_level = num;
} else if (IS_WORD ("msg_num")) {
msg_num_mode = num;
}
2013-12-06 12:14:41 -05:00
} else if (IS_WORD ("chat_with_peer")) {
GET_PEER;
in_chat_mode = 1;
chat_mode_id = id;
2013-11-09 13:23:11 -05:00
} else if (IS_WORD ("quit")) {
exit (0);
} else if (IS_WORD ("safe_quit")) {
safe_quit = 1;
2013-10-11 16:52:20 -04:00
}
2013-11-25 12:16:34 -05:00
}
2013-10-29 20:08:30 -04:00
#undef IS_WORD
#undef RET
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
}
int readline_active;
2013-10-11 16:52:20 -04:00
void rprintf (const char *format, ...) {
print_start ();
va_list ap;
va_start (ap, format);
vfprintf (stdout, format, ap);
va_end (ap);
print_end();
}
2013-10-18 15:30:24 -04:00
int saved_point;
char *saved_line;
int prompt_was;
void print_start (void) {
2013-10-29 20:08:30 -04:00
if (in_readline) { return; }
2013-10-18 15:30:24 -04:00
assert (!prompt_was);
if (readline_active) {
saved_point = rl_point;
#ifdef READLINE_GNU
saved_line = talloc (rl_end + 1);
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);
#else
assert (rl_end >= 0);
saved_line = talloc (rl_end + 1);
memcpy (saved_line, rl_line_buffer, rl_end + 1);
rl_line_buffer[0] = 0;
set_prompt ("");
#endif
2013-10-18 15:30:24 -04:00
rl_redisplay();
}
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; }
2013-10-18 15:30:24 -04:00
assert (prompt_was);
if (readline_active) {
set_prompt (get_default_prompt ());
#if READLINE_GNU
2013-10-18 15:30:24 -04:00
rl_replace_line(saved_line, 0);
#else
memcpy (rl_line_buffer, saved_line, rl_end + 1); // not safe, but I hope this would work.
#endif
2013-10-18 15:30:24 -04:00
rl_point = saved_point;
rl_redisplay();
tfree_str (saved_line);
2013-10-18 15:30:24 -04:00
}
prompt_was = 0;
}
void hexdump (int *in_ptr, int *in_end) {
print_start ();
int *ptr = in_ptr;
while (ptr < in_end) { printf (" %08x", *(ptr ++)); }
printf ("\n");
print_end ();
}
void logprintf (const char *format, ...) {
2013-11-21 14:35:49 -05:00
int x = 0;
if (!prompt_was) {
x = 1;
print_start ();
}
printf (COLOR_GREY " *** ");
2013-10-11 16:52:20 -04:00
va_list ap;
va_start (ap, format);
vfprintf (stdout, format, ap);
va_end (ap);
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) {
assert (color_stack_pos < 10);
color_stack[color_stack_pos ++] = color;
printf ("%s", color);
}
void pop_color (void) {
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);
}
}
void print_media (struct message_media *M) {
assert (M);
2013-10-18 15:30:24 -04:00
switch (M->type) {
case CODE_message_media_empty:
case CODE_decrypted_message_media_empty:
2013-10-18 15:30:24 -04:00
return;
case CODE_message_media_photo:
if (M->photo.caption && strlen (M->photo.caption)) {
printf ("[photo %s]", M->photo.caption);
} else {
printf ("[photo]");
}
2013-10-18 15:30:24 -04:00
return;
case CODE_message_media_video:
printf ("[video]");
return;
2013-11-15 05:37:14 -05:00
case CODE_message_media_audio:
printf ("[audio]");
return;
case CODE_message_media_document:
if (M->document.mime_type && M->document.caption) {
printf ("[document %s: type %s]", M->document.caption, M->document.mime_type);
} else {
printf ("[document]");
}
return;
2013-11-04 12:34:27 -05:00
case CODE_decrypted_message_media_photo:
printf ("[photo]");
return;
case CODE_decrypted_message_media_video:
printf ("[video]");
return;
2013-11-15 05:37:14 -05:00
case CODE_decrypted_message_media_audio:
printf ("[audio]");
return;
case CODE_decrypted_message_media_document:
printf ("[document]");
return;
2013-10-18 15:30:24 -04:00
case CODE_message_media_geo:
2013-10-23 14:23:33 -04:00
printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude);
2013-10-18 15:30:24 -04:00
return;
case CODE_message_media_contact:
printf ("[contact] ");
push_color (COLOR_RED);
printf ("%s %s ", M->first_name, M->last_name);
pop_color ();
printf ("%s", M->phone);
return;
case CODE_message_media_unsupported:
printf ("[unsupported]");
return;
default:
assert (0);
}
}
2013-10-23 06:24:59 -04:00
int unknown_user_list_pos;
int unknown_user_list[1000];
void print_user_name (peer_id_t id, peer_t *U) {
assert (get_peer_type (id) == PEER_USER);
2013-10-18 15:30:24 -04:00
push_color (COLOR_RED);
if (!U) {
printf ("user#%d", 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++) {
if (unknown_user_list[i] == 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);
unknown_user_list[unknown_user_list_pos ++] = get_peer_id (id);
2013-10-23 06:24:59 -04:00
}
2013-10-18 15:30:24 -04:00
} else {
2013-10-24 03:38:32 -04:00
if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) {
2013-10-23 06:24:59 -04:00
push_color (COLOR_REDB);
}
2013-11-21 14:35:49 -05:00
if ((U->flags & FLAG_DELETED)) {
2013-11-06 18:12:40 -05:00
printf ("deleted user#%d", get_peer_id (id));
2013-11-21 14:35:49 -05:00
} else if (!(U->flags & FLAG_CREATED)) {
printf ("empty user#%d", get_peer_id (id));
2013-11-06 18:12:40 -05:00
} else if (!U->user.first_name || !strlen (U->user.first_name)) {
2013-10-23 06:24:59 -04:00
printf ("%s", U->user.last_name);
2013-11-06 18:12:40 -05:00
} else if (!U->user.last_name || !strlen (U->user.last_name)) {
2013-10-23 06:24:59 -04:00
printf ("%s", U->user.first_name);
} else {
printf ("%s %s", U->user.first_name, U->user.last_name);
}
2013-10-24 03:38:32 -04:00
if (U->flags & (FLAG_USER_SELF | FLAG_USER_CONTACT)) {
2013-10-23 06:24:59 -04:00
pop_color ();
}
2013-10-18 15:30:24 -04:00
}
pop_color ();
}
void print_chat_name (peer_id_t id, peer_t *C) {
assert (get_peer_type (id) == PEER_CHAT);
2013-10-18 15:30:24 -04:00
push_color (COLOR_MAGENTA);
if (!C) {
printf ("chat#%d", get_peer_id (id));
2013-10-18 15:30:24 -04:00
} else {
printf ("%s", C->chat.title);
}
pop_color ();
}
void print_encr_chat_name (peer_id_t id, peer_t *C) {
assert (get_peer_type (id) == PEER_ENCR_CHAT);
push_color (COLOR_MAGENTA);
if (!C) {
printf ("encr_chat#%d", get_peer_id (id));
} else {
printf ("%s", C->print_name);
}
pop_color ();
}
void print_encr_chat_name_full (peer_id_t id, peer_t *C) {
assert (get_peer_type (id) == PEER_ENCR_CHAT);
push_color (COLOR_MAGENTA);
if (!C) {
printf ("encr_chat#%d", get_peer_id (id));
} else {
printf ("%s", C->print_name);
}
pop_color ();
}
2013-10-18 15:30:24 -04:00
static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
void print_date (long t) {
struct tm *tm = localtime (&t);
if (time (0) - t < 12 * 60 * 60) {
printf ("[%02d:%02d] ", tm->tm_hour, tm->tm_min);
} else {
printf ("[%02d %s]", tm->tm_mday, monthes[tm->tm_mon]);
}
}
2013-10-24 03:38:32 -04:00
void print_date_full (long t) {
struct tm *tm = localtime (&t);
printf ("[%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-18 15:30:24 -04:00
int our_id;
void print_service_message (struct message *M) {
assert (M);
print_start ();
push_color (COLOR_GREY);
2013-10-24 18:21:52 -04:00
push_color (COLOR_MAGENTA);
if (msg_num_mode) {
printf ("%lld ", M->id);
}
print_date (M->date);
2013-10-24 18:21:52 -04:00
pop_color ();
printf (" ");
2013-11-15 05:37:14 -05:00
if (get_peer_type (M->to_id) == PEER_CHAT) {
print_chat_name (M->to_id, user_chat_get (M->to_id));
} else {
assert (get_peer_type (M->to_id) == PEER_ENCR_CHAT);
2013-11-15 05:37:14 -05:00
print_encr_chat_name (M->to_id, user_chat_get (M->to_id));
}
printf (" ");
print_user_name (M->from_id, user_chat_get (M->from_id));
switch (M->action.type) {
case CODE_message_action_empty:
printf ("\n");
break;
2013-11-22 18:26:35 -05:00
case CODE_message_action_geo_chat_create:
printf ("Created geo chat\n");
break;
case CODE_message_action_geo_chat_checkin:
printf ("Checkin in geochat\n");
break;
case CODE_message_action_chat_create:
printf (" created chat %s. %d users\n", M->action.title, M->action.user_num);
break;
case CODE_message_action_chat_edit_title:
printf (" changed title to %s\n",
M->action.new_title);
break;
case CODE_message_action_chat_edit_photo:
printf (" changed photo\n");
break;
case CODE_message_action_chat_delete_photo:
printf (" deleted photo\n");
break;
case CODE_message_action_chat_add_user:
printf (" added user ");
print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user)));
printf ("\n");
break;
case CODE_message_action_chat_delete_user:
printf (" deleted user ");
print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user)));
printf ("\n");
break;
2013-11-15 05:37:14 -05:00
case CODE_decrypted_message_action_set_message_t_t_l:
printf (" set ttl to %d seconds. Unsupported yet\n", M->action.ttl);
break;
default:
assert (0);
}
pop_color ();
print_end ();
}
peer_id_t last_from_id;
peer_id_t last_to_id;
2013-10-16 15:19:39 -04:00
void print_message (struct message *M) {
assert (M);
2013-11-21 14:35:49 -05:00
if (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED)) {
2013-11-04 12:34:27 -05:00
return;
}
if (!(M->flags & FLAG_CREATED)) { return; }
if (M->service) {
print_service_message (M);
return;
}
2013-12-18 10:21:49 -05:00
if (!get_peer_type (M->to_id)) {
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
print_start ();
if (get_peer_type (M->to_id) == PEER_USER) {
if (M->out) {
2013-10-18 15:30:24 -04:00
push_color (COLOR_GREEN);
2013-10-25 15:50:10 -04:00
if (msg_num_mode) {
printf ("%lld ", M->id);
2013-10-25 15:50:10 -04:00
}
2013-10-18 15:30:24 -04:00
print_date (M->date);
pop_color ();
printf (" ");
print_user_name (M->to_id, user_chat_get (M->to_id));
push_color (COLOR_GREEN);
if (M->unread) {
printf (" <<< ");
} else {
printf (" ««« ");
}
2013-10-16 15:19:39 -04:00
} else {
2013-10-18 15:30:24 -04:00
push_color (COLOR_BLUE);
2013-10-25 15:50:10 -04:00
if (msg_num_mode) {
printf ("%lld ", M->id);
2013-10-25 15:50:10 -04:00
}
2013-10-18 15:30:24 -04:00
print_date (M->date);
pop_color ();
printf (" ");
print_user_name (M->from_id, user_chat_get (M->from_id));
push_color (COLOR_BLUE);
if (M->unread) {
printf (" >>> ");
} else {
printf (" »»» ");
}
}
2013-11-04 12:34:27 -05:00
} else if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) {
peer_t *P = user_chat_get (M->to_id);
assert (P);
if (M->out) {
push_color (COLOR_GREEN);
if (msg_num_mode) {
printf ("%lld ", M->id);
}
print_date (M->date);
printf (" ");
push_color (COLOR_CYAN);
printf (" %s", P->print_name);
pop_color ();
if (M->unread) {
printf (" <<< ");
} else {
printf (" ««« ");
}
} else {
push_color (COLOR_BLUE);
if (msg_num_mode) {
printf ("%lld ", M->id);
}
print_date (M->date);
push_color (COLOR_CYAN);
printf (" %s", P->print_name);
pop_color ();
if (M->unread) {
printf (" >>> ");
} else {
printf (" »»» ");
}
}
} else {
2013-11-04 12:34:27 -05:00
assert (get_peer_type (M->to_id) == PEER_CHAT);
2013-10-18 15:30:24 -04:00
push_color (COLOR_MAGENTA);
2013-10-25 15:50:10 -04:00
if (msg_num_mode) {
printf ("%lld ", M->id);
2013-10-25 15:50:10 -04:00
}
2013-10-18 15:30:24 -04:00
print_date (M->date);
pop_color ();
printf (" ");
print_chat_name (M->to_id, user_chat_get (M->to_id));
printf (" ");
print_user_name (M->from_id, user_chat_get (M->from_id));
if ((get_peer_type (M->from_id) == PEER_USER) && (get_peer_id (M->from_id) == our_id)) {
2013-10-18 15:30:24 -04:00
push_color (COLOR_GREEN);
} else {
push_color (COLOR_BLUE);
2013-10-16 15:19:39 -04:00
}
if (M->unread) {
printf (" >>> ");
} else {
printf (" »»» ");
}
2013-10-18 15:30:24 -04:00
}
if (get_peer_type (M->fwd_from_id) == PEER_USER) {
2013-10-24 18:21:52 -04:00
printf ("[fwd from ");
print_user_name (M->fwd_from_id, user_chat_get (M->fwd_from_id));
printf ("] ");
}
2013-10-18 15:30:24 -04:00
if (M->message && strlen (M->message)) {
printf ("%s", M->message);
}
if (M->media.type != CODE_message_media_empty) {
print_media (&M->media);
2013-10-16 15:19:39 -04:00
}
2013-10-18 15:30:24 -04:00
pop_color ();
assert (!color_stack_pos);
printf ("\n");
print_end();
2013-10-16 15:19:39 -04:00
}
void set_interface_callbacks (void) {
readline_active = 1;
rl_callback_handler_install (get_default_prompt (), interpreter);
rl_attempted_completion_function = (CPPFunction *) complete_text;
rl_completion_entry_function = (void *)complete_none;
}