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     Copyright Vincent Castellano 2015
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #ifdef USE_PYTHON
26 #include "python-tg.h"
27 
28 #include <string.h>
29 #include <stdlib.h>
30 #include <libgen.h>
31 
32 #include <Python.h>
33 #include "bytesobject.h"
34 
35 // Python 2/3 compat macros
36 #if PY_MAJOR_VERSION >= 3
37   #define MOD_ERROR_VAL NULL
38   #define MOD_SUCCESS_VAL(val) val
39   #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
40   #define MOD_DEF(ob, name, doc, methods) \
41           static struct PyModuleDef moduledef = { \
42           PyModuleDef_HEAD_INIT, name, doc, -1, methods, NULL, NULL, NULL, NULL,}; \
43           ob = PyModule_Create(&moduledef);
44   #define PyInt_FromLong PyLong_FromLong
45 #else
46   #define MOD_ERROR_VAL
47   #define MOD_SUCCESS_VAL(val)
48   #define MOD_INIT(name) void init##name(void)
49   #define MOD_DEF(ob, name, doc, methods) \
50           ob = Py_InitModule3(name, methods, doc);
51 #endif
52 
53 #define TGL_PYTHON_CALLBACK(name, func) \
54       PyObject *set##func(PyObject *dummy, PyObject *args) { \
55       PyObject *result = NULL; \
56       PyObject *temp; \
57       if (PyArg_ParseTuple(args, "O:set_##name", &temp)) { \
58         if (!PyCallable_Check(temp)) { \
59           PyErr_SetString(PyExc_TypeError, "parameter must be callable");\
60           return NULL;\
61         }\
62         Py_XINCREF(temp);\
63         Py_XDECREF(func);\
64         func = temp;\
65         Py_INCREF(Py_None);\
66         result = Py_None;\
67         }\
68         return result;\
69       }
70 
71 
72 // Python Imports
73 #include "datetime.h"
74 
75 // Custom Types
76 #include "python-types.h"
77 
78 
79 extern PyTypeObject tgl_PeerType;
80 extern PyTypeObject tgl_MsgType;
81 
82 //#include "interface.h"
83 //#include "auto/constants.h"
84 #include <tgl/tgl.h>
85 #include <tgl/tgl-queries.h>
86 #include "interface.h"
87 
88 #include <assert.h>
89 extern int verbosity;
90 extern struct tgl_state *TLS;
91 
92 
93 static int python_loaded;
94 
95 // TGL Python Exceptions
96 PyObject *TglError;
97 PyObject *PeerError;
98 PyObject *MsgError;
99 
100 
101 // Python update function callables
102 PyObject *_py_binlog_end;
103 PyObject *_py_diff_end;
104 PyObject *_py_our_id;
105 PyObject *_py_new_msg;
106 PyObject *_py_list_msg;
107 PyObject *_py_secret_chat_update;
108 PyObject *_py_user_update;
109 PyObject *_py_chat_update;
110 PyObject *_py_on_loop;
111 
112 PyObject* get_peer (tgl_peer_id_t id, tgl_peer_t *P);
113 
py_add_string_field(PyObject * dict,char * name,const char * value)114 void py_add_string_field (PyObject* dict, char *name, const char *value) {
115   assert (PyDict_Check(dict));
116   assert (name && strlen (name));
117   if (!value || !strlen (value)) { return; }
118   PyObject *str = PyUnicode_FromString(value);
119 
120   if(PyUnicode_Check(str))
121     PyDict_SetItemString (dict, name, str);
122 }
123 
py_add_string_field_arr(PyObject * list,int num,const char * value)124 void py_add_string_field_arr (PyObject* list, int num, const char *value) {
125   assert(PyList_Check(list));
126   if (!value || !strlen (value)) { return; }
127   if(num >= 0)
128     PyList_SetItem (list, num, PyUnicode_FromString (value));
129   else // Append
130     PyList_Append  (list, PyUnicode_FromString (value));
131 }
132 
py_add_num_field(PyObject * dict,const char * name,double value)133 void py_add_num_field (PyObject* dict, const char *name, double value) {
134   assert (PyDict_Check(dict));
135   assert (name && strlen (name));
136   PyDict_SetItemString (dict, name, PyFloat_FromDouble(value));
137 }
138 
get_tgl_peer_type(int x)139 PyObject* get_tgl_peer_type (int x) {
140   PyObject *type;
141 
142   switch (x) {
143   case TGL_PEER_USER:
144     type = PyUnicode_FromString("user");
145     break;
146   case TGL_PEER_CHAT:
147     type = PyUnicode_FromString("chat");
148     break;
149   case TGL_PEER_ENCR_CHAT:
150     type = PyUnicode_FromString("encr_chat");
151     break;
152   default:
153     assert (0);
154   }
155 
156   return type;
157 }
158 
get_update_types(unsigned flags)159 PyObject* get_update_types (unsigned flags) {
160   PyObject* types;
161   types = PyList_New(0);
162   if(types == NULL)
163     assert(0); // TODO handle python exception
164 
165   if (flags & TGL_UPDATE_CREATED) {
166     py_add_string_field_arr(types, -1, "created");
167   }
168   if (flags & TGL_UPDATE_DELETED) {
169     py_add_string_field_arr(types, -1, "deleted");
170   }
171   if (flags & TGL_UPDATE_PHONE) {
172     py_add_string_field_arr(types, -1, "phone");
173   }
174   if (flags & TGL_UPDATE_CONTACT) {
175     py_add_string_field_arr(types, -1, "contact");
176   }
177   if (flags & TGL_UPDATE_PHOTO) {
178     py_add_string_field_arr(types, -1, "photo");
179   }
180   if (flags & TGL_UPDATE_BLOCKED) {
181     py_add_string_field_arr(types, -1, "blocked");
182   }
183   if (flags & TGL_UPDATE_REAL_NAME) {
184     py_add_string_field_arr(types, -1, "real_name");
185   }
186   if (flags & TGL_UPDATE_NAME) {
187     py_add_string_field_arr(types, -1, "name");
188   }
189   if (flags & TGL_UPDATE_REQUESTED) {
190     py_add_string_field_arr(types, -1, "requested");
191   }
192   if (flags & TGL_UPDATE_WORKING) {
193     py_add_string_field_arr(types, -1, "working");
194   }
195   if (flags & TGL_UPDATE_FLAGS) {
196     py_add_string_field_arr(types, -1, "flags");
197   }
198   if (flags & TGL_UPDATE_TITLE) {
199     py_add_string_field_arr(types, -1, "title");
200   }
201   if (flags & TGL_UPDATE_ADMIN) {
202     py_add_string_field_arr(types, -1, "admin");
203   }
204   if (flags & TGL_UPDATE_MEMBERS) {
205     py_add_string_field_arr(types, -1, "members");
206   }
207   if (flags & TGL_UPDATE_ACCESS_HASH) {
208     py_add_string_field_arr(types, -1, "access_hash");
209   }
210   if (flags & TGL_UPDATE_USERNAME) {
211     py_add_string_field_arr(types, -1, "username");
212   }
213   return types;
214 }
215 
get_peer(tgl_peer_id_t id,tgl_peer_t * P)216 PyObject* get_peer (tgl_peer_id_t id, tgl_peer_t *P) {
217   PyObject *peer;
218 
219   peer = tgl_Peer_FromTglPeer(P);
220   return peer;
221 }
222 
get_message(struct tgl_message * M)223 PyObject* get_message (struct tgl_message *M) {
224   assert (M);
225   PyObject *msg;
226 
227   msg = tgl_Msg_FromTglMsg(M);
228   return msg;
229 }
230 
py_binlog_end(void)231 void py_binlog_end (void) {
232   if (!python_loaded) { return; }
233 
234   PyObject *arglist, *result;
235 
236   if(_py_binlog_end == NULL) {
237     logprintf("Callback not set for on_binlog_end\n");
238     return;
239   }
240 
241   arglist = Py_BuildValue("()");
242   result = PyEval_CallObject(_py_binlog_end, arglist);
243   Py_DECREF(arglist);
244 
245   if(result == NULL)
246     PyErr_Print();
247   else if(PyUnicode_Check(result))
248     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
249 
250   Py_XDECREF(result);
251 }
252 
py_diff_end(void)253 void py_diff_end (void) {
254   if (!python_loaded) { return; }
255 
256   PyObject *arglist, *result;
257 
258   if(_py_diff_end == NULL) {
259     logprintf("Callback not set for on_diff_end\n");
260     return;
261   }
262 
263   arglist = Py_BuildValue("()");
264   result = PyEval_CallObject(_py_diff_end, arglist);
265   Py_DECREF(arglist);
266   if(result == NULL)
267     PyErr_Print();
268   else if(PyUnicode_Check(result))
269     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
270 
271   Py_XDECREF(result);
272 }
273 
py_our_id(int id)274 void py_our_id (int id) {
275   if (!python_loaded) { return; }
276 
277   PyObject *arglist, *result;
278 
279   if(_py_our_id == NULL) {
280     logprintf("Callback not set for on_our_id\n");
281     return;
282   }
283 
284   arglist = Py_BuildValue("(i)", id);
285   result = PyEval_CallObject(_py_our_id, arglist);
286   Py_DECREF(arglist);
287   if(result == NULL)
288     PyErr_Print();
289   else if(PyUnicode_Check(result))
290     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
291 
292   Py_XDECREF(result);
293 }
294 
py_new_msg(struct tgl_message * M)295 void py_new_msg (struct tgl_message *M) {
296   if (!python_loaded) { return; }
297   PyObject *msg;
298   PyObject *arglist, *result;
299 
300   if(_py_new_msg == NULL) {
301     logprintf("Callback not set for on_new_msg\n");
302     return;
303   }
304 
305   msg = get_message (M);
306 
307   arglist = Py_BuildValue("(O)", msg);
308   result = PyEval_CallObject(_py_new_msg, arglist);
309   Py_DECREF(arglist);
310 
311   if(result == NULL)
312     PyErr_Print();
313   else if(PyUnicode_Check(result))
314     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
315 
316   Py_XDECREF(result);
317 }
318 
py_list_msg(struct tgl_message * M)319 void py_list_msg (struct tgl_message *M) {
320   if (!python_loaded) { return; }
321   PyObject *msg;
322   PyObject *arglist, *result;
323 
324   if(_py_list_msg == NULL) {
325     logprintf("Callback not set for on_msg_history");
326     return;
327   }
328 
329   msg = get_message (M);
330 
331   arglist = Py_BuildValue("(O)", msg);
332   result = PyEval_CallObject(_py_list_msg, arglist);
333   Py_DECREF(arglist);
334 
335   if(result == NULL)
336     PyErr_Print();
337   else if(PyUnicode_Check(result))
338     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
339 
340   Py_XDECREF(result);
341 }
342 
py_secret_chat_update(struct tgl_secret_chat * C,unsigned flags)343 void py_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) {
344   if (!python_loaded) { return; }
345   PyObject *peer, *types;
346   PyObject *arglist, *result;
347 
348   if(_py_secret_chat_update == NULL) {
349     logprintf("Callback not set for on_secret_chat_update\n");
350     return;
351   }
352 
353   peer = get_peer (C->id, (void *)C);
354   types = get_update_types (flags);
355 
356   arglist = Py_BuildValue("(OO)", peer, types);
357   result = PyEval_CallObject(_py_secret_chat_update, arglist);
358   Py_DECREF(arglist);
359 
360   if(result == NULL)
361     PyErr_Print();
362   else if(PyUnicode_Check(result))
363     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
364 
365   Py_XDECREF(result);
366 }
367 
368 
py_user_update(struct tgl_user * U,unsigned flags)369 void py_user_update (struct tgl_user *U, unsigned flags) {
370   if (!python_loaded) { return; }
371   PyObject *peer, *types;
372   PyObject *arglist, *result;
373 
374   if(_py_user_update == NULL) {
375     logprintf("Callback not set for on_user_update\n");
376     return;
377   }
378 
379   peer = get_peer (U->id, (void *)U);
380   types = get_update_types (flags);
381 
382   arglist = Py_BuildValue("(OO)", peer, types);
383   result = PyEval_CallObject(_py_user_update, arglist);
384   Py_DECREF(arglist);
385 
386   if(result == NULL)
387     PyErr_Print();
388   else if(PyUnicode_Check(result))
389     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
390 
391   Py_XDECREF(result);
392 }
393 
py_chat_update(struct tgl_chat * C,unsigned flags)394 void py_chat_update (struct tgl_chat *C, unsigned flags) {
395   if (!python_loaded) { return; }
396 
397   PyObject *peer, *types;
398   PyObject *arglist, *result;
399 
400   if(_py_chat_update == NULL) {
401     logprintf("Callback not set for on_chat_update\n");
402     return;
403   }
404 
405   peer = get_peer (C->id, (void *)C);
406   types = get_update_types (flags);
407 
408   arglist = Py_BuildValue("(OO)", peer, types);
409   result = PyEval_CallObject(_py_chat_update, arglist);
410   Py_DECREF(arglist);
411 
412   if(result == NULL)
413     PyErr_Print();
414   else if(PyUnicode_Check(result))
415     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
416 
417   Py_XDECREF(result);
418 }
419 
py_on_loop()420 void py_on_loop () {
421   if (!python_loaded) { return; }
422 
423   PyObject *result;
424 
425   if(_py_on_loop == NULL) {
426     logprintf("Callback not set for on_loop\n");
427     return;
428   }
429 
430   result = PyEval_CallObject(_py_on_loop, Py_BuildValue("()"));
431 
432   if(result == NULL)
433     PyErr_Print();
434   else if(PyUnicode_Check(result))
435     logprintf ("python: %s\n", PyBytes_AsString(PyUnicode_AsASCIIString(result)));
436 
437   Py_XDECREF(result);
438 }
439 
440 
441 ////extern tgl_peer_t *Peers[];
442 ////extern int peer_num;
443 //
444 #define MAX_PY_COMMANDS 1000
445 void *py_ptr[MAX_PY_COMMANDS];
446 static int pos;
447 //
448 //static inline tgl_peer_t *get_peer (const char *s) {
449 //  return tgl_peer_get_by_name (TLS, s);
450 //}
451 
452 enum py_query_type {
453   pq_contact_list,
454   pq_dialog_list,
455   pq_msg,
456   pq_send_typing,
457   pq_send_typing_abort,
458   pq_rename_chat,
459   pq_send_photo,
460   pq_chat_set_photo,
461   pq_set_profile_photo,
462   pq_set_profile_name,
463   pq_send_video,
464   pq_send_text,
465   pq_fwd,
466   pq_fwd_media,
467   pq_load_photo,
468   pq_load_video_thumb,
469   pq_load_video,
470   pq_chat_info,
471   pq_user_info,
472   pq_history,
473   pq_chat_add_user,
474   pq_chat_del_user,
475   pq_add_contact,
476   pq_del_contact,
477   pq_rename_contact,
478   pq_search,
479   pq_global_search,
480   pq_mark_read,
481   pq_create_secret_chat,
482   pq_create_group_chat,
483   pq_send_audio,
484   pq_send_document,
485   pq_send_file,
486   pq_load_audio,
487   pq_load_document,
488   pq_load_document_thumb,
489   pq_delete_msg,
490   pq_restore_msg,
491   pq_accept_secret_chat,
492   pq_send_contact,
493   pq_status_online,
494   pq_status_offline,
495   pq_send_location,
496   pq_extf,
497   pq_import_chat_link
498 };
499 
py_empty_cb(struct tgl_state * TLSR,void * cb_extra,int success)500 void py_empty_cb (struct tgl_state *TLSR, void *cb_extra, int success) {
501   assert (TLSR == TLS);
502   PyObject *callable = cb_extra;
503   PyObject *arglist = NULL;
504   PyObject *result = NULL;
505 
506   if(PyCallable_Check(callable)) {
507     arglist = Py_BuildValue("(O)", success ? Py_True : Py_False);
508     result = PyEval_CallObject(callable, arglist);
509     Py_DECREF(arglist);
510 
511     if(result == NULL)
512       PyErr_Print();
513 
514     Py_XDECREF(result);
515   }
516 
517   Py_XDECREF(callable);
518 }
519 
py_contact_list_cb(struct tgl_state * TLSR,void * cb_extra,int success,int num,struct tgl_user ** UL)520 void py_contact_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_user **UL) {
521   assert (TLSR == TLS);
522   PyObject *callable = cb_extra;
523   PyObject *arglist = NULL;
524   PyObject *peers = NULL;
525   PyObject *result = NULL;
526 
527   if(PyCallable_Check(callable)) {
528     peers = PyList_New(0);
529     if (success) {
530       int i;
531       for (i = 0; i < num; i++) {
532         PyList_Append(peers, get_peer (UL[i]->id, (void *)UL[i]));
533       }
534     }
535 
536     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peers);
537     result = PyEval_CallObject(callable, arglist);
538     Py_DECREF(arglist);
539 
540     if(result == NULL)
541       PyErr_Print();
542 
543     Py_XDECREF(result);
544   }
545 
546   Py_XDECREF(callable);
547 }
548 
py_dialog_list_cb(struct tgl_state * TLSR,void * cb_extra,int success,int num,tgl_peer_id_t peers[],tgl_message_id_t * msgs[],int unread[])549 void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], tgl_message_id_t *msgs[], int unread[]) {
550   assert (TLSR == TLS);
551   PyObject *callable = cb_extra;
552   PyObject *arglist = NULL;
553   PyObject *dialog_list = NULL;
554   PyObject *dialog = NULL;
555   PyObject *result = NULL;
556 
557   if(PyCallable_Check(callable)) {
558     dialog_list = PyList_New(0);
559     if (success) {
560       int i;
561       for (i = 0; i < num; i++) {
562         dialog = PyDict_New();
563         PyDict_SetItemString(dialog, "peer", get_peer(peers[i], tgl_peer_get (TLS, peers[i])));
564 
565         struct tgl_message *M = tgl_message_get (TLS, msgs[i]);
566         if (M && (M->flags & TGLMF_CREATED)) {
567           PyDict_SetItemString(dialog, "message", get_message(M));
568         }
569         PyDict_SetItemString(dialog, "unread", unread[i] ? Py_True : Py_False);
570 
571         PyList_Append(dialog_list, dialog);
572       }
573     }
574 
575     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, dialog_list);
576     result = PyEval_CallObject(callable, arglist);
577     Py_DECREF(arglist);
578 
579     if(result == NULL)
580       PyErr_Print();
581 
582     Py_XDECREF(result);
583   }
584 
585   Py_XDECREF(callable);
586 }
587 
py_msg_cb(struct tgl_state * TLSR,void * cb_extra,int success,struct tgl_message * M)588 void py_msg_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_message *M) {
589   assert (TLSR == TLS);
590   PyObject *callable = cb_extra;
591   PyObject *arglist = NULL;
592   PyObject *msg = NULL;
593   PyObject *result = NULL;
594 
595   if(PyCallable_Check(callable)) {
596     if (success && M && (M->flags & TGLMF_CREATED)) {
597       msg = get_message(M);
598     } else {
599       Py_INCREF(Py_None);
600       msg = Py_None;
601     }
602 
603     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, msg);
604     result = PyEval_CallObject(callable, arglist);
605     Py_DECREF(arglist);
606 
607     if(result == NULL)
608       PyErr_Print();
609 
610     Py_XDECREF(result);
611   }
612 
613   Py_XDECREF(callable);
614 }
615 
py_msg_list_cb(struct tgl_state * TLSR,void * cb_extra,int success,int num,struct tgl_message * M[])616 void py_msg_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, struct tgl_message *M[]) {
617   assert (TLSR == TLS);
618   PyObject *callable = cb_extra;
619   PyObject *arglist = NULL;
620   PyObject *msgs = NULL;
621   PyObject *result = NULL;
622 
623   if(PyCallable_Check(callable)) {
624     msgs = PyList_New(0);
625     if (success) {
626       int i;
627       for (i = 0; i < num; i++) {
628         PyList_Append(msgs, get_message (M[i]));
629       }
630     }
631 
632     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, msgs);
633     result = PyEval_CallObject(callable, arglist);
634     Py_DECREF(arglist);
635 
636     if(result == NULL)
637       PyErr_Print();
638 
639     Py_XDECREF(result);
640   }
641 
642   Py_XDECREF(callable);
643 }
644 
py_file_cb(struct tgl_state * TLSR,void * cb_extra,int success,const char * file_name)645 void py_file_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *file_name) {
646   assert (TLSR == TLS);
647   PyObject *callable = cb_extra;
648   PyObject *arglist = NULL;
649   PyObject *filename = NULL;
650   PyObject *result = NULL;
651 
652   if(PyCallable_Check(callable)) {
653     if(success)
654       filename = PyUnicode_FromString(file_name);
655     else {
656       Py_INCREF(Py_None);
657       filename = Py_None;
658     }
659 
660     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, filename);
661     result = PyEval_CallObject(callable, arglist);
662     Py_DECREF(arglist);
663 
664     if(result == NULL)
665       PyErr_Print();
666 
667     Py_XDECREF(result);
668   }
669 
670   Py_XDECREF(callable);
671 }
672 
py_chat_cb(struct tgl_state * TLSR,void * cb_extra,int success,struct tgl_chat * C)673 void py_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_chat *C) {
674   assert (TLSR == TLS);
675   PyObject *callable = cb_extra;
676   PyObject *arglist = NULL;
677   PyObject *peer = NULL;
678   PyObject *result = NULL;
679 
680   if(PyCallable_Check(callable)) {
681     if (success) {
682       peer = get_peer(C->id, (void *)C);
683     } else {
684       Py_INCREF(Py_None);
685       peer = Py_None;
686     }
687 
688     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peer);
689     result = PyEval_CallObject(callable, arglist);
690     Py_DECREF(arglist);
691 
692     if(result == NULL)
693       PyErr_Print();
694 
695     Py_XDECREF(result);
696   }
697 
698   Py_XDECREF(callable);
699 }
700 
py_secret_chat_cb(struct tgl_state * TLSR,void * cb_extra,int success,struct tgl_secret_chat * C)701 void py_secret_chat_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_secret_chat *C) {
702   assert (TLSR == TLS);
703   PyObject *callable = cb_extra;
704   PyObject *arglist = NULL;
705   PyObject *peer = NULL;
706   PyObject *result = NULL;
707 
708   if(PyCallable_Check(callable)) {
709     if (success) {
710       peer = get_peer(C->id, (void *)C);
711     } else {
712       Py_INCREF(Py_None);
713       peer = Py_None;
714     }
715 
716     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peer);
717     result = PyEval_CallObject(callable, arglist);
718     Py_DECREF(arglist);
719 
720     if(result == NULL)
721       PyErr_Print();
722 
723     Py_XDECREF(result);
724   }
725 
726   Py_XDECREF(callable);
727 }
728 
py_user_cb(struct tgl_state * TLSR,void * cb_extra,int success,struct tgl_user * C)729 void py_user_cb (struct tgl_state *TLSR, void *cb_extra, int success, struct tgl_user *C) {
730   assert (TLSR == TLS);
731   PyObject *callable = cb_extra;
732   PyObject *arglist = NULL;
733   PyObject *peer = NULL;
734   PyObject *result = NULL;
735 
736   if(PyCallable_Check(callable)) {
737     if (success) {
738       peer = get_peer(C->id, (void *)C);
739     } else {
740       Py_INCREF(Py_None);
741       peer = Py_None;
742     }
743 
744     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, peer);
745     result = PyEval_CallObject(callable, arglist);
746     Py_DECREF(arglist);
747 
748     if(result == NULL)
749       PyErr_Print();
750 
751     Py_XDECREF(result);
752   }
753 
754   Py_XDECREF(callable);
755 }
756 
py_str_cb(struct tgl_state * TLSR,void * cb_extra,int success,const char * data)757 void py_str_cb (struct tgl_state *TLSR, void *cb_extra, int success, const char *data) {
758   assert (TLSR == TLS);
759   PyObject *callable = cb_extra;
760   PyObject *arglist = NULL;
761   PyObject *str = NULL;
762   PyObject *result = NULL;
763 
764   if(PyCallable_Check(callable)) {
765     if(success)
766       str = PyUnicode_FromString(data);
767     else {
768       Py_INCREF(Py_None);
769       str = Py_None;
770     }
771 
772     arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, str);
773     result = PyEval_CallObject(callable, arglist);
774     Py_DECREF(arglist);
775 
776     if(result == NULL)
777       PyErr_Print();
778 
779     Py_XDECREF(result);
780   }
781 
782   Py_XDECREF(callable);
783 }
784 
785 #define PY_PEER_ID(x) (tgl_peer_id_t)((tgl_Peer*)x)->peer->id
786 #define PY_MSG_ID(x) (tgl_message_id_t*)x
787 
py_do_all(void)788 void py_do_all (void) {
789   int p = 0;
790 
791   // ping the python thread that we're doing the loop
792   py_on_loop();
793 
794   while (p < pos) {
795     assert (p + 2 <= pos);
796 
797     enum py_query_type f = (long)py_ptr[p ++];
798     PyObject *args = (PyObject *)py_ptr[p ++];
799 
800     const char *str, *str1, *str2, *str3;
801 
802     int preview = 0;
803     int reply_id = 0;
804     unsigned long long flags = 0;
805 
806     Py_ssize_t i;
807     tgl_user_id_t *ids;
808 
809     struct tgl_message *M;
810 
811     int len, len1, len2, len3;
812     int limit, offset;
813     long msg_id = 0;
814 
815     PyObject *pyObj1 = NULL;
816     PyObject *pyObj2 = NULL;
817     PyObject *cb_extra = NULL;
818 
819     PyObject *msg = NULL;
820     PyObject *peer = NULL;
821     PyObject *peer1 = NULL;
822 
823     switch (f) {
824     case pq_contact_list:
825       if(PyArg_ParseTuple(args, "|O", &cb_extra))
826         tgl_do_update_contact_list (TLS, py_contact_list_cb, cb_extra);
827       else
828         PyErr_Print();
829       break;
830     case pq_dialog_list:
831       if(PyArg_ParseTuple(args, "|O", &cb_extra))
832         tgl_do_get_dialog_list (TLS, 100, 0, py_dialog_list_cb, cb_extra);
833       else
834         PyErr_Print();
835       break;
836     case pq_msg:
837       if(PyArg_ParseTuple(args, "O!s#|OO", &tgl_PeerType, &peer, &str, &len, &cb_extra, &pyObj1)) {
838         if(pyObj1 && PyArg_ParseTuple(pyObj1, "ii", &preview, &reply_id)) {
839           if(preview != -1) {
840             if(preview)
841               flags |= TGL_SEND_MSG_FLAG_ENABLE_PREVIEW;
842             else
843               flags |= TGL_SEND_MSG_FLAG_DISABLE_PREVIEW;
844           }
845           flags |= TGL_SEND_MSG_FLAG_REPLY (reply_id);
846         }
847         tgl_do_send_message (TLS, PY_PEER_ID(peer), str, len, flags, NULL, py_msg_cb, cb_extra);
848       } else
849         PyErr_Print();
850 
851       Py_XDECREF(pyObj1);
852       break;
853     case pq_send_typing:
854       if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
855         tgl_do_send_typing (TLS, PY_PEER_ID(peer), tgl_typing_typing, py_empty_cb, cb_extra);
856       else
857         PyErr_Print();
858       break;
859     case pq_send_typing_abort:
860       if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
861         tgl_do_send_typing (TLS, PY_PEER_ID(peer), tgl_typing_cancel, py_empty_cb, cb_extra);
862       else
863         PyErr_Print();
864       break;
865     case pq_rename_chat:
866       if(PyArg_ParseTuple(args, "O!s#|O", &tgl_PeerType, &peer, &str, &len, &cb_extra))
867         tgl_do_rename_chat (TLS, PY_PEER_ID(peer), str, len, py_empty_cb, cb_extra);
868       else
869         PyErr_Print();
870       break;
871     case pq_send_photo:
872       if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
873         tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_PHOTO, py_msg_cb, cb_extra);
874       else
875         PyErr_Print();
876       break;
877     case pq_send_video:
878       if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
879         tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_VIDEO, py_msg_cb, cb_extra);
880       else
881         PyErr_Print();
882       break;
883     case pq_send_audio:
884       if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
885         tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUDIO, py_msg_cb, cb_extra);
886       else
887         PyErr_Print();
888       break;
889     case pq_send_document:
890       if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
891         tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, 0, py_msg_cb, cb_extra);
892       else
893         PyErr_Print();
894       break;
895     case pq_send_file:
896       if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
897         tgl_do_send_document (TLS, PY_PEER_ID(peer), str, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, py_msg_cb, cb_extra);
898       else
899         PyErr_Print();
900       break;
901     case pq_send_text:
902       if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
903         tgl_do_send_text (TLS, PY_PEER_ID(peer), str, 0, py_msg_cb, cb_extra);
904       else
905         PyErr_Print();
906       break;
907     case pq_chat_set_photo:
908       if(PyArg_ParseTuple(args, "O!s|O", &tgl_PeerType, &peer, &str, &cb_extra))
909         tgl_do_set_chat_photo (TLS, PY_PEER_ID(peer), str, py_empty_cb, cb_extra);
910       else
911         PyErr_Print();
912       break;
913     case pq_load_photo:
914     case pq_load_video:
915     case pq_load_audio:
916     case pq_load_document:
917       if(PyArg_ParseTuple(args, "O!O", &tgl_MsgType, &msg, &cb_extra))
918       {
919         M = ((tgl_Msg*)msg)->msg;
920         if (!M || (M->media.type != tgl_message_media_photo && M->media.type != tgl_message_media_document && M->media.type != tgl_message_media_document_encr)) {
921           py_file_cb (TLS, cb_extra, 0, 0);
922         } else {
923           if (M->media.type == tgl_message_media_photo) {
924             assert (M->media.photo);
925             tgl_do_load_photo (TLS, M->media.photo, py_file_cb, cb_extra);
926           } else if (M->media.type == tgl_message_media_document) {
927             tgl_do_load_document (TLS, M->media.document, py_file_cb, cb_extra);
928           } else {
929             tgl_do_load_encr_document (TLS, M->media.encr_document, py_file_cb, cb_extra);
930           }
931         }
932       }
933       break;
934     case pq_load_video_thumb:
935     case pq_load_document_thumb:
936       if(PyArg_ParseTuple(args, "O!O", &tgl_MsgType, &msg, &cb_extra))
937       {
938         M = ((tgl_Msg*)msg)->msg;
939         if (!M || (M->media.type != tgl_message_media_document)) {
940           py_file_cb (TLS, cb_extra, 0, 0);
941         } else {
942           tgl_do_load_document_thumb (TLS, M->media.document, py_file_cb, cb_extra);
943         }
944       }
945       break;
946 
947     case pq_fwd:
948       if(PyArg_ParseTuple(args, "O!l|O", &tgl_PeerType, &peer, &msg_id, &cb_extra))
949         tgl_do_forward_message (TLS, PY_PEER_ID(peer), PY_MSG_ID(msg_id), 0, py_msg_cb, cb_extra);
950       else
951         PyErr_Print();
952       break;
953     case pq_fwd_media:
954       if(PyArg_ParseTuple(args, "O!l|O", &tgl_PeerType, &peer, &msg_id, &cb_extra))
955         tgl_do_forward_media (TLS, PY_PEER_ID(peer), PY_MSG_ID(msg_id), 0, py_msg_cb, cb_extra);
956       else
957         PyErr_Print();
958       break;
959     case pq_chat_info:
960       if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
961         tgl_do_get_chat_info (TLS, PY_PEER_ID(peer), 0, py_chat_cb, cb_extra);
962       else
963         PyErr_Print();
964       break;
965     case pq_user_info:
966       if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
967         tgl_do_get_user_info (TLS, PY_PEER_ID(peer), 0, py_user_cb, cb_extra);
968       else
969         PyErr_Print();
970       break;
971     case pq_history:
972       if(PyArg_ParseTuple(args, "O!ii|O", &tgl_PeerType, &peer, &offset, &limit, &cb_extra))
973         tgl_do_get_history (TLS, PY_PEER_ID(peer), offset, limit, 0, py_msg_list_cb, cb_extra);
974       else
975         PyErr_Print();
976       break;
977     case pq_chat_add_user:
978       if(PyArg_ParseTuple(args, "O!O!|O", &tgl_PeerType, &peer, &tgl_PeerType, &peer1, &cb_extra))
979         tgl_do_add_user_to_chat (TLS, PY_PEER_ID(peer), PY_PEER_ID(peer1), 100, py_empty_cb, cb_extra);
980       else
981         PyErr_Print();
982       break;
983     case pq_chat_del_user:
984       if(PyArg_ParseTuple(args, "O!O!|O", &tgl_PeerType, &peer, &tgl_PeerType, &peer1, &cb_extra))
985         tgl_do_del_user_from_chat (TLS, PY_PEER_ID(peer), PY_PEER_ID(peer1), py_empty_cb, cb_extra);
986       else
987         PyErr_Print();
988       break;
989     case pq_add_contact:
990       if(PyArg_ParseTuple(args, "s#s#s#|O", &str1, &len1, &str2, &len2, &str3, &len3, &cb_extra))
991         tgl_do_add_contact (TLS, str1, len1, str2, len2, str3, len3, 0, py_contact_list_cb, cb_extra);
992       else
993         PyErr_Print();
994       break;
995     case pq_del_contact:
996       if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
997         tgl_do_del_contact (TLS, PY_PEER_ID(peer), py_empty_cb, cb_extra);
998       else
999         PyErr_Print();
1000       break;
1001     case pq_rename_contact:
1002       if(PyArg_ParseTuple(args, "s#s#s#|O", &str1, &len1, &str2, &len2, &str3, &len3, &cb_extra))
1003         tgl_do_add_contact (TLS, str1, len1, str2, len2, str3, len3, 1, py_contact_list_cb, cb_extra);
1004       else
1005         PyErr_Print();
1006       break;
1007     case pq_search:
1008       if(PyArg_ParseTuple(args, "O!s#|O", &tgl_PeerType, &peer, &str, &len, &cb_extra))
1009         tgl_do_msg_search (TLS, PY_PEER_ID(peer), 0, 0, 40, 0, str, len, py_msg_list_cb, cb_extra);
1010       else
1011         PyErr_Print();
1012       break;
1013     case pq_global_search:
1014       if(PyArg_ParseTuple(args, "s#|O", &str, &len, &cb_extra))
1015         tgl_do_msg_search (TLS, tgl_set_peer_id (TGL_PEER_UNKNOWN, 0), 0, 0, 40, 0, str, len, py_msg_list_cb, cb_extra);
1016       else
1017         PyErr_Print();
1018       break;
1019     case pq_mark_read:
1020       if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
1021         tgl_do_mark_read (TLS, PY_PEER_ID(peer), py_empty_cb, cb_extra);
1022       else
1023         PyErr_Print();
1024       break;
1025     case pq_set_profile_photo:
1026       if(PyArg_ParseTuple(args, "s|O", &str, &cb_extra))
1027         tgl_do_set_profile_photo (TLS, str, py_empty_cb, cb_extra);
1028       else
1029         PyErr_Print();
1030       break;
1031     case pq_set_profile_name:
1032       if(PyArg_ParseTuple(args, "s#s#|O", &str1, &len1, &str2, &len2, &cb_extra))
1033         tgl_do_set_profile_name (TLS, str1, len1, str2, len2, py_user_cb, cb_extra);
1034       else
1035         PyErr_Print();
1036       break;
1037     case pq_create_secret_chat:
1038       if(PyArg_ParseTuple(args, "O!|O", &tgl_PeerType, &peer, &cb_extra))
1039         tgl_do_create_secret_chat (TLS, PY_PEER_ID(peer), py_secret_chat_cb, cb_extra);
1040       else
1041         PyErr_Print();
1042       break;
1043     case pq_create_group_chat:
1044       if(PyArg_ParseTuple(args, "O!s#|O", &PyList_Type, &pyObj1, &str, &len, &cb_extra)) {
1045         if(PyList_GET_SIZE(pyObj1) > 2) {
1046           ids = (tgl_user_id_t *)malloc(PyList_GET_SIZE(pyObj1) * sizeof(tgl_user_id_t));
1047           for(i = 0; i < PyList_GET_SIZE(pyObj1); i++) {
1048             peer = PyList_GetItem(pyObj1, i);
1049             *(ids+i) = PY_PEER_ID(peer);
1050           }
1051           tgl_do_create_group_chat (TLS, PyList_GET_SIZE(pyObj1), ids, str, len, py_empty_cb, cb_extra);
1052 
1053           tfree(ids, PyList_GET_SIZE(pyObj1) * sizeof(tgl_user_id_t));
1054         } else {
1055             logprintf("create_group_chat: Argument 1 must be a list of at least 3 peers\n");
1056         }
1057       }
1058       Py_XDECREF(pyObj1);
1059       break;
1060     case pq_delete_msg:
1061     case pq_restore_msg:
1062       if(PyArg_ParseTuple(args, "l|O", &msg_id, &cb_extra))
1063         tgl_do_delete_msg (TLS, PY_MSG_ID(msg_id), py_empty_cb, cb_extra);
1064       else
1065         PyErr_Print();
1066       break;
1067 /*
1068     case pq_accept_secret_chat:
1069       tgl_do_accept_encr_chat_request (TLS, py_ptr[p + 1], py_secret_chat_cb, py_ptr[p]);
1070       break;
1071 */
1072     case pq_send_contact:
1073       if(PyArg_ParseTuple(args, "O!s#s#s#|O",  &tgl_PeerType, &peer, &str1, &len1, &str2, &len2,
1074                                                &str3, &len3, &cb_extra))
1075         tgl_do_send_contact (TLS, PY_PEER_ID(peer), str1, len1, str2, len2, str3, len3, 0, py_msg_cb, cb_extra);
1076       else
1077         PyErr_Print();
1078       break;
1079     case pq_status_online:
1080       if(PyArg_ParseTuple(args, "|O", &cb_extra))
1081         tgl_do_update_status (TLS, 1, py_empty_cb, cb_extra);
1082       else
1083         PyErr_Print();
1084       break;
1085     case pq_status_offline:
1086       if(PyArg_ParseTuple(args, "|O", &cb_extra))
1087         tgl_do_update_status (TLS, 0, py_empty_cb, cb_extra);
1088       else
1089         PyErr_Print();
1090       break;
1091     case pq_extf:
1092       if(PyArg_ParseTuple(args, "s#|O", &str, &len, &cb_extra))
1093         tgl_do_send_extf (TLS, str, len, py_str_cb, cb_extra);
1094       else
1095         PyErr_Print();
1096       break;
1097     case pq_import_chat_link:
1098       if(PyArg_ParseTuple(args, "s#|O", &str, &len, &cb_extra))
1099         tgl_do_import_chat_link  (TLS, str, len, py_empty_cb, cb_extra);
1100       else
1101         PyErr_Print();
1102       break;
1103     case pq_send_location:
1104       if(PyArg_ParseTuple(args, "O!O!O!|O", &tgl_PeerType, &peer, &PyFloat_Type, &pyObj1, &PyFloat_Type, &pyObj2, &cb_extra)){
1105         tgl_do_send_location (TLS, PY_PEER_ID(peer),
1106                               PyFloat_AsDouble(pyObj1), PyFloat_AsDouble(pyObj2), 0, py_msg_cb, cb_extra);
1107         Py_XDECREF(pyObj1);
1108         Py_XDECREF(pyObj2);
1109       } else
1110         PyErr_Print();
1111       break;
1112     default:
1113       assert (0);
1114     }
1115 
1116     // Increment reference on cb_extra as it is passed on to the callback to use
1117     Py_XINCREF(cb_extra);
1118 
1119     // Clean up any arg variables we could have used.
1120     //Py_XDECREF(args); // TODO: this is going negative ref and causing segfaults
1121     Py_XDECREF(peer);
1122     Py_XDECREF(peer1);
1123 
1124   }
1125   pos = 0;
1126 }
1127 
push_py_func(enum py_query_type type,PyObject * args)1128 PyObject* push_py_func(enum py_query_type type, PyObject *args) {
1129   assert(pos + 2 < MAX_PY_COMMANDS);
1130 
1131   py_ptr[pos ++] = (void *)(long)type;
1132   py_ptr[pos ++] = (void *)args;
1133 
1134   Py_INCREF(args);
1135   Py_RETURN_TRUE;
1136 }
1137 
1138 // Register functions to push commands on the queue
py_contact_list(PyObject * self,PyObject * args)1139 PyObject* py_contact_list(PyObject *self, PyObject *args) { return push_py_func(pq_contact_list, args); }
py_dialog_list(PyObject * self,PyObject * args)1140 PyObject* py_dialog_list(PyObject *self, PyObject *args) { return push_py_func(pq_dialog_list, args); }
py_rename_chat(PyObject * self,PyObject * args)1141 PyObject* py_rename_chat(PyObject *self, PyObject *args) { return push_py_func(pq_rename_chat, args); }
py_send_msg(PyObject * self,PyObject * args)1142 PyObject* py_send_msg(PyObject *self, PyObject *args) { return push_py_func(pq_msg, args); }
py_send_typing(PyObject * self,PyObject * args)1143 PyObject* py_send_typing(PyObject *self, PyObject *args) { return push_py_func(pq_send_typing, args); }
py_send_typing_abort(PyObject * self,PyObject * args)1144 PyObject* py_send_typing_abort(PyObject *self, PyObject *args) { return push_py_func(pq_send_typing_abort, args); }
py_send_photo(PyObject * self,PyObject * args)1145 PyObject* py_send_photo(PyObject *self, PyObject *args) { return push_py_func(pq_send_photo, args); }
py_send_video(PyObject * self,PyObject * args)1146 PyObject* py_send_video(PyObject *self, PyObject *args) { return push_py_func(pq_send_video, args); }
py_send_audio(PyObject * self,PyObject * args)1147 PyObject* py_send_audio(PyObject *self, PyObject *args) { return push_py_func(pq_send_audio, args); }
py_send_document(PyObject * self,PyObject * args)1148 PyObject* py_send_document(PyObject *self, PyObject *args) { return push_py_func(pq_send_document, args); }
py_send_file(PyObject * self,PyObject * args)1149 PyObject* py_send_file(PyObject *self, PyObject *args) { return push_py_func(pq_send_file, args); }
py_send_text(PyObject * self,PyObject * args)1150 PyObject* py_send_text(PyObject *self, PyObject *args) { return push_py_func(pq_send_text, args); }
py_chat_set_photo(PyObject * self,PyObject * args)1151 PyObject* py_chat_set_photo(PyObject *self, PyObject *args) { return push_py_func(pq_chat_set_photo, args); }
py_load_photo(PyObject * self,PyObject * args)1152 PyObject* py_load_photo(PyObject *self, PyObject *args) { return push_py_func(pq_load_photo, args); }
py_load_video(PyObject * self,PyObject * args)1153 PyObject* py_load_video(PyObject *self, PyObject *args) { return push_py_func(pq_load_video, args); }
py_load_video_thumb(PyObject * self,PyObject * args)1154 PyObject* py_load_video_thumb(PyObject *self, PyObject *args) { return push_py_func(pq_load_video_thumb, args); }
py_load_audio(PyObject * self,PyObject * args)1155 PyObject* py_load_audio(PyObject *self, PyObject *args) { return push_py_func(pq_load_audio, args); }
py_load_document(PyObject * self,PyObject * args)1156 PyObject* py_load_document(PyObject *self, PyObject *args) { return push_py_func(pq_load_document, args); }
py_load_document_thumb(PyObject * self,PyObject * args)1157 PyObject* py_load_document_thumb(PyObject *self, PyObject *args) { return push_py_func(pq_load_document_thumb, args); }
py_fwd(PyObject * self,PyObject * args)1158 PyObject* py_fwd(PyObject *self, PyObject *args) { return push_py_func(pq_fwd, args); }
py_fwd_media(PyObject * self,PyObject * args)1159 PyObject* py_fwd_media(PyObject *self, PyObject *args) { return push_py_func(pq_fwd_media, args); }
py_chat_info(PyObject * self,PyObject * args)1160 PyObject* py_chat_info(PyObject *self, PyObject *args) { return push_py_func(pq_chat_info, args); }
py_user_info(PyObject * self,PyObject * args)1161 PyObject* py_user_info(PyObject *self, PyObject *args) { return push_py_func(pq_chat_info, args); }
py_history(PyObject * self,PyObject * args)1162 PyObject* py_history(PyObject *self, PyObject *args) { return push_py_func(pq_history, args); }
py_chat_add_user(PyObject * self,PyObject * args)1163 PyObject* py_chat_add_user(PyObject *self, PyObject *args) { return push_py_func(pq_chat_add_user, args); }
py_chat_del_user(PyObject * self,PyObject * args)1164 PyObject* py_chat_del_user(PyObject *self, PyObject *args) { return push_py_func(pq_chat_del_user, args); }
py_add_contact(PyObject * self,PyObject * args)1165 PyObject* py_add_contact(PyObject *self, PyObject *args) { return push_py_func(pq_add_contact, args); }
py_del_contact(PyObject * self,PyObject * args)1166 PyObject* py_del_contact(PyObject *self, PyObject *args) { return push_py_func(pq_del_contact, args); }
py_rename_contact(PyObject * self,PyObject * args)1167 PyObject* py_rename_contact(PyObject *self, PyObject *args) { return push_py_func(pq_rename_contact, args); }
py_search(PyObject * self,PyObject * args)1168 PyObject* py_search(PyObject *self, PyObject *args) { return push_py_func(pq_search, args); }
py_global_search(PyObject * self,PyObject * args)1169 PyObject* py_global_search(PyObject *self, PyObject *args) { return push_py_func(pq_global_search, args); }
py_mark_read(PyObject * self,PyObject * args)1170 PyObject* py_mark_read(PyObject *self, PyObject *args) { return push_py_func(pq_mark_read, args); }
py_set_profile_photo(PyObject * self,PyObject * args)1171 PyObject* py_set_profile_photo(PyObject *self, PyObject *args) { return push_py_func(pq_set_profile_photo, args); }
py_set_profile_name(PyObject * self,PyObject * args)1172 PyObject* py_set_profile_name(PyObject *self, PyObject *args) { return push_py_func(pq_set_profile_name, args); }
py_create_secret_chat(PyObject * self,PyObject * args)1173 PyObject* py_create_secret_chat(PyObject *self, PyObject *args) { return push_py_func(pq_create_secret_chat, args); }
py_create_group_chat(PyObject * self,PyObject * args)1174 PyObject* py_create_group_chat(PyObject *self, PyObject *args) { return push_py_func(pq_create_group_chat, args); }
py_delete_msg(PyObject * self,PyObject * args)1175 PyObject* py_delete_msg(PyObject *self, PyObject *args) { return push_py_func(pq_delete_msg, args); }
py_restore_msg(PyObject * self,PyObject * args)1176 PyObject* py_restore_msg(PyObject *self, PyObject *args) { return push_py_func(pq_restore_msg, args); }
py_accept_secret_chat(PyObject * self,PyObject * args)1177 PyObject* py_accept_secret_chat(PyObject *self, PyObject *args) { return push_py_func(pq_accept_secret_chat, args); }
py_send_contact(PyObject * self,PyObject * args)1178 PyObject* py_send_contact(PyObject *self, PyObject *args) { return push_py_func(pq_send_contact, args); }
py_status_online(PyObject * self,PyObject * args)1179 PyObject* py_status_online(PyObject *self, PyObject *args) { return push_py_func(pq_status_online, args); }
py_status_offline(PyObject * self,PyObject * args)1180 PyObject* py_status_offline(PyObject *self, PyObject *args) { return push_py_func(pq_status_offline, args); }
py_send_location(PyObject * self,PyObject * args)1181 PyObject* py_send_location(PyObject *self, PyObject *args) { return push_py_func(pq_send_location, args); }
py_extf(PyObject * self,PyObject * args)1182 PyObject* py_extf(PyObject *self, PyObject *args) { return push_py_func(pq_extf, args); }
py_import_chat_link(PyObject * self,PyObject * args)1183 PyObject* py_import_chat_link(PyObject *self, PyObject *args) { return push_py_func(pq_import_chat_link, args); }
1184 
1185 extern int safe_quit;
1186 extern int exit_code;
py_safe_quit(PyObject * self,PyObject * args)1187 PyObject* py_safe_quit(PyObject *self, PyObject *args)
1188 {
1189   int exit_val = 0;
1190   if(PyArg_ParseTuple(args, "|i", &exit_val)) {
1191     safe_quit = 1;
1192     exit_code = exit_val;
1193   } else {
1194     PyErr_Print();
1195   }
1196 
1197   Py_RETURN_NONE;
1198 }
1199 
py_set_preview(PyObject * self,PyObject * args)1200 PyObject* py_set_preview(PyObject *self, PyObject *args)
1201 {
1202   int preview = 0;
1203   if(PyArg_ParseTuple(args, "p", &preview)) {
1204     if(preview)
1205       TLS->disable_link_preview = 0;
1206     else
1207       TLS->disable_link_preview = 1;
1208   } else {
1209     PyErr_Print();
1210   }
1211 
1212   Py_RETURN_NONE;
1213 }
1214 
1215 // Store callables for python functions
1216 TGL_PYTHON_CALLBACK("on_binlog_replay_end", _py_binlog_end);
1217 TGL_PYTHON_CALLBACK("on_get_difference_end", _py_diff_end);
1218 TGL_PYTHON_CALLBACK("on_our_id", _py_our_id);
1219 TGL_PYTHON_CALLBACK("on_msg_receive", _py_new_msg);
1220 TGL_PYTHON_CALLBACK("on_msg_history", _py_list_msg);
1221 TGL_PYTHON_CALLBACK("on_secret_chat_update", _py_secret_chat_update);
1222 TGL_PYTHON_CALLBACK("on_user_update", _py_user_update);
1223 TGL_PYTHON_CALLBACK("on_chat_update", _py_chat_update);
1224 TGL_PYTHON_CALLBACK("on_loop", _py_on_loop);
1225 
1226 static PyMethodDef py_tgl_methods[] = {
1227   {"get_contact_list", py_contact_list, METH_VARARGS, "retrieve contact list"},
1228   {"get_dialog_list", py_dialog_list, METH_VARARGS, ""},
1229   {"rename_chat", py_rename_chat, METH_VARARGS, ""},
1230   {"send_msg", py_send_msg, METH_VARARGS, "send message to user or chat"},
1231   {"send_typing", py_send_typing, METH_VARARGS, ""},
1232   {"send_typing_abort", py_send_typing_abort, METH_VARARGS, ""},
1233   {"send_photo", py_send_photo, METH_VARARGS, ""},
1234   {"send_video", py_send_video, METH_VARARGS, ""},
1235   {"send_audio", py_send_audio, METH_VARARGS, ""},
1236   {"send_document", py_send_document, METH_VARARGS, ""},
1237   {"send_file", py_send_file, METH_VARARGS, ""},
1238   {"send_text", py_send_text, METH_VARARGS, ""},
1239   {"chat_set_photo", py_chat_set_photo, METH_VARARGS, ""},
1240   {"load_photo", py_load_photo, METH_VARARGS, ""},
1241   {"load_video", py_load_video, METH_VARARGS, ""},
1242   {"load_video_thumb", py_load_video_thumb, METH_VARARGS, ""},
1243   {"load_audio", py_load_audio, METH_VARARGS, ""},
1244   {"load_document", py_load_document, METH_VARARGS, ""},
1245   {"load_document_thumb", py_load_document_thumb, METH_VARARGS, ""},
1246   {"fwd_msg", py_fwd, METH_VARARGS, ""},
1247   {"fwd_media", py_fwd_media, METH_VARARGS, ""},
1248   {"chat_info", py_chat_info, METH_VARARGS, ""},
1249   {"user_info", py_user_info, METH_VARARGS, ""},
1250   {"get_history", py_history, METH_VARARGS, ""},
1251   {"chat_add_user", py_chat_add_user, METH_VARARGS, ""},
1252   {"chat_del_user", py_chat_del_user, METH_VARARGS, ""},
1253   {"add_contact", py_add_contact, METH_VARARGS, ""},
1254   {"del_contact", py_del_contact, METH_VARARGS, ""},
1255   {"rename_contact", py_rename_contact, METH_VARARGS, ""},
1256   {"msg_search", py_search, METH_VARARGS, ""},
1257   {"msg_global_search", py_global_search, METH_VARARGS, ""},
1258   {"mark_read", py_mark_read, METH_VARARGS, ""},
1259   {"set_profile_photo", py_set_profile_photo, METH_VARARGS, ""},
1260   {"set_profile_name", py_set_profile_name, METH_VARARGS, ""},
1261   {"create_secret_chat", py_create_secret_chat, METH_VARARGS, ""},
1262   {"create_group_chat", py_create_group_chat, METH_VARARGS, ""},
1263   {"delete_msg", py_delete_msg, METH_VARARGS, ""},
1264   {"restore_msg", py_restore_msg, METH_VARARGS, ""},
1265   {"accept_secret_chat", py_accept_secret_chat, METH_VARARGS, ""},
1266   {"send_contact", py_send_contact, METH_VARARGS, ""},
1267   {"status_online", py_status_online, METH_VARARGS, ""},
1268   {"status_offline", py_status_offline, METH_VARARGS, ""},
1269   {"send_location", py_send_location, METH_VARARGS, ""},
1270   {"ext_function", py_extf, METH_VARARGS, ""},
1271   {"import_chat_link", py_import_chat_link, METH_VARARGS, ""},
1272   {"set_on_binlog_replay_end", set_py_binlog_end, METH_VARARGS, ""},
1273   {"set_on_get_difference_end", set_py_diff_end, METH_VARARGS, ""},
1274   {"set_on_our_id", set_py_our_id, METH_VARARGS, ""},
1275   {"set_on_msg_receive", set_py_new_msg, METH_VARARGS, ""},
1276   {"set_on_msg_history", set_py_list_msg, METH_VARARGS, ""},
1277   {"set_on_secret_chat_update", set_py_secret_chat_update, METH_VARARGS, ""},
1278   {"set_on_user_update", set_py_user_update, METH_VARARGS, ""},
1279   {"set_on_chat_update", set_py_chat_update, METH_VARARGS, ""},
1280   {"set_on_loop", set_py_on_loop, METH_VARARGS, ""},
1281   {"set_link_preview", py_set_preview, METH_VARARGS, ""},
1282   {"safe_quit", py_safe_quit, METH_VARARGS, ""},
1283   {"safe_exit", py_safe_quit, METH_VARARGS, ""}, // Alias to safe_quit for naming consistancy in python.
1284   { NULL, NULL, 0, NULL }
1285 };
1286 
py_add_action_enums(PyObject * m)1287 void py_add_action_enums(PyObject *m)
1288 {
1289   PyModule_AddIntConstant(m, "ACTION_NONE", tgl_message_action_none);
1290   PyModule_AddIntConstant(m, "ACTION_GEO_CHAT_CREATE", tgl_message_action_geo_chat_create);
1291   PyModule_AddIntConstant(m, "ACTION_GEO_CHAT_CHECKIN", tgl_message_action_geo_chat_checkin);
1292   PyModule_AddIntConstant(m, "ACTION_CHAT_CREATE", tgl_message_action_chat_create);
1293   PyModule_AddIntConstant(m, "ACTION_CHAT_EDIT_TITLE", tgl_message_action_chat_edit_title);
1294   PyModule_AddIntConstant(m, "ACTION_CHAT_EDIT_PHOTO", tgl_message_action_chat_edit_photo);
1295   PyModule_AddIntConstant(m, "ACTION_CHAT_DELETE_PHOTO", tgl_message_action_chat_delete_photo);
1296   PyModule_AddIntConstant(m, "ACTION_CHAT_ADD_USER", tgl_message_action_chat_add_users);
1297   PyModule_AddIntConstant(m, "ACTION_CHAT_ADD_USER_BY_LINK", tgl_message_action_chat_add_user_by_link);
1298   PyModule_AddIntConstant(m, "ACTION_CHAT_DELETE_USER", tgl_message_action_chat_delete_user);
1299   PyModule_AddIntConstant(m, "ACTION_SET_MESSAGE_TTL", tgl_message_action_set_message_ttl);
1300   PyModule_AddIntConstant(m, "ACTION_READ_MESSAGES", tgl_message_action_read_messages);
1301   PyModule_AddIntConstant(m, "ACTION_DELETE_MESSAGES", tgl_message_action_delete_messages);
1302   PyModule_AddIntConstant(m, "ACTION_SCREENSHOT_MESSAGES", tgl_message_action_screenshot_messages);
1303   PyModule_AddIntConstant(m, "ACTION_FLUSH_HISTORY", tgl_message_action_flush_history);
1304   PyModule_AddIntConstant(m, "ACTION_RESEND", tgl_message_action_resend);
1305   PyModule_AddIntConstant(m, "ACTION_NOTIFY_LAYER", tgl_message_action_notify_layer);
1306   PyModule_AddIntConstant(m, "ACTION_TYPING", tgl_message_action_typing);
1307   PyModule_AddIntConstant(m, "ACTION_NOOP", tgl_message_action_noop);
1308   PyModule_AddIntConstant(m, "ACTION_COMMIT_KEY", tgl_message_action_commit_key);
1309   PyModule_AddIntConstant(m, "ACTION_ABORT_KEY", tgl_message_action_abort_key);
1310   PyModule_AddIntConstant(m, "ACTION_REQUEST_KEY", tgl_message_action_request_key);
1311   PyModule_AddIntConstant(m, "ACTION_ACCEPT_KEY", tgl_message_action_accept_key);
1312 }
1313 
py_add_peer_type_enums(PyObject * m)1314 void py_add_peer_type_enums(PyObject *m)
1315 {
1316   PyModule_AddIntConstant(m, "PEER_USER", TGL_PEER_USER);
1317   PyModule_AddIntConstant(m, "PEER_CHAT", TGL_PEER_CHAT);
1318   PyModule_AddIntConstant(m, "PEER_ENCR_CHAT", TGL_PEER_ENCR_CHAT);
1319 }
1320 
1321 
MOD_INIT(tgl)1322 MOD_INIT(tgl)
1323 {
1324   PyObject *m;
1325 
1326   MOD_DEF(m, "tgl", NULL, py_tgl_methods)
1327 
1328   if (m == NULL)
1329     return MOD_ERROR_VAL;
1330 
1331   py_add_action_enums(m);
1332   py_add_peer_type_enums(m);
1333 
1334   if (PyType_Ready(&tgl_PeerType) < 0)
1335     return MOD_ERROR_VAL;
1336 
1337   Py_INCREF(&tgl_PeerType);
1338   PyModule_AddObject(m, "Peer", (PyObject *)&tgl_PeerType);
1339 
1340   if (PyType_Ready(&tgl_MsgType) < 0)
1341     return MOD_ERROR_VAL;
1342 
1343   Py_INCREF(&tgl_MsgType);
1344   PyModule_AddObject(m, "Msg", (PyObject *)&tgl_MsgType);
1345 
1346   TglError = PyErr_NewException("tgl.Error", NULL, NULL);
1347   Py_INCREF(TglError);
1348   PyModule_AddObject(m, "TglError", TglError);
1349 
1350   PeerError = PyErr_NewException("tgl.PeerError", NULL, NULL);
1351   Py_INCREF(PeerError);
1352   PyModule_AddObject(m, "PeerError", PeerError);
1353 
1354   MsgError = PyErr_NewException("tgl.MsgError", NULL, NULL);
1355   Py_INCREF(MsgError);
1356   PyModule_AddObject(m, "MsgError", MsgError);
1357 
1358   return MOD_SUCCESS_VAL(m);
1359 }
1360 
1361 
py_init(const char * file)1362 void py_init (const char *file) {
1363   if (!file) { return; }
1364   python_loaded = 0;
1365 
1366   PyObject *pModule;
1367 
1368   // Get a copy of the filename for dirname/basename, which may modify the string, and break const correctness
1369   char filename[1024];
1370   strncpy(filename, file, 1024);
1371 
1372 
1373 
1374 #if PY_MAJOR_VERSION >= 3
1375   PyImport_AppendInittab("tgl", &PyInit_tgl);
1376   Py_Initialize();
1377 #else
1378   Py_Initialize();
1379   inittgl();
1380 #endif
1381 
1382 
1383   PyObject* sysPath = PySys_GetObject((char*)"path");
1384   PyList_Append(sysPath, PyUnicode_FromString(dirname(filename)));
1385 
1386   // Recopy the string in, since dirname modified it.
1387   strncpy(filename, file, 1024);
1388 
1389   // remove .py extension from file, if any
1390   char* dot = strrchr(filename, '.');
1391   if (dot && strcmp(dot, ".py") == 0)
1392     *dot = 0;
1393   pModule = PyImport_Import(PyUnicode_FromString(basename(filename)));
1394 
1395   if(pModule == NULL || PyErr_Occurred()) { // Error loading script
1396     logprintf("Failed to load python script\n");
1397     PyErr_Print();
1398     exit(1);
1399   }
1400 
1401 
1402   python_loaded = 1;
1403   PyDateTime_IMPORT;
1404   logprintf("Python Initialized\n");
1405 }
1406 
1407 #endif
1408