1 /**
2  * @file   core.c
3  * @author Wei-Ning Huang (AZ) <aitjcize@gmail.com>
4  *
5  * Copyright (C) 2013 - 2014  Wei-Ning Huang (AZ) <aitjcize@gmail.com>
6  * All Rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include "core.h"
24 #include "util.h"
25 
26 #if PY_MAJOR_VERSION < 3
27 # define BUF_TC "s"
28 #else
29 # define BUF_TC "y"
30 #endif
31 
callback_log(Tox * tox,TOX_LOG_LEVEL level,const char * file,uint32_t line,const char * func,const char * message,void * self)32 static void callback_log(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func,
33                          const char *message, void* self)
34 {
35     PyObject_CallMethod((PyObject*)self, "on_log", "isiss", level, file, line,
36                         func, message);
37 }
38 
callback_self_connection_status(Tox * tox,TOX_CONNECTION connection_status,void * self)39 static void callback_self_connection_status(Tox* tox, TOX_CONNECTION connection_status,
40                                             void *self)
41 {
42     PyObject_CallMethod((PyObject*)self, "on_self_connection_status", "i",
43                         connection_status);
44 }
45 
callback_friend_request(Tox * tox,const uint8_t * public_key,const uint8_t * data,size_t length,void * self)46 static void callback_friend_request(Tox* tox, const uint8_t* public_key,
47                                     const uint8_t* data, size_t length, void* self)
48 {
49   uint8_t buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
50   memset(buf, 0, TOX_PUBLIC_KEY_SIZE * 2 + 1);
51 
52   bytes_to_hex_string(public_key, TOX_PUBLIC_KEY_SIZE, buf);
53 
54   PyObject_CallMethod((PyObject*)self, "on_friend_request", "ss#", buf, data,
55       length - (data[length - 1] == 0));
56 }
57 
callback_friend_message(Tox * tox,uint32_t friendnumber,TOX_MESSAGE_TYPE type,const uint8_t * message,size_t length,void * self)58 static void callback_friend_message(Tox *tox, uint32_t friendnumber, TOX_MESSAGE_TYPE type,
59                                     const uint8_t* message, size_t length, void* self)
60 {
61     PyObject_CallMethod((PyObject*)self, "on_friend_message", "iis#", friendnumber, type,
62                         message, length - (message[length - 1] == 0));
63 }
64 
callback_friend_name(Tox * tox,uint32_t friendnumber,const uint8_t * newname,size_t length,void * self)65 static void callback_friend_name(Tox *tox, uint32_t friendnumber,
66                                  const uint8_t* newname, size_t length, void* self)
67 {
68   PyObject_CallMethod((PyObject*)self, "on_friend_name", "is#", friendnumber,
69       newname, length - (newname[length - 1] == 0));
70 }
71 
callback_friend_status_message(Tox * tox,uint32_t friendnumber,const uint8_t * newstatus,size_t length,void * self)72 static void callback_friend_status_message(Tox *tox, uint32_t friendnumber,
73                                            const uint8_t *newstatus, size_t length, void* self)
74 {
75   PyObject_CallMethod((PyObject*)self, "on_friend_status_message", "is#", friendnumber,
76       newstatus, length - (newstatus[length - 1] == 0));
77 }
78 
callback_friend_status(Tox * tox,uint32_t friendnumber,TOX_USER_STATUS status,void * self)79 static void callback_friend_status(Tox *tox, uint32_t friendnumber, TOX_USER_STATUS status,
80                                    void* self)
81 {
82   PyObject_CallMethod((PyObject*)self, "on_friend_status", "ii", friendnumber,
83       status);
84 }
85 
callback_friend_typing(Tox * tox,uint32_t friendnumber,bool is_typing,void * self)86 static void callback_friend_typing(Tox *tox, uint32_t friendnumber,
87     bool is_typing, void* self)
88 {
89   PyObject_CallMethod((PyObject*)self, "on_friend_typing", "iO", friendnumber,
90       PyBool_FromLong(is_typing));
91 }
92 
callback_friend_read_receipt(Tox * tox,uint32_t friendnumber,uint32_t receipt,void * self)93 static void callback_friend_read_receipt(Tox *tox, uint32_t friendnumber,
94     uint32_t receipt, void* self)
95 {
96   PyObject_CallMethod((PyObject*)self, "on_friend_read_receipt", "ii", friendnumber,
97       receipt);
98 }
99 
callback_friend_connection_status(Tox * tox,uint32_t friendnumber,TOX_CONNECTION status,void * self)100 static void callback_friend_connection_status(Tox *tox, uint32_t friendnumber,
101     TOX_CONNECTION status, void* self)
102 {
103   PyObject_CallMethod((PyObject*)self, "on_friend_connection_status", "iO",
104       friendnumber, PyBool_FromLong(status));
105 }
106 
callback_conference_invite(Tox * tox,uint32_t friendnumber,TOX_CONFERENCE_TYPE type,const uint8_t * data,size_t length,void * self)107 static void callback_conference_invite(Tox *tox, uint32_t friendnumber, TOX_CONFERENCE_TYPE type,
108     const uint8_t *data, size_t length, void *self)
109 {
110   PyObject_CallMethod((PyObject*)self, "on_conference_invite", "ii" BUF_TC "#",
111       friendnumber, type, data, length);
112 }
113 
callback_conference_message(Tox * tox,uint32_t conference_number,uint32_t peer_number,TOX_MESSAGE_TYPE type,const uint8_t * message,size_t length,void * self)114 static void callback_conference_message(Tox *tox, uint32_t conference_number,
115     uint32_t peer_number, TOX_MESSAGE_TYPE type, const uint8_t* message, size_t length, void *self)
116 {
117   PyObject_CallMethod((PyObject*)self, "on_conference_message", "iiis#", conference_number,
118       peer_number, type, message, length - (message[length - 1] == 0));
119 }
120 
callback_conference_peer_name(Tox * tox,uint32_t conference_number,uint32_t peer_number,const uint8_t * name,size_t length,void * self)121 static void callback_conference_peer_name(Tox *tox, uint32_t conference_number,
122     uint32_t peer_number, const uint8_t *name, size_t length, void *self)
123 {
124   PyObject_CallMethod((PyObject*)self, "on_conference_peer_name", "ii" BUF_TC "#",
125       conference_number, peer_number, name, length);
126 }
127 
callback_conference_peer_list_changed(Tox * tox,uint32_t conference_number,void * self)128 static void callback_conference_peer_list_changed(Tox *tox, uint32_t conference_number, void *self)
129 {
130   PyObject_CallMethod((PyObject*)self, "on_conference_peer_list_changed", "i",
131       conference_number);
132 }
133 
callback_file_chunk_request(Tox * tox,uint32_t friend_number,uint32_t file_number,uint64_t position,size_t length,void * self)134 static void callback_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number,
135                                         uint64_t position, size_t length, void *self)
136 {
137     PyObject_CallMethod((PyObject*)self, "on_file_chunk_request", "iiKi",
138                         friend_number, file_number, position, length);
139 }
140 
141 
callback_file_recv(Tox * tox,uint32_t friend_number,uint32_t file_number,uint32_t kind,uint64_t file_size,const uint8_t * filename,size_t filename_length,void * self)142 static void callback_file_recv(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind,
143                                uint64_t file_size,
144                                const uint8_t *filename, size_t filename_length, void *self)
145 {
146     if (kind == TOX_FILE_KIND_AVATAR && filename != NULL) {
147         assert(TOX_HASH_LENGTH == filename_length);
148         char filename_hex[TOX_HASH_LENGTH * 2 + 1];
149         memset(filename_hex, 0, TOX_HASH_LENGTH * 2 + 1);
150         bytes_to_hex_string(filename, filename_length, (uint8_t*)filename_hex);
151 
152         PyObject_CallMethod((PyObject*)self, "on_file_recv", "iiiKs#",
153                             friend_number, file_number, kind, file_size, filename_hex, TOX_HASH_LENGTH * 2);
154     } else {
155         PyObject_CallMethod((PyObject*)self, "on_file_recv", "iiiKs#",
156                             friend_number, file_number, kind, file_size, filename, filename_length);
157     }
158 }
159 
callback_file_recv_control(Tox * tox,uint32_t friend_number,uint32_t file_number,TOX_FILE_CONTROL control,void * self)160 static void callback_file_recv_control(Tox *tox, uint32_t friend_number, uint32_t file_number,
161                                        TOX_FILE_CONTROL control, void *self)
162 {
163     PyObject_CallMethod((PyObject*)self, "on_file_recv_control", "iii",
164                         friend_number, file_number, control);
165 }
166 
callback_file_recv_chunk(Tox * tox,uint32_t friend_number,uint32_t file_number,uint64_t position,const uint8_t * data,size_t length,void * self)167 static void callback_file_recv_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number,
168                                      uint64_t position,
169                                      const uint8_t *data, size_t length, void *self)
170 {
171     PyObject_CallMethod((PyObject*)self, "on_file_recv_chunk", "iiK" BUF_TC "#",
172                         friend_number, file_number, position, data, length);
173 }
174 
init_options(ToxCore * self,PyObject * pyopts,struct Tox_Options * tox_opts)175 static void init_options(ToxCore* self, PyObject* pyopts, struct Tox_Options* tox_opts)
176 {
177     char *buf = NULL;
178     Py_ssize_t sz = 0;
179     PyObject *p = NULL;
180 
181     p = PyObject_GetAttrString(pyopts, "savedata_data");
182     PyBytes_AsStringAndSize(p, &buf, &sz);
183     if (sz > 0) {
184         uint8_t *savedata_data = calloc(1, sz); /* XXX: Memory leak! */
185         memcpy(savedata_data, buf, sz);
186         tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
187         tox_options_set_savedata_data(tox_opts, savedata_data, sz);
188     }
189 
190     p = PyObject_GetAttrString(pyopts, "proxy_host");
191     PyStringUnicode_AsStringAndSize(p, &buf, &sz);
192     if (sz > 0) {
193         char *proxy_host = calloc(1, sz); /* XXX: Memory leak! */
194         memcpy(proxy_host, buf, sz);
195         tox_options_set_proxy_host(tox_opts, proxy_host);
196     }
197 
198     p = PyObject_GetAttrString(pyopts, "proxy_port");
199     if (p) {
200         tox_options_set_proxy_port(tox_opts, PyLong_AsLong(p));
201     }
202 
203     p = PyObject_GetAttrString(pyopts, "proxy_type");
204     if (p) {
205         tox_options_set_proxy_type(tox_opts, PyLong_AsLong(p));
206     }
207 
208     p = PyObject_GetAttrString(pyopts, "ipv6_enabled");
209     if (p) {
210         tox_options_set_ipv6_enabled(tox_opts, p == Py_True);
211     }
212 
213     p = PyObject_GetAttrString(pyopts, "udp_enabled");
214     if (p) {
215         tox_options_set_udp_enabled(tox_opts, p == Py_True);
216     }
217 
218     p = PyObject_GetAttrString(pyopts, "start_port");
219     if (p) {
220         tox_options_set_start_port(tox_opts, PyLong_AsLong(p));
221     }
222 
223     p = PyObject_GetAttrString(pyopts, "end_port");
224     if (p) {
225         tox_options_set_end_port(tox_opts, PyLong_AsLong(p));
226     }
227 
228     p = PyObject_GetAttrString(pyopts, "tcp_port");
229     if (p) {
230         tox_options_set_tcp_port(tox_opts, PyLong_AsLong(p));
231     }
232 
233     tox_options_set_log_callback(tox_opts, callback_log);
234     tox_options_set_log_user_data(tox_opts, self);
235 }
236 
init_helper(ToxCore * self,PyObject * args)237 static int init_helper(ToxCore* self, PyObject* args)
238 {
239   if (self->tox != NULL) {
240     tox_kill(self->tox);
241     self->tox = NULL;
242   }
243 
244   PyObject *opts = NULL;
245 
246   if (args) {
247       if (!PyArg_ParseTuple(args, "O", &opts)) {
248           PyErr_SetString(PyExc_TypeError, "must supply a ToxOptions param");
249           return -1;
250       }
251   }
252 
253   struct Tox_Options *options = tox_options_new(NULL);
254 
255   if (opts != NULL) {
256       init_options(self, opts, options);
257   }
258 
259   TOX_ERR_NEW err = 0;
260   Tox* tox = tox_new(options, &err);
261   tox_options_free(options);
262 
263   if (tox == NULL) {
264       PyErr_Format(ToxOpError, "failed to initialize toxcore: %d", err);
265       return -1;
266   }
267 
268   tox_callback_self_connection_status(tox, callback_self_connection_status);
269   tox_callback_friend_request(tox, callback_friend_request);
270   tox_callback_friend_message(tox, callback_friend_message);
271   tox_callback_friend_name(tox, callback_friend_name);
272   tox_callback_friend_status_message(tox, callback_friend_status_message);
273   tox_callback_friend_status(tox, callback_friend_status);
274   tox_callback_friend_typing(tox, callback_friend_typing);
275   tox_callback_friend_read_receipt(tox, callback_friend_read_receipt);
276   tox_callback_friend_connection_status(tox, callback_friend_connection_status);
277   tox_callback_conference_invite(tox, callback_conference_invite);
278   tox_callback_conference_message(tox, callback_conference_message);
279   tox_callback_conference_peer_name(tox, callback_conference_peer_name);
280   tox_callback_conference_peer_list_changed(tox, callback_conference_peer_list_changed);
281   tox_callback_file_chunk_request(tox, callback_file_chunk_request);
282   tox_callback_file_recv_control(tox, callback_file_recv_control);
283   tox_callback_file_recv(tox, callback_file_recv);
284   tox_callback_file_recv_chunk(tox, callback_file_recv_chunk);
285 
286   self->tox = tox;
287 
288   return 0;
289 }
290 
291 static PyObject*
ToxCore_new(PyTypeObject * type,PyObject * args,PyObject * kwds)292 ToxCore_new(PyTypeObject *type, PyObject* args, PyObject* kwds)
293 {
294   ToxCore* self = (ToxCore*)type->tp_alloc(type, 0);
295   self->tox = NULL;
296 
297   /* We don't care about subclass's arguments */
298   if (init_helper(self, NULL) == -1) {
299     return NULL;
300   }
301 
302   return (PyObject*)self;
303 }
304 
ToxCore_init(ToxCore * self,PyObject * args,PyObject * kwds)305 static int ToxCore_init(ToxCore* self, PyObject* args, PyObject* kwds)
306 {
307   /* since __init__ in Python is optional(superclass need to call it
308    * explicitly), we need to initialize self->tox in ToxCore_new instead of
309    * init. If ToxCore_init is called, we re-initialize self->tox and pass
310    * the new ipv6enabled setting. */
311   return init_helper(self, args);
312 }
313 
314 static int
ToxCore_dealloc(ToxCore * self)315 ToxCore_dealloc(ToxCore* self)
316 {
317   if (self->tox) {
318     tox_kill(self->tox);
319     self->tox = NULL;
320   }
321   return 0;
322 }
323 
324 static PyObject*
ToxCore_callback_stub(ToxCore * self,PyObject * args)325 ToxCore_callback_stub(ToxCore* self, PyObject* args)
326 {
327   Py_RETURN_NONE;
328 }
329 
330 static PyObject*
ToxCore_self_get_address(ToxCore * self,PyObject * args)331 ToxCore_self_get_address(ToxCore* self, PyObject* args)
332 {
333   CHECK_TOX(self);
334 
335   uint8_t address[TOX_ADDRESS_SIZE];
336   uint8_t address_hex[TOX_ADDRESS_SIZE * 2 + 1];
337   memset(address_hex, 0, TOX_ADDRESS_SIZE * 2 + 1);
338 
339   tox_self_get_address(self->tox, address);
340   bytes_to_hex_string(address, TOX_ADDRESS_SIZE, address_hex);
341 
342   return PYSTRING_FromString((const char*)address_hex);
343 }
344 
345 static PyObject*
ToxCore_friend_add(ToxCore * self,PyObject * args)346 ToxCore_friend_add(ToxCore* self, PyObject* args)
347 {
348   CHECK_TOX(self);
349 
350   uint8_t* address = NULL;
351   int addr_length = 0;
352   uint8_t* data = NULL;
353   int data_length = 0;
354 
355   if (!PyArg_ParseTuple(args, "s#s#", &address, &addr_length, &data,
356         &data_length)) {
357     return NULL;
358   }
359 
360   uint8_t pk[TOX_ADDRESS_SIZE];
361   hex_string_to_bytes(address, TOX_ADDRESS_SIZE, pk);
362 
363   TOX_ERR_FRIEND_ADD err = 0;
364   uint32_t friend_number = 0;
365   friend_number = tox_friend_add(self->tox, pk, data, data_length, &err);
366   int success = friend_number == UINT32_MAX ? 0 : 1;
367 
368   switch (err) {
369   case TOX_ERR_FRIEND_ADD_TOO_LONG:
370     PyErr_SetString(ToxOpError, "message too long");
371     break;
372   case TOX_ERR_FRIEND_ADD_NO_MESSAGE:
373     PyErr_SetString(ToxOpError, "no message specified");
374     break;
375   case TOX_ERR_FRIEND_ADD_OWN_KEY:
376     PyErr_SetString(ToxOpError, "user's own key");
377     break;
378   case TOX_ERR_FRIEND_ADD_ALREADY_SENT:
379     PyErr_SetString(ToxOpError, "friend request already sent or already "
380         "a friend");
381     break;
382   case TOX_ERR_FRIEND_ADD_NULL:
383     PyErr_SetString(ToxOpError, "unknown error");
384     break;
385   case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:
386     PyErr_SetString(ToxOpError, "bad checksum in address");
387     break;
388   case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:
389     PyErr_SetString(ToxOpError, "the friend was already there but the "
390         "nospam was different");
391     break;
392   case TOX_ERR_FRIEND_ADD_MALLOC:
393     PyErr_SetString(ToxOpError, "increasing the friend list size fails");
394     break;
395   case TOX_ERR_FRIEND_ADD_OK:
396 #if 0
397       success = 1;
398 #endif
399       break;
400   }
401 
402   if (success) {
403     return PyLong_FromLong(friend_number);
404   } else {
405     return NULL;
406   }
407 }
408 
409 static PyObject*
ToxCore_friend_add_norequest(ToxCore * self,PyObject * args)410 ToxCore_friend_add_norequest(ToxCore* self, PyObject* args)
411 {
412   CHECK_TOX(self);
413 
414   uint8_t* address = NULL;
415   int addr_length = 0;
416 
417   if (!PyArg_ParseTuple(args, "s#", &address, &addr_length)) {
418     return NULL;
419   }
420 
421   uint8_t pk[TOX_ADDRESS_SIZE];
422   hex_string_to_bytes(address, TOX_ADDRESS_SIZE, pk);
423 
424   TOX_ERR_FRIEND_ADD err = 0;
425   int res = tox_friend_add_norequest(self->tox, pk, &err);
426   if (res == -1) {
427     PyErr_Format(ToxOpError, "failed to add friend: %d", err);
428     return NULL;
429   }
430 
431   return PyLong_FromLong(res);
432 }
433 
434 static PyObject*
ToxCore_friend_by_public_key(ToxCore * self,PyObject * args)435 ToxCore_friend_by_public_key(ToxCore* self, PyObject* args)
436 {
437   CHECK_TOX(self);
438 
439   uint8_t* id = NULL;
440   int addr_length = 0;
441 
442   if (!PyArg_ParseTuple(args, "s#", &id, &addr_length)) {
443     return NULL;
444   }
445 
446   uint8_t pk[TOX_PUBLIC_KEY_SIZE];
447   hex_string_to_bytes(id, TOX_PUBLIC_KEY_SIZE, pk);
448 
449   int ret = tox_friend_by_public_key(self->tox, pk, NULL);
450   if (ret == -1) {
451     PyErr_SetString(ToxOpError, "no such friend");
452     return NULL;
453   }
454 
455   return PyLong_FromLong(ret);
456 }
457 
458 static PyObject*
ToxCore_friend_get_public_key(ToxCore * self,PyObject * args)459 ToxCore_friend_get_public_key(ToxCore* self, PyObject* args)
460 {
461   CHECK_TOX(self);
462 
463   uint8_t pk[TOX_PUBLIC_KEY_SIZE + 1];
464   pk[TOX_PUBLIC_KEY_SIZE] = 0;
465 
466   uint8_t hex[TOX_PUBLIC_KEY_SIZE * 2 + 1];
467   memset(hex, 0, TOX_PUBLIC_KEY_SIZE * 2 + 1);
468 
469   int friend_num = 0;
470 
471   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
472     return NULL;
473   }
474 
475   tox_friend_get_public_key(self->tox, friend_num, pk, NULL);
476   bytes_to_hex_string(pk, TOX_PUBLIC_KEY_SIZE, hex);
477 
478   return PYSTRING_FromString((const char*)hex);
479 }
480 
481 static PyObject*
ToxCore_friend_delete(ToxCore * self,PyObject * args)482 ToxCore_friend_delete(ToxCore* self, PyObject* args)
483 {
484   CHECK_TOX(self);
485 
486   int friend_num = 0;
487 
488   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
489     return NULL;
490   }
491 
492   if (tox_friend_delete(self->tox, friend_num, NULL) == false) {
493     PyErr_SetString(ToxOpError, "failed to delete friend");
494     return NULL;
495   }
496 
497   Py_RETURN_TRUE;
498 }
499 
500 static PyObject*
ToxCore_friend_get_connection_status(ToxCore * self,PyObject * args)501 ToxCore_friend_get_connection_status(ToxCore* self, PyObject* args)
502 {
503   CHECK_TOX(self);
504 
505   int friend_num = 0;
506 
507   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
508     return NULL;
509   }
510 
511   int ret = tox_friend_get_connection_status(self->tox, friend_num, NULL);
512   if (ret == -1) {
513     PyErr_SetString(ToxOpError, "failed to get connection status");
514     return NULL;
515   }
516 
517   return PyBool_FromLong(ret);
518 }
519 
520 static PyObject*
ToxCore_friend_exists(ToxCore * self,PyObject * args)521 ToxCore_friend_exists(ToxCore* self, PyObject* args)
522 {
523   CHECK_TOX(self);
524 
525   int friend_num = 0;
526 
527   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
528     return NULL;
529   }
530 
531   int ret = tox_friend_exists(self->tox, friend_num);
532 
533   return PyBool_FromLong(ret);
534 }
535 
536 static PyObject*
ToxCore_friend_send_message(ToxCore * self,PyObject * args)537 ToxCore_friend_send_message(ToxCore* self, PyObject* args)
538 {
539   CHECK_TOX(self);
540 
541   int friend_num = 0;
542   int msg_type = 0;
543   int length = 0;
544   uint8_t* message = NULL;
545 
546   if (!PyArg_ParseTuple(args, "iis#", &friend_num, &msg_type, &message, &length)) {
547     return NULL;
548   }
549 
550   TOX_MESSAGE_TYPE type = msg_type;
551   TOX_ERR_FRIEND_SEND_MESSAGE errmsg = 0;
552   uint32_t ret = tox_friend_send_message(self->tox, friend_num, type, message, length, &errmsg);
553   if (ret == 0) {
554      PyErr_SetString(ToxOpError, "failed to send message");
555     return NULL;
556   }
557 
558   return PyLong_FromUnsignedLong(ret);
559 }
560 
561 static PyObject*
ToxCore_self_set_name(ToxCore * self,PyObject * args)562 ToxCore_self_set_name(ToxCore* self, PyObject* args)
563 {
564   CHECK_TOX(self);
565 
566   uint8_t* name = 0;
567   int length = 0;
568 
569   if (!PyArg_ParseTuple(args, "s#", &name, &length)) {
570     return NULL;
571   }
572 
573   if (tox_self_set_name(self->tox, name, length, NULL) == false) {
574     PyErr_SetString(ToxOpError, "failed to set_name");
575     return NULL;
576   }
577 
578   Py_RETURN_TRUE;
579 }
580 
581 static PyObject*
ToxCore_self_get_name(ToxCore * self,PyObject * args)582 ToxCore_self_get_name(ToxCore* self, PyObject* args)
583 {
584   CHECK_TOX(self);
585 
586   uint8_t buf[TOX_MAX_NAME_LENGTH];
587   memset(buf, 0, TOX_MAX_NAME_LENGTH);
588 
589   tox_self_get_name(self->tox, buf);
590 
591   return PYSTRING_FromString((const char*)buf);
592 }
593 
594 static PyObject*
ToxCore_self_get_name_size(ToxCore * self,PyObject * args)595 ToxCore_self_get_name_size(ToxCore* self, PyObject* args)
596 {
597   CHECK_TOX(self);
598 
599   int ret = tox_self_get_name_size(self->tox);
600   if (ret == -1) {
601     PyErr_SetString(ToxOpError, "failed to get self name size");
602     return NULL;
603   }
604 
605   return PyLong_FromUnsignedLong(ret);
606 }
607 
608 static PyObject*
ToxCore_friend_get_name(ToxCore * self,PyObject * args)609 ToxCore_friend_get_name(ToxCore* self, PyObject* args)
610 {
611   CHECK_TOX(self);
612 
613   int friend_num = 0;
614   uint8_t buf[TOX_MAX_NAME_LENGTH];
615   memset(buf, 0, TOX_MAX_NAME_LENGTH);
616 
617   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
618     return NULL;
619   }
620 
621   if (tox_friend_get_name(self->tox, friend_num, buf, NULL) == false) {
622     PyErr_SetString(ToxOpError, "failed to get name");
623     return NULL;
624   }
625 
626   return PYSTRING_FromString((const char*)buf);
627 }
628 
629 static PyObject*
ToxCore_friend_get_name_size(ToxCore * self,PyObject * args)630 ToxCore_friend_get_name_size(ToxCore* self, PyObject* args)
631 {
632   CHECK_TOX(self);
633 
634   int friend_num = 0;
635 
636   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
637     return NULL;
638   }
639 
640   int ret = tox_friend_get_name_size(self->tox, friend_num, NULL);
641   if (ret == -1) {
642     PyErr_SetString(ToxOpError, "failed to get name size");
643     return NULL;
644   }
645 
646   return PyLong_FromUnsignedLong(ret);
647 }
648 
649 static PyObject*
ToxCore_self_set_status_message(ToxCore * self,PyObject * args)650 ToxCore_self_set_status_message(ToxCore* self, PyObject* args)
651 {
652   CHECK_TOX(self);
653 
654   uint8_t* message;
655   int length;
656   if (!PyArg_ParseTuple(args, "s#", &message, &length)) {
657     return NULL;
658   }
659 
660   if (tox_self_set_status_message(self->tox, message, length, NULL) == false) {
661     PyErr_SetString(ToxOpError, "failed to set status_message");
662     return NULL;
663   }
664 
665   Py_RETURN_TRUE;
666 }
667 
668 static PyObject*
ToxCore_self_set_status(ToxCore * self,PyObject * args)669 ToxCore_self_set_status(ToxCore* self, PyObject* args)
670 {
671   CHECK_TOX(self);
672 
673   int status = 0;
674 
675   if (!PyArg_ParseTuple(args, "i", &status)) {
676     return NULL;
677   }
678 
679   tox_self_set_status(self->tox, status);
680   if (true == false) {
681     PyErr_SetString(ToxOpError, "failed to set status");
682     return NULL;
683   }
684 
685   Py_RETURN_NONE;
686 }
687 
688 
689 static PyObject*
ToxCore_friend_get_status_message_size(ToxCore * self,PyObject * args)690 ToxCore_friend_get_status_message_size(ToxCore* self, PyObject* args)
691 {
692   CHECK_TOX(self);
693 
694   int friend_num = 0;
695   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
696     return NULL;
697   }
698 
699   int ret = tox_friend_get_status_message_size(self->tox, friend_num, NULL);
700   return PyLong_FromLong(ret);
701 }
702 
703 static PyObject*
ToxCore_friend_get_status_message(ToxCore * self,PyObject * args)704 ToxCore_friend_get_status_message(ToxCore* self, PyObject* args)
705 {
706   CHECK_TOX(self);
707 
708   uint8_t buf[TOX_MAX_STATUS_MESSAGE_LENGTH];
709   int friend_num = 0;
710 
711   memset(buf, 0, TOX_MAX_STATUS_MESSAGE_LENGTH);
712 
713   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
714     return NULL;
715   }
716 
717   int ret = tox_friend_get_status_message(self->tox, friend_num, buf, NULL);
718 
719   if (ret == -1) {
720     PyErr_SetString(ToxOpError, "failed to get status_message");
721     return NULL;
722   }
723 
724   buf[TOX_MAX_STATUS_MESSAGE_LENGTH -1] = 0;
725 
726   return PYSTRING_FromString((const char*)buf);
727 }
728 
729 static PyObject*
ToxCore_self_get_status_message(ToxCore * self,PyObject * args)730 ToxCore_self_get_status_message(ToxCore* self, PyObject* args)
731 {
732   CHECK_TOX(self);
733 
734   uint8_t buf[TOX_MAX_STATUS_MESSAGE_LENGTH];
735   memset(buf, 0, TOX_MAX_STATUS_MESSAGE_LENGTH);
736 
737   tox_self_get_status_message(self->tox, buf);
738   buf[TOX_MAX_STATUS_MESSAGE_LENGTH -1] = 0;
739 
740   return PYSTRING_FromString((const char*)buf);
741 }
742 
743 static PyObject*
ToxCore_self_get_status_message_size(ToxCore * self,PyObject * args)744 ToxCore_self_get_status_message_size(ToxCore* self, PyObject* args)
745 {
746   CHECK_TOX(self);
747 
748   int ret = tox_self_get_status_message_size(self->tox);
749   if (ret == -1) {
750     PyErr_SetString(ToxOpError, "failed to get self status_message size");
751     return NULL;
752   }
753 
754   return PyLong_FromLong(ret);
755 }
756 
757 static PyObject*
ToxCore_friend_get_status(ToxCore * self,PyObject * args)758 ToxCore_friend_get_status(ToxCore* self, PyObject* args)
759 {
760   CHECK_TOX(self);
761 
762   int friend_num = 0;
763   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
764     return NULL;
765   }
766 
767   int status = tox_friend_get_status(self->tox, friend_num, NULL);
768 
769   return PyLong_FromLong(status);
770 }
771 
772 static PyObject*
ToxCore_self_get_status(ToxCore * self,PyObject * args)773 ToxCore_self_get_status(ToxCore* self, PyObject* args)
774 {
775   CHECK_TOX(self);
776 
777   int status = tox_self_get_status(self->tox);
778   return PyLong_FromLong(status);
779 }
780 
781 static PyObject*
ToxCore_friend_get_last_online(ToxCore * self,PyObject * args)782 ToxCore_friend_get_last_online(ToxCore* self, PyObject* args)
783 {
784   CHECK_TOX(self);
785 
786   int friend_num = 0;
787   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
788     return NULL;
789   }
790 
791   uint64_t status = tox_friend_get_last_online(self->tox, friend_num, NULL);
792 
793   if (status == 0) {
794     Py_RETURN_NONE;
795   }
796 
797   PyObject* datetime = PyImport_ImportModule("datetime");
798   PyObject* datetimeClass = PyObject_GetAttrString(datetime, "datetime");
799   PyObject* ret = PyObject_CallMethod(datetimeClass, "fromtimestamp", "K", status);
800 
801   return ret;
802 }
803 
804 static PyObject*
ToxCore_self_set_typing(ToxCore * self,PyObject * args)805 ToxCore_self_set_typing(ToxCore* self, PyObject* args)
806 {
807   CHECK_TOX(self);
808 
809   int friend_num = 0;
810   int is_typing = 0;
811 
812   if (!PyArg_ParseTuple(args, "ii", &friend_num, &is_typing)) {
813     return NULL;
814   }
815 
816   int status = tox_self_set_typing(self->tox, friend_num, is_typing, NULL);
817   return PyLong_FromLong(status);
818 }
819 
820 static PyObject*
ToxCore_friend_get_typing(ToxCore * self,PyObject * args)821 ToxCore_friend_get_typing(ToxCore* self, PyObject* args)
822 {
823   CHECK_TOX(self);
824 
825   int friend_num = 0;
826 
827   if (!PyArg_ParseTuple(args, "i", &friend_num)) {
828     return NULL;
829   }
830 
831   if (tox_friend_get_typing(self->tox, friend_num, NULL)) {
832     Py_RETURN_TRUE;
833   } else {
834     Py_RETURN_FALSE;
835   }
836 }
837 
838 static PyObject*
ToxCore_self_get_friend_list_size(ToxCore * self,PyObject * args)839 ToxCore_self_get_friend_list_size(ToxCore* self, PyObject* args)
840 {
841   CHECK_TOX(self);
842 
843   uint32_t count = tox_self_get_friend_list_size(self->tox);
844   return PyLong_FromUnsignedLong(count);
845 }
846 
847 static PyObject*
ToxCore_self_get_friend_list(ToxCore * self,PyObject * args)848 ToxCore_self_get_friend_list(ToxCore* self, PyObject* args)
849 {
850   CHECK_TOX(self);
851 
852   uint32_t count = tox_self_get_friend_list_size(self->tox);
853   uint32_t* list = (uint32_t*)malloc(count * sizeof(uint32_t));
854   if (!list) {
855     return NULL;
856   }
857 
858   uint32_t n = count;
859   tox_self_get_friend_list(self->tox, list);
860 
861   PyObject* plist = PyList_New(0);
862   if (!plist) {
863     free(list);
864     return NULL;
865   }
866 
867   uint32_t i = 0;
868   for (i = 0; i < n; ++i) {
869     PyList_Append(plist, PyLong_FromLong(list[i]));
870   }
871   free(list);
872 
873   return plist;
874 }
875 
876 static PyObject*
ToxCore_conference_new(ToxCore * self,PyObject * args)877 ToxCore_conference_new(ToxCore* self, PyObject* args)
878 {
879   CHECK_TOX(self);
880 
881   TOX_ERR_CONFERENCE_NEW error;
882   uint32_t conference_number = tox_conference_new(self->tox, &error);
883   if (error != TOX_ERR_CONFERENCE_NEW_OK) {
884     PyErr_SetString(ToxOpError, "failed to create conference");
885   }
886 
887   return PyLong_FromLong(conference_number);
888 }
889 
890 static PyObject*
ToxCore_conference_delete(ToxCore * self,PyObject * args)891 ToxCore_conference_delete(ToxCore* self, PyObject* args)
892 {
893   CHECK_TOX(self);
894 
895   int conference_number = 0;
896 
897   if (!PyArg_ParseTuple(args, "i", &conference_number)) {
898     return NULL;
899   }
900 
901   TOX_ERR_CONFERENCE_DELETE error;
902   tox_conference_delete(self->tox, conference_number, &error);
903   if (error != TOX_ERR_CONFERENCE_DELETE_OK) {
904     PyErr_SetString(ToxOpError, "failed to delete conference");
905   }
906 
907   Py_RETURN_NONE;
908 }
909 
910 static PyObject*
ToxCore_conference_get_title(ToxCore * self,PyObject * args)911 ToxCore_conference_get_title(ToxCore* self, PyObject* args)
912 {
913   CHECK_TOX(self);
914 
915   int conference_number = 0;
916   if (!PyArg_ParseTuple(args, "i", &conference_number)) {
917     return NULL;
918   }
919 
920   uint8_t buf[TOX_MAX_NAME_LENGTH];
921   memset(buf, 0, TOX_MAX_NAME_LENGTH);
922 
923   TOX_ERR_CONFERENCE_TITLE error;
924   tox_conference_get_title(self->tox, conference_number, buf, &error);
925   if (error != TOX_ERR_CONFERENCE_TITLE_OK) {
926     return PYSTRING_FromString("");  /* no title. */
927   }
928 
929   return PYSTRING_FromString((const char*)buf);
930 }
931 
932 static PyObject*
ToxCore_conference_set_title(ToxCore * self,PyObject * args)933 ToxCore_conference_set_title(ToxCore* self, PyObject* args)
934 {
935   CHECK_TOX(self);
936 
937   int conference_number = 0;
938   uint8_t* title = NULL;
939   uint32_t length = 0;
940 
941   if (!PyArg_ParseTuple(args, "is#", &conference_number, &title, &length)) {
942     return NULL;
943   }
944 
945   TOX_ERR_CONFERENCE_TITLE error;
946   tox_conference_set_title(self->tox, conference_number, title, length, &error);
947   if (error != TOX_ERR_CONFERENCE_TITLE_OK) {
948     PyErr_SetString(ToxOpError, "failed to set the conference title");
949   }
950 
951   Py_RETURN_NONE;
952 }
953 
954 static PyObject*
ToxCore_conference_get_type(ToxCore * self,PyObject * args)955 ToxCore_conference_get_type(ToxCore* self, PyObject* args)
956 {
957   CHECK_TOX(self);
958 
959   int conference_number = 0;
960   if (!PyArg_ParseTuple(args, "i", &conference_number)) {
961     return NULL;
962   }
963 
964   TOX_ERR_CONFERENCE_GET_TYPE error;
965   TOX_CONFERENCE_TYPE type = tox_conference_get_type(self->tox, conference_number, &error);
966   if (error != TOX_ERR_CONFERENCE_GET_TYPE_OK) {
967     PyErr_SetString(ToxOpError, "failed to get conference type");
968   }
969 
970   return PyLong_FromLong(type);
971 }
972 
973 static PyObject*
ToxCore_conference_peer_get_name(ToxCore * self,PyObject * args)974 ToxCore_conference_peer_get_name(ToxCore* self, PyObject* args)
975 {
976   CHECK_TOX(self);
977 
978   uint8_t buf[TOX_MAX_NAME_LENGTH];
979   memset(buf, 0, TOX_MAX_NAME_LENGTH);
980 
981   int conference_number = 0;
982   int peer_number = 0;
983   if (!PyArg_ParseTuple(args, "ii", &conference_number, &peer_number)) {
984     return NULL;
985   }
986 
987   TOX_ERR_CONFERENCE_PEER_QUERY error;
988   tox_conference_peer_get_name(self->tox, conference_number,
989       peer_number, buf, &error);
990   if (error != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
991     PyErr_SetString(ToxOpError, "failed to get conference peer name");
992   }
993 
994   return PYSTRING_FromString((const char*)buf);
995 }
996 
997 static PyObject*
ToxCore_conference_invite(ToxCore * self,PyObject * args)998 ToxCore_conference_invite(ToxCore* self, PyObject* args)
999 {
1000   CHECK_TOX(self);
1001 
1002   int friend_number = 0;
1003   int conference_number = 0;
1004   if (!PyArg_ParseTuple(args, "ii", &friend_number, &conference_number)) {
1005     return NULL;
1006   }
1007 
1008   TOX_ERR_CONFERENCE_INVITE error;
1009   tox_conference_invite(self->tox, friend_number, conference_number, &error);
1010   if (error != TOX_ERR_CONFERENCE_INVITE_OK) {
1011     PyErr_SetString(ToxOpError, "failed to invite friend");
1012   }
1013 
1014   Py_RETURN_NONE;
1015 }
1016 
1017 static PyObject*
ToxCore_conference_join(ToxCore * self,PyObject * args)1018 ToxCore_conference_join(ToxCore* self, PyObject* args)
1019 {
1020   CHECK_TOX(self);
1021 
1022   int friend_number = 0;
1023   uint8_t* cookie = NULL;
1024   int length = 0;
1025 
1026   if (!PyArg_ParseTuple(args, "is#", &friend_number, &cookie, &length)) {
1027     return NULL;
1028   }
1029 
1030   TOX_ERR_CONFERENCE_JOIN error;
1031   uint32_t ret = tox_conference_join(self->tox, friend_number, cookie, length,
1032       &error);
1033   if (error != TOX_ERR_CONFERENCE_JOIN_OK) {
1034     PyErr_SetString(ToxOpError, "failed to join conference");
1035   }
1036 
1037   return PyLong_FromLong(ret);
1038 }
1039 
1040 static PyObject*
ToxCore_conference_send_message(ToxCore * self,PyObject * args)1041 ToxCore_conference_send_message(ToxCore* self, PyObject* args)
1042 {
1043   CHECK_TOX(self);
1044 
1045   int conference_number = 0;
1046   int type = 0;
1047   uint8_t* message = NULL;
1048   uint32_t length = 0;
1049 
1050   if (!PyArg_ParseTuple(args, "iis#", &conference_number, &type, &message, &length)) {
1051     return NULL;
1052   }
1053 
1054   TOX_ERR_CONFERENCE_SEND_MESSAGE error;
1055   tox_conference_send_message(self->tox, conference_number, type, message, length, &error);
1056   if (error != TOX_ERR_CONFERENCE_SEND_MESSAGE_OK) {
1057     PyErr_SetString(ToxOpError, "failed to send conference message");
1058   }
1059 
1060   Py_RETURN_NONE;
1061 }
1062 
1063 static PyObject*
ToxCore_conference_peer_number_is_ours(ToxCore * self,PyObject * args)1064 ToxCore_conference_peer_number_is_ours(ToxCore* self, PyObject* args)
1065 {
1066   CHECK_TOX(self);
1067 
1068   int conference_number = 0;
1069   int peer_number = 0;
1070 
1071   if (!PyArg_ParseTuple(args, "ii", &conference_number, &peer_number)) {
1072     return NULL;
1073   }
1074 
1075   TOX_ERR_CONFERENCE_PEER_QUERY error;
1076   bool ret = tox_conference_peer_number_is_ours(self->tox, conference_number, peer_number, &error);
1077   if (error != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
1078     PyErr_SetString(ToxOpError, "failed to check if peer number is ours");
1079   }
1080 
1081   return PyLong_FromLong(ret);
1082 }
1083 
1084 static PyObject*
ToxCore_conference_peer_count(ToxCore * self,PyObject * args)1085 ToxCore_conference_peer_count(ToxCore* self, PyObject* args)
1086 {
1087   CHECK_TOX(self);
1088 
1089   int conference_number = 0;
1090 
1091   if (!PyArg_ParseTuple(args, "i", &conference_number)) {
1092     return NULL;
1093   }
1094 
1095   TOX_ERR_CONFERENCE_PEER_QUERY error;
1096   uint32_t count = tox_conference_peer_count(self->tox, conference_number, &error);
1097   if (error != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
1098     PyErr_SetString(ToxOpError, "failed to get conference peer count");
1099   }
1100 
1101   return PyLong_FromLong(count);
1102 }
1103 
1104 static PyObject*
ToxCore_conference_get_chatlist_size(ToxCore * self,PyObject * args)1105 ToxCore_conference_get_chatlist_size(ToxCore* self, PyObject* args)
1106 {
1107   CHECK_TOX(self);
1108 
1109   size_t n = tox_conference_get_chatlist_size(self->tox);
1110   return PyLong_FromUnsignedLong(n);
1111 }
1112 
1113 static PyObject*
ToxCore_conference_get_chatlist(ToxCore * self,PyObject * args)1114 ToxCore_conference_get_chatlist(ToxCore* self, PyObject* args)
1115 {
1116   CHECK_TOX(self);
1117 
1118   uint32_t count = tox_conference_get_chatlist_size(self->tox);
1119   uint32_t* list = (uint32_t*)malloc(count * sizeof(uint32_t));
1120   if (list == NULL) {
1121     PyErr_SetString(ToxOpError, "allocation failure");
1122     Py_RETURN_NONE;
1123   }
1124 
1125   tox_conference_get_chatlist(self->tox, list);
1126 
1127   PyObject* plist = PyList_New(0);
1128   if (!plist) {
1129     return NULL;
1130   }
1131 
1132   uint32_t i = 0;
1133   for (i = 0; i < count; ++i) {
1134     PyList_Append(plist, PyLong_FromLong(list[i]));
1135   }
1136   free(list);
1137 
1138   return plist;
1139 }
1140 
1141 static PyObject*
ToxCore_file_send(ToxCore * self,PyObject * args)1142 ToxCore_file_send(ToxCore* self, PyObject*args)
1143 {
1144     CHECK_TOX(self);
1145     uint32_t friend_number = 0;
1146     uint32_t kind = 0;
1147     uint64_t file_size = 0;
1148     uint8_t* file_id = NULL;
1149     uint8_t* filename = 0;
1150     int filename_length = 0;
1151 
1152     if (!PyArg_ParseTuple(args, "iiKss#", &friend_number, &kind, &file_size, &file_id,
1153                           &filename, &filename_length)) {
1154         return NULL;
1155     }
1156 
1157     TOX_ERR_FILE_SEND err = 0;
1158     uint32_t file_number =
1159         tox_file_send(self->tox, friend_number, kind, file_size, file_id, filename, filename_length, &err);
1160     if (file_number == UINT32_MAX) {
1161         PyErr_Format(ToxOpError, "tox_file_send() failed: %d", err);
1162         return NULL;
1163     }
1164 
1165     return PyLong_FromLong(file_number);
1166 }
1167 
1168 static PyObject*
ToxCore_file_control(ToxCore * self,PyObject * args)1169 ToxCore_file_control(ToxCore* self, PyObject* args)
1170 {
1171     CHECK_TOX(self);
1172     uint32_t friend_number = 0;
1173     uint32_t file_number = 0;
1174     int control = 0;
1175 
1176     if (!PyArg_ParseTuple(args, "iii", &friend_number, &file_number, &control)) {
1177         return NULL;
1178     }
1179 
1180     bool ret = tox_file_control(self->tox, friend_number, file_number, control, NULL);
1181     if (!ret) {
1182         PyErr_SetString(ToxOpError, "tox_file_control() failed");
1183         Py_RETURN_FALSE;
1184     }
1185 
1186     Py_RETURN_TRUE;
1187 }
1188 
1189 static PyObject*
ToxCore_file_send_chunk(ToxCore * self,PyObject * args)1190 ToxCore_file_send_chunk(ToxCore* self, PyObject* args)
1191 {
1192     CHECK_TOX(self);
1193     uint32_t friend_number = 0;
1194     uint32_t file_number = 0;
1195     uint64_t position = 0;
1196     uint8_t *data = 0;
1197     size_t length = 0;
1198 
1199     if (!PyArg_ParseTuple(args, "iiKs#", &friend_number, &file_number, &position,
1200                           &data, &length)) {
1201         return NULL;
1202     }
1203 
1204     TOX_ERR_FILE_SEND_CHUNK err = 0;
1205     bool ret = tox_file_send_chunk(self->tox, friend_number, file_number, position,
1206                                    data, length, &err);
1207     if (!ret) {
1208         PyErr_Format(ToxOpError, "tox_file_send_chunk() failed:%d", err);
1209         Py_RETURN_FALSE;
1210     }
1211 
1212     Py_RETURN_TRUE;
1213 }
1214 
1215 static PyObject*
ToxCore_file_seek(ToxCore * self,PyObject * args)1216 ToxCore_file_seek(ToxCore* self, PyObject* args)
1217 {
1218     CHECK_TOX(self);
1219     uint32_t friend_number = 0;
1220     uint32_t file_number = 0;
1221     uint64_t position = 0;
1222 
1223     if (!PyArg_ParseTuple(args, "iiK", &friend_number, &file_number, &position)) {
1224         return NULL;
1225     }
1226 
1227     TOX_ERR_FILE_SEEK err = 0;
1228     bool ret = tox_file_seek(self->tox, friend_number, file_number, position, &err);
1229 
1230     if (!ret) {
1231         PyErr_Format(ToxOpError, "tox_file_seek() failed: %d", err);
1232         Py_RETURN_FALSE;
1233     }
1234 
1235     Py_RETURN_TRUE;
1236 }
1237 
1238 static PyObject*
ToxCore_file_get_file_id(ToxCore * self,PyObject * args)1239 ToxCore_file_get_file_id(ToxCore* self, PyObject* args)
1240 {
1241     CHECK_TOX(self);
1242     uint32_t friend_number = 0;
1243     uint32_t file_number = 0;
1244 
1245     if (!PyArg_ParseTuple(args, "ii", &friend_number, &file_number)) {
1246         return NULL;
1247     }
1248 
1249     uint8_t file_id[TOX_FILE_ID_LENGTH + 1];
1250     file_id[TOX_FILE_ID_LENGTH] = 0;
1251 
1252     uint8_t hex[TOX_FILE_ID_LENGTH * 2 + 1];
1253     memset(hex, 0, TOX_FILE_ID_LENGTH * 2 + 1);
1254 
1255     TOX_ERR_FILE_GET err = 0;
1256     bool ret = tox_file_get_file_id(self->tox, friend_number, file_number, file_id, &err);
1257     if (!ret) {
1258         PyErr_Format(ToxOpError, "tox_file_get_file_id() failed: %d", err);
1259         Py_RETURN_NONE;
1260     }
1261 
1262     bytes_to_hex_string(file_id, TOX_FILE_ID_LENGTH, hex);
1263     return PYSTRING_FromStringAndSize((char*)hex, TOX_FILE_ID_LENGTH * 2);
1264 }
1265 
1266 static PyObject*
ToxCore_self_get_nospam(ToxCore * self,PyObject * args)1267 ToxCore_self_get_nospam(ToxCore* self, PyObject* args)
1268 {
1269   CHECK_TOX(self);
1270 
1271   uint32_t nospam = tox_self_get_nospam(self->tox);
1272 
1273   return PyLong_FromUnsignedLongLong(nospam);
1274 }
1275 
1276 static PyObject*
ToxCore_self_set_nospam(ToxCore * self,PyObject * args)1277 ToxCore_self_set_nospam(ToxCore* self, PyObject* args)
1278 {
1279   CHECK_TOX(self);
1280 
1281   uint32_t nospam = 0;
1282 
1283   if (!PyArg_ParseTuple(args, "I", &nospam)) {
1284     return NULL;
1285   }
1286 
1287   tox_self_set_nospam(self->tox, nospam);
1288   Py_RETURN_NONE;
1289 }
1290 
1291 static PyObject*
ToxCore_self_get_keys(ToxCore * self,PyObject * args)1292 ToxCore_self_get_keys(ToxCore* self, PyObject* args)
1293 {
1294   uint8_t public_key[TOX_PUBLIC_KEY_SIZE];
1295   uint8_t secret_key[TOX_PUBLIC_KEY_SIZE];
1296 
1297   uint8_t public_key_hex[TOX_PUBLIC_KEY_SIZE * 2 + 1];
1298   uint8_t secret_key_hex[TOX_PUBLIC_KEY_SIZE * 2 + 1];
1299 
1300   tox_self_get_public_key(self->tox, public_key);
1301   tox_self_get_secret_key(self->tox, secret_key);
1302   bytes_to_hex_string(public_key, TOX_PUBLIC_KEY_SIZE, public_key_hex);
1303   bytes_to_hex_string(secret_key, TOX_PUBLIC_KEY_SIZE, secret_key_hex);
1304 
1305   PyObject* res = PyTuple_New(2);
1306   PyTuple_SetItem(res, 0, PYSTRING_FromStringAndSize((char*)public_key_hex,
1307         TOX_PUBLIC_KEY_SIZE * 2));
1308   PyTuple_SetItem(res, 1, PYSTRING_FromStringAndSize((char*)secret_key_hex,
1309         TOX_PUBLIC_KEY_SIZE * 2));
1310   return res;
1311 }
1312 
1313 static PyObject*
ToxCore_bootstrap(ToxCore * self,PyObject * args)1314 ToxCore_bootstrap(ToxCore* self, PyObject* args)
1315 {
1316   CHECK_TOX(self);
1317 
1318   uint16_t port = 0;
1319   uint8_t* public_key = NULL;
1320   char* address = NULL;
1321   int addr_length = 0;
1322   int pk_length = 0;
1323   uint8_t pk[TOX_PUBLIC_KEY_SIZE];
1324 
1325   if (!PyArg_ParseTuple(args, "s#Hs#", &address, &addr_length, &port,
1326         &public_key, &pk_length)) {
1327     return NULL;
1328   }
1329 
1330   hex_string_to_bytes(public_key, TOX_PUBLIC_KEY_SIZE, pk);
1331   bool ret = tox_bootstrap(self->tox, address, port, pk, NULL);
1332 
1333   if (!ret) {
1334     PyErr_SetString(ToxOpError, "failed to resolve address");
1335     return NULL;
1336   }
1337 
1338   Py_RETURN_TRUE;
1339 }
1340 
1341 static PyObject*
ToxCore_add_tcp_relay(ToxCore * self,PyObject * args)1342 ToxCore_add_tcp_relay(ToxCore* self, PyObject* args)
1343 {
1344   CHECK_TOX(self);
1345 
1346   uint16_t port = 0;
1347   uint8_t* public_key = NULL;
1348   char* address = NULL;
1349   int addr_length = 0;
1350   int pk_length = 0;
1351   uint8_t pk[TOX_PUBLIC_KEY_SIZE];
1352 
1353   if (!PyArg_ParseTuple(args, "s#Hs#", &address, &addr_length, &port,
1354         &public_key, &pk_length)) {
1355     return NULL;
1356   }
1357 
1358   hex_string_to_bytes(public_key, TOX_PUBLIC_KEY_SIZE, pk);
1359   bool ret = tox_add_tcp_relay(self->tox, address, port, pk, NULL);
1360 
1361   if (!ret) {
1362     PyErr_SetString(ToxOpError, "failed to add tcp relay");
1363     return NULL;
1364   }
1365 
1366   Py_RETURN_TRUE;
1367 }
1368 
1369 static PyObject*
ToxCore_self_get_connection_status(ToxCore * self,PyObject * args)1370 ToxCore_self_get_connection_status(ToxCore* self, PyObject* args)
1371 {
1372   CHECK_TOX(self);
1373 
1374   TOX_CONNECTION conn = tox_self_get_connection_status(self->tox);
1375 
1376   return PyLong_FromLong(conn);
1377 }
1378 
1379 static PyObject*
ToxCore_kill(ToxCore * self,PyObject * args)1380 ToxCore_kill(ToxCore* self, PyObject* args)
1381 {
1382   CHECK_TOX(self);
1383 
1384   tox_kill(self->tox);
1385   self->tox = NULL;
1386 
1387   Py_RETURN_NONE;
1388 }
1389 
1390 static PyObject*
ToxCore_iteration_interval(ToxCore * self,PyObject * args)1391 ToxCore_iteration_interval(ToxCore* self, PyObject* args)
1392 {
1393   CHECK_TOX(self);
1394 
1395   uint32_t interval = tox_iteration_interval(self->tox);
1396 
1397   return PyLong_FromUnsignedLongLong(interval);
1398 }
1399 
1400 static PyObject*
ToxCore_iterate(ToxCore * self,PyObject * args)1401 ToxCore_iterate(ToxCore* self, PyObject* args)
1402 {
1403   CHECK_TOX(self);
1404 
1405   tox_iterate(self->tox, self);
1406 
1407   if (PyErr_Occurred()) {
1408     return NULL;
1409   }
1410   Py_RETURN_NONE;
1411 }
1412 
1413 static PyObject*
ToxCore_get_savedata_size(ToxCore * self,PyObject * args)1414 ToxCore_get_savedata_size(ToxCore* self, PyObject* args)
1415 {
1416   CHECK_TOX(self);
1417 
1418   uint32_t size = tox_get_savedata_size(self->tox);
1419 
1420   return PyLong_FromUnsignedLong(size);
1421 }
1422 
1423 static PyObject*
ToxCore_get_savedata(ToxCore * self,PyObject * args)1424 ToxCore_get_savedata(ToxCore* self, PyObject* args)
1425 {
1426   CHECK_TOX(self);
1427 
1428   uint32_t size = tox_get_savedata_size(self->tox);
1429   uint8_t* buf = (uint8_t*)malloc(size);
1430   tox_get_savedata(self->tox, buf);
1431 
1432   PyObject* res = PYBYTES_FromStringAndSize((const char*)buf, size);
1433   free(buf);
1434 
1435   return res;
1436 }
1437 
1438 static PyMethodDef Tox_methods[] = {
1439   {
1440     "on_log", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1441     "on_log(level, file, line, func, message)\n"
1442     "Callback for internal log messages, default implementation does "
1443     "nothing."
1444   },
1445   {
1446     "on_self_connection_status", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1447     "on_self_connection_status(friend_number, status)\n"
1448     "Callback for receiving read receipt, default implementation does "
1449     "nothing."
1450   },
1451   {
1452     "on_friend_request", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1453     "on_friend_request(address, message)\n"
1454     "Callback for receiving friend requests, default implementation does "
1455     "nothing."
1456   },
1457   {
1458     "on_friend_message", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1459     "on_friend_message(friend_number, type, message)\n"
1460     "Callback for receiving friend messages, default implementation does "
1461     "nothing."
1462   },
1463   {
1464     "on_friend_name", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1465     "on_friend_name(friend_number, new_name)\n"
1466     "Callback for receiving friend name changes, default implementation does "
1467     "nothing."
1468   },
1469   {
1470     "on_friend_status_message", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1471     "on_friend_status_message(friend_number, new_status)\n"
1472     "Callback for receiving friend status message changes, default "
1473     "implementation does nothing."
1474   },
1475   {
1476     "on_friend_status", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1477     "on_friend_status(friend_number, kind)\n"
1478     "Callback for receiving friend status changes, default implementation "
1479     "does nothing."
1480   },
1481   {
1482     "on_friend_typing", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1483     "on_friend_typing(friend_number, is_typing)\n"
1484     "Callback for receiving friend status changes, default implementation "
1485     "does nothing.\n\n"
1486   },
1487   {
1488     "on_friend_read_receipt", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1489     "on_friend_read_receipt(friend_number, receipt)\n"
1490     "Callback for receiving read receipt, default implementation does nothing."
1491   },
1492   {
1493     "on_friend_connection_status", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1494     "on_friend_connection_status(friend_number, status)\n"
1495     "Callback for receiving read receipt, default implementation does "
1496     "nothing.\n\n"
1497     "*status* is a boolean value which indicates the status of the friend "
1498     "indicated by *friend_number*. True means online and False means offline "
1499     "after previously online."
1500   },
1501   {
1502     "on_conference_invite", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1503     "on_conference_invite(friend_number, type, cookie)\n"
1504     "Callback for receiving conference invitations, default implementation does "
1505     "nothing.\n\n"
1506     ".. seealso ::\n"
1507     "    :meth:`.conference_get_type`"
1508   },
1509   {
1510     "on_conference_message", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1511     "on_conference_message(conference_number, peer_number, message)\n"
1512     "Callback for receiving conference messages, default implementation does "
1513     "nothing."
1514   },
1515   {
1516     "on_conference_peer_name", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1517     "on_conference_peer_name(conference_number, peer_number, name)\n"
1518     "Callback for nickname changes, default implementation does nothing.\n\n"
1519   },
1520   {
1521     "on_conference_peer_list_changed", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1522     "on_conference_peer_list_changed(conference_number)\n"
1523     "Callback for joins/parts, default implementation does nothing.\n\n"
1524   },
1525   {
1526     "on_file_recv", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1527     "on_file_recv(friend_number, file_number,  kind, file_size, filename)\n"
1528     "Callback for receiving file transfer, default implementation does nothing."
1529   },
1530   {
1531     "on_file_recv_control", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1532     "on_file_recv_control(friend_number, file_number, control)\n"
1533     "Callback for receiving file control, default implementation does nothing."
1534   },
1535   {
1536     "on_file_recv_chunk", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1537     "on_file_recv_chunk(friend_number, file_number, position, data)\n"
1538     "Callback for receiving file chunk, default implementation does nothing."
1539   },
1540   {
1541     "on_file_chunk_request", (PyCFunction)ToxCore_callback_stub, METH_VARARGS,
1542     "on_file_chunk_request(friend_number, file_number, position, length)\n"
1543     "Callback for more file chunk, default implementation does nothing."
1544   },
1545   {
1546     "self_get_address", (PyCFunction)ToxCore_self_get_address, METH_NOARGS,
1547     "self_get_address()\n"
1548     "Return address to give to others."
1549   },
1550   {
1551     "friend_add", (PyCFunction)ToxCore_friend_add, METH_VARARGS,
1552     "friend_add(address, message)\n"
1553     "Add a friend."
1554   },
1555   {
1556     "friend_add_norequest", (PyCFunction)ToxCore_friend_add_norequest, METH_VARARGS,
1557     "friend_add_norequest(address)\n"
1558     "Add a friend without sending request."
1559   },
1560   {
1561     "friend_by_public_key", (PyCFunction)ToxCore_friend_by_public_key, METH_VARARGS,
1562     "friend_by_public_key(friend_id)\n"
1563     "Return the friend id associated to that client id."
1564   },
1565   {
1566     "friend_get_public_key", (PyCFunction)ToxCore_friend_get_public_key, METH_VARARGS,
1567     "friend_get_public_key(friend_number)\n"
1568     "Return the public key associated to that friend number."
1569   },
1570   {
1571     "friend_delete", (PyCFunction)ToxCore_friend_delete, METH_VARARGS,
1572     "friend_delete(friend_number)\n"
1573     "Remove a friend."
1574   },
1575   {
1576     "friend_get_connection_status", (PyCFunction)ToxCore_friend_get_connection_status, METH_VARARGS,
1577     "friend_get_connection_status(friend_number)\n"
1578     "Return True if friend is connected(Online) else False."
1579   },
1580   {
1581     "friend_exists", (PyCFunction)ToxCore_friend_exists, METH_VARARGS,
1582     "friend_exists(friend_number)\n"
1583     "Checks if there exists a friend with given friendnumber."
1584   },
1585   {
1586     "friend_send_message", (PyCFunction)ToxCore_friend_send_message, METH_VARARGS,
1587     "friend_send_message(friend_number, type, message)\n"
1588     "Send a text chat message to an online friend."
1589   },
1590   {
1591     "self_set_name", (PyCFunction)ToxCore_self_set_name, METH_VARARGS,
1592     "self_set_name(name)\n"
1593     "Set our self nickname."
1594   },
1595   {
1596     "self_get_name", (PyCFunction)ToxCore_self_get_name, METH_NOARGS,
1597     "self_get_name()\n"
1598     "Get our self nickname."
1599   },
1600   {
1601     "self_get_name_size", (PyCFunction)ToxCore_self_get_name_size, METH_NOARGS,
1602     "self_get_name_size()\n"
1603     "Get our self nickname string length"
1604   },
1605   {
1606     "friend_get_name", (PyCFunction)ToxCore_friend_get_name, METH_VARARGS,
1607     "friend_get_name(friend_number)\n"
1608     "Get nickname of *friend_number*."
1609   },
1610   {
1611     "friend_get_name_size", (PyCFunction)ToxCore_friend_get_name_size, METH_VARARGS,
1612     "friend_get_name_size(friend_number)\n"
1613     "Get nickname length of *friend_number*."
1614   },
1615   {
1616     "self_set_status_message", (PyCFunction)ToxCore_self_set_status_message, METH_VARARGS,
1617     "self_set_status_message(message)\n"
1618     "Set our self status message."
1619   },
1620   {
1621     "self_set_status", (PyCFunction)ToxCore_self_set_status, METH_VARARGS,
1622     "self_set_status(status)\n"
1623     "Set our user status, status can have following values:\n\n"
1624     "+------------------------+--------------------+\n"
1625     "| kind                   | description        |\n"
1626     "+========================+====================+\n"
1627     "| Tox.USERSTATUS_NONE    | the user is online |\n"
1628     "+------------------------+--------------------+\n"
1629     "| Tox.USERSTATUS_AWAY    | the user is away   |\n"
1630     "+------------------------+--------------------+\n"
1631     "| Tox.USERSTATUS_BUSY    | the user is busy   |\n"
1632     "+------------------------+--------------------+\n"
1633     "| Tox.USERSTATUS_INVALID | invalid status     |\n"
1634     "+------------------------+--------------------+\n"
1635   },
1636   {
1637     "friend_get_status_message_size", (PyCFunction)ToxCore_friend_get_status_message_size, METH_VARARGS,
1638     "friend_get_status_message_size(friend_number)\n"
1639     "Return the length of *friend_number*'s status message."
1640   },
1641   {
1642     "friend_get_status_message", (PyCFunction)ToxCore_friend_get_status_message, METH_VARARGS,
1643     "friend_get_status_message(friend_number)\n"
1644     "Get status message of a friend."
1645   },
1646   {
1647     "self_get_status_message", (PyCFunction)ToxCore_self_get_status_message,
1648     METH_NOARGS,
1649     "self_get_status_message()\n"
1650     "Get status message of yourself."
1651   },
1652   {
1653     "self_get_status_message_size",
1654     (PyCFunction)ToxCore_self_get_status_message_size,
1655     METH_NOARGS,
1656     "self_get_status_message_size()\n"
1657     "Get status message string length of yourself."
1658   },
1659   {
1660     "friend_get_status", (PyCFunction)ToxCore_friend_get_status, METH_VARARGS,
1661     "friend_get_status(friend_number)\n"
1662     "Get friend status.\n\n"
1663     ".. seealso ::\n"
1664     "    :meth:`.set_user_status`"
1665   },
1666   {
1667     "self_get_status", (PyCFunction)ToxCore_self_get_status,
1668     METH_NOARGS,
1669     "self_get_status()\n"
1670     "Get user status of youself.\n\n"
1671     ".. seealso ::\n"
1672     "    :meth:`.set_user_status`"
1673   },
1674   {
1675     "friend_get_last_online", (PyCFunction)ToxCore_friend_get_last_online, METH_VARARGS,
1676     "friend_get_last_online(friend_number)\n"
1677     "returns datetime.datetime object representing the last time "
1678     "*friend_number* was seen online, or None if never seen."
1679   },
1680   {
1681     "self_set_typing", (PyCFunction)ToxCore_self_set_typing, METH_VARARGS,
1682     "self_set_typing(friend_number, is_typing)\n"
1683     "Set user typing status.\n\n"
1684   },
1685   {
1686     "friend_get_typing", (PyCFunction)ToxCore_friend_get_typing, METH_VARARGS,
1687     "friend_get_typing(friend_number)\n"
1688     "Return True is user is typing.\n\n"
1689   },
1690   {
1691     "self_get_friend_list_size", (PyCFunction)ToxCore_self_get_friend_list_size,
1692     METH_NOARGS,
1693     "self_get_friend_list_size()\n"
1694     "Return the number of friends."
1695   },
1696   {
1697     "self_get_friend_list", (PyCFunction)ToxCore_self_get_friend_list,
1698     METH_NOARGS,
1699     "self_get_friend_list()\n"
1700     "Get a list of valid friend numbers."
1701   },
1702   {
1703     "conference_get_title", (PyCFunction)ToxCore_conference_get_title, METH_VARARGS,
1704     "conference_get_title(conference_number)\n"
1705     "Returns the title for a conference."
1706   },
1707   {
1708     "conference_set_title", (PyCFunction)ToxCore_conference_set_title, METH_VARARGS,
1709     "conference_set_title(conference_number, title)\n"
1710     "Sets the title for a conference."
1711   },
1712   {
1713     "conference_get_type", (PyCFunction)ToxCore_conference_get_type, METH_VARARGS,
1714     "conference_get_type(conference_number)\n"
1715     "Return the type of conference, could be the following value:\n\n"
1716     "+--------------------------+-------------+\n"
1717     "| type                     | description |\n"
1718     "+==========================+=============+\n"
1719     "| Tox.CONFERENCE_TYPE_TEXT | text chat   |\n"
1720     "+--------------------------+-------------+\n"
1721     "| Tox.CONFERENCE_TYPE_AV   | video chat  |\n"
1722     "+--------------------------+-------------+\n"
1723   },
1724   {
1725     "conference_new", (PyCFunction)ToxCore_conference_new, METH_VARARGS,
1726     "conference_new()\n"
1727     "Creates a new conference and puts it in the chats array."
1728   },
1729   {
1730     "conference_delete", (PyCFunction)ToxCore_conference_delete, METH_VARARGS,
1731     "conference_delete(conference_number)\n"
1732     "Delete a conference from the chats array."
1733   },
1734   {
1735     "conference_peer_get_name", (PyCFunction)ToxCore_conference_peer_get_name, METH_VARARGS,
1736     "conference_peer_get_name(conference_number, peer_number)\n"
1737     "Get the conference peer's name."
1738   },
1739   {
1740     "conference_invite", (PyCFunction)ToxCore_conference_invite, METH_VARARGS,
1741     "conference_invite(friend_number, conference_number)\n"
1742     "Invite friend_number to conference_number."
1743   },
1744   {
1745     "conference_join", (PyCFunction)ToxCore_conference_join, METH_VARARGS,
1746     "conference_join(friend_number, cookie)\n"
1747     "Join a conference (you need to have been invited first.). Returns the "
1748     "conference number of success."
1749   },
1750   {
1751     "conference_send_message", (PyCFunction)ToxCore_conference_send_message, METH_VARARGS,
1752     "conference_send_message(conference_number, type, message)\n"
1753     "Send a conference message."
1754   },
1755   {
1756     "conference_peer_count", (PyCFunction)ToxCore_conference_peer_count, METH_VARARGS,
1757     "conference_peer_count(conference_number)\n"
1758     "Return the number of peers in the conference."
1759   },
1760   {
1761     "conference_get_chatlist_size", (PyCFunction)ToxCore_conference_get_chatlist_size, METH_VARARGS,
1762     "conference_get_chatlist_size()\n"
1763     "Return the number of conferences in the current Tox instance."
1764   },
1765   {
1766     "conference_peer_number_is_ours", (PyCFunction)ToxCore_conference_peer_number_is_ours, METH_VARARGS,
1767     "conference_peer_number_is_ours(conference_number, peer_number)\n"
1768     "Check if the current peer number corresponds to ours."
1769   },
1770   {
1771     "conference_get_chatlist", (PyCFunction)ToxCore_conference_get_chatlist, METH_VARARGS,
1772     "conference_get_chatlist()\n"
1773     "Return a list of valid conference numbers."
1774   },
1775   {
1776     "file_send", (PyCFunction)ToxCore_file_send, METH_VARARGS,
1777     "file_send(friend_number, kind, file_size, file_id, filename)\n"
1778     "Send a file send request. Returns file number to be sent."
1779   },
1780   {
1781     "file_control", (PyCFunction)ToxCore_file_control, METH_VARARGS,
1782     "file_control(friend_number, file_number, control)\n"
1783     "Send a file send request. Returns file number to be sent."
1784   },
1785   {
1786     "file_send_chunk", (PyCFunction)ToxCore_file_send_chunk, METH_VARARGS,
1787     "file_send_chunk(friend_number, file_number, position, data)\n"
1788     "Send a file send request. Returns file number to be sent."
1789   },
1790   {
1791     "file_seek", (PyCFunction)ToxCore_file_seek, METH_VARARGS,
1792     "file_seek(friend_number, file_number, position)\n"
1793     "Send a file send request. Returns file number to be sent."
1794   },
1795   {
1796     "file_get_file_id", (PyCFunction)ToxCore_file_get_file_id, METH_VARARGS,
1797     "file_get_file_id(friend_number, file_number)\n"
1798     "Send a file send request. Returns file id's hex string"
1799   },
1800   {
1801     "self_get_nospam", (PyCFunction)ToxCore_self_get_nospam,
1802     METH_NOARGS,
1803     "self_get_nospam()\n"
1804     "get nospam part from ID"
1805   },
1806   {
1807     "self_set_nospam", (PyCFunction)ToxCore_self_set_nospam, METH_VARARGS,
1808     "self_set_nospam(nospam)\n"
1809     "set nospam part of ID. *nospam* should be of type uint32"
1810   },
1811   {
1812     "self_get_keys", (PyCFunction)ToxCore_self_get_keys,
1813     METH_NOARGS,
1814     "self_get_keys()\n"
1815     "Get the public and secret key from the Tox object. Return a tuple "
1816     "(public_key, secret_key)"
1817   },
1818   {
1819     "bootstrap", (PyCFunction)ToxCore_bootstrap, METH_VARARGS,
1820     "bootstrap(address, port, public_key)\n"
1821     "Resolves address into an IP address. If successful, sends a 'get nodes'"
1822     "request to the given node with ip, port."
1823   },
1824   {
1825     "add_tcp_relay", (PyCFunction)ToxCore_add_tcp_relay, METH_VARARGS,
1826     "add_tcp_relay(address, port, public_key)\n"
1827     ""
1828   },
1829   {
1830     "self_get_connection_status", (PyCFunction)ToxCore_self_get_connection_status, METH_NOARGS,
1831     "self_get_connection_status()\n"
1832     "Return False if we are not connected to the DHT."
1833   },
1834   {
1835     "kill", (PyCFunction)ToxCore_kill, METH_NOARGS,
1836     "kill()\n"
1837     "Run this before closing shop."
1838   },
1839   {
1840     "iteration_interval", (PyCFunction)ToxCore_iteration_interval, METH_NOARGS,
1841     "iteration_interval()\n"
1842     "returns time (in ms) before the next tox_iterate() needs to be run on success."
1843   },
1844   {
1845     "iterate", (PyCFunction)ToxCore_iterate, METH_NOARGS,
1846     "iterate()\n"
1847     "The main loop that needs to be run at least 20 times per second."
1848   },
1849   {
1850     "get_savedata_size", (PyCFunction)ToxCore_get_savedata_size, METH_NOARGS,
1851     "get_savedata_size()\n"
1852     "return size of messenger data (for saving)."
1853   },
1854   {
1855     "get_savedata", (PyCFunction)ToxCore_get_savedata, METH_NOARGS,
1856     "get_savedata()\n"
1857     "Return messenger blob in str."
1858   },
1859   {
1860     NULL, NULL, 0,
1861     NULL,
1862   }
1863 };
1864 
1865 PyTypeObject ToxCoreType = {
1866 #if PY_MAJOR_VERSION >= 3
1867   PyVarObject_HEAD_INIT(NULL, 0)
1868 #else
1869   PyObject_HEAD_INIT(NULL)
1870   0,                         /*ob_size*/
1871 #endif
1872   "Tox",                     /*tp_name*/
1873   sizeof(ToxCore),           /*tp_basicsize*/
1874   0,                         /*tp_itemsize*/
1875   (destructor)ToxCore_dealloc, /*tp_dealloc*/
1876   0,                         /*tp_print*/
1877   0,                         /*tp_getattr*/
1878   0,                         /*tp_setattr*/
1879   0,                         /*tp_compare*/
1880   0,                         /*tp_repr*/
1881   0,                         /*tp_as_number*/
1882   0,                         /*tp_as_sequence*/
1883   0,                         /*tp_as_mapping*/
1884   0,                         /*tp_hash */
1885   0,                         /*tp_call*/
1886   0,                         /*tp_str*/
1887   0,                         /*tp_getattro*/
1888   0,                         /*tp_setattro*/
1889   0,                         /*tp_as_buffer*/
1890   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1891   "ToxCore object",          /* tp_doc */
1892   0,                         /* tp_traverse */
1893   0,                         /* tp_clear */
1894   0,                         /* tp_richcompare */
1895   0,                         /* tp_weaklistoffset */
1896   0,                         /* tp_iter */
1897   0,                         /* tp_iternext */
1898   Tox_methods,               /* tp_methods */
1899   0,                         /* tp_members */
1900   0,                         /* tp_getset */
1901   0,                         /* tp_base */
1902   0,                         /* tp_dict */
1903   0,                         /* tp_descr_get */
1904   0,                         /* tp_descr_set */
1905   0,                         /* tp_dictoffset */
1906   (initproc)ToxCore_init,    /* tp_init */
1907   0,                         /* tp_alloc */
1908   ToxCore_new,               /* tp_new */
1909 };
1910 
ToxCore_install_dict()1911 void ToxCore_install_dict()
1912 {
1913 #define SET(name)                                            \
1914     PyObject* obj_##name = PyLong_FromLong(TOX_##name);      \
1915     PyDict_SetItemString(dict, #name, obj_##name);           \
1916     Py_DECREF(obj_##name);
1917 
1918     PyObject* dict = PyDict_New();
1919     SET(ERR_FRIEND_ADD_TOO_LONG)
1920     SET(ERR_FRIEND_ADD_NO_MESSAGE)
1921     SET(ERR_FRIEND_ADD_OWN_KEY)
1922     SET(ERR_FRIEND_ADD_ALREADY_SENT)
1923     SET(ERR_FRIEND_ADD_NULL)
1924     SET(ERR_FRIEND_ADD_BAD_CHECKSUM)
1925     SET(ERR_FRIEND_ADD_SET_NEW_NOSPAM)
1926     SET(ERR_FRIEND_ADD_MALLOC)
1927     SET(CONNECTION_NONE)
1928     SET(CONNECTION_TCP)
1929     SET(CONNECTION_UDP)
1930     SET(PROXY_TYPE_NONE)
1931     SET(PROXY_TYPE_HTTP)
1932     SET(PROXY_TYPE_SOCKS5)
1933     SET(MESSAGE_TYPE_NORMAL)
1934     SET(MESSAGE_TYPE_ACTION)
1935     SET(SAVEDATA_TYPE_NONE)
1936     SET(SAVEDATA_TYPE_TOX_SAVE)
1937     SET(SAVEDATA_TYPE_SECRET_KEY)
1938     SET(USER_STATUS_NONE)
1939     SET(USER_STATUS_AWAY)
1940     SET(USER_STATUS_BUSY)
1941     SET(FILE_KIND_DATA)
1942     SET(FILE_KIND_AVATAR)
1943     SET(FILE_CONTROL_RESUME)
1944     SET(FILE_CONTROL_PAUSE)
1945     SET(FILE_CONTROL_CANCEL)
1946     SET(CONFERENCE_TYPE_TEXT)
1947     SET(CONFERENCE_TYPE_AV)
1948     SET(LOG_LEVEL_TRACE)
1949     SET(LOG_LEVEL_DEBUG)
1950     SET(LOG_LEVEL_INFO)
1951     SET(LOG_LEVEL_WARNING)
1952     SET(LOG_LEVEL_ERROR)
1953 
1954 #undef SET
1955 
1956   ToxCoreType.tp_dict = dict;
1957 }
1958