1 /*
2 This file is part of telegram-cli.
3
4 Telegram-cli is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 Telegram-cli is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this telegram-cli. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright Vitaly Valtman 2013-2015
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifdef USE_PYTHON
25 # include "python-tg.h"
26 #endif
27
28 #ifndef _GNU_SOURCE
29 #define _GNU_SOURCE
30 #endif
31
32 #include <assert.h>
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <time.h>
38
39 #ifdef READLINE_GNU
40 #include <readline/readline.h>
41 #include <readline/history.h>
42 #else
43 #include <readline/readline.h>
44 #include <readline/history.h>
45 #endif
46 #include <unistd.h>
47
48 //#include "queries.h"
49
50 #include "interface.h"
51 #include "telegram.h"
52
53 #ifdef EVENT_V2
54 #include <event2/event.h>
55 #include <event2/bufferevent.h>
56 #include <event2/buffer.h>
57 #else
58 #include <event.h>
59 #include "event-old.h"
60 #endif
61 //#include "auto/constants.h"
62 //#include "tools.h"
63 //#include "structures.h"
64
65 #ifdef USE_LUA
66 # include "lua-tg.h"
67 #endif
68
69
70 //#include "mtproto-common.h"
71
72 #include <tgl/tgl.h>
73 #include <tgl/tgl-queries.h>
74 #include "loop.h"
75
76 #ifndef PATH_MAX
77 #define PATH_MAX 4096
78 #endif
79
80 #ifdef __APPLE__
81 #define OPEN_BIN "open %s"
82 #else
83 #define OPEN_BIN "xdg-open %s"
84 #endif
85
86 #ifdef USE_JSON
87 # include <jansson.h>
88 # include "json-tg.h"
89 #endif
90
91 #include "tgl/mtproto-common.h"
92 #include "auto/auto-store.h"
93 #include "auto/auto-fetch-ds.h"
94 #include "auto/auto-types.h"
95 #include "auto/auto-free-ds.h"
96
97 #include <errno.h>
98
99 #include "tgl/tree.h"
100
101 struct username_peer_pair {
102 const char *username;
103 tgl_peer_t *peer;
104 };
105
106 #define username_peer_pair_cmp(a,b) strcmp (a->username, b->username)
107 DEFINE_TREE (username_peer_pair, struct username_peer_pair *, username_peer_pair_cmp, NULL)
108 struct tree_username_peer_pair *username_peer_pair;
109
110 struct username_peer_pair *current_map;
111
112 #define ALLOW_MULT 1
113 char *default_prompt = "> ";
114
115 extern int read_one_string;
116 extern char one_string[];
117 extern int one_string_len;
118 extern char *one_string_prompt;
119 extern int one_string_flags;
120 extern int enable_json;
121 int disable_auto_accept;
122 int msg_num_mode;
123 int permanent_msg_id_mode;
124 int permanent_peer_id_mode;
125 int disable_colors;
126 extern int alert_sound;
127 extern int auto_mark_read;
128 extern int binlog_read;
129 extern char *home_directory;
130 int do_html;
131
132 int safe_quit;
133
134 int in_readline;
135 int readline_active;
136
137 int log_level;
138
139 char *line_ptr;
140
141 int in_chat_mode;
142 tgl_peer_id_t chat_mode_id;
143 extern int readline_disabled;
144
145 extern int disable_output;
146
147 struct in_ev *notify_ev;
148
149 extern int usfd;
150 extern int sfd;
151 extern int use_ids;
152
153 extern int daemonize;
154
155 extern struct tgl_state *TLS;
156 int readline_deactivated;
157
158 void fail_interface (struct tgl_state *TLS, struct in_ev *ev, int error_code, const char *format, ...) __attribute__ (( format (printf, 4, 5)));
159 void event_incoming (struct bufferevent *bev, short what, void *_arg);
160
is_same_word(const char * s,size_t l,const char * word)161 int is_same_word (const char *s, size_t l, const char *word) {
162 return s && word && strlen (word) == l && !memcmp (s, word, l);
163 }
164
skip_wspc(void)165 static void skip_wspc (void) {
166 while (*line_ptr && ((unsigned char)*line_ptr) <= ' ') {
167 line_ptr ++;
168 }
169 }
170
171 static char *cur_token;
172 static int cur_token_len;
173 static int cur_token_end_str;
174 static int cur_token_quoted;
175
176 #define SOCKET_ANSWER_MAX_SIZE (1 << 25)
177 static char socket_answer[SOCKET_ANSWER_MAX_SIZE + 1];
178 static int socket_answer_pos = -1;
179
socket_answer_start(void)180 void socket_answer_start (void) {
181 socket_answer_pos = 0;
182 }
183
184 static void socket_answer_add_printf (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
socket_answer_add_printf(const char * format,...)185 void socket_answer_add_printf (const char *format, ...) {
186 if (socket_answer_pos < 0) { return; }
187 va_list ap;
188 va_start (ap, format);
189 socket_answer_pos += vsnprintf (socket_answer + socket_answer_pos, SOCKET_ANSWER_MAX_SIZE - socket_answer_pos, format, ap);
190 va_end (ap);
191 if (socket_answer_pos > SOCKET_ANSWER_MAX_SIZE) { socket_answer_pos = -1; }
192 }
193
socket_answer_end(struct in_ev * ev)194 void socket_answer_end (struct in_ev *ev) {
195 if (ev->bev) {
196 static char s[100];
197 sprintf (s, "ANSWER %d\n", socket_answer_pos);
198 bufferevent_write (ev->bev, s, strlen (s));
199 bufferevent_write (ev->bev, socket_answer, socket_answer_pos);
200 bufferevent_write (ev->bev, "\n", 1);
201 }
202 socket_answer_pos = -1;
203 }
204
205 #define mprintf(ev,...) \
206 if (ev) { socket_answer_add_printf (__VA_ARGS__); } \
207 else { printf (__VA_ARGS__); }
208
209 #define mprint_start(ev,...) \
210 if (!ev) { print_start (__VA_ARGS__); } \
211 else { socket_answer_start (); }
212
213 #define mprint_end(ev,...) \
214 if (!ev) { print_end (__VA_ARGS__); } \
215 else { socket_answer_end (ev); }
216
217 #define mpush_color(ev,...) \
218 if (!ev) { push_color (__VA_ARGS__); }
219
220 #define mpop_color(ev,...) \
221 if (!ev) { pop_color (__VA_ARGS__); }
222
unescape_token(char * start,char * end)223 static void unescape_token (char *start, char *end) {
224 static char cur_token_buff[(1 << 20) + 1];
225 cur_token_len = 0;
226 cur_token = cur_token_buff;
227 while (start < end) {
228 assert (cur_token_len < (1 << 20));
229 switch (*start) {
230 case '\\':
231 start ++;
232 switch (*start) {
233 case 'n':
234 cur_token[cur_token_len ++] = '\n';
235 break;
236 case 'r':
237 cur_token[cur_token_len ++] = '\r';
238 break;
239 case 't':
240 cur_token[cur_token_len ++] = '\t';
241 break;
242 case 'b':
243 cur_token[cur_token_len ++] = '\b';
244 break;
245 case 'a':
246 cur_token[cur_token_len ++] = '\a';
247 break;
248 default:
249 cur_token[cur_token_len ++] = *start;
250 break;
251 }
252 break;
253 default:
254 cur_token[cur_token_len ++] = *start;;
255 break;
256 }
257 start ++;
258 }
259 cur_token[cur_token_len] = 0;
260 }
261
262 int force_end_mode;
next_token(void)263 static void next_token (void) {
264 skip_wspc ();
265 cur_token_end_str = 0;
266 cur_token_quoted = 0;
267 if (!*line_ptr) {
268 cur_token_len = 0;
269 cur_token_end_str = 1;
270 return;
271 }
272 char c = *line_ptr;
273 char *start = line_ptr;
274 if (c == '"' || c == '\'') {
275 cur_token_quoted = 1;
276 line_ptr ++;
277 int esc = 0;
278 while (*line_ptr && (esc || *line_ptr != c)) {
279 if (*line_ptr == '\\') {
280 esc = 1 - esc;
281 } else {
282 esc = 0;
283 }
284 line_ptr ++;
285 }
286 if (!*line_ptr) {
287 cur_token_len = -2;
288 } else {
289 unescape_token (start + 1, line_ptr);
290 line_ptr ++;
291 }
292 } else {
293 while (*line_ptr && ((unsigned char)*line_ptr) > ' ') {
294 line_ptr ++;
295 }
296 cur_token = start;
297 cur_token_len = line_ptr - start;
298 cur_token_end_str = (!force_end_mode) && (*line_ptr == 0);
299 }
300 }
301
next_token_end(void)302 void next_token_end (void) {
303 skip_wspc ();
304
305 if (*line_ptr && *line_ptr != '"' && *line_ptr != '\'') {
306 cur_token_quoted = 0;
307 cur_token = line_ptr;
308 while (*line_ptr) { line_ptr ++; }
309 cur_token_len = line_ptr - cur_token;
310 while (((unsigned char)cur_token[cur_token_len - 1]) <= ' ' && cur_token_len >= 0) {
311 cur_token_len --;
312 }
313 assert (cur_token_len > 0);
314 cur_token_end_str = !force_end_mode;
315 return;
316 } else {
317 if (*line_ptr) {
318 next_token ();
319 skip_wspc ();
320 if (*line_ptr) {
321 cur_token_len = -1;
322 }
323 } else {
324 next_token ();
325 }
326 }
327 }
328
next_token_end_ac(void)329 void next_token_end_ac (void) {
330 skip_wspc ();
331
332 if (*line_ptr && *line_ptr != '"' && *line_ptr != '\'') {
333 cur_token_quoted = 0;
334 cur_token = line_ptr;
335 while (*line_ptr) { line_ptr ++; }
336 cur_token_len = line_ptr - cur_token;
337 assert (cur_token_len > 0);
338 cur_token_end_str = !force_end_mode;
339 return;
340 } else {
341 if (*line_ptr) {
342 next_token ();
343 skip_wspc ();
344 if (*line_ptr) {
345 cur_token_len = -1;
346 }
347 } else {
348 next_token ();
349 }
350 }
351 }
352
353 #define NOT_FOUND (int)0x80000000
354 tgl_peer_id_t TGL_PEER_NOT_FOUND = {.peer_id = NOT_FOUND};
355
cur_token_int(void)356 long long cur_token_int (void) {
357 if (cur_token_len <= 0) {
358 return NOT_FOUND;
359 } else {
360 char c = cur_token[cur_token_len];
361 cur_token[cur_token_len] = 0;
362 char *end = 0;
363 long long x = strtoll (cur_token, &end, 0);
364 cur_token[cur_token_len] = c;
365 if (end != cur_token + cur_token_len) {
366 return NOT_FOUND;
367 } else {
368 return x;
369 }
370 }
371 }
372
hex2int(char c)373 int hex2int (char c) {
374 if (c >= '0' && c <= '9') { return c - '0'; }
375 if (c >= 'a' && c <= 'f') { return c - 'a' + 10; }
376 assert (0);
377 return 0;
378 }
379
print_permanent_msg_id(tgl_message_id_t id)380 char *print_permanent_msg_id (tgl_message_id_t id) {
381 static char buf[2 * sizeof (tgl_message_id_t) + 1];
382
383 unsigned char *s = (void *)&id;
384 int i;
385 for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) {
386 sprintf (buf + 2 * i, "%02x", (unsigned)s[i]);
387 }
388 return buf;
389 }
390
print_permanent_peer_id(tgl_peer_id_t id)391 char *print_permanent_peer_id (tgl_peer_id_t id) {
392 static char buf[2 * sizeof (tgl_peer_id_t) + 2];
393 buf[0] = '$';
394
395 unsigned char *s = (void *)&id;
396 int i;
397 for (i = 0; i < (int)sizeof (tgl_peer_id_t); i++) {
398 sprintf (buf + 1 + 2 * i, "%02x", (unsigned)s[i]);
399 }
400 return buf;
401 }
402
parse_input_msg_id(const char * s,int l)403 tgl_message_id_t parse_input_msg_id (const char *s, int l) {
404 if (!s || l <= 0) {
405 tgl_message_id_t id;
406 memset (&id, 0, sizeof (id));
407 id.peer_type = 0;
408 return id;
409 } else {
410 tgl_message_id_t id;
411 memset (&id, 0, sizeof (id));
412
413 if (l == 2 * sizeof (tgl_message_id_t)) {
414 int i;
415 for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) {
416 if (
417 (s[i] < '0' || s[i] > '9') &&
418 (s[i] < 'a' || s[i] > 'f')
419 ) {
420 id.peer_type = 0;
421 return id;
422 }
423 }
424 unsigned char *d = (void *)&id;
425 for (i = 0; i < (int)sizeof (tgl_message_id_t); i++) {
426 d[i] = hex2int (s[2 * i]) * 16 + hex2int (s[2 * i + 1]);
427 }
428 return id;
429 } else {
430 char *sc = tstrndup (s, l);
431 char *end = 0;
432 long long x = strtoll (sc, &end, 0);
433 tfree_str (sc);
434 if (end != sc + l) {
435 id.peer_type = 0;
436 } else {
437 id.peer_type = TGL_PEER_TEMP_ID;
438 id.id = x;
439 }
440 return id;
441 }
442 }
443 }
444
cur_token_msg_id(void)445 tgl_message_id_t cur_token_msg_id (void) {
446 return parse_input_msg_id (cur_token, cur_token_len);
447 }
448
cur_token_double(void)449 double cur_token_double (void) {
450 if (cur_token_len <= 0) {
451 return NOT_FOUND;
452 } else {
453 char c = cur_token[cur_token_len];
454 cur_token[cur_token_len] = 0;
455 char *end = 0;
456 double x = strtod (cur_token, &end);
457 cur_token[cur_token_len] = c;
458 if (end != cur_token + cur_token_len) {
459 return NOT_FOUND;
460 } else {
461 return x;
462 }
463 }
464 }
465
parse_input_peer_id(const char * s,int l,int mask)466 tgl_peer_id_t parse_input_peer_id (const char *s, int l, int mask) {
467 if (!s || l <= 0) { return TGL_PEER_NOT_FOUND; }
468
469 if (*s == '$') {
470 s ++;
471 l --;
472 if (l != 2 * sizeof (tgl_peer_id_t)) {
473 return TGL_PEER_NOT_FOUND;
474 }
475
476 tgl_peer_id_t res;
477 unsigned char *r = (void *)&res;
478 int i;
479 for (i = 0; i < l; i++) {
480 if ((s[i] < '0' || s[i] > '9') &&
481 (s[i] < 'a' || s[i] > 'f')) {
482 return TGL_PEER_NOT_FOUND;
483 }
484 }
485 for (i = 0; i < (int)sizeof (tgl_peer_id_t); i++) {
486 r[i] = hex2int (s[2 * i]) * 16 + hex2int (s[2 * i + 1]);
487 }
488
489 if (mask && tgl_get_peer_type (res) != mask) {
490 return TGL_PEER_NOT_FOUND;
491 }
492
493 return res;
494 }
495
496 if (*s == '@') {
497 s ++;
498 l --;
499 char *tmp = tstrndup (s, l);
500 struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&tmp);
501 tfree_str (tmp);
502 if (p && (!mask || tgl_get_peer_type (p->peer->id) == mask)) {
503 return p->peer->id;
504 } else {
505 return TGL_PEER_NOT_FOUND;
506 }
507 }
508
509 const char *ss[] = {"user#id", "user#", "chat#id", "chat#", "secret_chat#id", "secret_chat#", "channel#id", "channel#"};
510 int tt[] = {TGL_PEER_USER, TGL_PEER_USER, TGL_PEER_CHAT, TGL_PEER_CHAT, TGL_PEER_ENCR_CHAT, TGL_PEER_ENCR_CHAT, TGL_PEER_CHANNEL, TGL_PEER_CHANNEL};
511
512 char *sc = tstrndup (s, l);
513
514 int i;
515 for (i = 0; i < 8; i++) if (!mask || mask == tt[i]) {
516 int x = strlen (ss[i]);
517 if (l > x && !memcmp (s, ss[i], x)) {
518 int r = atoi (sc + x);
519 tfree_str (sc);
520 if (r < 0) { return TGL_PEER_NOT_FOUND; }
521 tgl_peer_t *P = tgl_peer_get (TLS, tgl_set_peer_id (tt[i], r));
522 if (!P) { return TGL_PEER_NOT_FOUND; }
523 return P->id;
524 }
525 }
526
527 tgl_peer_t *P = tgl_peer_get_by_name (TLS, sc);
528 tfree_str (sc);
529
530 if (P && (!mask || tgl_get_peer_type (P->id) == mask)) {
531 return P->id;
532 } else {
533 return TGL_PEER_NOT_FOUND;
534 }
535 }
536
cur_token_user(void)537 tgl_peer_id_t cur_token_user (void) {
538 return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_USER);
539 }
540
cur_token_chat(void)541 tgl_peer_id_t cur_token_chat (void) {
542 return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_CHAT);
543 }
544
cur_token_encr_chat(void)545 tgl_peer_id_t cur_token_encr_chat (void) {
546 return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_ENCR_CHAT);
547 }
548
cur_token_channel(void)549 tgl_peer_id_t cur_token_channel (void) {
550 return parse_input_peer_id (cur_token, cur_token_len, TGL_PEER_CHANNEL);
551 }
552
cur_token_peer(void)553 tgl_peer_id_t cur_token_peer (void) {
554 return parse_input_peer_id (cur_token, cur_token_len, 0);
555 }
556 /*
557 static tgl_peer_t *mk_peer (tgl_peer_id_t id) {
558 if (tgl_get_peer_type (id) == NOT_FOUND) { return 0; }
559 tgl_peer_t *P = tgl_peer_get (TLS, id);
560 if (!P) {
561 if (tgl_get_peer_type (id) == TGL_PEER_USER) {
562 tgl_insert_empty_user (TLS, tgl_get_peer_id (id));
563 }
564 if (tgl_get_peer_type (id) == TGL_PEER_CHAT) {
565 tgl_insert_empty_chat (TLS, tgl_get_peer_id (id));
566 }
567 P = tgl_peer_get (TLS, id);
568 }
569 return P;
570 }*/
571
get_default_prompt(void)572 char *get_default_prompt (void) {
573 static char buf[1000];
574 int l = 0;
575 if (in_chat_mode) {
576 tgl_peer_t *U = tgl_peer_get (TLS, chat_mode_id);
577 assert (U && U->print_name);
578 l += snprintf (buf + l, 999 - l, COLOR_RED "%.*s " COLOR_NORMAL, 100, U->print_name);
579 }
580 if (TLS->unread_messages || TLS->cur_uploading_bytes || TLS->cur_downloading_bytes) {
581 l += snprintf (buf + l, 999 - l, COLOR_RED "[");
582 int ok = 0;
583 if (TLS->unread_messages) {
584 l += snprintf (buf + l, 999 - l, "%d unread", TLS->unread_messages);
585 ok = 1;
586 }
587 if (TLS->cur_uploading_bytes) {
588 if (ok) { *(buf + l) = ' '; l ++; }
589 ok = 1;
590 l += snprintf (buf + l, 999 - l, "%lld%%Up", 100 * TLS->cur_uploaded_bytes / TLS->cur_uploading_bytes);
591 }
592 if (TLS->cur_downloading_bytes) {
593 if (ok) { *(buf + l) = ' '; l ++; }
594 ok = 1;
595 l += snprintf (buf + l, 999 - l, "%lld%%Down", 100 * TLS->cur_downloaded_bytes / TLS->cur_downloading_bytes);
596 }
597 l += snprintf (buf + l, 999 - l, "]" COLOR_NORMAL);
598 l += snprintf (buf + l, 999 - l, "%s", default_prompt);
599 return buf;
600 }
601 l += snprintf (buf + l, 999 - l, "%s", default_prompt);
602 return buf;
603 }
604
complete_none(const char * text,int state)605 char *complete_none (const char *text, int state) {
606 return 0;
607 }
608
609
set_prompt(const char * s)610 void set_prompt (const char *s) {
611 if (readline_disabled) { return; }
612 rl_set_prompt (s);
613 }
614
update_prompt(void)615 void update_prompt (void) {
616 if (readline_disabled) {
617 fflush (stdout);
618 return;
619 }
620 if (read_one_string) { return; }
621 print_start ();
622 set_prompt (get_default_prompt ());
623 if (readline_active) {
624 rl_redisplay ();
625 }
626 print_end ();
627 }
628
629 char *modifiers[] = {
630 "[offline]",
631 "[enable_preview]",
632 "[disable_preview]",
633 "[html]",
634 "[reply=",
635 0
636 };
637
638 char *in_chat_commands[] = {
639 "/exit",
640 "/quit",
641 "/history",
642 "/read",
643 0
644 };
645
646 enum command_argument {
647 ca_none,
648 ca_user,
649 ca_chat,
650 ca_secret_chat,
651 ca_channel,
652 ca_peer,
653 ca_file_name,
654 ca_file_name_end,
655 ca_period,
656 ca_number,
657 ca_double,
658 ca_string_end,
659 ca_msg_string_end,
660 ca_string,
661 ca_modifier,
662 ca_command,
663 ca_extf,
664 ca_msg_id,
665
666
667 ca_optional = 256
668 };
669
670 struct arg {
671 int flags;
672 union {
673 //tgl_peer_t *P;
674 //struct tgl_message *M;
675 char *str;
676 long long num;
677 double dval;
678 tgl_message_id_t msg_id;
679 tgl_peer_id_t peer_id;
680 };
681 };
682
683 struct command {
684 char *name;
685 enum command_argument args[10];
686 void (*fun)(struct command *command, int arg_num, struct arg args[], struct in_ev *ev);
687 char *desc;
688 void *arg;
689 };
690
691
692 int offline_mode;
693 int reply_id;
694 int disable_msg_preview;
695
696 void print_user_list_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_user *UL[]);
697 void print_msg_list_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]);
698 void print_msg_list_history_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]);
699 void print_msg_list_success_gw (struct tgl_state *TLS, void *extra, int success, int num, struct tgl_message *ML[]);
700 void print_dialog_list_gw (struct tgl_state *TLS, void *extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]);
701 void print_chat_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C);
702 void print_channel_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_channel *C);
703 void print_user_info_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_user *C);
704 void print_filename_gw (struct tgl_state *TLS, void *extra, int success, const char *name);
705 void print_string_gw (struct tgl_state *TLS, void *extra, int success, const char *name);
706 void open_filename_gw (struct tgl_state *TLS, void *extra, int success, const char *name);
707 void print_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E);
708 void print_card_gw (struct tgl_state *TLS, void *extra, int success, int size, int *card);
709 void print_user_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U);
710 void print_peer_gw (struct tgl_state *TLS, void *extra, int success, tgl_peer_t *U);
711 void print_msg_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M);
712 void print_msg_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M);
713 void print_encr_chat_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E);;
714 void print_success_gw (struct tgl_state *TLS, void *extra, int success);
715
716 struct command commands[];
717
718 /* {{{ client methods */
do_help(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)719 void do_help (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
720 assert (arg_num == 1);
721 if (ev) { mprint_start (ev); }
722 int total = 0;
723 mpush_color (ev, COLOR_YELLOW);
724 struct command *cmd = commands;
725 while (cmd->name) {
726 if (!args[0].str || !strcmp (args[0].str, cmd->name)) {
727 int tab_index = strchr (cmd->desc, '\t') - cmd->desc;
728 mprintf (ev, "%-55.*s %s\n", tab_index, cmd->desc, cmd->desc + tab_index + 1);
729 total ++;
730 }
731 cmd ++;
732 }
733 if (!total) {
734 assert (arg_num == 1);
735 mprintf (ev, "Unknown command '%s'\n", args[0].str);
736 }
737 mpop_color (ev);
738 if (ev) { mprint_end (ev); }
739 if (!ev) {
740 fflush (stdout);
741 }
742 }
743
do_get_terms_of_service(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)744 void do_get_terms_of_service (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
745 assert (!arg_num);
746 if (ev) { ev->refcnt ++; }
747 tgl_do_get_terms_of_service (TLS, print_string_gw, ev);
748 }
749
do_stats(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)750 void do_stats (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
751 assert (!arg_num);
752 static char stat_buf[1 << 15];
753 tgl_print_stat (TLS, stat_buf, (1 << 15) - 1);
754 if (ev) { mprint_start (ev); }
755 mprintf (ev, "%s\n", stat_buf);
756 if (ev) { mprint_end (ev); }
757 if (!ev) {
758 fflush (stdout);
759 }
760 }
761
do_show_license(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)762 void do_show_license (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
763 assert (!arg_num);
764 static char *b =
765 #include "LICENSE.h"
766 ;
767 if (ev) { mprint_start (ev); }
768 mprintf (ev, "%s", b);
769 if (ev) { mprint_end (ev); }
770 }
771
do_quit(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)772 void do_quit (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
773 if (daemonize) {
774 event_incoming (ev->bev, BEV_EVENT_EOF, ev);
775 }
776 do_halt (0);
777 }
778
do_safe_quit(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)779 void do_safe_quit (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
780 if (daemonize) {
781 event_incoming (ev->bev, BEV_EVENT_EOF, ev);
782 }
783 safe_quit = 1;
784 }
785
do_set(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)786 void do_set (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
787 int num = args[1].num;
788 if (!strcmp (args[0].str, "debug_verbosity")) {
789 tgl_set_verbosity (TLS, num);
790 } else if (!strcmp (args[0].str, "log_level")) {
791 log_level = num;
792 } else if (!strcmp (args[0].str, "msg_num")) {
793 msg_num_mode = num;
794 } else if (!strcmp (args[0].str, "alert")) {
795 alert_sound = num;
796 } else if (!strcmp (args[0].str, "auto_mark_read")) {
797 auto_mark_read = num;
798 }
799 }
800
do_chat_with_peer(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)801 void do_chat_with_peer (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
802 if (!ev) {
803 in_chat_mode = 1;
804 chat_mode_id = args[0].peer_id;
805 }
806 }
807
do_main_session(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)808 void do_main_session (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
809 if (notify_ev && !--notify_ev->refcnt) {
810 free (notify_ev);
811 }
812 notify_ev = ev;
813 if (ev) { ev->refcnt ++; }
814 }
815
do_version(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)816 void do_version (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
817 assert (!arg_num);
818 if (ev) { mprint_start (ev); }
819 mpush_color (ev, COLOR_YELLOW);
820 mprintf (ev, "Telegram-cli version %s (uses tgl version %s)\n", TELEGRAM_CLI_VERSION, TGL_VERSION);
821 #ifdef TGL_AVOID_OPENSSL
822 mprintf (ev, "uses libgcrypt for encryption\n");
823 #else
824 mprintf (ev, "uses libopenssl for encryption\n");
825 #endif
826 mpop_color (ev);
827 if (ev) { mprint_end (ev); }
828 if (!ev) {
829 fflush (stdout);
830 }
831
832 }
833 /* }}} */
834
835 #define ARG2STR_DEF(n,def) args[n].str ? args[n].str : def, args[n].str ? strlen (args[n].str) : strlen (def)
836 #define ARG2STR(n) args[n].str, args[n].str ? strlen (args[n].str) : 0
837
838 /* {{{ WORK WITH ACCOUNT */
839
do_set_password(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)840 void do_set_password (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
841 assert (arg_num == 1);
842 if (ev) { ev->refcnt ++; }
843 tgl_do_set_password (TLS, ARG2STR_DEF(0, "empty"), print_success_gw, ev);
844 }
845 /* }}} */
846
847 /* {{{ SENDING MESSAGES */
848
do_msg(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)849 void do_msg (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
850 assert (arg_num == 2);
851 if (ev) { ev->refcnt ++; }
852 vlogprintf (E_DEBUG, "reply_id=%d, disable=%d\n", reply_id, disable_msg_preview);
853 tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, NULL, print_msg_success_gw, ev);
854 if (auto_mark_read)
855 tgl_do_mark_read (TLS, args[0].peer_id, 0, 0);
856 }
857
do_post(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)858 void do_post (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
859 assert (arg_num == 2);
860 if (ev) { ev->refcnt ++; }
861 vlogprintf (E_DEBUG, "reply_id=%d, disable=%d\n", reply_id, disable_msg_preview);
862 tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(1), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | TGLMF_POST_AS_CHANNEL | do_html, NULL, print_msg_success_gw, ev);
863 }
864
do_msg_kbd(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)865 void do_msg_kbd (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
866 assert (arg_num == 3);
867 if (ev) { ev->refcnt ++; }
868
869 clear_packet ();
870 if (tglf_store_type (TLS, ARG2STR(1), TYPE_TO_PARAM (reply_markup)) < 0) {
871 fail_interface (TLS, ev, ENOSYS, "can not parse reply markup");
872 return;
873 }
874 in_ptr = packet_buffer;
875 in_end = packet_ptr;
876
877 struct tl_ds_reply_markup *DS_RM = fetch_ds_type_reply_markup (TYPE_TO_PARAM (reply_markup));
878 assert (DS_RM);
879
880 tgl_do_send_message (TLS, args[0].peer_id, ARG2STR(2), TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, DS_RM, print_msg_success_gw, ev);
881
882 free_ds_type_reply_markup (DS_RM, TYPE_TO_PARAM (reply_markup));
883 }
884
do_reply(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)885 void do_reply (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
886 assert (arg_num == 2);
887 if (ev) { ev->refcnt ++; }
888 tgl_do_reply_message (TLS, &args[0].msg_id, ARG2STR(1), disable_msg_preview | do_html, print_msg_success_gw, ev);
889
890 if (auto_mark_read) {
891 /* attempt to mark the conversation as read */
892 struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id);
893 if (M) {
894 /* if it's a chat get its id, else get the user id that is != from our */
895 tgl_peer_id_t id = (M->to_id.peer_type == TGL_PEER_CHAT ||
896 M->to_id.peer_id != TLS->our_id.peer_id)? M->to_id : M->from_id;
897 tgl_do_mark_read (TLS, id, 0, 0);
898 }
899 }
900 }
901
do_send_text(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)902 void do_send_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
903 assert (arg_num == 2);
904 if (ev) { ev->refcnt ++; }
905 tgl_do_send_text (TLS, args[0].peer_id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | do_html, print_msg_success_gw, ev);
906 }
907
do_post_text(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)908 void do_post_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
909 assert (arg_num == 2);
910 if (ev) { ev->refcnt ++; }
911 tgl_do_send_text (TLS, args[0].peer_id, args[1].str, TGL_SEND_MSG_FLAG_REPLY(reply_id) | disable_msg_preview | TGLMF_POST_AS_CHANNEL | do_html, print_msg_success_gw, ev);
912 }
do_reply_text(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)913 void do_reply_text (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
914 assert (arg_num == 2);
915 if (ev) { ev->refcnt ++; }
916 tgl_do_reply_text (TLS, &args[0].msg_id, args[1].str, disable_msg_preview | do_html, print_msg_success_gw, ev);
917 }
918
_do_send_file(struct command * command,int arg_num,struct arg args[],struct in_ev * ev,unsigned long long flags)919 static void _do_send_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev, unsigned long long flags) {
920 assert (arg_num >= 2);
921 if (ev) { ev->refcnt ++; }
922 tgl_do_send_document (TLS, args[0].peer_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);
923 }
924
925
do_send_photo(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)926 void do_send_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
927 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO);
928 }
929
do_send_file(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)930 void do_send_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
931 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO);
932 }
933
do_send_audio(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)934 void do_send_audio (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
935 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO);
936 }
937
do_send_video(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)938 void do_send_video (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
939 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO);
940 }
941
do_send_document(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)942 void do_send_document (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
943 _do_send_file (command, arg_num, args, ev, 0);
944 }
945
do_post_photo(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)946 void do_post_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
947 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO | TGLMF_POST_AS_CHANNEL);
948 }
949
do_post_file(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)950 void do_post_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
951 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO | TGLMF_POST_AS_CHANNEL);
952 }
953
do_post_audio(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)954 void do_post_audio (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
955 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO | TGLMF_POST_AS_CHANNEL);
956 }
957
do_post_video(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)958 void do_post_video (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
959 _do_send_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO | TGLMF_POST_AS_CHANNEL);
960 }
961
do_post_document(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)962 void do_post_document (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
963 _do_send_file (command, arg_num, args, ev, TGLMF_POST_AS_CHANNEL);
964 }
965
_do_reply_file(struct command * command,int arg_num,struct arg args[],struct in_ev * ev,unsigned long long flags)966 void _do_reply_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev, unsigned long long flags) {
967 assert (arg_num >= 2);
968 if (ev) { ev->refcnt ++; }
969 tgl_do_reply_document (TLS, &args[0].msg_id, args[1].str, arg_num == 2 ? NULL : args[2].str, arg_num == 2 ? 0 : strlen (args[2].str), flags, print_msg_success_gw, ev);
970 }
971
do_reply_photo(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)972 void do_reply_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
973 _do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO);
974 }
975
do_reply_file(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)976 void do_reply_file (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
977 _do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO);
978 }
979
do_reply_audio(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)980 void do_reply_audio (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
981 _do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO);
982 }
983
do_reply_video(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)984 void do_reply_video (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
985 _do_reply_file (command, arg_num, args, ev, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO);
986 }
987
do_reply_document(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)988 void do_reply_document (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
989 _do_reply_file (command, arg_num, args, ev, 0);
990 }
991
do_fwd(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)992 void do_fwd (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
993 assert (arg_num >= 2);
994 if (ev) { ev->refcnt ++; }
995 assert (arg_num <= 1000);
996 //if (arg_num == 2) {
997 // tgl_do_forward_message (TLS, args[0].P->id, &args[1].msg_id, 0, print_msg_success_gw, ev);
998 // if (auto_mark_read)
999 // tgl_do_mark_read (TLS, args[0].P->id, 0, 0);
1000 //} else {
1001 static tgl_message_id_t *list[1000];
1002 int i;
1003 for (i = 0; i < arg_num - 1; i++) {
1004 list[i] = &args[i + 1].msg_id;
1005 }
1006 tgl_do_forward_messages (TLS, args[0].peer_id, arg_num - 1, (void *)list, 0, print_msg_list_success_gw, ev);
1007 if (auto_mark_read)
1008 tgl_do_mark_read (TLS, args[0].peer_id, 0, 0);
1009 //}
1010 }
1011
do_fwd_media(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1012 void do_fwd_media (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1013 assert (arg_num == 2);
1014 if (ev) { ev->refcnt ++; }
1015 tgl_do_forward_media (TLS, args[0].peer_id, &args[1].msg_id, 0, print_msg_success_gw, ev);
1016 }
1017
do_send_contact(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1018 void do_send_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1019 assert (arg_num == 4);
1020 if (ev) { ev->refcnt ++; }
1021 tgl_do_send_contact (TLS, args[0].peer_id, ARG2STR (1), ARG2STR (2), ARG2STR (3), TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev);
1022 }
1023
do_reply_contact(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1024 void do_reply_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1025 assert (arg_num == 4);
1026 if (ev) { ev->refcnt ++; }
1027 tgl_do_reply_contact (TLS, &args[0].msg_id, ARG2STR (1), ARG2STR (2), ARG2STR (3), 0, print_msg_success_gw, ev);
1028 }
1029
do_send_location(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1030 void do_send_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1031 assert (arg_num == 3);
1032 if (ev) { ev->refcnt ++; }
1033 tgl_do_send_location (TLS, args[0].peer_id, args[1].dval, args[2].dval, TGL_SEND_MSG_FLAG_REPLY(reply_id), print_msg_success_gw, ev);
1034 }
1035
do_post_location(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1036 void do_post_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1037 assert (arg_num == 3);
1038 if (ev) { ev->refcnt ++; }
1039 tgl_do_send_location (TLS, args[0].peer_id, args[1].dval, args[2].dval, TGL_SEND_MSG_FLAG_REPLY(reply_id) | TGLMF_POST_AS_CHANNEL, print_msg_success_gw, ev);
1040 }
1041
do_reply_location(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1042 void do_reply_location (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1043 assert (arg_num == 3);
1044 if (ev) { ev->refcnt ++; }
1045 tgl_do_reply_location (TLS, &args[0].msg_id, args[1].dval, args[2].dval, 0, print_msg_success_gw, ev);
1046 }
1047
do_broadcast(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1048 void do_broadcast (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1049 assert (arg_num >= 1 && arg_num <= 1000);
1050 static tgl_peer_id_t ids[1000];
1051 int i;
1052 for (i = 0; i < arg_num - 1; i++) {
1053 ids[i] = args[i].peer_id;
1054 }
1055 if (ev) { ev->refcnt ++; }
1056 tgl_do_send_broadcast (TLS, arg_num - 1, ids, args[arg_num - 1].str, strlen (args[arg_num - 1].str), disable_msg_preview | do_html, print_msg_list_success_gw, ev);
1057 }
1058
1059 /* }}} */
1060
1061 /* {{{ EDITING SELF PROFILE */
1062
do_get_self(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1063 void do_get_self(struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1064 if (ev) { ev->refcnt ++; }
1065 tgl_do_get_user_info (TLS, TLS->our_id, 0, print_user_info_gw, ev);
1066 }
1067
do_set_profile_photo(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1068 void do_set_profile_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1069 assert (arg_num == 1);
1070 if (ev) { ev->refcnt ++; }
1071 tgl_do_set_profile_photo (TLS, args[0].str, print_success_gw, ev);
1072 }
1073
do_set_profile_name(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1074 void do_set_profile_name (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1075 assert (arg_num == 2);
1076 if (ev) { ev->refcnt ++; }
1077 tgl_do_set_profile_name (TLS, ARG2STR (0), ARG2STR (1), print_user_gw, ev);
1078 }
1079
do_set_username(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1080 void do_set_username (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1081 assert (arg_num == 1);
1082 if (ev) { ev->refcnt ++; }
1083 tgl_do_set_username (TLS, ARG2STR (0), print_user_gw, ev);
1084 }
1085
do_set_phone_number(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1086 void do_set_phone_number (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1087 assert (arg_num == 1);
1088 if (ev) { ev->refcnt ++; }
1089 tgl_do_set_phone_number (TLS, ARG2STR (0), print_success_gw, ev);
1090 }
1091
do_status_online(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1092 void do_status_online (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1093 assert (!arg_num);
1094 if (ev) { ev->refcnt ++; }
1095 tgl_do_update_status (TLS, 1, print_success_gw, ev);
1096 }
1097
do_status_offline(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1098 void do_status_offline (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1099 assert (!arg_num);
1100 if (ev) { ev->refcnt ++; }
1101 tgl_do_update_status (TLS, 0, print_success_gw, ev);
1102 }
1103
do_export_card(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1104 void do_export_card (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1105 assert (!arg_num);
1106 if (ev) { ev->refcnt ++; }
1107 tgl_do_export_card (TLS, print_card_gw, ev);
1108 }
1109
1110 /* }}} */
1111
1112 /* {{{ WORKING WITH GROUP CHATS */
1113
do_chat_set_photo(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1114 void do_chat_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1115 assert (arg_num == 2);
1116 if (ev) { ev->refcnt ++; }
1117 tgl_do_set_chat_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev);
1118 }
1119
do_rename_chat(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1120 void do_rename_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1121 assert (arg_num == 2);
1122 if (ev) { ev->refcnt ++; }
1123 tgl_do_rename_chat (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev);
1124 }
1125
do_chat_info(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1126 void do_chat_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1127 assert (arg_num == 1);
1128 if (ev) { ev->refcnt ++; }
1129 tgl_do_get_chat_info (TLS, args[0].peer_id, offline_mode, print_chat_info_gw, ev);
1130 }
1131
do_channel_info(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1132 void do_channel_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1133 assert (arg_num == 1);
1134 if (ev) { ev->refcnt ++; }
1135 tgl_do_get_channel_info (TLS, args[0].peer_id, offline_mode, print_channel_info_gw, ev);
1136 }
1137
do_chat_add_user(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1138 void do_chat_add_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1139 assert (arg_num == 3);
1140 if (ev) { ev->refcnt ++; }
1141 tgl_do_add_user_to_chat (TLS, args[0].peer_id, args[1].peer_id, args[2].num != NOT_FOUND ? args[2].num : 100, print_success_gw, ev);
1142 }
1143
do_chat_del_user(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1144 void do_chat_del_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1145 assert (arg_num == 2);
1146 if (ev) { ev->refcnt ++; }
1147 tgl_do_del_user_from_chat (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev);
1148 }
1149
do_create_group_chat(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1150 void do_create_group_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1151 assert (arg_num >= 1 && arg_num <= 1000);
1152 static tgl_peer_id_t ids[1000];
1153 int i;
1154 for (i = 0; i < arg_num - 1; i++) {
1155 ids[i] = args[i + 1].peer_id;
1156 }
1157
1158 if (ev) { ev->refcnt ++; }
1159 tgl_do_create_group_chat (TLS, arg_num - 1, ids, ARG2STR (0), print_success_gw, ev);
1160 }
1161
do_export_chat_link(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1162 void do_export_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1163 assert (arg_num == 1);
1164 if (ev) { ev->refcnt ++; }
1165 tgl_do_export_chat_link (TLS, args[0].peer_id, print_string_gw, ev);
1166 }
1167
do_import_chat_link(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1168 void do_import_chat_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1169 assert (arg_num == 1);
1170 if (ev) { ev->refcnt ++; }
1171 tgl_do_import_chat_link (TLS, ARG2STR (0), print_success_gw, ev);
1172 }
1173
do_channel_invite(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1174 void do_channel_invite (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1175 assert (arg_num == 2);
1176 if (ev) { ev->refcnt ++; }
1177 tgl_do_channel_invite_user (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev);
1178 }
1179
do_channel_kick(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1180 void do_channel_kick (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1181 assert (arg_num == 2);
1182 if (ev) { ev->refcnt ++; }
1183 tgl_do_channel_kick_user (TLS, args[0].peer_id, args[1].peer_id, print_success_gw, ev);
1184 }
1185
do_channel_get_members(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1186 void do_channel_get_members (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1187 assert (arg_num == 3);
1188 if (ev) { ev->refcnt ++; }
1189 tgl_do_channel_get_members (TLS, args[0].peer_id, args[1].num == NOT_FOUND ? 100 : args[1].num, args[2].num == NOT_FOUND ? 0 : args[2].num, 0, print_user_list_gw, ev);
1190 }
1191
do_channel_get_admins(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1192 void do_channel_get_admins (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1193 assert (arg_num == 3);
1194 if (ev) { ev->refcnt ++; }
1195 tgl_do_channel_get_members (TLS, args[0].peer_id, args[1].num == NOT_FOUND ? 100 : args[1].num, args[2].num == NOT_FOUND ? 0 : args[2].num, 1, print_user_list_gw, ev);
1196 }
1197
do_chat_upgrade(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1198 void do_chat_upgrade (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1199 assert (arg_num == 1);
1200 if (ev) { ev->refcnt ++; }
1201 tgl_do_upgrade_group (TLS, args[0].peer_id, print_success_gw, ev);
1202 }
1203
1204
1205 /* }}} */
1206
1207 /* {{{ WORKING WITH USERS */
1208
1209
do_user_info(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1210 void do_user_info (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1211 assert (arg_num == 1);
1212 if (ev) { ev->refcnt ++; }
1213 tgl_do_get_user_info (TLS, args[0].peer_id, offline_mode, print_user_info_gw, ev);
1214 }
1215
do_add_contact(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1216 void do_add_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1217 assert (arg_num == 3);
1218 if (ev) { ev->refcnt ++; }
1219 tgl_do_add_contact (TLS, ARG2STR (0), ARG2STR (1), ARG2STR (2), 0, print_user_list_gw, ev);
1220 }
1221
do_rename_contact(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1222 void do_rename_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1223 assert (arg_num == 3);
1224
1225 tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id);
1226 if (P && P->user.phone) {
1227 if (ev) { ev->refcnt ++; }
1228 tgl_do_add_contact (TLS, P->user.phone, strlen (P->user.phone), args[1].str, strlen (args[1].str), args[2].str, strlen (args[2].str), 0, print_user_list_gw, ev);
1229 } else {
1230 if (ev) { ev->refcnt ++; }
1231 print_success_gw (TLS, ev, 0);
1232 }
1233 }
1234
do_del_contact(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1235 void do_del_contact (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1236 assert (arg_num == 1);
1237 if (ev) { ev->refcnt ++; }
1238 tgl_do_del_contact (TLS, args[0].peer_id, print_success_gw, ev);
1239 }
1240
1241
do_import_card(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1242 void do_import_card (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1243 assert (arg_num == 1);
1244 char *s = args[0].str;
1245 int l = strlen (s);
1246 if (l > 0) {
1247 int i;
1248 static int p[10];
1249 int pp = 0;
1250 int cur = 0;
1251 int ok = 1;
1252 for (i = 0; i < l; i ++) {
1253 if (s[i] >= '0' && s[i] <= '9') {
1254 cur = cur * 16 + s[i] - '0';
1255 } else if (s[i] >= 'a' && s[i] <= 'f') {
1256 cur = cur * 16 + s[i] - 'a' + 10;
1257 } else if (s[i] == ':') {
1258 if (pp >= 9) {
1259 ok = 0;
1260 break;
1261 }
1262 p[pp ++] = cur;
1263 cur = 0;
1264 }
1265 }
1266 if (ok) {
1267 p[pp ++] = cur;
1268 if (ev) { ev->refcnt ++; }
1269 tgl_do_import_card (TLS, pp, p, print_user_gw, ev);
1270 }
1271 }
1272 }
1273
do_block_user(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1274 void do_block_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1275 assert (arg_num == 1);
1276 if (ev) { ev->refcnt ++; }
1277 tgl_do_block_user (TLS, args[0].peer_id, print_success_gw, ev);
1278 }
1279
do_unblock_user(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1280 void do_unblock_user (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1281 assert (arg_num == 1);
1282 if (ev) { ev->refcnt ++; }
1283 tgl_do_unblock_user (TLS, args[0].peer_id, print_success_gw, ev);
1284 }
1285 /* }}} */
1286
1287 /* {{{ WORKING WITH SECRET CHATS */
1288
do_accept_secret_chat(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1289 void do_accept_secret_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1290 assert (arg_num == 1);
1291 if (ev) { ev->refcnt ++; }
1292
1293 tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id);
1294 if (P) {
1295 tgl_do_accept_encr_chat_request (TLS, &P->encr_chat, print_encr_chat_success_gw, ev);
1296 } else {
1297 print_success_gw (TLS, ev, 0);
1298 }
1299 }
1300
do_set_ttl(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1301 void do_set_ttl (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1302 assert (arg_num == 2);
1303 if (ev) { ev->refcnt ++; }
1304 tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id);
1305 if (P && P->encr_chat.state == sc_ok) {
1306 tgl_do_set_encr_chat_ttl (TLS, &P->encr_chat, args[1].num, print_msg_success_gw, ev);
1307 } else {
1308 print_success_gw (TLS, ev, 0);
1309 }
1310 }
1311
do_visualize_key(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1312 void do_visualize_key (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1313 assert (arg_num == 1);
1314 static char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN};
1315 static unsigned char buf[16];
1316 memset (buf, 0, sizeof (buf));
1317 tgl_do_visualize_key (TLS, args[0].peer_id, buf);
1318 mprint_start (ev);
1319 int i;
1320 for (i = 0; i < 16; i++) {
1321 int x = buf[i];
1322 int j;
1323 for (j = 0; j < 4; j ++) {
1324 if (!ev) {
1325 mpush_color (ev, colors[x & 3]);
1326 mpush_color (ev, COLOR_INVERSE);
1327 }
1328 if (!disable_colors && !ev) {
1329 mprintf (ev, " ");
1330 } else {
1331 switch (x & 3) {
1332 case 0:
1333 mprintf (ev, " ");
1334 break;
1335 case 1:
1336 mprintf (ev, "--");
1337 break;
1338 case 2:
1339 mprintf (ev, "==");
1340 break;
1341 case 3:
1342 mprintf (ev, "||");
1343 break;
1344 }
1345 }
1346 if (!ev) {
1347 mpop_color (ev);
1348 mpop_color (ev);
1349 }
1350 x = x >> 2;
1351 }
1352 if (i & 1) {
1353 mprintf (ev, "\n");
1354 }
1355 }
1356 mprint_end (ev);
1357 }
1358
1359
do_create_secret_chat(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1360 void do_create_secret_chat (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1361 assert (arg_num == 1);
1362 if (ev) { ev->refcnt ++; }
1363 tgl_do_create_secret_chat (TLS, args[0].peer_id, print_secret_chat_gw, ev);
1364 }
1365
1366 /* }}} */
1367
1368 /* WORKING WITH CHANNELS {{{ */
1369
do_rename_channel(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1370 void do_rename_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1371 assert (arg_num == 2);
1372 if (ev) { ev->refcnt ++; }
1373 tgl_do_rename_channel (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev);
1374 }
1375
do_channel_set_photo(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1376 void do_channel_set_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1377 assert (arg_num == 2);
1378 if (ev) { ev->refcnt ++; }
1379 tgl_do_set_channel_photo (TLS, args[0].peer_id, args[1].str, print_success_gw, ev);
1380 }
1381
do_channel_set_about(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1382 void do_channel_set_about (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1383 assert (arg_num == 2);
1384 if (ev) { ev->refcnt ++; }
1385 tgl_do_channel_set_about (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev);
1386 }
1387
do_channel_set_admin(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1388 void do_channel_set_admin (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1389 assert (arg_num == 3);
1390 if (ev) { ev->refcnt ++; }
1391 tgl_do_channel_set_admin (TLS, args[0].peer_id, args[1].peer_id, args[2].num, print_success_gw, ev);
1392 }
1393
do_channel_set_username(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1394 void do_channel_set_username (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1395 assert (arg_num == 2);
1396 if (ev) { ev->refcnt ++; }
1397 tgl_do_channel_set_username (TLS, args[0].peer_id, ARG2STR (1), print_success_gw, ev);
1398 }
1399
do_create_channel(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1400 void do_create_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1401 assert (arg_num >= 2 && arg_num <= 1000);
1402 static tgl_peer_id_t ids[1000];
1403 int i;
1404 for (i = 0; i < arg_num - 2; i++) {
1405 ids[i] = args[i + 2].peer_id;
1406 }
1407
1408 if (ev) { ev->refcnt ++; }
1409 tgl_do_create_channel (TLS, arg_num - 2, ids, ARG2STR (0), ARG2STR (1), 1, print_success_gw, ev);
1410 }
1411
do_join_channel(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1412 void do_join_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1413 assert (arg_num == 1);
1414 if (ev) { ev->refcnt ++; }
1415 tgl_do_join_channel (TLS, args[0].peer_id, print_success_gw, ev);
1416 }
1417
do_leave_channel(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1418 void do_leave_channel (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1419 assert (arg_num == 1);
1420 if (ev) { ev->refcnt ++; }
1421 tgl_do_leave_channel (TLS, args[0].peer_id, print_success_gw, ev);
1422 }
1423
do_export_channel_link(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1424 void do_export_channel_link (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1425 assert (arg_num == 1);
1426 if (ev) { ev->refcnt ++; }
1427 tgl_do_export_channel_link (TLS, args[0].peer_id, print_string_gw, ev);
1428 }
1429
1430 /* }}} */
1431
1432 /* {{{ WORKING WITH DIALOG LIST */
1433
do_dialog_list(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1434 void do_dialog_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1435 assert (arg_num <= 2);
1436 if (ev) { ev->refcnt ++; }
1437 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);
1438 }
1439
do_channel_list(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1440 void do_channel_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1441 assert (arg_num <= 2);
1442 if (ev) { ev->refcnt ++; }
1443 tgl_do_get_channels_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);
1444 }
1445
do_resolve_username(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1446 void do_resolve_username (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1447 assert (arg_num == 1);
1448 if (ev) { ev->refcnt ++; }
1449 tgl_do_contact_search (TLS, args[0].str, strlen (args[0].str), print_peer_gw, ev);
1450 }
1451
do_contact_list(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1452 void do_contact_list (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1453 assert (!arg_num);
1454 if (ev) { ev->refcnt ++; }
1455 tgl_do_update_contact_list (TLS, print_user_list_gw, ev);
1456 }
1457
1458 /* }}} */
1459
1460 /* {{{ WORKING WITH ONE DIALOG */
1461
do_mark_read(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1462 void do_mark_read (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1463 assert (arg_num == 1);
1464 if (ev) { ev->refcnt ++; }
1465 tgl_do_mark_read (TLS, args[0].peer_id, print_success_gw, ev);
1466 }
1467
do_history(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1468 void do_history (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1469 assert (arg_num == 3);
1470 if (ev) { ev->refcnt ++; }
1471 tgl_do_get_history (TLS, args[0].peer_id, args[2].num != NOT_FOUND ? args[2].num : 0, args[1].num != NOT_FOUND ? args[1].num : 40, offline_mode, print_msg_list_history_gw, ev);
1472 }
1473
1474 void print_fail (struct in_ev *ev);
1475
do_send_typing(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1476 void do_send_typing (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1477 assert (arg_num == 2);
1478 enum tgl_typing_status status = tgl_typing_typing; //de
1479 if (args[1].num != NOT_FOUND) {
1480 if (args[1].num > 0 && args[1].num > 10) {
1481 fail_interface (TLS, ev, ENOSYS, "illegal typing status");
1482 return;
1483 }
1484 status = (enum tgl_typing_status) args[1].num; // if the status parameter is given, and is in range.
1485 }
1486 if (ev) { ev->refcnt ++; }
1487 tgl_do_send_typing (TLS, args[0].peer_id, status, print_success_gw, ev);
1488 }
1489
do_send_typing_abort(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1490 void do_send_typing_abort (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1491 assert (arg_num == 1);
1492 if (ev) { ev->refcnt ++; }
1493 tgl_do_send_typing (TLS, args[0].peer_id, tgl_typing_cancel, print_success_gw, ev);
1494 }
1495
1496 /* }}} */
1497
1498 /* {{{ WORKING WITH MEDIA */
1499
1500 #define DO_LOAD_PHOTO(tp,act,actf) \
1501 void do_ ## act ## _ ## tp (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \
1502 assert (arg_num == 1);\
1503 if (ev) { ev->refcnt ++; vlogprintf (E_WARNING, "refcnt+\n"); }\
1504 struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id);\
1505 if (M && !(M->flags & TGLMF_SERVICE)) {\
1506 if (ev) { ev->refcnt ++; } \
1507 if (M->media.type == tgl_message_media_photo) { \
1508 tgl_do_load_photo (TLS, M->media.photo, actf, ev);\
1509 } else if (M->media.type == tgl_message_media_document) {\
1510 tgl_do_load_document (TLS, M->media.document, actf, ev);\
1511 } else if (M->media.type == tgl_message_media_video) {\
1512 tgl_do_load_video (TLS, M->media.document, actf, ev);\
1513 } else if (M->media.type == tgl_message_media_audio) {\
1514 tgl_do_load_audio (TLS, M->media.document, actf, ev);\
1515 } else if (M->media.type == tgl_message_media_document_encr) {\
1516 tgl_do_load_encr_document (TLS, M->media.encr_document, actf, ev); \
1517 } else if (M->media.type == tgl_message_media_webpage) {\
1518 actf (TLS, ev, 1, M->media.webpage->url);\
1519 } else if (M->media.type == tgl_message_media_geo || M->media.type == tgl_message_media_venue) { \
1520 static char s[1000]; \
1521 sprintf (s, "https://maps.google.com/?q=%.6lf,%.6lf", M->media.geo.latitude, M->media.geo.longitude);\
1522 actf (TLS, ev, 1, s);\
1523 }\
1524 }\
1525 }
1526
1527 #define DO_LOAD_PHOTO_THUMB(tp,act,actf) \
1528 void do_ ## act ## _ ## tp ## _thumb (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) { \
1529 assert (arg_num == 1);\
1530 if (ev) { ev->refcnt ++; vlogprintf (E_WARNING, "refcnt+\n"); }\
1531 struct tgl_message *M = tgl_message_get (TLS, &args[0].msg_id);\
1532 if (M && !(M->flags & TGLMF_SERVICE)) {\
1533 if (M->media.type == tgl_message_media_document) {\
1534 if (ev) { ev->refcnt ++; } \
1535 tgl_do_load_document_thumb (TLS, M->media.document, actf, ev);\
1536 }\
1537 }\
1538 }
1539
DO_LOAD_PHOTO(photo,load,print_filename_gw)1540 DO_LOAD_PHOTO(photo, load, print_filename_gw)
1541 DO_LOAD_PHOTO(video, load, print_filename_gw)
1542 DO_LOAD_PHOTO(audio, load, print_filename_gw)
1543 DO_LOAD_PHOTO(document, load, print_filename_gw)
1544 DO_LOAD_PHOTO(file, load, print_filename_gw)
1545 DO_LOAD_PHOTO_THUMB(video, load, print_filename_gw)
1546 DO_LOAD_PHOTO_THUMB(document, load, print_filename_gw)
1547 DO_LOAD_PHOTO_THUMB(file, load, print_filename_gw)
1548 DO_LOAD_PHOTO(photo, open, open_filename_gw)
1549 DO_LOAD_PHOTO(video, open, open_filename_gw)
1550 DO_LOAD_PHOTO(audio, open, open_filename_gw)
1551 DO_LOAD_PHOTO(document, open, open_filename_gw)
1552 DO_LOAD_PHOTO(file, open, open_filename_gw)
1553 DO_LOAD_PHOTO_THUMB(video, open, open_filename_gw)
1554 DO_LOAD_PHOTO_THUMB(document, open, open_filename_gw)
1555 DO_LOAD_PHOTO_THUMB(file, open, open_filename_gw)
1556 DO_LOAD_PHOTO(any, open, open_filename_gw)
1557
1558 void do_load_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1559 assert (arg_num == 1);
1560 if (ev) { ev->refcnt ++; }
1561
1562 tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id);
1563 if (P) {
1564 tgl_do_load_file_location (TLS, &P->user.photo_big, print_filename_gw, ev);
1565 } else {
1566 print_filename_gw (TLS, ev, 0, NULL);
1567 }
1568 }
1569
do_view_user_photo(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1570 void do_view_user_photo (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1571 assert (arg_num == 1);
1572 if (ev) { ev->refcnt ++; }
1573
1574 tgl_peer_t *P = tgl_peer_get (TLS, args[0].peer_id);
1575 if (P) {
1576 tgl_do_load_file_location (TLS, &P->user.photo_big, print_filename_gw, ev);
1577 } else {
1578 open_filename_gw (TLS, ev, 0, NULL);
1579 }
1580 }
1581
1582 /* }}} */
1583
1584 /* {{{ ANOTHER MESSAGES FUNCTIONS */
1585
do_search(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1586 void do_search (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1587 assert (arg_num == 6);
1588 int limit;
1589 if (args[1].num != NOT_FOUND) {
1590 limit = args[1].num;
1591 } else {
1592 limit = 40;
1593 }
1594 int from;
1595 if (args[2].num != NOT_FOUND) {
1596 from = args[2].num;
1597 } else {
1598 from = 0;
1599 }
1600 int to;
1601 if (args[3].num != NOT_FOUND) {
1602 to = args[3].num;
1603 } else {
1604 to = 0;
1605 }
1606 int offset;
1607 if (args[4].num != NOT_FOUND) {
1608 offset = args[4].num;
1609 } else {
1610 offset = 0;
1611 }
1612 if (ev) { ev->refcnt ++; }
1613 tgl_do_msg_search (TLS, args[0].peer_id, from, to, limit, offset, args[5].str, strlen (args[5].str), print_msg_list_gw, ev);
1614 }
1615
do_delete_msg(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1616 void do_delete_msg (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1617 if (ev) { ev->refcnt ++; }
1618 tgl_do_delete_msg (TLS, &args[0].msg_id, print_success_gw, ev);
1619 }
1620
do_get_message(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1621 void do_get_message (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1622 assert (arg_num == 1);
1623 if (ev) { ev->refcnt ++; }
1624 tgl_do_get_message (TLS, &args[0].msg_id, print_msg_gw, ev);
1625 }
1626
1627 /* }}} */
1628
1629 /* {{{ BOT */
1630
do_start_bot(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1631 void do_start_bot (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1632 assert (arg_num == 3);
1633 if (ev) { ev->refcnt ++; }
1634 tgl_do_start_bot (TLS, args[0].peer_id, args[1].peer_id, ARG2STR(2), print_success_gw, ev);
1635 }
1636 /* }}} */
1637
1638 extern char *default_username;
1639 extern char *config_filename;
1640 extern char *prefix;
1641 extern char *auth_file_name;
1642 extern char *state_file_name;
1643 extern char *secret_chat_file_name;
1644 extern char *downloads_directory;
1645 extern char *config_directory;
1646 extern char *binlog_file_name;
1647 extern char *lua_file;
1648 extern char *python_file;
1649 extern struct event *term_ev;
1650
do_clear(struct command * command,int arg_num,struct arg args[],struct in_ev * ev)1651 void do_clear (struct command *command, int arg_num, struct arg args[], struct in_ev *ev) {
1652 logprintf ("Do_clear\n");
1653 free (default_username);
1654 tfree_str (config_filename);
1655 //free (prefix);
1656 tfree_str (auth_file_name);
1657 tfree_str (state_file_name);
1658 tfree_str (secret_chat_file_name);
1659 tfree_str (downloads_directory);
1660 //tfree_str (config_directory);
1661 tfree_str (binlog_file_name);
1662 tfree_str (lua_file);
1663 tfree_str (python_file);
1664 if (home_directory) {
1665 tfree_str (home_directory);
1666 }
1667 clear_history ();
1668 event_free (term_ev);
1669 struct event_base *ev_base = TLS->ev_base;
1670 tgl_free_all (TLS);
1671 event_base_free (ev_base);
1672 logprintf ("Bytes left allocated: %lld\n", tgl_get_allocated_bytes ());
1673 do_halt (0);
1674 }
1675
1676
1677 #define MAX_COMMANDS_SIZE 1000
1678 struct command commands[MAX_COMMANDS_SIZE] = {
1679 {"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},
1680 {"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},
1681 {"block_user", {ca_user, ca_none}, do_block_user, "block_user <user>\tBlocks user", NULL},
1682 {"broadcast", {ca_user, ca_period, ca_string_end, ca_none}, do_broadcast, "broadcast <user>+ <text>\tSends text to several users at once", NULL},
1683 {"channel_get_admins", {ca_channel, ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_channel_get_admins, "channel_get_admins <channel> [limit=100] [offset=0]\tGets channel admins", NULL},
1684 {"channel_get_members", {ca_channel, ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_channel_get_members, "channel_get_members <channel> [limit=100] [offset=0]\tGets channel members", NULL},
1685 {"channel_info", {ca_channel, ca_none}, do_channel_info, "channel_info <channel>\tPrints info about channel (id, members, admin, etc.)", NULL},
1686 {"channel_invite", {ca_channel, ca_user, ca_none}, do_channel_invite, "channel_invite <channel> <user>\tInvites user to channel", NULL},
1687 {"channel_join", {ca_channel, ca_none}, do_join_channel, "channel_join <channel>\tJoins to channel", NULL},
1688 {"channel_kick", {ca_channel, ca_user, ca_none}, do_channel_kick, "channel_kick <channel> <user>\tKicks user from channel", NULL},
1689 {"channel_leave", {ca_channel, ca_none}, do_leave_channel, "channel_leave <channel>\tLeaves from channel", NULL},
1690 {"channel_list", {ca_number | ca_optional, ca_number | ca_optional, ca_none}, do_channel_list, "channel_list [limit=100] [offset=0]\tList of last channels", NULL},
1691 {"channel_set_about", {ca_channel, ca_string, ca_none}, do_channel_set_about, "channel_set_about <channel> <about>\tSets channel about info.", NULL},
1692 {"channel_set_admin", {ca_channel, ca_user, ca_number, ca_none}, do_channel_set_admin, "channel_set_admin <channel> <admin> <type>\tSets channel admin. 0 - not admin, 1 - moderator, 2 - editor", NULL},
1693 {"channel_set_username", {ca_channel, ca_string, ca_none}, do_channel_set_username, "channel_set_username <channel> <username>\tSets channel username info.", NULL},
1694 {"channel_set_photo", {ca_channel, ca_file_name_end, ca_none}, do_channel_set_photo, "channel_set_photo <channel> <filename>\tSets channel photo. Photo will be cropped to square", NULL},
1695 {"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},
1696 {"chat_del_user", {ca_chat, ca_user, ca_none}, do_chat_del_user, "chat_del_user <chat> <user>\tDeletes user from chat", NULL},
1697 {"chat_info", {ca_chat, ca_none}, do_chat_info, "chat_info <chat>\tPrints info about chat (id, members, admin, etc.)", NULL},
1698 {"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},
1699 {"chat_upgrade", {ca_chat, ca_none}, do_chat_upgrade, "chat_upgrade <chat>\tUpgrades chat to megagroup", NULL},
1700 {"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},
1701 {"clear", {ca_none}, do_clear, "clear\tClears all data and exits. For debug.", NULL},
1702 {"contact_list", {ca_none}, do_contact_list, "contact_list\tPrints contact list", NULL},
1703 {"contact_search", {ca_string, ca_none}, do_resolve_username, "contact_search username\tSearches user by username", NULL},
1704 {"create_channel", {ca_string, ca_string, ca_user | ca_optional, ca_period, ca_none}, do_create_channel, "create_channel <name> <about> <user>+\tCreates channel with users", NULL},
1705 {"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},
1706 {"create_secret_chat", {ca_user, ca_none}, do_create_secret_chat, "create_secret_chat <user>\tStarts creation of secret chat", NULL},
1707 {"del_contact", {ca_user, ca_none}, do_del_contact, "del_contact <user>\tDeletes contact from contact list", NULL},
1708 {"delete_msg", {ca_msg_id, ca_none}, do_delete_msg, "delete_msg <msg-id>\tDeletes message", NULL},
1709 {"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},
1710 {"export_card", {ca_none}, do_export_card, "export_card\tPrints card that can be imported by another user with import_card method", NULL},
1711 {"export_channel_link", {ca_channel, ca_none}, do_export_channel_link, "export_channel_link\tPrints channel link that can be used to join to channel", NULL},
1712 {"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},
1713 {"fwd", {ca_peer, ca_msg_id, ca_period, ca_none}, do_fwd, "fwd <peer> <msg-id>+\tForwards message to peer. Forward to secret chats is forbidden", NULL},
1714 {"fwd_media", {ca_peer, ca_msg_id, 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},
1715 {"get_terms_of_service", {ca_none}, do_get_terms_of_service, "get_terms_of_service\tPrints telegram's terms of service", NULL},
1716 {"get_message", {ca_msg_id, ca_none}, do_get_message, "get_message <msg-id>\tGet message by id", NULL},
1717 {"get_self", {ca_none}, do_get_self, "get_self \tGet our user info", NULL},
1718 {"help", {ca_command | ca_optional, ca_none}, do_help, "help [command]\tPrints this help", NULL},
1719 {"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},
1720 {"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},
1721 {"import_chat_link", {ca_string, ca_none}, do_import_chat_link, "import_chat_link <hash>\tJoins to chat by link", NULL},
1722 {"import_channel_link", {ca_string, ca_none}, do_import_chat_link, "import_channel_link <hash>\tJoins to channel by link", NULL},
1723 {"load_audio", {ca_msg_id, ca_none}, do_load_audio, "load_audio <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1724 {"load_channel_photo", {ca_channel, ca_none}, do_load_user_photo, "load_channel_photo <channel>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1725 {"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},
1726 {"load_document", {ca_msg_id, ca_none}, do_load_document, "load_document <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1727 {"load_document_thumb", {ca_msg_id, ca_none}, do_load_document_thumb, "load_document_thumb <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1728 {"load_file", {ca_msg_id, ca_none}, do_load_file, "load_file <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1729 {"load_file_thumb", {ca_msg_id, ca_none}, do_load_file_thumb, "load_file_thumb <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1730 {"load_photo", {ca_msg_id, ca_none}, do_load_photo, "load_photo <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1731 {"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},
1732 {"load_video", {ca_msg_id, ca_none}, do_load_video, "load_video <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1733 {"load_video_thumb", {ca_msg_id, ca_none}, do_load_video_thumb, "load_video_thumb <msg-id>\tDownloads file to downloads dirs. Prints file name after download end", NULL},
1734 {"main_session", {ca_none}, do_main_session, "main_session\tSends updates to this connection (or terminal). Useful only with listening socket", NULL},
1735 {"mark_read", {ca_peer, ca_none}, do_mark_read, "mark_read <peer>\tMarks messages with peer as read", NULL},
1736 {"msg", {ca_peer, ca_msg_string_end, ca_none}, do_msg, "msg <peer> <text>\tSends text message to peer", NULL},
1737 {"msg_kbd", {ca_peer, ca_string, ca_msg_string_end, ca_none}, do_msg_kbd, "msg <peer> <kbd> <text>\tSends text message to peer with custom kbd", NULL},
1738 {"post", {ca_peer, ca_msg_string_end, ca_none}, do_post, "post <peer> <text>\tSends text message to peer as admin", NULL},
1739 {"post_audio", {ca_peer, ca_file_name, ca_none}, do_post_audio, "post_audio <peer> <file>\tPosts audio to peer", NULL},
1740 {"post_document", {ca_peer, ca_file_name, ca_none}, do_post_document, "post_document <peer> <file>\tPosts document to peer", NULL},
1741 {"post_file", {ca_peer, ca_file_name, ca_none}, do_post_file, "post_file <peer> <file>\tSends document to peer", NULL},
1742 {"post_location", {ca_peer, ca_double, ca_double, ca_none}, do_post_location, "post_location <peer> <latitude> <longitude>\tSends geo location", NULL},
1743 {"post_photo", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_post_photo, "post_photo <peer> <file> [caption]\tSends photo to peer", NULL},
1744 {"post_text", {ca_peer, ca_file_name_end, ca_none}, do_post_text, "post_text <peer> <file>\tSends contents of text file as plain text message", NULL},
1745 {"post_video", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_post_video, "post_video <peer> <file> [caption]\tSends video to peer", NULL},
1746 {"quit", {ca_none}, do_quit, "quit\tQuits immediately", NULL},
1747 {"rename_channel", {ca_channel, ca_string_end, ca_none}, do_rename_channel, "rename_channel <channel> <new name>\tRenames channel", NULL},
1748 {"rename_chat", {ca_chat, ca_string_end, ca_none}, do_rename_chat, "rename_chat <chat> <new name>\tRenames chat", NULL},
1749 {"rename_contact", {ca_user, ca_string, ca_string, ca_none}, do_rename_contact, "rename_contact <user> <first name> <last name>\tRenames contact", NULL},
1750 {"reply", {ca_msg_id, ca_msg_string_end, ca_none}, do_reply, "reply <msg-id> <text>\tSends text reply to message", NULL},
1751 {"reply_audio", {ca_msg_id, ca_file_name, ca_none}, do_send_audio, "reply_audio <msg-id> <file>\tSends audio to peer", NULL},
1752 {"reply_contact", {ca_msg_id, 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},
1753 {"reply_document", {ca_msg_id, ca_file_name, ca_none}, do_reply_document, "reply_document <msg-id> <file>\tSends document to peer", NULL},
1754 {"reply_file", {ca_msg_id, ca_file_name, ca_none}, do_reply_file, "reply_file <msg-id> <file>\tSends document to peer", NULL},
1755 {"reply_location", {ca_msg_id, ca_double, ca_double, ca_none}, do_reply_location, "reply_location <msg-id> <latitude> <longitude>\tSends geo location", NULL},
1756 {"reply_photo", {ca_msg_id, ca_file_name, ca_string_end | ca_optional, ca_none}, do_reply_photo, "reply_photo <msg-id> <file> [caption]\tSends photo to peer", NULL},
1757 //{"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},
1758 {"reply_video", {ca_msg_id, ca_file_name, ca_none}, do_reply_video, "reply_video <msg-id> <file>\tSends video to peer", NULL},
1759 {"resolve_username", {ca_string, ca_none}, do_resolve_username, "resolve_username username\tSearches user by username", NULL},
1760 //{"restore_msg", {ca_number, ca_none}, do_restore_msg, "restore_msg <msg-id>\tRestores message. Only available shortly (one hour?) after deletion", NULL},
1761 {"safe_quit", {ca_none}, do_safe_quit, "safe_quit\tWaits for all queries to end, then quits", NULL},
1762 {"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},
1763 //{"secret_chat_rekey", { ca_secret_chat, ca_none}, do_secret_chat_rekey, "generate new key for active secret chat", NULL},
1764 {"send_audio", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_audio, "send_audio <peer> <file>\tSends audio to peer", NULL},
1765 {"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},
1766 {"send_document", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_document, "send_document <peer> <file>\tSends document to peer", NULL},
1767 {"send_file", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_file, "send_file <peer> <file>\tSends document to peer", NULL},
1768 {"send_location", {ca_peer, ca_double, ca_double, ca_none}, do_send_location, "send_location <peer> <latitude> <longitude>\tSends geo location", NULL},
1769 {"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},
1770 {"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},
1771 {"send_typing", {ca_peer, ca_number | ca_optional, ca_none}, do_send_typing, "send_typing <peer> [status]\tSends typing notification. You can supply a custom status (range 0-10): none, typing, cancel, record video, upload video, record audio, upload audio, upload photo, upload document, geo, choose contact.", NULL},
1772 {"send_typing_abort", {ca_peer, ca_none}, do_send_typing_abort, "send_typing_abort <peer>\tSends typing notification abort", NULL},
1773 {"send_video", {ca_peer, ca_file_name, ca_string_end | ca_optional, ca_none}, do_send_video, "send_video <peer> <file> [caption]\tSends video to peer", NULL},
1774 {"set", {ca_string, ca_number, ca_none}, do_set, "set <param> <value>\tSets value of param. Currently available: log_level, debug_verbosity, alarm, auto_mark_read, msg_num", NULL},
1775 {"set_password", {ca_string | ca_optional, ca_none}, do_set_password, "set_password <hint>\tSets password", NULL},
1776 {"set_profile_name", {ca_string, ca_string, ca_none}, do_set_profile_name, "set_profile_name <first-name> <last-name>\tSets profile name.", NULL},
1777 {"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},
1778 {"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},
1779 {"set_username", {ca_string, ca_none}, do_set_username, "set_username <name>\tSets username.", NULL},
1780 {"set_phone_number", {ca_string, ca_none}, do_set_phone_number, "set_phone_number <phone>\tChanges the phone number of this account", NULL},
1781 {"show_license", {ca_none}, do_show_license, "show_license\tPrints contents of GPL license", NULL},
1782 {"start_bot", {ca_user, ca_chat, ca_string, ca_none}, do_start_bot, "start_bot <bot> <chat> <data>\tAdds bot to chat", NULL},
1783 {"stats", {ca_none}, do_stats, "stats\tFor debug purpose", NULL},
1784 {"status_online", {ca_none}, do_status_online, "status_online\tSets status as online", NULL},
1785 {"status_offline", {ca_none}, do_status_offline, "status_offline\tSets status as offline", NULL},
1786 {"unblock_user", {ca_user, ca_none}, do_unblock_user, "unblock_user <user>\tUnblocks user", NULL},
1787 {"user_info", {ca_user, ca_none}, do_user_info, "user_info <user>\tPrints info about user (id, last online, phone)", NULL},
1788 {"version", {ca_none}, do_version, "version\tPrints client and library version", NULL},
1789 {"view_audio", {ca_msg_id, ca_none}, do_open_audio, "view_audio <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
1790 {"view_channel_photo", {ca_channel, ca_none}, do_view_user_photo, "view_channel_photo <channel>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
1791 {"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},
1792 {"view_document", {ca_msg_id, ca_none}, do_open_document, "view_document <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
1793 {"view_document_thumb", {ca_msg_id, 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},
1794 {"view_file", {ca_msg_id, ca_none}, do_open_file, "view_file <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
1795 {"view_file_thumb", {ca_msg_id, 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},
1796 {"view_photo", {ca_msg_id, ca_none}, do_open_photo, "view_photo <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
1797 {"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},
1798 {"view_video", {ca_msg_id, ca_none}, do_open_video, "view_video <msg-id>\tDownloads file to downloads dirs. Then tries to open it with system default action", NULL},
1799 {"view_video_thumb", {ca_msg_id, 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},
1800 {"view", {ca_msg_id, ca_none}, do_open_any, "view <msg-id>\tTries to view message contents", NULL},
1801 {"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}
1802 };
1803
register_new_command(struct command * cmd)1804 void register_new_command (struct command *cmd) {
1805 int i = 0;
1806 while (commands[i].name) {
1807 i ++;
1808 }
1809 assert (i < MAX_COMMANDS_SIZE - 1);
1810 commands[i] = *cmd;
1811 }
1812
1813 tgl_peer_t *autocomplete_peer;
1814 tgl_message_id_t autocomplete_id;
1815
get_complete_mode(void)1816 enum command_argument get_complete_mode (void) {
1817 force_end_mode = 0;
1818 line_ptr = rl_line_buffer;
1819 autocomplete_peer = NULL;
1820 autocomplete_id.peer_type = NOT_FOUND;
1821
1822 while (1) {
1823 next_token ();
1824 if (cur_token_quoted) { return ca_none; }
1825 if (cur_token_len <= 0) { return ca_command; }
1826 if (*cur_token == '[') {
1827 if (cur_token_end_str) {
1828 return ca_modifier;
1829 }
1830 if (cur_token[cur_token_len - 1] != ']') {
1831 return ca_none;
1832 }
1833 continue;
1834 }
1835 break;
1836 }
1837 if (cur_token_quoted) { return ca_none; }
1838 if (cur_token_end_str) { return ca_command; }
1839 if (*cur_token == '(') { return ca_extf; }
1840
1841 struct command *command = commands;
1842 int n = 0;
1843 struct tgl_command;
1844 while (command->name) {
1845 if (is_same_word (cur_token, cur_token_len, command->name)) {
1846 break;
1847 }
1848 n ++;
1849 command ++;
1850 }
1851
1852 if (!command->name) {
1853 return ca_none;
1854 }
1855
1856 enum command_argument *flags = command->args;
1857 while (1) {
1858 int period = 0;
1859 if (*flags == ca_period) {
1860 flags --;
1861 period = 1;
1862 }
1863 enum command_argument op = (*flags) & 255;
1864 int opt = (*flags) & ca_optional;
1865
1866 if (op == ca_none) { return ca_none; }
1867 if (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) {
1868 next_token_end_ac ();
1869
1870 if (cur_token_len < 0 || !cur_token_end_str) {
1871 return ca_none;
1872 } else {
1873 return op;
1874 }
1875 }
1876
1877 char *save = line_ptr;
1878 next_token ();
1879 if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double || op == ca_msg_id || op == ca_command || op == ca_channel) {
1880 if (cur_token_quoted) {
1881 if (opt) {
1882 line_ptr = save;
1883 flags ++;
1884 continue;
1885 } else if (period) {
1886 line_ptr = save;
1887 flags += 2;
1888 continue;
1889 } else {
1890 return ca_none;
1891 }
1892 } else {
1893 if (cur_token_end_str) { return op; }
1894
1895 int ok = 1;
1896 switch (op) {
1897 case ca_user:
1898 ok = (tgl_get_peer_type (cur_token_user ()) != NOT_FOUND);
1899 break;
1900 case ca_chat:
1901 ok = (tgl_get_peer_type (cur_token_chat ()) != NOT_FOUND);
1902 break;
1903 case ca_secret_chat:
1904 ok = (tgl_get_peer_type (cur_token_encr_chat ()) != NOT_FOUND);
1905 break;
1906 case ca_channel:
1907 ok = (tgl_get_peer_type (cur_token_channel ()) != NOT_FOUND);
1908 break;
1909 case ca_peer:
1910 ok = (tgl_get_peer_type (cur_token_peer ()) != NOT_FOUND);
1911 if (ok) {
1912 autocomplete_peer = tgl_peer_get (TLS, cur_token_peer ());
1913 autocomplete_id.peer_type = NOT_FOUND;
1914 }
1915 break;
1916 case ca_number:
1917 ok = (cur_token_int () != NOT_FOUND);
1918 break;
1919 case ca_msg_id:
1920 ok = (cur_token_msg_id ().peer_type != 0);
1921 if (ok) {
1922 autocomplete_peer = NULL;
1923 autocomplete_id = cur_token_msg_id ();
1924 }
1925 break;
1926 case ca_double:
1927 ok = (cur_token_double () != NOT_FOUND);
1928 break;
1929 case ca_command:
1930 ok = cur_token_len > 0;
1931 break;
1932 default:
1933 assert (0);
1934 }
1935
1936 if (opt && !ok) {
1937 line_ptr = save;
1938 flags ++;
1939 continue;
1940 }
1941 if (period && !ok) {
1942 line_ptr = save;
1943 flags += 2;
1944 continue;
1945 }
1946 if (!ok) {
1947 return ca_none;
1948 }
1949
1950 flags ++;
1951 continue;
1952 }
1953 }
1954 if (op == ca_string || op == ca_file_name) {
1955 if (cur_token_end_str) {
1956 return op;
1957 } else {
1958 flags ++;
1959 continue;
1960 }
1961 }
1962 assert (0);
1963 }
1964 }
1965
complete_string_list(char ** list,int index,const char * text,int len,char ** R)1966 int complete_string_list (char **list, int index, const char *text, int len, char **R) {
1967 index ++;
1968 while (list[index] && strncmp (list[index], text, len)) {
1969 index ++;
1970 }
1971 if (list[index]) {
1972 *R = strdup (list[index]);
1973 assert (*R);
1974 return index;
1975 } else {
1976 *R = 0;
1977 return -1;
1978 }
1979 }
1980 void print_msg_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M);
1981 void print_encr_chat_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E);;
1982 void print_success_gw (struct tgl_state *TLS, void *extra, int success);
1983
complete_command_list(int index,const char * text,int len,char ** R)1984 int complete_command_list (int index, const char *text, int len, char **R) {
1985 index ++;
1986 while (commands[index].name && strncmp (commands[index].name, text, len)) {
1987 index ++;
1988 }
1989 if (commands[index].name) {
1990 *R = strdup (commands[index].name);
1991 assert (*R);
1992 return index;
1993 } else {
1994 *R = 0;
1995 return -1;
1996 }
1997 }
1998
1999
complete_spec_message_answer(struct tgl_message * M,int index,const char * text,int len,char ** R)2000 int complete_spec_message_answer (struct tgl_message *M, int index, const char *text, int len, char **R) {
2001 if (!M || !M->reply_markup || !M->reply_markup->rows) {
2002 *R = NULL;
2003 return -1;
2004 }
2005 index ++;
2006
2007 int total = M->reply_markup->row_start[M->reply_markup->rows];
2008 while (index < total && strncmp (M->reply_markup->buttons[index], text, len)) {
2009 index ++;
2010 }
2011
2012 if (index < total) {
2013 *R = strdup (M->reply_markup->buttons[index]);
2014 assert (*R);
2015 return index;
2016 } else {
2017 *R = NULL;
2018 return -1;
2019 }
2020 }
2021
complete_message_answer(tgl_peer_t * P,int index,const char * text,int len,char ** R)2022 int complete_message_answer (tgl_peer_t *P, int index, const char *text, int len, char **R) {
2023 struct tgl_message *M = P->last;
2024 while (M && (M->flags & TGLMF_OUT)) {
2025 M = M->next;
2026 }
2027
2028
2029 return complete_spec_message_answer (M, index, text, len, R);
2030 }
2031
complete_user_command(tgl_peer_t * P,int index,const char * text,int len,char ** R)2032 int complete_user_command (tgl_peer_t *P, int index, const char *text, int len, char **R) {
2033 if (len <= 0 || *text != '/') {
2034 return complete_message_answer (P, index, text, len, R);
2035 }
2036 text ++;
2037 len --;
2038 struct tgl_user *U = (void *)P;
2039 if (!U->bot_info) {
2040 *R = NULL;
2041 return -1;
2042 }
2043 if (index >= U->bot_info->commands_num) {
2044 return U->bot_info->commands_num + complete_message_answer (P, index - U->bot_info->commands_num, text - 1, len + 1, R);
2045 }
2046
2047 index ++;
2048 while (index < U->bot_info->commands_num && strncmp (U->bot_info->commands[index].command, text, len)) {
2049 index ++;
2050 }
2051 if (index < U->bot_info->commands_num) {
2052 *R = NULL;
2053 assert (asprintf (R, "/%s", U->bot_info->commands[index].command) >= 0);
2054 assert (*R);
2055 return index;
2056 } else {
2057 return U->bot_info->commands_num + complete_message_answer (P, index - U->bot_info->commands_num, text - 1, len + 1, R);
2058 }
2059 }
2060
complete_chat_command(tgl_peer_t * P,int index,const char * text,int len,char ** R)2061 int complete_chat_command (tgl_peer_t *P, int index, const char *text, int len, char **R) {
2062 if (len <= 0 || *text != '/') {
2063 return complete_message_answer (P, index, text, len, R);
2064 }
2065 text ++;
2066 len --;
2067
2068 index ++;
2069
2070 int tot = 0;
2071 int i;
2072 for (i = 0; i < P->chat.user_list_size; i++) {
2073 struct tgl_user *U = (void *)tgl_peer_get (TLS, TGL_MK_USER (P->chat.user_list[i].user_id));
2074 if (!U) { continue; }
2075 if (!U->bot_info) { continue; }
2076 int p = len - 1;
2077 while (p >= 0 && text[p] != '@') { p --; }
2078 if (p < 0) { p = len; }
2079 while (index - tot < U->bot_info->commands_num && strncmp (U->bot_info->commands[index - tot].command, text, p)) {
2080 index ++;
2081 }
2082 if (index - tot < U->bot_info->commands_num) {
2083 *R = NULL;
2084 if (U->username) {
2085 assert (asprintf (R, "/%s@%s", U->bot_info->commands[index].command, U->username) >= 0);
2086 } else {
2087 assert (asprintf (R, "/%s", U->bot_info->commands[index].command) >= 0);
2088 }
2089
2090 assert (*R);
2091 return index;
2092 }
2093 tot += U->bot_info->commands_num;
2094 }
2095
2096 if (index == tot) {
2097 return tot + complete_message_answer (P, index - tot, text - 1, len + 1, R);
2098 } else {
2099 return tot + complete_message_answer (P, index - tot - 1, text - 1, len + 1, R);
2100 }
2101 }
2102
complete_username(int mode,int index,const char * text,int len,char ** R)2103 int complete_username (int mode, int index, const char *text, int len, char **R) {
2104 *R = NULL;
2105 if (len > 0 && *text == '@') {
2106 text ++;
2107 len --;
2108 }
2109 index ++;
2110 while (index < TLS->peer_num) {
2111 tgl_peer_t *P = TLS->Peers[index];
2112 if (mode && tgl_get_peer_type (P->id) != mode) {
2113 index ++;
2114 continue;
2115 }
2116 char *u = NULL;
2117 if (tgl_get_peer_type (P->id) == TGL_PEER_USER) {
2118 u = P->user.username;
2119 } else if (tgl_get_peer_type (P->id) == TGL_PEER_CHANNEL) {
2120 u = P->channel.username;
2121 }
2122 if (!u) {
2123 index ++;
2124 continue;
2125 }
2126 if ((int)strlen (u) < len || memcmp (u, text, len)) {
2127 index ++;
2128 continue;
2129 }
2130 *R = malloc (strlen (u) + 2);
2131 *R[0] = '@';
2132 memcpy (*R + 1, u, strlen (u) + 1);
2133 break;
2134 }
2135 if (index == TLS->peer_num) {
2136 return -1;
2137 }
2138 return index;
2139 }
2140
command_generator(const char * text,int state)2141 char *command_generator (const char *text, int state) {
2142 #ifndef DISABLE_EXTF
2143 static int len;
2144 #endif
2145 static int index;
2146 static enum command_argument mode;
2147 static char *command_pos;
2148 static int command_len;
2149
2150 if (in_chat_mode) {
2151 char *R = 0;
2152 index = complete_string_list (in_chat_commands, index, text, rl_point, &R);
2153 return R;
2154 }
2155
2156 char c = 0;
2157 c = rl_line_buffer[rl_point];
2158 rl_line_buffer[rl_point] = 0;
2159 if (!state) {
2160 #ifndef DISABLE_EXTF
2161 len = strlen (text);
2162 #endif
2163 index = -1;
2164
2165 mode = get_complete_mode ();
2166 command_pos = cur_token;
2167 command_len = cur_token_len;
2168 } else {
2169 if (mode != ca_file_name && mode != ca_file_name_end && index == -1) { return 0; }
2170 }
2171
2172 if (mode == ca_none || mode == ca_string || mode == ca_string_end || mode == ca_number || mode == ca_double || mode == ca_msg_id) {
2173 if (c) { rl_line_buffer[rl_point] = c; }
2174 return 0;
2175 }
2176 assert (command_len >= 0);
2177
2178 char *R = 0;
2179 switch (mode & 255) {
2180 case ca_command:
2181 index = complete_command_list (index, command_pos, command_len, &R);
2182 if (c) { rl_line_buffer[rl_point] = c; }
2183 return R;
2184 case ca_user:
2185 if (command_len && command_pos[0] == '@') {
2186 index = complete_username (TGL_PEER_USER, index, command_pos, command_len, &R);
2187 } else {
2188 index = tgl_complete_user_list (TLS, index, command_pos, command_len, &R);
2189 }
2190 if (c) { rl_line_buffer[rl_point] = c; }
2191 return R;
2192 case ca_peer:
2193 if (command_len && command_pos[0] == '@') {
2194 index = complete_username (0, index, command_pos, command_len, &R);
2195 } else {
2196 index = tgl_complete_peer_list (TLS, index, command_pos, command_len, &R);
2197 }
2198 if (c) { rl_line_buffer[rl_point] = c; }
2199 return R;
2200 case ca_file_name:
2201 case ca_file_name_end:
2202 if (c) { rl_line_buffer[rl_point] = c; }
2203 R = rl_filename_completion_function (command_pos, state);
2204 return R;
2205 case ca_chat:
2206 index = tgl_complete_chat_list (TLS, index, command_pos, command_len, &R);
2207 if (c) { rl_line_buffer[rl_point] = c; }
2208 return R;
2209 case ca_secret_chat:
2210 index = tgl_complete_encr_chat_list (TLS, index, command_pos, command_len, &R);
2211 if (c) { rl_line_buffer[rl_point] = c; }
2212 return R;
2213 case ca_channel:
2214 if (command_len && command_pos[0] == '@') {
2215 index = complete_username (TGL_PEER_CHANNEL, index, command_pos, command_len, &R);
2216 } else {
2217 index = tgl_complete_channel_list (TLS, index, command_pos, command_len, &R);
2218 }
2219 if (c) { rl_line_buffer[rl_point] = c; }
2220 return R;
2221 case ca_modifier:
2222 index = complete_string_list (modifiers, index, command_pos, command_len, &R);
2223 if (c) { rl_line_buffer[rl_point] = c; }
2224 return R;
2225 case ca_msg_string_end:
2226 if (autocomplete_peer) {
2227 if (tgl_get_peer_type (autocomplete_peer->id) == TGL_PEER_USER) {
2228 index = complete_user_command (autocomplete_peer, index, command_pos, command_len, &R);
2229 }
2230 if (tgl_get_peer_type (autocomplete_peer->id) == TGL_PEER_CHAT) {
2231 index = complete_chat_command (autocomplete_peer, index, command_pos, command_len, &R);
2232 }
2233 }
2234 if (autocomplete_id.peer_type != (unsigned)NOT_FOUND) {
2235 struct tgl_message *M = tgl_message_get (TLS, &autocomplete_id);
2236 if (M) {
2237 if (command_len > 0 && *command_pos == '/') {
2238 tgl_peer_t *P = tgl_peer_get (TLS, M->from_id);
2239 if (P) {
2240 index = complete_user_command (autocomplete_peer, index, command_pos, command_len, &R);
2241 }
2242 } else {
2243 index = complete_spec_message_answer (M, index, command_pos, command_len, &R);
2244 }
2245 }
2246 }
2247 if (c) { rl_line_buffer[rl_point] = c; }
2248 return R;
2249 #ifndef DISABLE_EXTF
2250 case ca_extf:
2251 index = tglf_extf_autocomplete (TLS, text, len, index, &R, rl_line_buffer, rl_point);
2252 if (c) { rl_line_buffer[rl_point] = c; }
2253 return R;
2254 #endif
2255 default:
2256 if (c) { rl_line_buffer[rl_point] = c; }
2257 return 0;
2258 }
2259 }
2260
2261 int count = 1;
work_modifier(const char * s,int l)2262 void work_modifier (const char *s, int l) {
2263 if (is_same_word (s, l, "[offline]")) {
2264 offline_mode = 1;
2265 }
2266 if (sscanf (s, "[reply=%d]", &reply_id) >= 1) {
2267 }
2268
2269 if (is_same_word (s, l, "[html]")) {
2270 do_html = TGLMF_HTML;
2271 }
2272 if (is_same_word (s, l, "[disable_preview]")) {
2273 disable_msg_preview = TGL_SEND_MSG_FLAG_DISABLE_PREVIEW;
2274 }
2275 if (is_same_word (s, l, "[enable_preview]")) {
2276 disable_msg_preview = TGL_SEND_MSG_FLAG_ENABLE_PREVIEW;
2277 }
2278 #ifdef ALLOW_MULT
2279 if (sscanf (s, "[x%d]", &count) >= 1) {
2280 }
2281 #endif
2282 }
2283
print_fail(struct in_ev * ev)2284 void print_fail (struct in_ev *ev) {
2285 mprint_start (ev);
2286 if (!enable_json) {
2287 mprintf (ev, "FAIL: %d: %s\n", TLS->error_code, TLS->error);
2288 } else {
2289 #ifdef USE_JSON
2290 json_t *res = json_object ();
2291 assert (json_object_set_new (res, "result", json_string ("FAIL")) >= 0);
2292 assert (json_object_set_new (res, "error_code", json_integer (TLS->error_code)) >= 0);
2293 assert (json_object_set_new (res, "error", json_string (TLS->error ? TLS->error : "")) >= 0);
2294 char *s = json_dumps (res, 0);
2295 mprintf (ev, "%s\n", s);
2296 json_decref (res);
2297 free (s);
2298 #endif
2299 }
2300 mprint_end (ev);
2301 }
2302
fail_interface(struct tgl_state * TLS,struct in_ev * ev,int error_code,const char * format,...)2303 void fail_interface (struct tgl_state *TLS, struct in_ev *ev, int error_code, const char *format, ...) {
2304 static char error[1001];
2305
2306 va_list ap;
2307 va_start (ap, format);
2308 int error_len = vsnprintf (error, 1000, format, ap);
2309 va_end (ap);
2310 if (error_len > 1000) { error_len = 1000; }
2311 error[error_len] = 0;
2312
2313 mprint_start (ev);
2314 if (!enable_json) {
2315 mprintf (ev, "FAIL: %d: %s\n", error_code, error);
2316 } else {
2317 #ifdef USE_JSON
2318 json_t *res = json_object ();
2319 assert (json_object_set_new (res, "result", json_string ("FAIL")) >= 0);
2320 assert (json_object_set_new (res, "error_code", json_integer (error_code)) >= 0);
2321 assert (json_object_set_new (res, "error", json_string (error)) >= 0);
2322 char *s = json_dumps (res, 0);
2323 mprintf (ev, "%s\n", s);
2324 json_decref (res);
2325 free (s);
2326 #endif
2327 }
2328 mprint_end (ev);
2329 }
2330
print_success(struct in_ev * ev)2331 void print_success (struct in_ev *ev) {
2332 if (ev || enable_json) {
2333 mprint_start (ev);
2334 if (!enable_json) {
2335 mprintf (ev, "SUCCESS\n");
2336 } else {
2337 #ifdef USE_JSON
2338 json_t *res = json_object ();
2339 assert (json_object_set_new (res, "result", json_string ("SUCCESS")) >= 0);
2340 char *s = json_dumps (res, 0);
2341 mprintf (ev, "%s\n", s);
2342 json_decref (res);
2343 free (s);
2344 #endif
2345 }
2346 mprint_end (ev);
2347 }
2348 }
2349
print_success_gw(struct tgl_state * TLSR,void * extra,int success)2350 void print_success_gw (struct tgl_state *TLSR, void *extra, int success) {
2351 assert (TLS == TLSR);
2352 struct in_ev *ev = extra;
2353 if (ev && !--ev->refcnt) {
2354 free (ev);
2355 return;
2356 }
2357 if (!success) { print_fail (ev); return; }
2358 else { print_success (ev); return; }
2359 }
2360
print_msg_success_gw(struct tgl_state * TLS,void * extra,int success,struct tgl_message * M)2361 void print_msg_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_message *M) {
2362 write_secret_chat_file ();
2363 print_success_gw (TLS, extra, success);
2364 }
2365
print_msg_list_success_gw(struct tgl_state * TLSR,void * extra,int success,int num,struct tgl_message * ML[])2366 void print_msg_list_success_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_message *ML[]) {
2367 assert (TLS == TLSR);
2368 print_success_gw (TLSR, extra, success);
2369 }
2370
print_encr_chat_success_gw(struct tgl_state * TLS,void * extra,int success,struct tgl_secret_chat * E)2371 void print_encr_chat_success_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E) {
2372 write_secret_chat_file ();
2373 print_success_gw (TLS, extra, success);
2374 }
2375
print_msg_list_gw(struct tgl_state * TLSR,void * extra,int success,int num,struct tgl_message * ML[])2376 void print_msg_list_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_message *ML[]) {
2377 assert (TLS == TLSR);
2378 struct in_ev *ev = extra;
2379 if (ev && !--ev->refcnt) {
2380 free (ev);
2381 return;
2382 }
2383 if (!success) { print_fail (ev); return; }
2384
2385 mprint_start (ev);
2386 if (!enable_json) {
2387 int i;
2388 for (i = num - 1; i >= 0; i--) {
2389 #ifdef USE_LUA
2390 lua_list_msg (ML[i]);
2391 #endif
2392 #ifdef USE_PYTHON
2393 py_list_msg (ML[i]);
2394 #endif
2395 print_message (ev, ML[i]);
2396 }
2397 } else {
2398 #ifdef USE_JSON
2399 json_t *res = json_array ();
2400 int i;
2401 for (i = num - 1; i >= 0; i--) {
2402 #ifdef USE_LUA
2403 lua_list_msg (ML[i]);
2404 #endif
2405 #ifdef USE_PYTHON
2406 py_list_msg (ML[i]);
2407 #endif
2408 json_t *a = json_pack_message (ML[i]);
2409 assert (json_array_append_new (res, a) >= 0);
2410 }
2411 char *s = json_dumps (res, 0);
2412 mprintf (ev, "%s\n", s);
2413 json_decref (res);
2414 free (s);
2415 #endif
2416 }
2417 mprint_end (ev);
2418 }
2419
print_msg_list_history_gw(struct tgl_state * TLSR,void * extra,int success,int num,struct tgl_message * ML[])2420 void print_msg_list_history_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_message *ML[]) {
2421 print_msg_list_gw (TLSR, extra, success, num, ML);
2422 if (num > 0) {
2423 if (tgl_cmp_peer_id (ML[0]->to_id, TLS->our_id)) {
2424 tgl_do_messages_mark_read (TLS, ML[0]->to_id, ML[0]->server_id, 0, NULL, NULL);
2425 } else {
2426 tgl_do_messages_mark_read (TLS, ML[0]->from_id, ML[0]->server_id, 0, NULL, NULL);
2427 }
2428 }
2429 }
2430
print_msg_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_message * M)2431 void print_msg_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_message *M) {
2432 assert (TLS == TLSR);
2433 struct in_ev *ev = extra;
2434 if (ev && !--ev->refcnt) {
2435 free (ev);
2436 return;
2437 }
2438 if (!success) { print_fail (ev); return; }
2439 mprint_start (ev);
2440 if (!enable_json) {
2441 print_message (ev, M);
2442 } else {
2443 #ifdef USE_JSON
2444 json_t *res = json_pack_message (M);
2445 char *s = json_dumps (res, 0);
2446 mprintf (ev, "%s\n", s);
2447 json_decref (res);
2448 free (s);
2449 #endif
2450 }
2451 mprint_end (ev);
2452 }
2453
print_user_list_gw(struct tgl_state * TLSR,void * extra,int success,int num,struct tgl_user * UL[])2454 void print_user_list_gw (struct tgl_state *TLSR, void *extra, int success, int num, struct tgl_user *UL[]) {
2455 assert (TLS == TLSR);
2456 struct in_ev *ev = extra;
2457 if (ev && !--ev->refcnt) {
2458 free (ev);
2459 return;
2460 }
2461 if (!success) { print_fail (ev); return; }
2462 mprint_start (ev);
2463 if (!enable_json) {
2464 int i;
2465 for (i = num - 1; i >= 0; i--) {
2466 print_user_name (ev, UL[i]->id, (void *)UL[i]);
2467 mprintf (ev, "\n");
2468 }
2469 } else {
2470 #ifdef USE_JSON
2471 json_t *res = json_array ();
2472 int i;
2473 for (i = num - 1; i >= 0; i--) {
2474 json_t *a = json_pack_peer (UL[i]->id);
2475 assert (json_array_append_new (res, a) >= 0);
2476 }
2477 char *s = json_dumps (res, 0);
2478 mprintf (ev, "%s\n", s);
2479 json_decref (res);
2480 free (s);
2481 #endif
2482 }
2483 mprint_end (ev);
2484 }
2485
print_user_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_user * U)2486 void print_user_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_user *U) {
2487 assert (TLS == TLSR);
2488 struct in_ev *ev = extra;
2489 if (ev && !--ev->refcnt) {
2490 free (ev);
2491 return;
2492 }
2493 if (!success) { print_fail (ev); return; }
2494 mprint_start (ev);
2495 if (!enable_json) {
2496 print_user_name (ev, U->id, (void *)U);
2497 mprintf (ev, "\n");
2498 } else {
2499 #ifdef USE_JSON
2500 json_t *res = json_pack_peer (U->id);
2501 char *s = json_dumps (res, 0);
2502 mprintf (ev, "%s\n", s);
2503 json_decref (res);
2504 free (s);
2505 #endif
2506 }
2507 mprint_end (ev);
2508 }
2509
print_chat_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_chat * U)2510 void print_chat_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_chat *U) {
2511 assert (TLS == TLSR);
2512 struct in_ev *ev = extra;
2513 if (ev && !--ev->refcnt) {
2514 free (ev);
2515 return;
2516 }
2517 if (!success) { print_fail (ev); return; }
2518 mprint_start (ev);
2519 if (!enable_json) {
2520 print_chat_name (ev, U->id, (void *)U);
2521 mprintf (ev, "\n");
2522 } else {
2523 #ifdef USE_JSON
2524 json_t *res = json_pack_peer (U->id);
2525 char *s = json_dumps (res, 0);
2526 mprintf (ev, "%s\n", s);
2527 json_decref (res);
2528 free (s);
2529 #endif
2530 }
2531 mprint_end (ev);
2532 }
2533
print_channel_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_channel * U)2534 void print_channel_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_channel *U) {
2535 assert (TLS == TLSR);
2536 struct in_ev *ev = extra;
2537 if (ev && !--ev->refcnt) {
2538 free (ev);
2539 return;
2540 }
2541 if (!success) { print_fail (ev); return; }
2542 mprint_start (ev);
2543 if (!enable_json) {
2544 print_channel_name (ev, U->id, (void *)U);
2545 mprintf (ev, "\n");
2546 } else {
2547 #ifdef USE_JSON
2548 json_t *res = json_pack_peer (U->id);
2549 char *s = json_dumps (res, 0);
2550 mprintf (ev, "%s\n", s);
2551 json_decref (res);
2552 free (s);
2553 #endif
2554 }
2555 mprint_end (ev);
2556 }
2557
2558
print_peer_gw(struct tgl_state * TLSR,void * extra,int success,tgl_peer_t * U)2559 void print_peer_gw (struct tgl_state *TLSR, void *extra, int success, tgl_peer_t *U) {
2560 if (!success) {
2561 print_user_gw (TLSR, extra, success, (void *)U);
2562 return;
2563 }
2564 switch (tgl_get_peer_type (U->id)) {
2565 case TGL_PEER_USER:
2566 print_user_gw (TLSR, extra, success, (void *)U);
2567 break;
2568 case TGL_PEER_CHAT:
2569 print_chat_gw (TLSR, extra, success, (void *)U);
2570 break;
2571 case TGL_PEER_CHANNEL:
2572 print_channel_gw (TLSR, extra, success, (void *)U);
2573 break;
2574 default:
2575 assert (0);
2576 }
2577 }
2578
print_filename_gw(struct tgl_state * TLSR,void * extra,int success,const char * name)2579 void print_filename_gw (struct tgl_state *TLSR, void *extra, int success, const char *name) {
2580 assert (TLS == TLSR);
2581 struct in_ev *ev = extra;
2582 if (ev && !--ev->refcnt) {
2583 free (ev);
2584 return;
2585 }
2586 if (!success) { print_fail (ev); return; }
2587 mprint_start (ev);
2588 if (!enable_json) {
2589 mprintf (ev, "Saved to %s\n", name);
2590 } else {
2591 #ifdef USE_JSON
2592 json_t *res = json_object ();
2593 assert (json_object_set_new (res, "result", json_string (name)) >= 0);
2594 assert (json_object_set_new (res, "event", json_string ("download")) >= 0);
2595 char *s = json_dumps (res, 0);
2596 mprintf (ev, "%s\n", s);
2597 json_decref (res);
2598 free (s);
2599 #endif
2600 }
2601 mprint_end (ev);
2602 }
2603
print_string_gw(struct tgl_state * TLSR,void * extra,int success,const char * name)2604 void print_string_gw (struct tgl_state *TLSR, void *extra, int success, const char *name) {
2605 assert (TLS == TLSR);
2606 struct in_ev *ev = extra;
2607 if (ev && !--ev->refcnt) {
2608 free (ev);
2609 return;
2610 }
2611 if (!success) { print_fail (ev); return; }
2612 mprint_start (ev);
2613 if (!enable_json) {
2614 mprintf (ev, "%s\n", name);
2615 } else {
2616 #ifdef USE_JSON
2617 json_t *res = json_object ();
2618 assert (json_object_set_new (res, "result", json_string (name)) >= 0);
2619 char *s = json_dumps (res, 0);
2620 mprintf (ev, "%s\n", s);
2621 json_decref (res);
2622 free (s);
2623 #endif
2624 }
2625 mprint_end (ev);
2626 }
2627
open_filename_gw(struct tgl_state * TLSR,void * extra,int success,const char * name)2628 void open_filename_gw (struct tgl_state *TLSR, void *extra, int success, const char *name) {
2629 assert (TLS == TLSR);
2630 struct in_ev *ev = extra;
2631 if (ev && !--ev->refcnt) {
2632 free (ev);
2633 return;
2634 }
2635 if (ev) { return; }
2636 if (!success) { print_fail (ev); return; }
2637 static char buf[PATH_MAX];
2638 if (snprintf (buf, sizeof (buf), OPEN_BIN, name) >= (int) sizeof (buf)) {
2639 logprintf ("Open image command buffer overflow\n");
2640 } else {
2641 int pid = fork ();
2642 if (!pid) {
2643 execl("/bin/sh", "sh", "-c", buf, (char *) 0);
2644 exit (0);
2645 }
2646 }
2647 }
2648
print_chat_info_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_chat * C)2649 void print_chat_info_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_chat *C) {
2650 assert (TLS == TLSR);
2651 struct in_ev *ev = extra;
2652 if (ev && !--ev->refcnt) {
2653 free (ev);
2654 return;
2655 }
2656 if (!success) { print_fail (ev); return; }
2657 mprint_start (ev);
2658
2659 if (!enable_json) {
2660 tgl_peer_t *U = (void *)C;
2661 mpush_color (ev, COLOR_YELLOW);
2662 mprintf (ev, "Chat ");
2663 print_chat_name (ev, U->id, U);
2664 mprintf (ev, " (id %d) members:\n", tgl_get_peer_id (U->id));
2665 int i;
2666 for (i = 0; i < C->user_list_size; i++) {
2667 mprintf (ev, "\t\t");
2668 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)));
2669 mprintf (ev, " invited by ");
2670 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)));
2671 mprintf (ev, " at ");
2672 print_date_full (ev, C->user_list[i].date);
2673 if (C->user_list[i].user_id == C->admin_id) {
2674 mprintf (ev, " admin");
2675 }
2676 mprintf (ev, "\n");
2677 }
2678 mpop_color (ev);
2679 } else {
2680 #ifdef USE_JSON
2681 json_t *res = json_pack_peer (C->id);
2682 char *s = json_dumps (res, 0);
2683 mprintf (ev, "%s\n", s);
2684 json_decref (res);
2685 free (s);
2686 #endif
2687 }
2688
2689 mprint_end (ev);
2690 }
2691
print_channel_info_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_channel * C)2692 void print_channel_info_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_channel *C) {
2693 assert (TLS == TLSR);
2694 struct in_ev *ev = extra;
2695 if (ev && !--ev->refcnt) {
2696 free (ev);
2697 return;
2698 }
2699 if (!success) { print_fail (ev); return; }
2700 mprint_start (ev);
2701
2702 if (!enable_json) {
2703 tgl_peer_t *U = (void *)C;
2704 mpush_color (ev, COLOR_YELLOW);
2705 mprintf (ev, "Channel ");
2706 if (U->flags & TGLCHF_OFFICIAL) {
2707 mprintf (ev, "[verified] ");
2708 }
2709 if (U->flags & TGLCHF_BROADCAST) {
2710 mprintf (ev, "[broadcast] ");
2711 }
2712 if (U->flags & TGLCHF_MEGAGROUP) {
2713 mprintf (ev, "[megagroup] ");
2714 }
2715 if (U->flags & TGLCHF_DEACTIVATED) {
2716 mprintf (ev, "[deactivated] ");
2717 }
2718 print_channel_name (ev, U->id, U);
2719 if (C->username) {
2720 mprintf (ev, " @%s", C->username);
2721 }
2722 mprintf (ev, " (#%d):\n", tgl_get_peer_id (U->id));
2723 mprintf (ev, "\tabout: %s\n", C->about);
2724 mprintf (ev, "\t%d participants, %d admins, %d kicked\n", C->participants_count, C->admins_count, C->kicked_count);
2725 mpop_color (ev);
2726 } else {
2727 #ifdef USE_JSON
2728 json_t *res = json_pack_peer (C->id);
2729 char *s = json_dumps (res, 0);
2730 mprintf (ev, "%s\n", s);
2731 json_decref (res);
2732 free (s);
2733 #endif
2734 }
2735
2736 mprint_end (ev);
2737 }
2738
print_user_status(struct tgl_user_status * S,struct in_ev * ev)2739 void print_user_status (struct tgl_user_status *S, struct in_ev *ev) {
2740 assert(!enable_json); //calling functions print_user_info_gw() and user_status_upd() already check.
2741 if (S->online > 0) {
2742 mprintf (ev, "online (was online ");
2743 print_date_full (ev, S->when);
2744 mprintf (ev, ")");
2745 } else {
2746 if (S->online == 0) {
2747 mprintf (ev, "offline");
2748 } else if (S->online == -1) {
2749 mprintf (ev, "offline (was online ");
2750 print_date_full (ev, S->when);
2751 mprintf (ev, ")");
2752 } else if (S->online == -2) {
2753 mprintf (ev, "offline (was online recently)");
2754 } else if (S->online == -3) {
2755 mprintf (ev, "offline (was online last week)");
2756 } else if (S->online == -4) {
2757 mprintf (ev, "offline (was online last month)");
2758 }
2759 }
2760 }
2761
print_user_info_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_user * U)2762 void print_user_info_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_user *U) {
2763 assert (TLS == TLSR);
2764 struct in_ev *ev = extra;
2765 if (ev && !--ev->refcnt) {
2766 free (ev);
2767 return;
2768 }
2769 if (!success) { print_fail (ev); return; }
2770 mprint_start (ev);
2771 tgl_peer_t *C = (void *)U;
2772 if (!enable_json) {
2773 mpush_color (ev, COLOR_YELLOW);
2774 mprintf (ev, "User ");
2775 print_user_name (ev, U->id, C);
2776 if (U->username) {
2777 mprintf (ev, " @%s", U->username);
2778 }
2779 mprintf (ev, " (#%d):\n", tgl_get_peer_id (U->id));
2780 mprintf (ev, "\tphone: %s\n", U->phone);
2781 mprintf (ev, "\t");
2782 print_user_status (&U->status, ev);
2783 mprintf (ev, "\n");
2784
2785 if (U->bot_info) {
2786 mprintf (ev, "\tshare_text: %s\n", U->bot_info->share_text);
2787 mprintf (ev, "\tdescription: %s\n", U->bot_info->description);
2788 mprintf (ev, "\tcommands:\n");
2789
2790 int i;
2791 for (i = 0; i < U->bot_info->commands_num; i++) {
2792 mprintf (ev, "\t\t/%s: %s\n", U->bot_info->commands[i].command, U->bot_info->commands[i].description);
2793 }
2794 }
2795 mpop_color (ev);
2796 } else {
2797 #ifdef USE_JSON
2798 json_t *res = json_pack_peer (U->id);
2799 char *s = json_dumps (res, 0);
2800 mprintf (ev, "%s\n", s);
2801 json_decref (res);
2802 free (s);
2803 #endif
2804 }
2805 mprint_end (ev);
2806 }
2807
print_secret_chat_gw(struct tgl_state * TLSR,void * extra,int success,struct tgl_secret_chat * E)2808 void print_secret_chat_gw (struct tgl_state *TLSR, void *extra, int success, struct tgl_secret_chat *E) {
2809 assert (TLS == TLSR);
2810 struct in_ev *ev = extra;
2811 if (ev && !--ev->refcnt) {
2812 free (ev);
2813 return;
2814 }
2815 if (!success) { print_fail (ev); return; }
2816 mprint_start (ev);
2817 if (!enable_json) {
2818 mpush_color (ev, COLOR_YELLOW);
2819 mprintf (ev, " Encrypted chat ");
2820 print_encr_chat_name (ev, E->id, (void *)E);
2821 mprintf (ev, " is now in wait state\n");
2822 mpop_color (ev);
2823 } else {
2824 #ifdef USE_JSON
2825 json_t *res = json_pack_peer (E->id);
2826 char *s = json_dumps (res, 0);
2827 mprintf (ev, "%s\n", s);
2828 json_decref (res);
2829 free (s);
2830 #endif
2831 }
2832 mprint_end (ev);
2833 }
2834
print_dialog_list_gw(struct tgl_state * TLSR,void * extra,int success,int size,tgl_peer_id_t peers[],tgl_message_id_t * last_msg_id[],int unread_count[])2835 void print_dialog_list_gw (struct tgl_state *TLSR, void *extra, int success, int size, tgl_peer_id_t peers[], tgl_message_id_t *last_msg_id[], int unread_count[]) {
2836 assert (TLS == TLSR);
2837 struct in_ev *ev = extra;
2838 if (ev && !--ev->refcnt) {
2839 free (ev);
2840 return;
2841 }
2842 if (!success) { print_fail (ev); return; }
2843 mprint_start (ev);
2844 if (!enable_json) {
2845 mpush_color (ev, COLOR_YELLOW);
2846 int i;
2847 for (i = size - 1; i >= 0; i--) {
2848 tgl_peer_t *UC;
2849 switch (tgl_get_peer_type (peers[i])) {
2850 case TGL_PEER_USER:
2851 UC = tgl_peer_get (TLS, peers[i]);
2852 mprintf (ev, "User ");
2853 print_user_name (ev, peers[i], UC);
2854 mprintf (ev, ": %d unread\n", unread_count[i]);
2855 break;
2856 case TGL_PEER_CHAT:
2857 UC = tgl_peer_get (TLS, peers[i]);
2858 mprintf (ev, "Chat ");
2859 print_chat_name (ev, peers[i], UC);
2860 mprintf (ev, ": %d unread\n", unread_count[i]);
2861 break;
2862 case TGL_PEER_CHANNEL:
2863 UC = tgl_peer_get (TLS, peers[i]);
2864 mprintf (ev, "Channel ");
2865 print_channel_name (ev, peers[i], UC);
2866 mprintf (ev, ": %d unread\n", unread_count[i]);
2867 break;
2868 }
2869 }
2870 mpop_color (ev);
2871 } else {
2872 #ifdef USE_JSON
2873 json_t *res = json_array ();
2874 int i;
2875 for (i = size - 1; i >= 0; i--) {
2876 json_t *a = json_pack_peer (peers[i]);
2877 assert (json_object_set_new (a, "unread", json_integer (unread_count[i])) >= 0);
2878 assert (json_array_append_new (res, a) >= 0);
2879 }
2880 char *s = json_dumps (res, 0);
2881 mprintf (ev, "%s\n", s);
2882 json_decref (res);
2883 free (s);
2884 #endif
2885 }
2886 mprint_end (ev);
2887 }
2888
interpreter_chat_mode(char * line)2889 void interpreter_chat_mode (char *line) {
2890 if (line == NULL || /* EOF received */
2891 !strncmp (line, "/exit", 5) || !strncmp (line, "/quit", 5)) {
2892 in_chat_mode = 0;
2893 update_prompt ();
2894 return;
2895 }
2896 if (!strncmp (line, "/history", 8)) {
2897 int limit = 40;
2898 sscanf (line, "/history %99d", &limit);
2899 if (limit < 0 || limit > 1000) { limit = 40; }
2900 tgl_do_get_history (TLS, chat_mode_id, 0, limit, offline_mode, print_msg_list_gw, 0);
2901 return;
2902 }
2903 if (!strncmp (line, "/read", 5)) {
2904 tgl_do_mark_read (TLS, chat_mode_id, 0, 0);
2905 return;
2906 }
2907 if (strlen (line) > 0) {
2908 tgl_do_send_message (TLS, chat_mode_id, line, strlen (line), 0, NULL, 0, 0);
2909 if (auto_mark_read)
2910 tgl_do_mark_read (TLS, chat_mode_id, 0, 0);
2911 }
2912 }
2913
2914 #define MAX_UNREAD_MESSAGE_COUNT 10000
2915 struct tgl_message *unread_message_list[MAX_UNREAD_MESSAGE_COUNT];
2916 int unread_message_count;
2917 struct event *unread_message_event;
2918
2919
print_read_list(int num,struct tgl_message * list[])2920 void print_read_list (int num, struct tgl_message *list[]) {
2921 time_t t = time(NULL);
2922 struct tm tm = *localtime(&t);
2923 struct in_ev *ev = notify_ev;
2924 int i;
2925 mprint_start (ev);
2926 for (i = 0; i < num; i++) if (list[i]) {
2927 if (enable_json) {
2928 #ifdef USE_JSON
2929 json_t *res = json_pack_read (list[i]);
2930 char *s = json_dumps (res, 0);
2931 mprintf (ev, "%s\n", s);
2932 json_decref (res);
2933 free (s);
2934 #endif
2935 }
2936 tgl_peer_id_t to_id;
2937 if (!tgl_cmp_peer_id (list[i]->to_id, TLS->our_id)) {
2938 to_id = list[i]->from_id;
2939 } else {
2940 to_id = list[i]->to_id;
2941 }
2942 int j;
2943 int c1 = 0;
2944 int c2 = 0;
2945 for (j = i; j < num; j++) if (list[j]) {
2946 tgl_peer_id_t end_id;
2947 if (!tgl_cmp_peer_id (list[j]->to_id, TLS->our_id)) {
2948 end_id = list[j]->from_id;
2949 } else {
2950 end_id = list[j]->to_id;
2951 }
2952 if (!tgl_cmp_peer_id (to_id, end_id)) {
2953 if (list[j]->flags & TGLMF_OUT) {
2954 c1 ++;
2955 } else {
2956 c2 ++;
2957 }
2958 list[j] = 0;
2959 }
2960 }
2961
2962 assert (c1 + c2 > 0);
2963 if (!enable_json) {
2964 mpush_color (ev, COLOR_YELLOW);
2965 switch (tgl_get_peer_type (to_id)) {
2966 case TGL_PEER_USER:
2967 mprintf (ev, "User ");
2968 print_user_name (ev, to_id, tgl_peer_get (TLS, to_id));
2969 break;
2970 case TGL_PEER_CHAT:
2971 mprintf (ev, "Chat ");
2972 print_chat_name (ev, to_id, tgl_peer_get (TLS, to_id));
2973 break;
2974 case TGL_PEER_ENCR_CHAT:
2975 mprintf (ev, "Secret chat ");
2976 print_encr_chat_name (ev, to_id, tgl_peer_get (TLS, to_id));
2977 break;
2978 default:
2979 assert (0);
2980 }
2981 mprintf (ev, " marked read %d outbox and %d inbox messages -- [%d/%02d/%02d %02d:%02d:%02d]\n", c1, c2, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
2982 mpop_color (ev);
2983 }
2984 }
2985 mprint_end (ev);
2986 }
2987
unread_message_alarm(evutil_socket_t fd,short what,void * arg)2988 void unread_message_alarm (evutil_socket_t fd, short what, void *arg) {
2989 print_read_list (unread_message_count, unread_message_list);
2990 unread_message_count = 0;
2991 event_free (unread_message_event);
2992 unread_message_event = 0;
2993 }
2994
mark_read_upd(struct tgl_state * TLSR,int num,struct tgl_message * list[])2995 void mark_read_upd (struct tgl_state *TLSR, int num, struct tgl_message *list[]) {
2996 assert (TLSR == TLS);
2997 if (!binlog_read) { return; }
2998 if (log_level < 1) { return; }
2999
3000 if (unread_message_count + num <= MAX_UNREAD_MESSAGE_COUNT) {
3001 memcpy (unread_message_list + unread_message_count, list, num * sizeof (void *));
3002 unread_message_count += num;
3003
3004 if (!unread_message_event) {
3005 unread_message_event = evtimer_new (TLS->ev_base, unread_message_alarm, 0);
3006 static struct timeval ptimeout = { 1, 0};
3007 event_add (unread_message_event, &ptimeout);
3008 }
3009 } else {
3010 print_read_list (unread_message_count, unread_message_list);
3011 print_read_list (num, list);
3012 unread_message_count = 0;
3013 if (unread_message_event) {
3014 event_free (unread_message_event);
3015 unread_message_event = 0;
3016 }
3017 }
3018 }
3019
print_typing(struct in_ev * ev,enum tgl_typing_status status)3020 void print_typing (struct in_ev *ev, enum tgl_typing_status status) {
3021
3022 time_t t = time(NULL);
3023 struct tm tm = *localtime(&t);
3024
3025 switch (status) {
3026 case tgl_typing_none:
3027 mprintf (ev, "doing nothing");
3028 break;
3029 case tgl_typing_typing:
3030 mprintf (ev, "typing -- [%d/%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);
3031 break;
3032 case tgl_typing_cancel:
3033 mprintf (ev, "deleting typed message -- [%d/%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);
3034 break;
3035 case tgl_typing_record_video:
3036 mprintf (ev, "recording video -- [%d/%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);
3037 break;
3038 case tgl_typing_upload_video:
3039 mprintf (ev, "uploading video -- [%d/%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);
3040 break;
3041 case tgl_typing_record_audio:
3042 mprintf (ev, "recording audio -- [%d/%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);
3043 break;
3044 case tgl_typing_upload_audio:
3045 mprintf (ev, "uploading audio -- [%d/%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);
3046 break;
3047 case tgl_typing_upload_photo:
3048 mprintf (ev, "uploading photo -- [%d/%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);
3049 break;
3050 case tgl_typing_upload_document:
3051 mprintf (ev, "uploading document -- [%d/%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);
3052 break;
3053 case tgl_typing_geo:
3054 mprintf (ev, "choosing location -- [%d/%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);
3055 break;
3056 case tgl_typing_choose_contact:
3057 mprintf (ev, "choosing contact -- [%d/%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);
3058 break;
3059 }
3060 }
3061
type_notification_upd(struct tgl_state * TLSR,struct tgl_user * U,enum tgl_typing_status status)3062 void type_notification_upd (struct tgl_state *TLSR, struct tgl_user *U, enum tgl_typing_status status) {
3063 assert (TLSR == TLS);
3064 if (log_level < 2 || (disable_output && !notify_ev)) { return; }
3065 if (enable_json) { return; }
3066 struct in_ev *ev = notify_ev;
3067 mprint_start (ev);
3068 mpush_color (ev, COLOR_YELLOW);
3069 mprintf (ev, "User ");
3070 print_user_name (ev, U->id, (void *)U);
3071 mprintf (ev, " is ");
3072 print_typing (ev, status);
3073 mprintf (ev, "\n");
3074 mpop_color (ev);
3075 mprint_end (ev);
3076 }
3077
type_in_chat_notification_upd(struct tgl_state * TLSR,struct tgl_user * U,struct tgl_chat * C,enum tgl_typing_status status)3078 void type_in_chat_notification_upd (struct tgl_state *TLSR, struct tgl_user *U, struct tgl_chat *C, enum tgl_typing_status status) {
3079 assert (TLSR == TLS);
3080 if (log_level < 2 || (disable_output && !notify_ev)) { return; }
3081 if (enable_json) { return; }
3082 struct in_ev *ev = notify_ev;
3083 mprint_start (ev);
3084 mpush_color (ev, COLOR_YELLOW);
3085 mprintf (ev, "User ");
3086 print_user_name (ev, U->id, (void *)U);
3087 mprintf (ev, " is ");
3088 print_typing (ev, status);
3089 mprintf (ev, " in chat ");
3090 print_chat_name (ev, C->id, (void *)C);
3091 mprintf (ev, "\n");
3092 mpop_color (ev);
3093 mprint_end (ev);
3094 }
3095
3096
print_message_gw(struct tgl_state * TLSR,struct tgl_message * M)3097 void print_message_gw (struct tgl_state *TLSR, struct tgl_message *M) {
3098 assert (TLSR == TLS);
3099 #ifdef USE_LUA
3100 lua_new_msg (M);
3101 #endif
3102 #ifdef USE_PYTHON
3103 py_new_msg (M);
3104 #endif
3105 if (!binlog_read) { return; }
3106 if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) {
3107 write_secret_chat_file ();
3108 }
3109 if (alert_sound) {
3110 play_sound ();
3111 }
3112 if (disable_output && !notify_ev) { return; }
3113 struct in_ev *ev = notify_ev;
3114 mprint_start (ev);
3115 if (!enable_json) {
3116 print_message (ev, M);
3117 } else {
3118 #ifdef USE_JSON
3119 json_t *res = json_pack_message (M);
3120 char *s = json_dumps (res, 0);
3121 mprintf (ev, "%s\n", s);
3122 json_decref (res);
3123 free (s);
3124 #endif
3125 }
3126 mprint_end (ev);
3127 }
3128
our_id_gw(struct tgl_state * TLSR,tgl_peer_id_t id)3129 void our_id_gw (struct tgl_state *TLSR, tgl_peer_id_t id) {
3130 assert (TLSR == TLS);
3131 #ifdef USE_LUA
3132 lua_our_id (id);
3133 #endif
3134 #ifdef USE_PYTHON
3135 py_our_id (tgl_get_peer_id (id));
3136 #endif
3137 }
3138
print_peer_updates(struct in_ev * ev,int flags)3139 void print_peer_updates (struct in_ev *ev, int flags) {
3140 time_t t = time(NULL);
3141 struct tm tm = *localtime(&t);
3142
3143 if (flags & TGL_UPDATE_PHONE) {
3144 mprintf (ev, " phone -- [%d/%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);
3145 }
3146 if (flags & TGL_UPDATE_CONTACT) {
3147 mprintf (ev, " contact -- [%d/%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);
3148 }
3149 if (flags & TGL_UPDATE_PHOTO) {
3150 mprintf (ev, " photo -- [%d/%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);
3151 }
3152 if (flags & TGL_UPDATE_BLOCKED) {
3153 mprintf (ev, " blocked -- [%d/%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);
3154 }
3155 if (flags & TGL_UPDATE_REAL_NAME) {
3156 mprintf (ev, " name -- [%d/%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);
3157 }
3158 if (flags & TGL_UPDATE_NAME) {
3159 mprintf (ev, " contact_name -- [%d/%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);
3160 }
3161 if (flags & TGL_UPDATE_REQUESTED) {
3162 mprintf (ev, " status -- [%d/%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);
3163 }
3164 if (flags & TGL_UPDATE_WORKING) {
3165 mprintf (ev, " status -- [%d/%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);
3166 }
3167 if (flags & TGL_UPDATE_FLAGS) {
3168 mprintf (ev, " flags -- [%d/%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);
3169 }
3170 if (flags & TGL_UPDATE_TITLE) {
3171 mprintf (ev, " title -- [%d/%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);
3172 }
3173 if (flags & TGL_UPDATE_ADMIN) {
3174 mprintf (ev, " admin -- [%d/%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);
3175 }
3176 if (flags & TGL_UPDATE_MEMBERS) {
3177 mprintf (ev, " members -- [%d/%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);
3178 }
3179 if (flags & TGL_UPDATE_ACCESS_HASH) {
3180 mprintf (ev, " access_hash -- [%d/%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);
3181 }
3182 if (flags & TGL_UPDATE_USERNAME) {
3183 mprintf (ev, " username -- [%d/%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);
3184 }
3185 }
3186
json_peer_update(struct in_ev * ev,tgl_peer_t * P,unsigned flags)3187 void json_peer_update (struct in_ev *ev, tgl_peer_t *P, unsigned flags) {
3188 #ifdef USE_JSON
3189 json_t *res = json_object ();
3190 assert (json_object_set_new (res, "event", json_string ("updates")) >= 0);
3191 assert (json_object_set_new (res, "peer", json_pack_peer (P->id)) >= 0);
3192 assert (json_object_set_new (res, "updates", json_pack_updates (flags)) >= 0);
3193 char *s = json_dumps (res, 0);
3194 mprintf (ev, "%s\n", s);
3195 json_decref (res);
3196 free (s);
3197 #endif
3198 }
3199
peer_update_username(tgl_peer_t * P,const char * username)3200 void peer_update_username (tgl_peer_t *P, const char *username) {
3201 if (!username) {
3202 if (P->extra) {
3203 struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra);
3204 assert (p);
3205 username_peer_pair = tree_delete_username_peer_pair (username_peer_pair, p);
3206 tfree_str (P->extra);
3207 tfree (p, sizeof (*p));
3208 P->extra = NULL;
3209 }
3210 return;
3211 }
3212 assert (username);
3213 if (P->extra && !strcmp (P->extra, username)) {
3214 return;
3215 }
3216 if (P->extra) {
3217 struct username_peer_pair *p = tree_lookup_username_peer_pair (username_peer_pair, (void *)&P->extra);
3218 assert (p);
3219 username_peer_pair = tree_delete_username_peer_pair (username_peer_pair, p);
3220 tfree_str (P->extra);
3221 tfree (p, sizeof (*p));
3222 P->extra = NULL;
3223 }
3224
3225 P->extra = tstrdup (username);
3226 struct username_peer_pair *p = talloc (sizeof (*p));
3227 p->peer = P;
3228 p->username = P->extra;
3229
3230 username_peer_pair = tree_insert_username_peer_pair (username_peer_pair, p, rand ());
3231 }
3232
user_update_gw(struct tgl_state * TLSR,struct tgl_user * U,unsigned flags)3233 void user_update_gw (struct tgl_state *TLSR, struct tgl_user *U, unsigned flags) {
3234 assert (TLSR == TLS);
3235 #ifdef USE_LUA
3236 lua_user_update (U, flags);
3237 #endif
3238 #ifdef USE_PYTHON
3239 py_user_update (U, flags);
3240 #endif
3241
3242 peer_update_username ((void *)U, U->username);
3243
3244 if (disable_output && !notify_ev) { return; }
3245 if (!binlog_read) { return; }
3246 struct in_ev *ev = notify_ev;
3247
3248 if (!(flags & TGL_UPDATE_CREATED)) {
3249 mprint_start (ev);
3250 if (!enable_json) {
3251 mpush_color (ev, COLOR_YELLOW);
3252 mprintf (ev, "User ");
3253 print_user_name (ev, U->id, (void *)U);
3254 if (!(flags & TGL_UPDATE_DELETED)) {
3255 mprintf (ev, " updated");
3256 print_peer_updates (ev, flags);
3257 } else {
3258 mprintf (ev, " deleted");
3259 }
3260 mprintf (ev, "\n");
3261 mpop_color (ev);
3262 } else {
3263 json_peer_update (ev, (void *)U, flags);
3264 }
3265 mprint_end (ev);
3266 }
3267 }
3268
chat_update_gw(struct tgl_state * TLSR,struct tgl_chat * U,unsigned flags)3269 void chat_update_gw (struct tgl_state *TLSR, struct tgl_chat *U, unsigned flags) {
3270 assert (TLSR == TLS);
3271 #ifdef USE_LUA
3272 lua_chat_update (U, flags);
3273 #endif
3274 #ifdef USE_PYTHON
3275 py_chat_update (U, flags);
3276 #endif
3277
3278 if (disable_output && !notify_ev) { return; }
3279 if (!binlog_read) { return; }
3280 struct in_ev *ev = notify_ev;
3281
3282 if (!(flags & TGL_UPDATE_CREATED)) {
3283 mprint_start (ev);
3284 if (!enable_json) {
3285 mpush_color (ev, COLOR_YELLOW);
3286 mprintf (ev, "Chat ");
3287 print_chat_name (ev, U->id, (void *)U);
3288 if (!(flags & TGL_UPDATE_DELETED)) {
3289 mprintf (ev, " updated");
3290 print_peer_updates (ev, flags);
3291 } else {
3292 mprintf (ev, " deleted");
3293 }
3294 mprintf (ev, "\n");
3295 mpop_color (ev);
3296 } else {
3297 json_peer_update (ev, (void *)U, flags);
3298 }
3299 mprint_end (ev);
3300 }
3301 }
3302
secret_chat_update_gw(struct tgl_state * TLSR,struct tgl_secret_chat * U,unsigned flags)3303 void secret_chat_update_gw (struct tgl_state *TLSR, struct tgl_secret_chat *U, unsigned flags) {
3304 assert (TLSR == TLS);
3305 #ifdef USE_LUA
3306 lua_secret_chat_update (U, flags);
3307 #endif
3308 #ifdef USE_PYTHON
3309 py_secret_chat_update (U, flags);
3310 #endif
3311
3312 if ((flags & TGL_UPDATE_WORKING) || (flags & TGL_UPDATE_DELETED)) {
3313 write_secret_chat_file ();
3314 }
3315
3316 if (!binlog_read) { return; }
3317
3318 if ((flags & TGL_UPDATE_REQUESTED) && !disable_auto_accept) {
3319 //tgl_do_accept_encr_chat_request (TLS, U, 0, 0);
3320 tgl_do_accept_encr_chat_request (TLS, U, print_encr_chat_success_gw, 0);
3321 }
3322
3323 if (disable_output && !notify_ev) { return; }
3324 struct in_ev *ev = notify_ev;
3325
3326
3327 if (!(flags & TGL_UPDATE_CREATED)) {
3328 mprint_start (ev);
3329 if (!enable_json) {
3330 mpush_color (ev, COLOR_YELLOW);
3331 mprintf (ev, "Secret chat ");
3332 print_encr_chat_name (ev, U->id, (void *)U);
3333 if (!(flags & TGL_UPDATE_DELETED)) {
3334 mprintf (ev, " updated");
3335 print_peer_updates (ev, flags);
3336 } else {
3337 mprintf (ev, " deleted");
3338 }
3339 mprintf (ev, "\n");
3340 mpop_color (ev);
3341 } else {
3342 json_peer_update (ev, (void *)U, flags);
3343 }
3344 mprint_end (ev);
3345 }
3346 }
3347
channel_update_gw(struct tgl_state * TLSR,struct tgl_channel * U,unsigned flags)3348 void channel_update_gw (struct tgl_state *TLSR, struct tgl_channel *U, unsigned flags) {
3349 assert (TLSR == TLS);
3350
3351 peer_update_username ((void *)U, U->username);
3352
3353 if (disable_output && !notify_ev) { return; }
3354 if (!binlog_read) { return; }
3355 }
3356
print_card_gw(struct tgl_state * TLSR,void * extra,int success,int size,int * card)3357 void print_card_gw (struct tgl_state *TLSR, void *extra, int success, int size, int *card) {
3358 assert (TLSR == TLS);
3359 struct in_ev *ev = extra;
3360 if (ev && !--ev->refcnt) {
3361 free (ev);
3362 return;
3363 }
3364 if (!success) { print_fail (ev); return; }
3365 mprint_start (ev);
3366 if (!enable_json) {
3367 mprintf (ev, "Card: ");
3368 int i;
3369 for (i = 0; i < size; i++) {
3370 mprintf (ev, "%08x%c", card[i], i == size - 1 ? '\n' : ':');
3371 }
3372 } else {
3373 #ifdef USE_JSON
3374 static char q[1000];
3375 int pos = 0;
3376 int i;
3377 for (i = 0; i < size; i++) {
3378 pos += sprintf (q + pos, "%08x%s", card[i], i == size - 1 ? "" : ":");
3379 }
3380 json_t *res = json_object ();
3381 assert (json_object_set_new (res, "result", json_string (q)) >= 0);
3382 char *s = json_dumps (res, 0);
3383 mprintf (ev, "%s\n", s);
3384 json_decref (res);
3385 free (s);
3386 #endif
3387 }
3388 mprint_end (ev);
3389 }
3390
callback_extf(struct tgl_state * TLS,void * extra,int success,const char * buf)3391 void callback_extf (struct tgl_state *TLS, void *extra, int success, const char *buf) {
3392 struct in_ev *ev = extra;
3393 if (ev && !--ev->refcnt) {
3394 free (ev);
3395 return;
3396 }
3397 if (!success) { print_fail (ev); return; }
3398 mprint_start (ev);
3399 if (!enable_json) {
3400 mprintf (ev, "%s\n", buf);
3401 } else {
3402 #ifdef USE_JSON
3403 json_t *res = json_object ();
3404 assert (json_object_set_new (res, "result", json_string (buf)) >= 0);
3405 char *s = json_dumps (res, 0);
3406 mprintf (ev, "%s\n", s);
3407 json_decref (res);
3408 free (s);
3409 #endif
3410 }
3411 mprint_end (ev);
3412 }
3413
user_status_upd(struct tgl_state * TLS,struct tgl_user * U)3414 void user_status_upd (struct tgl_state *TLS, struct tgl_user *U) {
3415 if (disable_output && !notify_ev) { return; }
3416 if (!binlog_read) { return; }
3417 if (log_level < 3) { return; }
3418 struct in_ev *ev = notify_ev;
3419 mprint_start (ev);
3420 if (!enable_json)
3421 {
3422 mpush_color (ev, COLOR_YELLOW);
3423 mprintf (ev, "User ");
3424 print_user_name(ev, U->id, (void *) U);
3425 mprintf (ev, " ");
3426 print_user_status(&U->status, ev);
3427 mprintf (ev, "\n");
3428 mpop_color (ev);
3429 } else {
3430 #ifdef USE_JSON
3431 json_t *res = json_pack_user_status(U);
3432 char *s = json_dumps (res, 0);
3433 mprintf (ev, "%s\n", s);
3434 json_decref (res);
3435 free (s);
3436 #endif
3437 }
3438 mprint_end (ev);
3439 }
3440
3441 void on_login (struct tgl_state *TLS);
3442 void on_failed_login (struct tgl_state *TLS);
3443 void on_started (struct tgl_state *TLS);
3444 void do_get_values (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values,
3445 void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), void *arg);
3446
3447 struct tgl_update_callback upd_cb = {
3448 .new_msg = print_message_gw,
3449 .marked_read = mark_read_upd,
3450 .logprintf = logprintf,
3451 .get_values = do_get_values,
3452 .logged_in = on_login,
3453 .started = on_started,
3454 .type_notification = type_notification_upd,
3455 .type_in_chat_notification = type_in_chat_notification_upd,
3456 .type_in_secret_chat_notification = 0,
3457 .status_notification = 0,
3458 .user_registered = 0,
3459 .user_activated = 0,
3460 .new_authorization = 0,
3461 .user_update = user_update_gw,
3462 .chat_update = chat_update_gw,
3463 .secret_chat_update = secret_chat_update_gw,
3464 .channel_update = channel_update_gw,
3465 .msg_receive = print_message_gw,
3466 .our_id = our_id_gw,
3467 .user_status_update = user_status_upd,
3468 .on_failed_login = on_failed_login
3469 };
3470
3471
interpreter_ex(char * line,void * ex)3472 void interpreter_ex (char *line, void *ex) {
3473 force_end_mode = 1;
3474 assert (!in_readline);
3475 in_readline = 1;
3476 if (in_chat_mode) {
3477 interpreter_chat_mode (line);
3478 in_readline = 0;
3479 return;
3480 }
3481
3482 do_html = 0;
3483 line_ptr = line;
3484 offline_mode = 0;
3485 reply_id = 0;
3486 disable_msg_preview = 0;
3487 count = 1;
3488 if (!line) {
3489 do_safe_quit (NULL, 0, NULL, NULL);
3490 in_readline = 0;
3491 return;
3492 }
3493 if (!*line) {
3494 in_readline = 0;
3495 return;
3496 }
3497
3498 if (line && *line) {
3499 add_history (line);
3500 }
3501
3502 if (*line == '(') {
3503 struct in_ev *ev = ex;
3504 if (ev) { ev->refcnt ++; }
3505 tgl_do_send_extf (TLS, line, strlen (line), callback_extf, ev);
3506 in_readline = 0;
3507 return;
3508 }
3509
3510 while (1) {
3511 next_token ();
3512 if (cur_token_quoted) {
3513 in_readline = 0;
3514 fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
3515 return;
3516 }
3517
3518 if (cur_token_len <= 0) {
3519 in_readline = 0;
3520 fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
3521 return;
3522 }
3523
3524 if (*cur_token == '[') {
3525 if (cur_token_end_str) {
3526 in_readline = 0;
3527 fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
3528 return;
3529 }
3530 if (cur_token[cur_token_len - 1] != ']') {
3531 in_readline = 0;
3532 fail_interface (TLS, ex, ENOSYS, "can not parse modifier");
3533 return;
3534 }
3535 work_modifier (cur_token, cur_token_len);
3536 continue;
3537 }
3538 break;
3539 }
3540 if (cur_token_quoted || cur_token_end_str) {
3541 fail_interface (TLS, ex, ENOSYS, "can not parse command name");
3542 in_readline = 0;
3543 return;
3544 }
3545
3546
3547
3548 struct command *command = commands;
3549 int n = 0;
3550 struct tgl_command;
3551 while (command->name) {
3552 if (is_same_word (cur_token, cur_token_len, command->name)) {
3553 break;
3554 }
3555 n ++;
3556 command ++;
3557 }
3558
3559 if (!command->name) {
3560 fail_interface (TLS, ex, ENOSYS, "can not find command '%.*s'", cur_token_len, cur_token);
3561 in_readline = 0;
3562 return;
3563 }
3564
3565 enum command_argument *flags = command->args;
3566 void (*fun)(struct command *, int, struct arg[], struct in_ev *) = command->fun;
3567 int args_num = 0;
3568 static struct arg args[1000];
3569 while (1) {
3570 assert (args_num < 1000);
3571 args[args_num].flags = 0;
3572 int period = 0;
3573 if (*flags == ca_period) {
3574 flags --;
3575 }
3576 if (*flags != ca_none && *(flags + 1) == ca_period) {
3577 period = 1;
3578 }
3579 enum command_argument op = (*flags) & 255;
3580 int opt = (*flags) & ca_optional;
3581
3582 if (op == ca_none) {
3583 next_token ();
3584 if (cur_token_end_str) {
3585 int z;
3586 for (z = 0; z < count; z ++) {
3587 fun (command, args_num, args, ex);
3588 }
3589 } else {
3590 fail_interface (TLS, ex, ENOSYS, "too many args #%d", args_num);
3591 }
3592 break;
3593 }
3594
3595 if (op == ca_string_end || op == ca_file_name_end || op == ca_msg_string_end) {
3596 next_token_end ();
3597 if (cur_token_len < 0) {
3598 fail_interface (TLS, ex, ENOSYS, "can not parse string_end arg #%d", args_num);
3599 break;
3600 } else {
3601 args[args_num].flags = 1;
3602 args[args_num ++].str = strndup (cur_token, cur_token_len);
3603 int z;
3604 for (z = 0; z < count; z ++) {
3605 fun (command, args_num, args, ex);
3606 }
3607 break;
3608 }
3609 }
3610
3611 char *save = line_ptr;
3612 next_token ();
3613
3614 if (period && cur_token_end_str) {
3615 int z;
3616 for (z = 0; z < count; z ++) {
3617 fun (command, args_num, args, ex);
3618 }
3619 break;
3620 }
3621
3622 if (op == ca_user || op == ca_chat || op == ca_secret_chat || op == ca_peer || op == ca_number || op == ca_double || op == ca_msg_id || op == ca_channel) {
3623 if (cur_token_quoted) {
3624 if (opt) {
3625 if (op != ca_number && op != ca_double && op != ca_msg_id) {
3626 args[args_num ++].peer_id = TGL_PEER_NOT_FOUND;
3627 } else {
3628 if (op == ca_number) {
3629 args[args_num ++].num = NOT_FOUND;
3630 } else if (op == ca_msg_id) {
3631 args[args_num ++].msg_id.peer_type = 0;
3632 } else {
3633 args[args_num ++].dval = NOT_FOUND;
3634 }
3635 }
3636 line_ptr = save;
3637 flags ++;
3638 continue;
3639 } else if (period) {
3640 line_ptr = save;
3641 flags += 2;
3642 continue;
3643 } else {
3644 break;
3645 }
3646 } else {
3647 if (cur_token_end_str) {
3648 if (opt) {
3649 if (op != ca_number && op != ca_double && op != ca_msg_id) {
3650 args[args_num ++].peer_id = TGL_PEER_NOT_FOUND;
3651 } else {
3652 if (op == ca_number) {
3653 args[args_num ++].num = NOT_FOUND;
3654 } else if (op == ca_msg_id) {
3655 args[args_num ++].msg_id.peer_type = 0;
3656 } else {
3657 args[args_num ++].dval = NOT_FOUND;
3658 }
3659 }
3660 line_ptr = save;
3661 flags ++;
3662 continue;
3663 } else if (period) {
3664 line_ptr = save;
3665 flags += 2;
3666 continue;
3667 } else {
3668 break;
3669 }
3670 }
3671 int ok = 1;
3672 switch (op) {
3673 case ca_user:
3674 args[args_num ++].peer_id = cur_token_user ();
3675 ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND;
3676 break;
3677 case ca_chat:
3678 args[args_num ++].peer_id = cur_token_chat ();
3679 ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND;
3680 break;
3681 case ca_secret_chat:
3682 args[args_num ++].peer_id = cur_token_encr_chat ();
3683 ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND;
3684 break;
3685 case ca_channel:
3686 args[args_num ++].peer_id = cur_token_channel ();
3687 ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND;
3688 break;
3689 case ca_peer:
3690 args[args_num ++].peer_id = cur_token_peer ();
3691 ok = tgl_get_peer_id (args[args_num - 1].peer_id) != NOT_FOUND;
3692 break;
3693 case ca_number:
3694 args[args_num ++].num = cur_token_int ();
3695 ok = (args[args_num - 1].num != NOT_FOUND);
3696 break;
3697 case ca_msg_id:
3698 args[args_num ++].msg_id = cur_token_msg_id ();
3699 ok = (args[args_num - 1].msg_id.peer_type != 0);
3700 break;
3701 case ca_double:
3702 args[args_num ++].dval = cur_token_double ();
3703 ok = (args[args_num - 1].dval != NOT_FOUND);
3704 break;
3705 default:
3706 assert (0);
3707 }
3708
3709 if (period && !ok) {
3710 line_ptr = save;
3711 flags += 2;
3712 args_num --;
3713 continue;
3714 }
3715 if (opt && !ok) {
3716 line_ptr = save;
3717 flags ++;
3718 continue;
3719 }
3720 if (!ok) {
3721 fail_interface (TLS, ex, ENOSYS, "can not parse arg #%d", args_num);
3722 break;
3723 }
3724
3725 flags ++;
3726 continue;
3727 }
3728 }
3729 if (op == ca_string || op == ca_file_name || op == ca_command) {
3730 if (cur_token_end_str || cur_token_len < 0) {
3731 if (opt) {
3732 args[args_num ++].str = NULL;
3733 flags ++;
3734 continue;
3735 }
3736 fail_interface (TLS, ex, ENOSYS, "can not parse string arg #%d", args_num);
3737 break;
3738 } else {
3739 args[args_num].flags = 1;
3740 args[args_num ++].str = strndup (cur_token, cur_token_len);
3741 flags ++;
3742 continue;
3743 }
3744 }
3745 //assert (0);
3746 }
3747 int i;
3748 for (i = 0; i < args_num; i++) {
3749 if (args[i].flags & 1) {
3750 free (args[i].str);
3751 }
3752 }
3753
3754 update_prompt ();
3755 in_readline = 0;
3756 }
3757
interpreter(char * line)3758 void interpreter (char *line) {
3759 interpreter_ex (line, 0);
3760 }
3761
3762 int readline_active;
3763 /*void rprintf (const char *format, ...) {
3764 mprint_start (ev);
3765 va_list ap;
3766 va_start (ap, format);
3767 vfprintf (stdout, format, ap);
3768 va_end (ap);
3769 print_end();
3770 }*/
3771
3772 int saved_point;
3773 char *saved_line;
3774 static int prompt_was;
3775
3776
deactivate_readline(void)3777 void deactivate_readline (void) {
3778 if (read_one_string) {
3779 printf ("\033[2K\r");
3780 fflush (stdout);
3781 } else {
3782 saved_point = rl_point;
3783 saved_line = malloc (rl_end + 1);
3784 assert (saved_line);
3785 saved_line[rl_end] = 0;
3786 memcpy (saved_line, rl_line_buffer, rl_end);
3787
3788 rl_save_prompt();
3789 rl_replace_line("", 0);
3790 rl_redisplay();
3791 }
3792 }
3793
3794
reactivate_readline(void)3795 void reactivate_readline (void) {
3796 if (read_one_string) {
3797 printf ("%s ", one_string_prompt);
3798 if (!(one_string_flags & 1)) {
3799 printf ("%.*s", one_string_len, one_string);
3800 }
3801 fflush (stdout);
3802 } else {
3803 set_prompt (get_default_prompt ());
3804 rl_replace_line(saved_line, 0);
3805 rl_point = saved_point;
3806 rl_redisplay();
3807 free (saved_line);
3808 }
3809 }
3810
print_start(void)3811 void print_start (void) {
3812 if (in_readline) { return; }
3813 if (readline_disabled) { return; }
3814 assert (!prompt_was);
3815 if (readline_active) {
3816 deactivate_readline ();
3817 }
3818 prompt_was = 1;
3819 }
3820
print_end(void)3821 void print_end (void) {
3822 if (in_readline) { return; }
3823 if (readline_disabled) {
3824 fflush (stdout);
3825 return;
3826 }
3827 assert (prompt_was);
3828 if (readline_active) {
3829 reactivate_readline ();
3830 }
3831 prompt_was = 0;
3832 }
3833
3834 /*void hexdump (int *in_ptr, int *in_end) {
3835 mprint_start (ev);
3836 int *ptr = in_ptr;
3837 while (ptr < in_end) { mprintf (ev, " %08x", *(ptr ++)); }
3838 mprintf (ev, "\n");
3839 mprint_end (ev);
3840 }*/
3841
logprintf(const char * format,...)3842 void logprintf (const char *format, ...) {
3843 int x = 0;
3844 if (!prompt_was) {
3845 x = 1;
3846 print_start ();
3847 }
3848 if (!disable_colors) {
3849 printf (COLOR_GREY);
3850 }
3851 printf (" *** ");
3852
3853
3854 double T = tglt_get_double_time ();
3855 printf ("%.6lf ", T);
3856
3857 va_list ap;
3858 va_start (ap, format);
3859 vfprintf (stdout, format, ap);
3860 va_end (ap);
3861 if (!disable_colors) {
3862 printf (COLOR_NORMAL);
3863 }
3864 if (x) {
3865 print_end ();
3866 }
3867 }
3868
3869 int color_stack_pos;
3870 const char *color_stack[10];
3871
push_color(const char * color)3872 void push_color (const char *color) {
3873 if (disable_colors) { return; }
3874 assert (color_stack_pos < 10);
3875 color_stack[color_stack_pos ++] = color;
3876 printf ("%s", color);
3877 }
3878
pop_color(void)3879 void pop_color (void) {
3880 if (disable_colors) { return; }
3881 assert (color_stack_pos > 0);
3882 color_stack_pos --;
3883 if (color_stack_pos >= 1) {
3884 printf ("%s", color_stack[color_stack_pos - 1]);
3885 } else {
3886 printf ("%s", COLOR_NORMAL);
3887 }
3888 }
3889
print_media(struct in_ev * ev,struct tgl_message_media * M)3890 void print_media (struct in_ev *ev, struct tgl_message_media *M) {
3891 assert (M);
3892 switch (M->type) {
3893 case tgl_message_media_none:
3894 return;
3895 case tgl_message_media_photo:
3896 if (!M->photo) {
3897 mprintf (ev, "[photo bad]");
3898 } else if (M->photo->caption && strlen (M->photo->caption)) {
3899 mprintf (ev, "[photo %s]", M->photo->caption);
3900 } else {
3901 mprintf (ev, "[photo]");
3902 }
3903 if (M->caption) {
3904 mprintf (ev, " %s", M->caption);
3905 }
3906 return;
3907 case tgl_message_media_document:
3908 case tgl_message_media_audio:
3909 case tgl_message_media_video:
3910 mprintf (ev, "[");
3911 assert (M->document);
3912 if (M->document->flags & TGLDF_IMAGE) {
3913 mprintf (ev, "image");
3914 } else if (M->document->flags & TGLDF_AUDIO) {
3915 mprintf (ev, "audio");
3916 } else if (M->document->flags & TGLDF_VIDEO) {
3917 mprintf (ev, "video");
3918 } else if (M->document->flags & TGLDF_STICKER) {
3919 mprintf (ev, "sticker");
3920 } else {
3921 mprintf (ev, "document");
3922 }
3923
3924 if (M->document->caption && strlen (M->document->caption)) {
3925 mprintf (ev, " %s:", M->document->caption);
3926 } else {
3927 mprintf (ev, ":");
3928 }
3929
3930 if (M->document->mime_type) {
3931 mprintf (ev, " type=%s", M->document->mime_type);
3932 }
3933
3934 if (M->document->w && M->document->h) {
3935 mprintf (ev, " size=%dx%d", M->document->w, M->document->h);
3936 }
3937
3938 if (M->document->duration) {
3939 mprintf (ev, " duration=%d", M->document->duration);
3940 }
3941
3942 mprintf (ev, " size=");
3943 if (M->document->size < (1 << 10)) {
3944 mprintf (ev, "%dB", M->document->size);
3945 } else if (M->document->size < (1 << 20)) {
3946 mprintf (ev, "%dKiB", M->document->size >> 10);
3947 } else if (M->document->size < (1 << 30)) {
3948 mprintf (ev, "%dMiB", M->document->size >> 20);
3949 } else {
3950 mprintf (ev, "%dGiB", M->document->size >> 30);
3951 }
3952
3953 mprintf (ev, "]");
3954
3955 if (M->caption) {
3956 mprintf (ev, " %s", M->caption);
3957 }
3958
3959 return;
3960 case tgl_message_media_document_encr:
3961 mprintf (ev, "[");
3962 if (M->encr_document->flags & TGLDF_IMAGE) {
3963 mprintf (ev, "image");
3964 } else if (M->encr_document->flags & TGLDF_AUDIO) {
3965 mprintf (ev, "audio");
3966 } else if (M->encr_document->flags & TGLDF_VIDEO) {
3967 mprintf (ev, "video");
3968 } else if (M->encr_document->flags & TGLDF_STICKER) {
3969 mprintf (ev, "sticker");
3970 } else {
3971 mprintf (ev, "document");
3972 }
3973
3974 if (M->encr_document->caption && strlen (M->encr_document->caption)) {
3975 mprintf (ev, " %s:", M->encr_document->caption);
3976 } else {
3977 mprintf (ev, ":");
3978 }
3979
3980 if (M->encr_document->mime_type) {
3981 mprintf (ev, " type=%s", M->encr_document->mime_type);
3982 }
3983
3984 if (M->encr_document->w && M->encr_document->h) {
3985 mprintf (ev, " size=%dx%d", M->encr_document->w, M->encr_document->h);
3986 }
3987
3988 if (M->encr_document->duration) {
3989 mprintf (ev, " duration=%d", M->encr_document->duration);
3990 }
3991
3992 mprintf (ev, " size=");
3993 if (M->encr_document->size < (1 << 10)) {
3994 mprintf (ev, "%dB", M->encr_document->size);
3995 } else if (M->encr_document->size < (1 << 20)) {
3996 mprintf (ev, "%dKiB", M->encr_document->size >> 10);
3997 } else if (M->encr_document->size < (1 << 30)) {
3998 mprintf (ev, "%dMiB", M->encr_document->size >> 20);
3999 } else {
4000 mprintf (ev, "%dGiB", M->encr_document->size >> 30);
4001 }
4002
4003 mprintf (ev, "]");
4004
4005 return;
4006 case tgl_message_media_geo:
4007 mprintf (ev, "[geo https://maps.google.com/?q=%.6lf,%.6lf]", M->geo.latitude, M->geo.longitude);
4008 return;
4009 case tgl_message_media_contact:
4010 mprintf (ev, "[contact] ");
4011 mpush_color (ev, COLOR_RED);
4012 mprintf (ev, "%s %s ", M->first_name, M->last_name);
4013 mpop_color (ev);
4014 mprintf (ev, "%s", M->phone);
4015 return;
4016 case tgl_message_media_unsupported:
4017 mprintf (ev, "[unsupported]");
4018 return;
4019 case tgl_message_media_webpage:
4020 mprintf (ev, "[webpage:");
4021 assert (M->webpage);
4022 if (M->webpage->url) {
4023 mprintf (ev, " url:'%s'", M->webpage->url);
4024 }
4025 if (M->webpage->title) {
4026 mprintf (ev, " title:'%s'", M->webpage->title);
4027 }
4028 if (M->webpage->description) {
4029 mprintf (ev, " description:'%s'", M->webpage->description);
4030 }
4031 if (M->webpage->author) {
4032 mprintf (ev, " author:'%s'", M->webpage->author);
4033 }
4034 mprintf (ev, "]");
4035 break;
4036 case tgl_message_media_venue:
4037 mprintf (ev, "[geo https://maps.google.com/?q=%.6lf,%.6lf", M->venue.geo.latitude, M->venue.geo.longitude);
4038
4039 if (M->venue.title) {
4040 mprintf (ev, " title:'%s'", M->venue.title);
4041 }
4042
4043 if (M->venue.address) {
4044 mprintf (ev, " address:'%s'", M->venue.address);
4045 }
4046 if (M->venue.provider) {
4047 mprintf (ev, " provider:'%s'", M->venue.provider);
4048 }
4049 if (M->venue.venue_id) {
4050 mprintf (ev, " id:'%s'", M->venue.venue_id);
4051 }
4052
4053 mprintf (ev, "]");
4054 return;
4055
4056 default:
4057 mprintf (ev, "x = %d\n", M->type);
4058 M->type = tgl_message_media_unsupported;
4059 break;
4060 }
4061 }
4062
4063 int unknown_user_list_pos;
4064 int unknown_user_list[1000];
4065
print_peer_permanent_name(struct in_ev * ev,tgl_peer_id_t id)4066 void print_peer_permanent_name (struct in_ev *ev, tgl_peer_id_t id) {
4067 mprintf (ev, "%s", print_permanent_peer_id (id));
4068 }
4069
print_user_name(struct in_ev * ev,tgl_peer_id_t id,tgl_peer_t * U)4070 void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U) {
4071 if(tgl_get_peer_type (id) == TGL_PEER_CHAT)
4072 {
4073 return;
4074 }
4075 assert (tgl_get_peer_type (id) == TGL_PEER_USER);
4076 mpush_color (ev, COLOR_RED);
4077 if (permanent_peer_id_mode) {
4078 print_peer_permanent_name (ev, id);
4079 mpop_color (ev);
4080 return;
4081 }
4082 if (!U) {
4083 mprintf (ev, "user#%d", tgl_get_peer_id (id));
4084 int i;
4085 int ok = 1;
4086 for (i = 0; i < unknown_user_list_pos; i++) {
4087 if (unknown_user_list[i] == tgl_get_peer_id (id)) {
4088 ok = 0;
4089 break;
4090 }
4091 }
4092 if (ok) {
4093 assert (unknown_user_list_pos < 1000);
4094 unknown_user_list[unknown_user_list_pos ++] = tgl_get_peer_id (id);
4095 }
4096 } else {
4097 if (U->flags & (TGLUF_SELF | TGLUF_CONTACT)) {
4098 mpush_color (ev, COLOR_REDB);
4099 }
4100 if ((U->flags & TGLUF_DELETED)) {
4101 mprintf (ev, "deleted user#%d", tgl_get_peer_id (id));
4102 } else if (!(U->flags & TGLUF_CREATED)) {
4103 mprintf (ev, "user#%d", tgl_get_peer_id (id));
4104 } else if (use_ids) {
4105 mprintf (ev, "user#%d", tgl_get_peer_id (id));
4106 } else if (!U->user.first_name || !strlen (U->user.first_name)) {
4107 mprintf (ev, "%s", U->user.last_name);
4108 } else if (!U->user.last_name || !strlen (U->user.last_name)) {
4109 mprintf (ev, "%s", U->user.first_name);
4110 } else {
4111 mprintf (ev, "%s %s", U->user.first_name, U->user.last_name);
4112 }
4113 if (U->flags & (TGLUF_SELF | TGLUF_CONTACT)) {
4114 mpop_color (ev);
4115 }
4116 }
4117 mpop_color (ev);
4118 }
4119
print_chat_name(struct in_ev * ev,tgl_peer_id_t id,tgl_peer_t * C)4120 void print_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) {
4121 assert (tgl_get_peer_type (id) == TGL_PEER_CHAT);
4122 mpush_color (ev, COLOR_MAGENTA);
4123 if (permanent_peer_id_mode) {
4124 print_peer_permanent_name (ev, id);
4125 mpop_color (ev);
4126 return;
4127 }
4128 if (!C || use_ids) {
4129 mprintf (ev, "chat#%d", tgl_get_peer_id (id));
4130 } else {
4131 mprintf (ev, "%s", C->chat.title);
4132 }
4133 mpop_color (ev);
4134 }
4135
print_channel_name(struct in_ev * ev,tgl_peer_id_t id,tgl_peer_t * C)4136 void print_channel_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) {
4137 assert (tgl_get_peer_type (id) == TGL_PEER_CHANNEL);
4138 mpush_color (ev, COLOR_CYAN);
4139 if (permanent_peer_id_mode) {
4140 print_peer_permanent_name (ev, id);
4141 mpop_color (ev);
4142 return;
4143 }
4144 if (!C || use_ids) {
4145 mprintf (ev, "channel#%d", tgl_get_peer_id (id));
4146 } else {
4147 mprintf (ev, "%s", C->channel.title);
4148 }
4149 mpop_color (ev);
4150 }
4151
print_encr_chat_name(struct in_ev * ev,tgl_peer_id_t id,tgl_peer_t * C)4152 void print_encr_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) {
4153 assert (tgl_get_peer_type (id) == TGL_PEER_ENCR_CHAT);
4154 mpush_color (ev, COLOR_MAGENTA);
4155 if (permanent_peer_id_mode) {
4156 print_peer_permanent_name (ev, id);
4157 mpop_color (ev);
4158 return;
4159 }
4160 if (!C || use_ids) {
4161 mprintf (ev, "encr_chat#%d", tgl_get_peer_id (id));
4162 } else {
4163 mprintf (ev, "%s", C->print_name);
4164 }
4165 mpop_color (ev);
4166 }
4167
print_peer_name(struct in_ev * ev,tgl_peer_id_t id,tgl_peer_t * C)4168 void print_peer_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C) {
4169 switch (tgl_get_peer_type (id)) {
4170 case TGL_PEER_USER:
4171 print_user_name (ev, id, C);
4172 return;
4173 case TGL_PEER_CHAT:
4174 print_chat_name (ev, id, C);
4175 return;
4176 case TGL_PEER_CHANNEL:
4177 print_channel_name (ev, id, C);
4178 return;
4179 case TGL_PEER_ENCR_CHAT:
4180 print_encr_chat_name (ev, id, C);
4181 return;
4182 default:
4183 assert (0);
4184 }
4185 }
4186
4187 static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
print_date(struct in_ev * ev,long t)4188 void print_date (struct in_ev *ev, long t) {
4189 struct tm *tm = localtime ((void *)&t);
4190 if (time (0) - t < 12 * 60 * 60) {
4191 mprintf (ev, "[%02d:%02d] ", tm->tm_hour, tm->tm_min);
4192 } else if (time (0) - t < 24 * 60 * 60 * 180) {
4193 mprintf (ev, "[%02d %s]", tm->tm_mday, monthes[tm->tm_mon]);
4194 } else {
4195 mprintf (ev, "[%02d %s %d]", tm->tm_mday, monthes[tm->tm_mon], tm->tm_year + 1900);
4196 }
4197 }
4198
print_date_full(struct in_ev * ev,long t)4199 void print_date_full (struct in_ev *ev, long t) {
4200 struct tm *tm = localtime ((void *)&t);
4201 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);
4202 }
4203
print_msg_id(struct in_ev * ev,tgl_message_id_t msg_id,struct tgl_message * M)4204 void print_msg_id (struct in_ev *ev, tgl_message_id_t msg_id, struct tgl_message *M) {
4205 if (msg_num_mode) {
4206 if (!permanent_msg_id_mode) {
4207 if (M) {
4208 mprintf (ev, "%d", M->temp_id);
4209 } else {
4210 mprintf (ev, "???");
4211 }
4212 } else {
4213 mprintf (ev, "%s", print_permanent_msg_id (msg_id));
4214 }
4215 }
4216 }
4217
print_service_message(struct in_ev * ev,struct tgl_message * M)4218 void print_service_message (struct in_ev *ev, struct tgl_message *M) {
4219 assert (M);
4220 //print_start ();
4221 mpush_color (ev, COLOR_GREY);
4222
4223 if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL) {
4224 mpush_color (ev, COLOR_CYAN);
4225 } else {
4226 mpush_color (ev, COLOR_MAGENTA);
4227 }
4228 print_msg_id (ev, M->permanent_id, M);
4229 mprintf (ev, " ");
4230 print_date (ev, M->date);
4231 mpop_color (ev);
4232 mprintf (ev, " ");
4233 if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) {
4234 print_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
4235 } else if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL) {
4236 print_channel_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
4237 } else {
4238 assert (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT);
4239 print_encr_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
4240 }
4241
4242 if (tgl_get_peer_type (M->from_id) == TGL_PEER_USER) {
4243 mprintf (ev, " ");
4244 print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id));
4245 }
4246
4247 switch (M->action.type) {
4248 case tgl_message_action_none:
4249 mprintf (ev, "\n");
4250 break;
4251 case tgl_message_action_geo_chat_create:
4252 mprintf (ev, "Created geo chat\n");
4253 break;
4254 case tgl_message_action_geo_chat_checkin:
4255 mprintf (ev, "Checkin in geochat\n");
4256 break;
4257 case tgl_message_action_chat_create:
4258 mprintf (ev, " created chat %s. %d users\n", M->action.title, M->action.user_num);
4259 break;
4260 case tgl_message_action_chat_edit_title:
4261 mprintf (ev, " changed title to %s\n",
4262 M->action.new_title);
4263 break;
4264 case tgl_message_action_chat_edit_photo:
4265 mprintf (ev, " changed photo\n");
4266 break;
4267 case tgl_message_action_chat_delete_photo:
4268 mprintf (ev, " deleted photo\n");
4269 break;
4270 case tgl_message_action_chat_add_users:
4271 mprintf (ev, " added users:");
4272 {
4273 int i;
4274 for (i = 0; i < M->action.user_num; i++) {
4275 print_user_name (ev, tgl_set_peer_id (TGL_PEER_USER, M->action.users[i]), tgl_peer_get (TLS, tgl_set_peer_id (TGL_PEER_USER, M->action.users[i])));
4276 }
4277 }
4278 mprintf (ev, "\n");
4279 break;
4280 case tgl_message_action_chat_add_user_by_link:
4281 mprintf (ev, " added by link from ");
4282 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)));
4283 mprintf (ev, "\n");
4284 break;
4285 case tgl_message_action_chat_delete_user:
4286 mprintf (ev, " deleted user ");
4287 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)));
4288 mprintf (ev, "\n");
4289 break;
4290 case tgl_message_action_set_message_ttl:
4291 mprintf (ev, " set ttl to %d seconds. Unsupported yet\n", M->action.ttl);
4292 break;
4293 case tgl_message_action_read_messages:
4294 mprintf (ev, " %d messages marked read\n", M->action.read_cnt);
4295 break;
4296 case tgl_message_action_delete_messages:
4297 mprintf (ev, " %d messages deleted\n", M->action.delete_cnt);
4298 break;
4299 case tgl_message_action_screenshot_messages:
4300 mprintf (ev, " %d messages screenshoted\n", M->action.screenshot_cnt);
4301 break;
4302 case tgl_message_action_flush_history:
4303 mprintf (ev, " cleared history\n");
4304 break;
4305 case tgl_message_action_resend:
4306 mprintf (ev, " resend query\n");
4307 break;
4308 case tgl_message_action_notify_layer:
4309 mprintf (ev, " updated layer to %d\n", M->action.layer);
4310 break;
4311 case tgl_message_action_typing:
4312 mprintf (ev, " is ");
4313 print_typing (ev, M->action.typing);
4314 break;
4315 case tgl_message_action_noop:
4316 mprintf (ev, " noop\n");
4317 break;
4318 case tgl_message_action_request_key:
4319 mprintf (ev, " request rekey #%016llx\n", M->action.exchange_id);
4320 break;
4321 case tgl_message_action_accept_key:
4322 mprintf (ev, " accept rekey #%016llx\n", M->action.exchange_id);
4323 break;
4324 case tgl_message_action_commit_key:
4325 mprintf (ev, " commit rekey #%016llx\n", M->action.exchange_id);
4326 break;
4327 case tgl_message_action_abort_key:
4328 mprintf (ev, " abort rekey #%016llx\n", M->action.exchange_id);
4329 break;
4330 case tgl_message_action_channel_create:
4331 mprintf (ev, " created channel %s\n", M->action.title);
4332 break;
4333 case tgl_message_action_migrated_to:
4334 mprintf (ev, " migrated to channel\n");
4335 break;
4336 case tgl_message_action_migrated_from:
4337 mprintf (ev, " migrated from group '%s'\n", M->action.title);
4338 break;
4339 }
4340 mpop_color (ev);
4341 //print_end ();
4342 }
4343
4344 tgl_peer_id_t last_from_id;
4345 tgl_peer_id_t last_to_id;
4346
print_message(struct in_ev * ev,struct tgl_message * M)4347 void print_message (struct in_ev *ev, struct tgl_message *M) {
4348 assert (M);
4349 if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) {
4350 return;
4351 }
4352 if (!(M->flags & TGLMF_CREATED)) { return; }
4353 if (M->flags & TGLMF_SERVICE) {
4354 print_service_message (ev, M);
4355 return;
4356 }
4357 if (!tgl_get_peer_type (M->to_id)) {
4358 logprintf ("Bad msg\n");
4359 return;
4360 }
4361
4362 last_from_id = M->from_id;
4363 last_to_id = M->to_id;
4364
4365 //print_start ();
4366
4367 // Sending to a USER
4368 if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) {
4369 if (M->flags & TGLMF_OUT) {
4370 mpush_color (ev, COLOR_GREEN);
4371 print_msg_id (ev, M->permanent_id, M);
4372 mprintf (ev, " ");
4373 print_date (ev, M->date);
4374 mpop_color (ev);
4375 mprintf (ev, " ");
4376 print_user_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
4377 mpush_color (ev, COLOR_GREEN);
4378 if (M->flags & TGLMF_UNREAD) {
4379 mprintf (ev, " <<< ");
4380 } else {
4381 mprintf (ev, " ««« ");
4382 }
4383 } else {
4384 mpush_color (ev, COLOR_BLUE);
4385 print_msg_id (ev, M->permanent_id, M);
4386 mprintf (ev, " ");
4387 print_date (ev, M->date);
4388 mpop_color (ev);
4389 mprintf (ev, " ");
4390 print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id));
4391 mpush_color (ev, COLOR_BLUE);
4392 if (M->flags & TGLMF_UNREAD) {
4393 mprintf (ev, " >>> ");
4394 } else {
4395 mprintf (ev, " »»» ");
4396 }
4397 }
4398 } else if (tgl_get_peer_type (M->to_id) == TGL_PEER_ENCR_CHAT) {
4399 tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
4400 assert (P);
4401 if (M->flags & TGLMF_UNREAD) {
4402 mpush_color (ev, COLOR_GREEN);
4403 print_msg_id (ev, M->permanent_id, M);
4404 mprintf (ev, " ");
4405 print_date (ev, M->date);
4406 mprintf (ev, " ");
4407 mpush_color (ev, COLOR_CYAN);
4408 mprintf (ev, " %s", P->print_name);
4409 mpop_color (ev);
4410 if (M->flags & TGLMF_UNREAD) {
4411 mprintf (ev, " <<< ");
4412 } else {
4413 mprintf (ev, " ««« ");
4414 }
4415 } else {
4416 mpush_color (ev, COLOR_BLUE);
4417 print_msg_id (ev, M->permanent_id, M);
4418 mprintf (ev, " ");
4419 print_date (ev, M->date);
4420 mpush_color (ev, COLOR_CYAN);
4421 mprintf (ev, " %s", P->print_name);
4422 mpop_color (ev);
4423 if (M->flags & TGLMF_UNREAD) {
4424 mprintf (ev, " >>> ");
4425 } else {
4426 mprintf (ev, " »»» ");
4427 }
4428 }
4429 }
4430 // Sending to a CHAT
4431 else if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) {
4432
4433 mpush_color (ev, COLOR_MAGENTA);
4434
4435 print_msg_id (ev, M->permanent_id, M);
4436
4437 mprintf (ev, " ");
4438 print_date (ev, M->date);
4439 mpop_color (ev);
4440 mprintf (ev, " ");
4441 mprintf (ev, "[GROUP:");
4442 print_chat_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
4443 mprintf (ev, "]");
4444 mprintf (ev, " ");
4445 print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id));
4446 if (!tgl_cmp_peer_id (M->from_id, TLS->our_id)) {
4447 mpush_color (ev, COLOR_GREEN);
4448 } else {
4449 mpush_color (ev, COLOR_BLUE);
4450 }
4451 if (M->flags & TGLMF_UNREAD) {
4452 mprintf (ev, " >>> ");
4453 } else {
4454 mprintf (ev, " »»» ");
4455 }
4456
4457 } else {
4458 assert (tgl_get_peer_type (M->to_id) == TGL_PEER_CHANNEL);
4459
4460 mpush_color (ev, COLOR_CYAN);
4461 print_msg_id (ev, M->permanent_id, M);
4462 mprintf (ev, " ");
4463 print_date (ev, M->date);
4464 mpop_color (ev);
4465 mprintf (ev, " ");
4466 print_channel_name (ev, M->to_id, tgl_peer_get (TLS, M->to_id));
4467
4468 if (tgl_get_peer_type (M->from_id) == TGL_PEER_USER) {
4469 mprintf (ev, " ");
4470 print_user_name (ev, M->from_id, tgl_peer_get (TLS, M->from_id));
4471 if (!tgl_cmp_peer_id (M->from_id, TLS->our_id)) {
4472 mpush_color (ev, COLOR_GREEN);
4473 } else {
4474 mpush_color (ev, COLOR_BLUE);
4475 }
4476 } else {
4477 mpush_color (ev, COLOR_BLUE);
4478 }
4479 if (M->flags & TGLMF_UNREAD) {
4480 mprintf (ev, " >>> ");
4481 } else {
4482 mprintf (ev, " »»» ");
4483 }
4484 }
4485 if (tgl_get_peer_type (M->fwd_from_id) > 0) {
4486 mprintf (ev, "[fwd from ");
4487 print_peer_name (ev, M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id));
4488 mprintf (ev, " ");
4489 print_date (ev, M->date);
4490 mprintf (ev, "] ");
4491 }
4492 if (M->reply_id) {
4493 mprintf (ev, "[reply to ");
4494 tgl_message_id_t msg_id = M->permanent_id;
4495 msg_id.id = M->reply_id;
4496 struct tgl_message *N = tgl_message_get (TLS, &msg_id);
4497 print_msg_id (ev, msg_id, N);
4498 mprintf (ev, "] ");
4499 }
4500 if (M->flags & TGLMF_MENTION) {
4501 mprintf (ev, "[mention] ");
4502 }
4503 if (M->message && strlen (M->message)) {
4504 mprintf (ev, "%s", M->message);
4505 }
4506 if (M->media.type != tgl_message_media_none) {
4507 if (M->message && strlen (M->message)) {
4508 mprintf (ev, " ");
4509 }
4510 print_media (ev, &M->media);
4511 }
4512 mpop_color (ev);
4513 assert (!color_stack_pos);
4514 mprintf (ev, "\n");
4515 //print_end();
4516 }
4517
play_sound(void)4518 void play_sound (void) {
4519 printf ("\a");
4520 }
4521
set_interface_callbacks(void)4522 void set_interface_callbacks (void) {
4523 if (readline_disabled) { return; }
4524 readline_active = 1;
4525 rl_filename_quote_characters = strdup (" ");
4526 rl_basic_word_break_characters = strdup (" ");
4527
4528
4529 rl_callback_handler_install (get_default_prompt (), interpreter);
4530 rl_completion_entry_function = command_generator;
4531 }
4532