Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to 20150617 #1

Merged
merged 13 commits into from
Jun 17, 2015
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
1.3.2
* use TGL-2.0.2
* add block/unblock user methods
* support for autocomplete for bot's commands
1.3.1
* added error codes
1.3.0
Expand Down
57 changes: 57 additions & 0 deletions README-Cygwin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
### Installation on Windows
To use telegram-cli in Windows, you should compile with Cygwin which has POSIX API functionality.

Install [Cygwin](https://www.cygwin.com/) and cygwin's package manager, [apt-cyg](https://github.com/transcode-open/apt-cyg).

In Cygwin Terminal, install compiler and tools :

apt-cyg install cygwin32-gcc-core cygwin32-gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip

Now you have a compiler, but no libraries. You need readline, openssl, libconfig, liblua, python and libjansson to use telegram-cli's full functionality.


Then Clone GitHub Repository in Cygwin Terminal

git clone --recursive https://github.com/vysheng/tg.git


In Cygwin Terminal, type:

apt-cyg install libevent-devel openssl-devel libreadline-devel lua-devel python3
(Install package 'python' to use Python 2.7, or install package 'python3' to use Python 3)

libconfig and libjansson is not in cygwin's package, so you should compile yourself.

Compile libconfig

wget http://www.hyperrealm.com/libconfig/libconfig-1.5.tar.gz
tar xvf libconfig-1.5.tar.gz && cd libconfig-1.5
./configure
make && make install && cd ..

Compile libjansson

wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz
tar xvf jansson-2.7.tar.gz && cd jansson-2.7
./configure
make && make install && cd ..

Then, go to tg directory then generate Makefile.

cd tg
./configure

We need to patch Makefile and loop.c to compile in cygwin. Download this [patch](https://gist.github.com/ied206/d774a445f36004d263ab) then untar. Then, patch in tg directory.

patch -p1 < telegram-cli-cygwin.patch

Then
make

After compile is done, **telegram-cli.exe** will be generated in **bin** directory.

To run telegram-cli, type

bin/telegram-cli -k tg-server.pub

**Caution**: A binary compiled with Cygwin should be run in Cygwin Terminal.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ If two or more peers have same name, <sharp>number is appended to the name. (for
* **stats** - just for debugging
* **show_license** - prints contents of GPLv2
* **help** - prints this help
* **get_self** - get our user info

#### Card
* **export_card** - print your 'card' that anyone can later use to import your contact
Expand Down
160 changes: 152 additions & 8 deletions interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,30 @@ void next_token_end (void) {
}
}

void next_token_end_ac (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;
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 ();
}
}
}

#define NOT_FOUND (int)0x80000000
tgl_peer_id_t TGL_PEER_NOT_FOUND = {.id = NOT_FOUND};

Expand Down Expand Up @@ -569,6 +593,7 @@ enum command_argument {
ca_number,
ca_double,
ca_string_end,
ca_msg_string_end,
ca_string,
ca_modifier,
ca_command,
Expand Down Expand Up @@ -856,6 +881,11 @@ void do_broadcast (struct command *command, int arg_num, struct arg args[], stru

/* {{{ EDITING SELF PROFILE */

void do_get_self(struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
if (ev) { ev->refcnt ++; }
tgl_do_get_user_info (TLS, TGL_MK_USER(TLS->our_id), 0, print_user_info_gw, ev);
}

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 ++; }
Expand Down Expand Up @@ -1344,6 +1374,7 @@ struct command commands[MAX_COMMANDS_SIZE] = {
{"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_media <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},
{"get_self", {ca_none}, do_get_self, "get_self \tGet our user info", 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},
Expand All @@ -1360,11 +1391,11 @@ struct command commands[MAX_COMMANDS_SIZE] = {
{"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},
{"msg", {ca_peer, ca_msg_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, "reply <msg-id> <text>\tSends text reply to message", NULL},
{"reply", {ca_number, ca_msg_string_end, ca_none}, do_reply, "reply <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},
Expand Down Expand Up @@ -1422,9 +1453,14 @@ void register_new_command (struct command *cmd) {
commands[i] = *cmd;
}

tgl_peer_t *autocomplete_peer;
int autocomplete_id;

enum command_argument get_complete_mode (void) {
force_end_mode = 0;
line_ptr = rl_line_buffer;
autocomplete_peer = NULL;
autocomplete_id = 0;

while (1) {
next_token ();
Expand Down Expand Up @@ -1471,8 +1507,9 @@ enum command_argument get_complete_mode (void) {
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 (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) {
next_token_end_ac ();

if (cur_token_len < 0 || !cur_token_end_str) {
return ca_none;
} else {
Expand Down Expand Up @@ -1510,10 +1547,18 @@ enum command_argument get_complete_mode (void) {
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);
ok = (tgl_get_peer_type (cur_token_peer ()) != NOT_FOUND);
if (ok) {
autocomplete_peer = tgl_peer_get (TLS, cur_token_peer ());
autocomplete_id = 0;
}
break;
case ca_number:
ok = (cur_token_int () != NOT_FOUND);
if (ok) {
autocomplete_peer = NULL;
autocomplete_id = cur_token_int ();
}
break;
case ca_double:
ok = (cur_token_double () != NOT_FOUND);
Expand Down Expand Up @@ -1585,6 +1630,70 @@ int complete_command_list (int index, const char *text, int len, char **R) {
}
}


int complete_spec_message_answer (struct tgl_message *M, int index, const char *text, int len, char **R) {
if (!M || !M->reply_markup || !M->reply_markup->rows) {
*R = NULL;
return -1;
}
index ++;

int total = M->reply_markup->row_start[M->reply_markup->rows];
while (index < total && strncmp (M->reply_markup->buttons[index], text, len)) {
index ++;
}

if (index < total) {
*R = strdup (M->reply_markup->buttons[index]);
assert (*R);
return index;
} else {
*R = NULL;
return -1;
}
}

int complete_message_answer (tgl_peer_t *P, int index, const char *text, int len, char **R) {
struct tgl_message *M = P->last;
while (M && (M->flags & TGLMF_OUT)) {
M = M->next;
}


return complete_spec_message_answer (M, index, text, len, R);
}

int complete_user_command (tgl_peer_t *P, int index, const char *text, int len, char **R) {
if (len <= 0 || *text != '/') {
return complete_message_answer (P, index, text, len, R);
}
text ++;
len --;
struct tgl_user *U = (void *)P;
index ++;
if (!U->bot_info) {
*R = NULL;
return -1;
}
while (index < U->bot_info->commands_num && strncmp (U->bot_info->commands[index].command, text, len)) {
index ++;
}
if (index < U->bot_info->commands_num) {
*R = NULL;
assert (asprintf (R, "/%s", U->bot_info->commands[index].command) >= 0);
assert (*R);
return index;
} else {
*R = NULL;
return -1;
}
}

int complete_chat_command (tgl_peer_t *P, int index, const char *text, int len, char **R) {
*R = NULL;
return -1;
}

char *command_generator (const char *text, int state) {
#ifndef DISABLE_EXTF
static int len;
Expand Down Expand Up @@ -1616,7 +1725,7 @@ char *command_generator (const char *text, int state) {
if (mode != ca_file_name && mode != ca_file_name_end && index == -1) { return 0; }
}

if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double) {
if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double) {
if (c) { rl_line_buffer[rl_point] = c; }
return 0;
}
Expand Down Expand Up @@ -1653,6 +1762,30 @@ char *command_generator (const char *text, int state) {
index = complete_string_list (modifiers, index, command_pos, command_len, &R);
if (c) { rl_line_buffer[rl_point] = c; }
return R;
case ca_msg_string_end:
if (autocomplete_peer) {
if (tgl_get_peer_type (autocomplete_peer->id) == TGL_PEER_USER) {
index = complete_user_command (autocomplete_peer, index, command_pos, command_len, &R);
}
if (tgl_get_peer_type (autocomplete_peer->id) == TGL_PEER_CHAT) {
index = complete_chat_command (autocomplete_peer, index, command_pos, command_len, &R);
}
}
if (autocomplete_id) {
struct tgl_message *M = tgl_message_get (TLS, autocomplete_id);
if (M) {
if (command_len > 0 && *command_pos == '/') {
tgl_peer_t *P = tgl_peer_get (TLS, M->from_id);
if (P) {
index = complete_user_command (autocomplete_peer, index, command_pos, command_len, &R);
}
} else {
index = complete_spec_message_answer (M, index, command_pos, command_len, &R);
}
}
}
if (c) { rl_line_buffer[rl_point] = c; }
return R;
#ifndef DISABLE_EXTF
case ca_extf:
index = tglf_extf_autocomplete (TLS, text, len, index, &R, rl_line_buffer, rl_point);
Expand Down Expand Up @@ -2049,6 +2182,17 @@ void print_user_info_gw (struct tgl_state *TLSR, void *extra, int success, struc
mprintf (ev, "\t");
print_user_status (&U->status, ev);
mprintf (ev, "\n");

if (U->bot_info) {
mprintf (ev, "\tshare_text: %s\n", U->bot_info->share_text);
mprintf (ev, "\tdescription: %s\n", U->bot_info->description);
mprintf (ev, "\tcommands:\n");

int i;
for (i = 0; i < U->bot_info->commands_num; i++) {
mprintf (ev, "\t\t/%s <%s>: %s\n", U->bot_info->commands[i].command, U->bot_info->commands[i].params, U->bot_info->commands[i].description);
}
}
mpop_color (ev);
} else {
#ifdef USE_JSON
Expand Down Expand Up @@ -2782,7 +2926,7 @@ void interpreter_ex (char *line, void *ex) {
break;
}

if (op == ca_string_end || op == ca_file_name_end) {
if (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) {
next_token_end ();
if (cur_token_len < 0) {
fail_interface (TLS, ex, ENOSYS, "can not parse string_end arg #%d", args_num);
Expand Down Expand Up @@ -2915,7 +3059,7 @@ void interpreter_ex (char *line, void *ex) {
continue;
}
}
assert (0);
//assert (0);
}
int i;
for (i = 0; i < args_num; i++) {
Expand Down
2 changes: 1 addition & 1 deletion json-tg.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void json_pack_encr_chat (json_t *res, tgl_peer_t *P) {

json_t *json_pack_peer (tgl_peer_id_t id) {
tgl_peer_t *P = tgl_peer_get (TLS, id);
assert (P);
//assert (P);
json_t *res = json_object ();
assert (json_object_set (res, "id", json_integer (tgl_get_peer_id (id))) >= 0);

Expand Down
Loading