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