ffi-tox 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/ProjectTox-Core/AUTHORS +0 -0
  3. data/ProjectTox-Core/ChangeLog +0 -0
  4. data/ProjectTox-Core/INSTALL +370 -0
  5. data/ProjectTox-Core/INSTALL.md +455 -56
  6. data/ProjectTox-Core/Makefile.am +35 -0
  7. data/ProjectTox-Core/NEWS +0 -0
  8. data/ProjectTox-Core/README +43 -0
  9. data/ProjectTox-Core/README.md +34 -44
  10. data/ProjectTox-Core/auto_tests/Makefile.inc +110 -0
  11. data/ProjectTox-Core/auto_tests/TCP_test.c +519 -0
  12. data/ProjectTox-Core/auto_tests/assoc_test.c +160 -0
  13. data/ProjectTox-Core/auto_tests/crypto_test.c +302 -0
  14. data/ProjectTox-Core/auto_tests/dht_test.c +362 -0
  15. data/ProjectTox-Core/auto_tests/encryptsave_test.c +104 -0
  16. data/ProjectTox-Core/auto_tests/friends_test.c +238 -0
  17. data/ProjectTox-Core/auto_tests/helpers.h +15 -0
  18. data/ProjectTox-Core/auto_tests/messenger_test.c +365 -0
  19. data/ProjectTox-Core/auto_tests/network_test.c +171 -0
  20. data/ProjectTox-Core/auto_tests/onion_test.c +363 -0
  21. data/ProjectTox-Core/auto_tests/skeleton_test.c +49 -0
  22. data/ProjectTox-Core/auto_tests/tox_test.c +454 -0
  23. data/ProjectTox-Core/auto_tests/toxav_basic_test.c +597 -0
  24. data/ProjectTox-Core/auto_tests/toxav_many_test.c +402 -0
  25. data/ProjectTox-Core/autogen.sh +6 -0
  26. data/ProjectTox-Core/build/Makefile.am +14 -0
  27. data/ProjectTox-Core/configure.ac +694 -0
  28. data/ProjectTox-Core/dist-build/android-arm.sh +3 -0
  29. data/ProjectTox-Core/dist-build/android-armv7.sh +3 -0
  30. data/ProjectTox-Core/dist-build/android-build.sh +59 -0
  31. data/ProjectTox-Core/dist-build/android-mips.sh +3 -0
  32. data/ProjectTox-Core/dist-build/android-x86.sh +3 -0
  33. data/ProjectTox-Core/docs/Group-Chats.md +71 -0
  34. data/ProjectTox-Core/docs/Hardening.txt +60 -0
  35. data/ProjectTox-Core/docs/Hardening_docs.txt +30 -0
  36. data/ProjectTox-Core/docs/Prevent_Tracking.txt +160 -0
  37. data/ProjectTox-Core/docs/TCP_Network.txt +154 -0
  38. data/ProjectTox-Core/docs/TODO +62 -0
  39. data/ProjectTox-Core/docs/Tox_middle_level_network_protocol.txt +120 -0
  40. data/ProjectTox-Core/docs/av_api.md +194 -0
  41. data/ProjectTox-Core/libtoxav.pc.in +11 -0
  42. data/ProjectTox-Core/libtoxcore.pc.in +11 -0
  43. data/ProjectTox-Core/m4/ax_have_epoll.m4 +104 -0
  44. data/ProjectTox-Core/m4/ax_pthread.m4 +317 -0
  45. data/ProjectTox-Core/m4/pkg.m4 +199 -0
  46. data/ProjectTox-Core/other/DHT_bootstrap.c +121 -58
  47. data/ProjectTox-Core/other/DHTnodes +3 -0
  48. data/ProjectTox-Core/other/Makefile.inc +20 -0
  49. data/ProjectTox-Core/other/bootstrap_node_packets.c +65 -0
  50. data/ProjectTox-Core/other/tox.png +0 -0
  51. data/ProjectTox-Core/testing/DHT_test.c +170 -98
  52. data/ProjectTox-Core/testing/Makefile.inc +112 -0
  53. data/ProjectTox-Core/testing/Messenger_test.c +133 -69
  54. data/ProjectTox-Core/testing/dns3_test.c +115 -0
  55. data/ProjectTox-Core/testing/misc_tools.c +59 -13
  56. data/ProjectTox-Core/testing/nTox.c +1127 -264
  57. data/ProjectTox-Core/testing/nTox.h +10 -19
  58. data/ProjectTox-Core/testing/tox_shell.c +159 -0
  59. data/ProjectTox-Core/testing/tox_sync.c +299 -0
  60. data/ProjectTox-Core/tools/README +11 -0
  61. data/ProjectTox-Core/tools/astylerc +11 -0
  62. data/ProjectTox-Core/tools/pre-commit +17 -0
  63. data/ProjectTox-Core/toxav/Makefile.inc +36 -0
  64. data/ProjectTox-Core/toxav/codec.c +357 -0
  65. data/ProjectTox-Core/toxav/codec.h +116 -0
  66. data/ProjectTox-Core/toxav/msi.c +1949 -0
  67. data/ProjectTox-Core/toxav/msi.h +267 -0
  68. data/ProjectTox-Core/toxav/rtp.c +600 -0
  69. data/ProjectTox-Core/toxav/rtp.h +196 -0
  70. data/ProjectTox-Core/toxav/toxav.c +1148 -0
  71. data/ProjectTox-Core/toxav/toxav.h +389 -0
  72. data/ProjectTox-Core/toxcore/DHT.c +2521 -0
  73. data/ProjectTox-Core/toxcore/DHT.h +412 -0
  74. data/ProjectTox-Core/toxcore/LAN_discovery.c +322 -0
  75. data/ProjectTox-Core/{core → toxcore}/LAN_discovery.h +17 -12
  76. data/ProjectTox-Core/toxcore/Makefile.inc +67 -0
  77. data/ProjectTox-Core/toxcore/Messenger.c +3006 -0
  78. data/ProjectTox-Core/toxcore/Messenger.h +818 -0
  79. data/ProjectTox-Core/toxcore/TCP_client.c +858 -0
  80. data/ProjectTox-Core/toxcore/TCP_client.h +156 -0
  81. data/ProjectTox-Core/toxcore/TCP_server.c +1332 -0
  82. data/ProjectTox-Core/toxcore/TCP_server.h +181 -0
  83. data/ProjectTox-Core/toxcore/assoc.c +1033 -0
  84. data/ProjectTox-Core/toxcore/assoc.h +104 -0
  85. data/ProjectTox-Core/toxcore/crypto_core.c +278 -0
  86. data/ProjectTox-Core/toxcore/crypto_core.h +151 -0
  87. data/ProjectTox-Core/toxcore/friend_requests.c +175 -0
  88. data/ProjectTox-Core/toxcore/friend_requests.h +83 -0
  89. data/ProjectTox-Core/toxcore/group_chats.c +837 -0
  90. data/ProjectTox-Core/toxcore/group_chats.h +199 -0
  91. data/ProjectTox-Core/toxcore/list.c +256 -0
  92. data/ProjectTox-Core/toxcore/list.h +85 -0
  93. data/ProjectTox-Core/toxcore/logger.c +153 -0
  94. data/ProjectTox-Core/toxcore/logger.h +84 -0
  95. data/ProjectTox-Core/toxcore/misc_tools.h +70 -0
  96. data/ProjectTox-Core/toxcore/net_crypto.c +2753 -0
  97. data/ProjectTox-Core/toxcore/net_crypto.h +410 -0
  98. data/ProjectTox-Core/toxcore/network.c +979 -0
  99. data/ProjectTox-Core/toxcore/network.h +367 -0
  100. data/ProjectTox-Core/toxcore/onion.c +540 -0
  101. data/ProjectTox-Core/toxcore/onion.h +150 -0
  102. data/ProjectTox-Core/toxcore/onion_announce.c +433 -0
  103. data/ProjectTox-Core/toxcore/onion_announce.h +139 -0
  104. data/ProjectTox-Core/toxcore/onion_client.c +1347 -0
  105. data/ProjectTox-Core/toxcore/onion_client.h +253 -0
  106. data/ProjectTox-Core/toxcore/ping.c +346 -0
  107. data/ProjectTox-Core/toxcore/ping.h +47 -0
  108. data/ProjectTox-Core/toxcore/ping_array.c +162 -0
  109. data/ProjectTox-Core/toxcore/ping_array.h +75 -0
  110. data/ProjectTox-Core/toxcore/tox.c +940 -0
  111. data/ProjectTox-Core/toxcore/tox.h +734 -0
  112. data/ProjectTox-Core/toxcore/util.c +193 -0
  113. data/ProjectTox-Core/toxcore/util.h +63 -0
  114. data/ProjectTox-Core/toxdns/Makefile.inc +29 -0
  115. data/ProjectTox-Core/toxdns/toxdns.c +238 -0
  116. data/ProjectTox-Core/toxdns/toxdns.h +88 -0
  117. data/ProjectTox-Core/toxencryptsave/Makefile.inc +45 -0
  118. data/ProjectTox-Core/toxencryptsave/toxencryptsave.c +179 -0
  119. data/ProjectTox-Core/toxencryptsave/toxencryptsave.h +74 -0
  120. data/interfaces/libtox.i +2 -6
  121. data/lib/ffi-tox/libtox.rb +406 -28
  122. metadata +124 -46
  123. data/ProjectTox-Core/CMakeLists.txt +0 -50
  124. data/ProjectTox-Core/cmake/FindLIBCONFIG.cmake +0 -15
  125. data/ProjectTox-Core/cmake/FindNaCl.cmake +0 -17
  126. data/ProjectTox-Core/cmake/FindSODIUM.cmake +0 -15
  127. data/ProjectTox-Core/core/CMakeLists.txt +0 -19
  128. data/ProjectTox-Core/core/DHT.c +0 -1104
  129. data/ProjectTox-Core/core/DHT.h +0 -111
  130. data/ProjectTox-Core/core/LAN_discovery.c +0 -79
  131. data/ProjectTox-Core/core/Lossless_UDP.c +0 -755
  132. data/ProjectTox-Core/core/Lossless_UDP.h +0 -106
  133. data/ProjectTox-Core/core/Messenger.c +0 -596
  134. data/ProjectTox-Core/core/Messenger.h +0 -165
  135. data/ProjectTox-Core/core/friend_requests.c +0 -131
  136. data/ProjectTox-Core/core/friend_requests.h +0 -51
  137. data/ProjectTox-Core/core/net_crypto.c +0 -575
  138. data/ProjectTox-Core/core/net_crypto.h +0 -134
  139. data/ProjectTox-Core/core/network.c +0 -205
  140. data/ProjectTox-Core/core/network.h +0 -134
  141. data/ProjectTox-Core/docs/commands.md +0 -25
  142. data/ProjectTox-Core/docs/start_guide.de.md +0 -40
  143. data/ProjectTox-Core/docs/start_guide.md +0 -38
  144. data/ProjectTox-Core/other/CMakeLists.txt +0 -9
  145. data/ProjectTox-Core/testing/CMakeLists.txt +0 -18
  146. data/ProjectTox-Core/testing/DHT_cryptosendfiletest.c +0 -228
  147. data/ProjectTox-Core/testing/DHT_sendfiletest.c +0 -176
  148. data/ProjectTox-Core/testing/Lossless_UDP_testclient.c +0 -214
  149. data/ProjectTox-Core/testing/Lossless_UDP_testserver.c +0 -201
  150. data/ProjectTox-Core/testing/misc_tools.h +0 -29
  151. data/ProjectTox-Core/testing/nTox_win32.c +0 -387
  152. data/ProjectTox-Core/testing/nTox_win32.h +0 -40
  153. data/ProjectTox-Core/testing/rect.py +0 -45
@@ -28,23 +28,28 @@
28
28
 
29
29
  #include "DHT.h"
30
30
 
31
- #ifdef __cplusplus
32
- extern "C" {
31
+ /* Used for get_broadcast(). */
32
+ #ifdef __linux
33
+ #include <sys/ioctl.h>
34
+ #include <arpa/inet.h>
35
+ #include <linux/netdevice.h>
33
36
  #endif
34
37
 
35
- /*Send a LAN discovery pcaket to the broadcast address with port port*/
36
- int send_LANdiscovery(uint16_t port);
38
+ /* Interval in seconds between LAN discovery packet sending. */
39
+ #define LAN_DISCOVERY_INTERVAL 10
37
40
 
41
+ /* Send a LAN discovery pcaket to the broadcast address with port port. */
42
+ int send_LANdiscovery(uint16_t port, DHT *dht);
38
43
 
39
- /* if we receive a packet we call this function so it can be handled.
40
- return 0 if packet is handled correctly.
41
- return 1 if it didn't handle the packet or if the packet was shit. */
42
- int LANdiscovery_handlepacket(uint8_t *packet, uint32_t length, IP_Port source);
43
-
44
+ /* Sets up packet handlers. */
45
+ void LANdiscovery_init(DHT *dht);
44
46
 
47
+ /* checks if a given IP isn't routable
48
+ *
49
+ * return 0 if ip is a LAN ip.
50
+ * return -1 if it is not.
51
+ */
52
+ int LAN_ip(IP ip);
45
53
 
46
- #ifdef __cplusplus
47
- }
48
- #endif
49
54
 
50
55
  #endif
@@ -0,0 +1,67 @@
1
+ lib_LTLIBRARIES += libtoxcore.la
2
+
3
+ libtoxcore_la_include_HEADERS = \
4
+ ../toxcore/tox.h
5
+
6
+ libtoxcore_la_includedir = $(includedir)/tox
7
+
8
+ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
9
+ ../toxcore/DHT.c \
10
+ ../toxcore/network.h \
11
+ ../toxcore/network.c \
12
+ ../toxcore/crypto_core.h \
13
+ ../toxcore/crypto_core.c \
14
+ ../toxcore/ping_array.h \
15
+ ../toxcore/ping_array.c \
16
+ ../toxcore/net_crypto.h \
17
+ ../toxcore/net_crypto.c \
18
+ ../toxcore/friend_requests.h \
19
+ ../toxcore/friend_requests.c \
20
+ ../toxcore/LAN_discovery.h \
21
+ ../toxcore/LAN_discovery.c \
22
+ ../toxcore/Messenger.h \
23
+ ../toxcore/Messenger.c \
24
+ ../toxcore/ping.h \
25
+ ../toxcore/ping.c \
26
+ ../toxcore/tox.h \
27
+ ../toxcore/tox.c \
28
+ ../toxcore/util.h \
29
+ ../toxcore/util.c \
30
+ ../toxcore/group_chats.h \
31
+ ../toxcore/group_chats.c \
32
+ ../toxcore/assoc.h \
33
+ ../toxcore/assoc.c \
34
+ ../toxcore/onion.h \
35
+ ../toxcore/onion.c \
36
+ ../toxcore/logger.h \
37
+ ../toxcore/logger.c \
38
+ ../toxcore/onion_announce.h \
39
+ ../toxcore/onion_announce.c \
40
+ ../toxcore/onion_client.h \
41
+ ../toxcore/onion_client.c \
42
+ ../toxcore/TCP_client.h \
43
+ ../toxcore/TCP_client.c \
44
+ ../toxcore/TCP_server.h \
45
+ ../toxcore/TCP_server.c \
46
+ ../toxcore/list.c \
47
+ ../toxcore/list.h \
48
+ ../toxcore/misc_tools.h
49
+
50
+ libtoxcore_la_CFLAGS = -I$(top_srcdir) \
51
+ -I$(top_srcdir)/toxcore \
52
+ $(LIBSODIUM_CFLAGS) \
53
+ $(NACL_CFLAGS) \
54
+ $(PTHREAD_CFLAGS)
55
+
56
+ libtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \
57
+ $(EXTRA_LT_LDFLAGS) \
58
+ $(LIBSODIUM_LDFLAGS) \
59
+ $(NACL_LDFLAGS) \
60
+ $(MATH_LDFLAGS) \
61
+ $(RT_LIBS) \
62
+ $(WINSOCK2_LIBS)
63
+
64
+ libtoxcore_la_LIBADD = $(LIBSODIUM_LIBS) \
65
+ $(NACL_OBJECTS) \
66
+ $(NAC_LIBS) \
67
+ $(PTHREAD_LIBS)
@@ -0,0 +1,3006 @@
1
+ /* Messenger.c
2
+ *
3
+ * An implementation of a simple text chat only messenger on the tox network core.
4
+ *
5
+ * Copyright (C) 2013 Tox project All Rights Reserved.
6
+ *
7
+ * This file is part of Tox.
8
+ *
9
+ * Tox is free software: you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation, either version 3 of the License, or
12
+ * (at your option) any later version.
13
+ *
14
+ * Tox is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+ #ifdef HAVE_CONFIG_H
25
+ #include "config.h"
26
+ #endif
27
+
28
+ #ifdef DEBUG
29
+ #include <assert.h>
30
+ #endif
31
+
32
+ #include "logger.h"
33
+ #include "Messenger.h"
34
+ #include "assoc.h"
35
+ #include "network.h"
36
+ #include "util.h"
37
+
38
+
39
+ #define MIN(a,b) (((a)<(b))?(a):(b))
40
+
41
+
42
+ static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status);
43
+ static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,
44
+ uint32_t length, uint8_t congestion_control);
45
+
46
+ // friend_not_valid determines if the friendnumber passed is valid in the Messenger object
47
+ static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber)
48
+ {
49
+ return (unsigned int)friendnumber >= m->numfriends;
50
+ }
51
+
52
+ static int add_online_friend(Messenger *m, int32_t friendnumber)
53
+ {
54
+ if (friend_not_valid(m, friendnumber))
55
+ return -1;
56
+
57
+ ++m->numonline_friends;
58
+ return 0;
59
+ }
60
+
61
+
62
+ static int remove_online_friend(Messenger *m, int32_t friendnumber)
63
+ {
64
+ if (friend_not_valid(m, friendnumber))
65
+ return -1;
66
+
67
+ --m->numonline_friends;
68
+ return 0;
69
+ }
70
+ /* Set the size of the friend list to numfriends.
71
+ *
72
+ * return -1 if realloc fails.
73
+ */
74
+ int realloc_friendlist(Messenger *m, uint32_t num)
75
+ {
76
+ if (num == 0) {
77
+ free(m->friendlist);
78
+ m->friendlist = NULL;
79
+ return 0;
80
+ }
81
+
82
+ Friend *newfriendlist = realloc(m->friendlist, num * sizeof(Friend));
83
+
84
+ if (newfriendlist == NULL)
85
+ return -1;
86
+
87
+ m->friendlist = newfriendlist;
88
+ return 0;
89
+ }
90
+
91
+ /* return the friend id associated to that public key.
92
+ * return -1 if no such friend.
93
+ */
94
+ int32_t getfriend_id(const Messenger *m, const uint8_t *client_id)
95
+ {
96
+ uint32_t i;
97
+
98
+ for (i = 0; i < m->numfriends; ++i) {
99
+ if (m->friendlist[i].status > 0)
100
+ if (id_equal(client_id, m->friendlist[i].client_id))
101
+ return i;
102
+ }
103
+
104
+ return -1;
105
+ }
106
+
107
+ /* Copies the public key associated to that friend id into client_id buffer.
108
+ * Make sure that client_id is of size CLIENT_ID_SIZE.
109
+ *
110
+ * return 0 if success.
111
+ * return -1 if failure.
112
+ */
113
+ int getclient_id(const Messenger *m, int32_t friendnumber, uint8_t *client_id)
114
+ {
115
+ if (friend_not_valid(m, friendnumber))
116
+ return -1;
117
+
118
+ if (m->friendlist[friendnumber].status > 0) {
119
+ memcpy(client_id, m->friendlist[friendnumber].client_id, CLIENT_ID_SIZE);
120
+ return 0;
121
+ }
122
+
123
+ return -1;
124
+ }
125
+ /* TODO: Another checksum algorithm might be better.
126
+ *
127
+ * return a uint16_t that represents the checksum of address of length len.
128
+ */
129
+ static uint16_t address_checksum(const uint8_t *address, uint32_t len)
130
+ {
131
+ uint8_t checksum[2] = {0};
132
+ uint16_t check;
133
+ uint32_t i;
134
+
135
+ for (i = 0; i < len; ++i)
136
+ checksum[i % 2] ^= address[i];
137
+
138
+ memcpy(&check, checksum, sizeof(check));
139
+ return check;
140
+ }
141
+
142
+ /* Format: [client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]
143
+ *
144
+ * return FRIEND_ADDRESS_SIZE byte address to give to others.
145
+ */
146
+ void getaddress(const Messenger *m, uint8_t *address)
147
+ {
148
+ id_copy(address, m->net_crypto->self_public_key);
149
+ uint32_t nospam = get_nospam(&(m->fr));
150
+ memcpy(address + crypto_box_PUBLICKEYBYTES, &nospam, sizeof(nospam));
151
+ uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
152
+ memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum));
153
+ }
154
+
155
+ /* callback for recv TCP relay nodes. */
156
+ static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key)
157
+ {
158
+ Messenger *m = object;
159
+
160
+ if (friend_not_valid(m, number))
161
+ return -1;
162
+
163
+ if (m->friendlist[number].crypt_connection_id != -1) {
164
+ return add_tcp_relay_peer(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port, public_key);
165
+ } else {
166
+ return add_tcp_relay(m->net_crypto, ip_port, public_key);
167
+ }
168
+ }
169
+
170
+ /*
171
+ * Add a friend.
172
+ * Set the data that will be sent along with friend request.
173
+ * Address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes.
174
+ * data is the data and length is the length.
175
+ *
176
+ * return the friend number if success.
177
+ * return FA_TOOLONG if message length is too long.
178
+ * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte).
179
+ * return FAERR_OWNKEY if user's own key.
180
+ * return FAERR_ALREADYSENT if friend request already sent or already a friend.
181
+ * return FAERR_UNKNOWN for unknown error.
182
+ * return FAERR_BADCHECKSUM if bad checksum in address.
183
+ * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different.
184
+ * (the nospam for that friend was set to the new one).
185
+ * return FAERR_NOMEM if increasing the friend list size fails.
186
+ */
187
+ int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length)
188
+ {
189
+ if (length > MAX_FRIEND_REQUEST_DATA_SIZE)
190
+ return FAERR_TOOLONG;
191
+
192
+ uint8_t client_id[crypto_box_PUBLICKEYBYTES];
193
+ id_copy(client_id, address);
194
+
195
+ if (!public_key_valid(client_id))
196
+ return FAERR_BADCHECKSUM;
197
+
198
+ uint16_t check, checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
199
+ memcpy(&check, address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), sizeof(check));
200
+
201
+ if (check != checksum)
202
+ return FAERR_BADCHECKSUM;
203
+
204
+ if (length < 1)
205
+ return FAERR_NOMESSAGE;
206
+
207
+ if (id_equal(client_id, m->net_crypto->self_public_key))
208
+ return FAERR_OWNKEY;
209
+
210
+ int32_t friend_id = getfriend_id(m, client_id);
211
+
212
+ if (friend_id != -1) {
213
+ if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED)
214
+ return FAERR_ALREADYSENT;
215
+
216
+ uint32_t nospam;
217
+ memcpy(&nospam, address + crypto_box_PUBLICKEYBYTES, sizeof(nospam));
218
+
219
+ if (m->friendlist[friend_id].friendrequest_nospam == nospam)
220
+ return FAERR_ALREADYSENT;
221
+
222
+ m->friendlist[friend_id].friendrequest_nospam = nospam;
223
+ return FAERR_SETNEWNOSPAM;
224
+ }
225
+
226
+ /* Resize the friend list if necessary. */
227
+ if (realloc_friendlist(m, m->numfriends + 1) != 0)
228
+ return FAERR_NOMEM;
229
+
230
+ memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend));
231
+
232
+ int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id);
233
+
234
+ if (onion_friendnum == -1)
235
+ return FAERR_UNKNOWN;
236
+
237
+ uint32_t i;
238
+
239
+ for (i = 0; i <= m->numfriends; ++i) {
240
+ if (m->friendlist[i].status == NOFRIEND) {
241
+ m->friendlist[i].onion_friendnum = onion_friendnum;
242
+ m->friendlist[i].status = FRIEND_ADDED;
243
+ m->friendlist[i].crypt_connection_id = -1;
244
+ m->friendlist[i].friendrequest_lastsent = 0;
245
+ m->friendlist[i].friendrequest_timeout = FRIENDREQUEST_TIMEOUT;
246
+ id_copy(m->friendlist[i].client_id, client_id);
247
+ m->friendlist[i].statusmessage = calloc(1, 1);
248
+ m->friendlist[i].statusmessage_length = 1;
249
+ m->friendlist[i].userstatus = USERSTATUS_NONE;
250
+ m->friendlist[i].is_typing = 0;
251
+ memcpy(m->friendlist[i].info, data, length);
252
+ m->friendlist[i].info_size = length;
253
+ m->friendlist[i].message_id = 0;
254
+ m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */
255
+ memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t));
256
+ recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i);
257
+
258
+ if (m->numfriends == i)
259
+ ++m->numfriends;
260
+
261
+ return i;
262
+ }
263
+ }
264
+
265
+ return FAERR_UNKNOWN;
266
+ }
267
+
268
+ int32_t m_addfriend_norequest(Messenger *m, const uint8_t *client_id)
269
+ {
270
+ if (getfriend_id(m, client_id) != -1)
271
+ return -1;
272
+
273
+ if (!public_key_valid(client_id))
274
+ return -1;
275
+
276
+ /* Resize the friend list if necessary. */
277
+ if (realloc_friendlist(m, m->numfriends + 1) != 0)
278
+ return -1;
279
+
280
+ if (id_equal(client_id, m->net_crypto->self_public_key))
281
+ return -1;
282
+
283
+ memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend));
284
+
285
+ int32_t onion_friendnum = onion_addfriend(m->onion_c, client_id);
286
+
287
+ if (onion_friendnum == -1)
288
+ return -1;
289
+
290
+ uint32_t i;
291
+
292
+ for (i = 0; i <= m->numfriends; ++i) {
293
+ if (m->friendlist[i].status == NOFRIEND) {
294
+ m->friendlist[i].onion_friendnum = onion_friendnum;
295
+ m->friendlist[i].status = FRIEND_CONFIRMED;
296
+ m->friendlist[i].crypt_connection_id = -1;
297
+ m->friendlist[i].friendrequest_lastsent = 0;
298
+ id_copy(m->friendlist[i].client_id, client_id);
299
+ m->friendlist[i].statusmessage = calloc(1, 1);
300
+ m->friendlist[i].statusmessage_length = 1;
301
+ m->friendlist[i].userstatus = USERSTATUS_NONE;
302
+ m->friendlist[i].is_typing = 0;
303
+ m->friendlist[i].message_id = 0;
304
+ m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */
305
+ recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i);
306
+
307
+ if (m->numfriends == i)
308
+ ++m->numfriends;
309
+
310
+ return i;
311
+ }
312
+ }
313
+
314
+ return -1;
315
+ }
316
+
317
+ /* Remove a friend.
318
+ *
319
+ * return 0 if success.
320
+ * return -1 if failure.
321
+ */
322
+ int m_delfriend(Messenger *m, int32_t friendnumber)
323
+ {
324
+ if (friend_not_valid(m, friendnumber))
325
+ return -1;
326
+
327
+ if (m->friendlist[friendnumber].status == FRIEND_ONLINE)
328
+ remove_online_friend(m, friendnumber);
329
+
330
+ onion_delfriend(m->onion_c, m->friendlist[friendnumber].onion_friendnum);
331
+ crypto_kill(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id);
332
+ free(m->friendlist[friendnumber].statusmessage);
333
+ remove_request_received(&(m->fr), m->friendlist[friendnumber].client_id);
334
+ memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend));
335
+ uint32_t i;
336
+
337
+ for (i = m->numfriends; i != 0; --i) {
338
+ if (m->friendlist[i - 1].status != NOFRIEND)
339
+ break;
340
+ }
341
+
342
+ m->numfriends = i;
343
+
344
+ if (realloc_friendlist(m, m->numfriends) != 0)
345
+ return FAERR_NOMEM;
346
+
347
+ return 0;
348
+ }
349
+
350
+ int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber)
351
+ {
352
+ if (friend_not_valid(m, friendnumber))
353
+ return -1;
354
+
355
+ return m->friendlist[friendnumber].status == FRIEND_ONLINE;
356
+ }
357
+
358
+ int m_friend_exists(const Messenger *m, int32_t friendnumber)
359
+ {
360
+ if (friend_not_valid(m, friendnumber))
361
+ return 0;
362
+
363
+ return m->friendlist[friendnumber].status > NOFRIEND;
364
+ }
365
+
366
+ /* Send a text chat message to an online friend.
367
+ *
368
+ * return the message id if packet was successfully put into the send queue.
369
+ * return 0 if it was not.
370
+ */
371
+ uint32_t m_sendmessage(Messenger *m, int32_t friendnumber, const uint8_t *message, uint32_t length)
372
+ {
373
+ if (friend_not_valid(m, friendnumber))
374
+ return 0;
375
+
376
+ uint32_t msgid = ++m->friendlist[friendnumber].message_id;
377
+
378
+ if (msgid == 0)
379
+ msgid = 1; // Otherwise, false error
380
+
381
+ if (m_sendmessage_withid(m, friendnumber, msgid, message, length)) {
382
+ return msgid;
383
+ }
384
+
385
+ return 0;
386
+ }
387
+
388
+ uint32_t m_sendmessage_withid(Messenger *m, int32_t friendnumber, uint32_t theid, const uint8_t *message,
389
+ uint32_t length)
390
+ {
391
+ if (length >= (MAX_CRYPTO_DATA_SIZE - sizeof(theid)) || length == 0)
392
+ return 0;
393
+
394
+ uint8_t temp[sizeof(theid) + length];
395
+ theid = htonl(theid);
396
+ memcpy(temp, &theid, sizeof(theid));
397
+ memcpy(temp + sizeof(theid), message, length);
398
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_MESSAGE, temp, sizeof(temp), 0);
399
+ }
400
+
401
+ /* Send an action to an online friend.
402
+ *
403
+ * return the message id if packet was successfully put into the send queue.
404
+ * return 0 if it was not.
405
+ */
406
+ uint32_t m_sendaction(Messenger *m, int32_t friendnumber, const uint8_t *action, uint32_t length)
407
+ {
408
+ if (friend_not_valid(m, friendnumber))
409
+ return 0;
410
+
411
+ uint32_t msgid = ++m->friendlist[friendnumber].message_id;
412
+
413
+ if (msgid == 0)
414
+ msgid = 1; // Otherwise, false error
415
+
416
+ if (m_sendaction_withid(m, friendnumber, msgid, action, length)) {
417
+ return msgid;
418
+ }
419
+
420
+ return 0;
421
+ }
422
+
423
+ uint32_t m_sendaction_withid(const Messenger *m, int32_t friendnumber, uint32_t theid, const uint8_t *action,
424
+ uint32_t length)
425
+ {
426
+ if (length >= (MAX_CRYPTO_DATA_SIZE - sizeof(theid)) || length == 0)
427
+ return 0;
428
+
429
+ uint8_t temp[sizeof(theid) + length];
430
+ theid = htonl(theid);
431
+ memcpy(temp, &theid, sizeof(theid));
432
+ memcpy(temp + sizeof(theid), action, length);
433
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_ACTION, temp, sizeof(temp), 0);
434
+ }
435
+
436
+ /* Send a name packet to friendnumber.
437
+ * length is the length with the NULL terminator.
438
+ */
439
+ static int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length)
440
+ {
441
+ if (length > MAX_NAME_LENGTH || length == 0)
442
+ return 0;
443
+
444
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length, 0);
445
+ }
446
+
447
+ /* Set the name and name_length of a friend.
448
+ *
449
+ * return 0 if success.
450
+ * return -1 if failure.
451
+ */
452
+ int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length)
453
+ {
454
+ if (friend_not_valid(m, friendnumber))
455
+ return -1;
456
+
457
+ if (length > MAX_NAME_LENGTH || length == 0)
458
+ return -1;
459
+
460
+ m->friendlist[friendnumber].name_length = length;
461
+ memcpy(m->friendlist[friendnumber].name, name, length);
462
+ return 0;
463
+ }
464
+
465
+ /* Set our nickname
466
+ * name must be a string of maximum MAX_NAME_LENGTH length.
467
+ * length must be at least 1 byte.
468
+ * length is the length of name with the NULL terminator.
469
+ *
470
+ * return 0 if success.
471
+ * return -1 if failure.
472
+ */
473
+ int setname(Messenger *m, const uint8_t *name, uint16_t length)
474
+ {
475
+ if (length > MAX_NAME_LENGTH || length == 0)
476
+ return -1;
477
+
478
+ memcpy(m->name, name, length);
479
+ m->name_length = length;
480
+ uint32_t i;
481
+
482
+ for (i = 0; i < m->numfriends; ++i)
483
+ m->friendlist[i].name_sent = 0;
484
+
485
+ for (i = 0; i < m->numchats; i++)
486
+ if (m->chats[i] != NULL)
487
+ set_nick(m->chats[i], name, length); /* TODO: remove this (group nicks should not be tied to the global one) */
488
+
489
+ return 0;
490
+ }
491
+
492
+ /* Get our nickname and put it in name.
493
+ * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
494
+ *
495
+ * return the length of the name.
496
+ */
497
+ uint16_t getself_name(const Messenger *m, uint8_t *name)
498
+ {
499
+ if (name == NULL) {
500
+ return 0;
501
+ }
502
+
503
+ memcpy(name, m->name, m->name_length);
504
+
505
+ return m->name_length;
506
+ }
507
+
508
+ /* Get name of friendnumber and put it in name.
509
+ * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
510
+ *
511
+ * return length of name if success.
512
+ * return -1 if failure.
513
+ */
514
+ int getname(const Messenger *m, int32_t friendnumber, uint8_t *name)
515
+ {
516
+ if (friend_not_valid(m, friendnumber))
517
+ return -1;
518
+
519
+ memcpy(name, m->friendlist[friendnumber].name, m->friendlist[friendnumber].name_length);
520
+ return m->friendlist[friendnumber].name_length;
521
+ }
522
+
523
+ int m_get_name_size(const Messenger *m, int32_t friendnumber)
524
+ {
525
+ if (friend_not_valid(m, friendnumber))
526
+ return -1;
527
+
528
+ return m->friendlist[friendnumber].name_length;
529
+ }
530
+
531
+ int m_get_self_name_size(const Messenger *m)
532
+ {
533
+ return m->name_length;
534
+ }
535
+
536
+ int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length)
537
+ {
538
+ if (length > MAX_STATUSMESSAGE_LENGTH)
539
+ return -1;
540
+
541
+ memcpy(m->statusmessage, status, length);
542
+ m->statusmessage_length = length;
543
+
544
+ uint32_t i;
545
+
546
+ for (i = 0; i < m->numfriends; ++i)
547
+ m->friendlist[i].statusmessage_sent = 0;
548
+
549
+ return 0;
550
+ }
551
+
552
+ int m_set_userstatus(Messenger *m, uint8_t status)
553
+ {
554
+ if (status >= USERSTATUS_INVALID) {
555
+ return -1;
556
+ }
557
+
558
+ m->userstatus = status;
559
+ uint32_t i;
560
+
561
+ for (i = 0; i < m->numfriends; ++i)
562
+ m->friendlist[i].userstatus_sent = 0;
563
+
564
+ return 0;
565
+ }
566
+
567
+ /* return the size of friendnumber's user status.
568
+ * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
569
+ */
570
+ int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber)
571
+ {
572
+ if (friend_not_valid(m, friendnumber))
573
+ return -1;
574
+
575
+ return m->friendlist[friendnumber].statusmessage_length;
576
+ }
577
+
578
+ /* Copy the user status of friendnumber into buf, truncating if needed to maxlen
579
+ * bytes, use m_get_statusmessage_size to find out how much you need to allocate.
580
+ */
581
+ int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen)
582
+ {
583
+ if (friend_not_valid(m, friendnumber))
584
+ return -1;
585
+
586
+ int msglen = MIN(maxlen, m->friendlist[friendnumber].statusmessage_length);
587
+
588
+ memcpy(buf, m->friendlist[friendnumber].statusmessage, msglen);
589
+ memset(buf + msglen, 0, maxlen - msglen);
590
+ return msglen;
591
+ }
592
+
593
+ /* return the size of friendnumber's user status.
594
+ * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
595
+ */
596
+ int m_get_self_statusmessage_size(const Messenger *m)
597
+ {
598
+ return m->statusmessage_length;
599
+ }
600
+
601
+ int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf, uint32_t maxlen)
602
+ {
603
+ int msglen = MIN(maxlen, m->statusmessage_length);
604
+ memcpy(buf, m->statusmessage, msglen);
605
+ memset(buf + msglen, 0, maxlen - msglen);
606
+ return msglen;
607
+ }
608
+
609
+ uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber)
610
+ {
611
+ if (friend_not_valid(m, friendnumber))
612
+ return USERSTATUS_INVALID;
613
+
614
+ uint8_t status = m->friendlist[friendnumber].userstatus;
615
+
616
+ if (status >= USERSTATUS_INVALID) {
617
+ status = USERSTATUS_NONE;
618
+ }
619
+
620
+ return status;
621
+ }
622
+
623
+ uint8_t m_get_self_userstatus(const Messenger *m)
624
+ {
625
+ return m->userstatus;
626
+ }
627
+
628
+ uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber)
629
+ {
630
+ if (friend_not_valid(m, friendnumber))
631
+ return -1;
632
+
633
+ return m->friendlist[friendnumber].ping_lastrecv;
634
+ }
635
+
636
+ int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing)
637
+
638
+ {
639
+ if (is_typing != 0 && is_typing != 1) {
640
+ return -1;
641
+ }
642
+
643
+ if (friend_not_valid(m, friendnumber))
644
+ return -1;
645
+
646
+ m->friendlist[friendnumber].user_istyping = is_typing;
647
+ m->friendlist[friendnumber].user_istyping_sent = 0;
648
+
649
+ return 0;
650
+ }
651
+
652
+ uint8_t m_get_istyping(const Messenger *m, int32_t friendnumber)
653
+ {
654
+ if (friend_not_valid(m, friendnumber))
655
+ return -1;
656
+
657
+ return m->friendlist[friendnumber].is_typing;
658
+ }
659
+
660
+ static int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length)
661
+ {
662
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length, 0);
663
+ }
664
+
665
+ static int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status)
666
+ {
667
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status), 0);
668
+ }
669
+
670
+ static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing)
671
+ {
672
+ uint8_t typing = is_typing;
673
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0);
674
+ }
675
+
676
+ static int send_ping(const Messenger *m, int32_t friendnumber)
677
+ {
678
+ int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_ALIVE, 0, 0, 0);
679
+
680
+ if (ret == 1)
681
+ m->friendlist[friendnumber].ping_lastsent = unix_time();
682
+
683
+ return ret;
684
+ }
685
+
686
+ static int send_relays(const Messenger *m, int32_t friendnumber)
687
+ {
688
+ Node_format nodes[MAX_SHARED_RELAYS];
689
+ uint8_t data[1024];
690
+ int n, length;
691
+
692
+ n = copy_connected_tcp_relays(m->net_crypto, nodes, MAX_SHARED_RELAYS);
693
+ length = pack_nodes(data, sizeof(data), nodes, n);
694
+
695
+ int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_SHARE_RELAYS, data, length, 0);
696
+
697
+ if (ret == 1)
698
+ m->friendlist[friendnumber].share_relays_lastsent = unix_time();
699
+
700
+ return ret;
701
+ }
702
+
703
+
704
+
705
+ static int set_friend_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length)
706
+ {
707
+ if (friend_not_valid(m, friendnumber))
708
+ return -1;
709
+
710
+ uint8_t *newstatus = calloc(length + 1, 1);
711
+ memcpy(newstatus, status, length);
712
+ free(m->friendlist[friendnumber].statusmessage);
713
+ m->friendlist[friendnumber].statusmessage = newstatus;
714
+ m->friendlist[friendnumber].statusmessage_length = length;
715
+ return 0;
716
+ }
717
+
718
+ static void set_friend_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status)
719
+ {
720
+ m->friendlist[friendnumber].userstatus = status;
721
+ }
722
+
723
+ static void set_friend_typing(const Messenger *m, int32_t friendnumber, uint8_t is_typing)
724
+ {
725
+ m->friendlist[friendnumber].is_typing = is_typing;
726
+ }
727
+
728
+ /* Sets whether we send read receipts for friendnumber. */
729
+ void m_set_sends_receipts(Messenger *m, int32_t friendnumber, int yesno)
730
+ {
731
+ if (yesno != 0 && yesno != 1)
732
+ return;
733
+
734
+ if (friend_not_valid(m, friendnumber))
735
+ return;
736
+
737
+ m->friendlist[friendnumber].receives_read_receipts = yesno;
738
+ }
739
+
740
+ /* static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); */
741
+ /* Set the function that will be executed when a friend request is received. */
742
+ void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, uint16_t,
743
+ void *), void *userdata)
744
+ {
745
+ void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, uint16_t, void *) = (void *)function;
746
+ callback_friendrequest(&(m->fr), handle_friendrequest, m, userdata);
747
+ }
748
+
749
+ /* Set the function that will be executed when a message from a friend is received. */
750
+ void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *),
751
+ void *userdata)
752
+ {
753
+ m->friend_message = function;
754
+ m->friend_message_userdata = userdata;
755
+ }
756
+
757
+ void m_callback_action(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *),
758
+ void *userdata)
759
+ {
760
+ m->friend_action = function;
761
+ m->friend_action_userdata = userdata;
762
+ }
763
+
764
+ void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *),
765
+ void *userdata)
766
+ {
767
+ m->friend_namechange = function;
768
+ m->friend_namechange_userdata = userdata;
769
+ }
770
+
771
+ void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *),
772
+ void *userdata)
773
+ {
774
+ m->friend_statusmessagechange = function;
775
+ m->friend_statuschange_userdata = userdata;
776
+ }
777
+
778
+ void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata)
779
+ {
780
+ m->friend_userstatuschange = function;
781
+ m->friend_userstatuschange_userdata = userdata;
782
+ }
783
+
784
+ void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata)
785
+ {
786
+ m->friend_typingchange = function;
787
+ m->friend_typingchange_userdata = userdata;
788
+ }
789
+
790
+ void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, int32_t, uint32_t, void *), void *userdata)
791
+ {
792
+ m->read_receipt = function;
793
+ m->read_receipt_userdata = userdata;
794
+ }
795
+
796
+ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *), void *userdata)
797
+ {
798
+ m->friend_connectionstatuschange = function;
799
+ m->friend_connectionstatuschange_userdata = userdata;
800
+ }
801
+
802
+ void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, void *),
803
+ void *userdata)
804
+ {
805
+ m->friend_connectionstatuschange_internal = function;
806
+ m->friend_connectionstatuschange_internal_userdata = userdata;
807
+ }
808
+
809
+ static void break_files(const Messenger *m, int32_t friendnumber);
810
+ static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status)
811
+ {
812
+ if (status == NOFRIEND)
813
+ return;
814
+
815
+ const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE;
816
+ const uint8_t is_online = status == FRIEND_ONLINE;
817
+
818
+ onion_set_friend_online(m->onion_c, m->friendlist[friendnumber].onion_friendnum, is_online);
819
+
820
+ if (is_online != was_online) {
821
+ if (was_online) {
822
+ break_files(m, friendnumber);
823
+ remove_online_friend(m, friendnumber);
824
+ } else {
825
+ add_online_friend(m, friendnumber);
826
+ }
827
+
828
+ m->friendlist[friendnumber].status = status;
829
+
830
+ if (m->friend_connectionstatuschange)
831
+ m->friend_connectionstatuschange(m, friendnumber, is_online, m->friend_connectionstatuschange_userdata);
832
+
833
+ if (m->friend_connectionstatuschange_internal)
834
+ m->friend_connectionstatuschange_internal(m, friendnumber, is_online,
835
+ m->friend_connectionstatuschange_internal_userdata);
836
+ }
837
+ }
838
+
839
+ void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status)
840
+ {
841
+ check_friend_connectionstatus(m, friendnumber, status);
842
+ m->friendlist[friendnumber].status = status;
843
+ }
844
+
845
+ static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,
846
+ uint32_t length, uint8_t congestion_control)
847
+ {
848
+ if (friend_not_valid(m, friendnumber))
849
+ return 0;
850
+
851
+ if (length >= MAX_CRYPTO_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE)
852
+ return 0;
853
+
854
+ uint8_t packet[length + 1];
855
+ packet[0] = packet_id;
856
+
857
+ if (length != 0)
858
+ memcpy(packet + 1, data, length);
859
+
860
+ return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1,
861
+ congestion_control) != -1;
862
+ }
863
+
864
+ /**********GROUP CHATS************/
865
+
866
+ /* return 1 if the groupnumber is not valid.
867
+ * return 0 if the groupnumber is valid.
868
+ */
869
+ static uint8_t groupnumber_not_valid(const Messenger *m, int groupnumber)
870
+ {
871
+ if ((unsigned int)groupnumber >= m->numchats)
872
+ return 1;
873
+
874
+ if (m->chats == NULL)
875
+ return 1;
876
+
877
+ if (m->chats[groupnumber] == NULL)
878
+ return 1;
879
+
880
+ return 0;
881
+ }
882
+
883
+
884
+ /* returns valid ip port of connected friend on success
885
+ * returns zeroed out IP_Port on failure
886
+ */
887
+ static IP_Port get_friend_ipport(const Messenger *m, int32_t friendnumber)
888
+ {
889
+ IP_Port zero;
890
+ memset(&zero, 0, sizeof(zero));
891
+
892
+ if (friend_not_valid(m, friendnumber))
893
+ return zero;
894
+
895
+ int crypt_id = m->friendlist[friendnumber].crypt_connection_id;
896
+
897
+ uint8_t direct_connected;
898
+
899
+ if (crypto_connection_status(m->net_crypto, crypt_id, &direct_connected) != CRYPTO_CONN_ESTABLISHED)
900
+ return zero;
901
+
902
+ if (direct_connected == 0)
903
+ return zero;
904
+
905
+ return m->net_crypto->crypto_connections[crypt_id].ip_port;
906
+ }
907
+
908
+ /* returns the group number of the chat with public key group_public_key.
909
+ * returns -1 on failure.
910
+ */
911
+ static int group_num(const Messenger *m, const uint8_t *group_public_key)
912
+ {
913
+ uint32_t i;
914
+
915
+ for (i = 0; i < m->numchats; ++i) {
916
+ if (m->chats[i] != NULL)
917
+ if (id_equal(m->chats[i]->self_public_key, group_public_key))
918
+ return i;
919
+ }
920
+
921
+ return -1;
922
+ }
923
+
924
+ /* Set the callback for group invites.
925
+ *
926
+ * Function(Messenger *m, int32_t friendnumber, uint8_t *group_public_key, void *userdata)
927
+ */
928
+ void m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, void *),
929
+ void *userdata)
930
+ {
931
+ m->group_invite = function;
932
+ m->group_invite_userdata = userdata;
933
+ }
934
+
935
+ /* Set the callback for group messages.
936
+ *
937
+ * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)
938
+ */
939
+ void m_callback_group_message(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *),
940
+ void *userdata)
941
+ {
942
+ m->group_message = function;
943
+ m->group_message_userdata = userdata;
944
+ }
945
+
946
+ /* Set the callback for group actions.
947
+ *
948
+ * Function(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)
949
+ */
950
+ void m_callback_group_action(Messenger *m, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t, void *),
951
+ void *userdata)
952
+ {
953
+ m->group_action = function;
954
+ m->group_action_userdata = userdata;
955
+ }
956
+
957
+ /* Set callback function for peer name list changes.
958
+ *
959
+ * It gets called every time the name list changes(new peer/name, deleted peer)
960
+ * Function(Tox *tox, int groupnumber, void *userdata)
961
+ */
962
+ void m_callback_group_namelistchange(Messenger *m, void (*function)(Messenger *m, int, int, uint8_t, void *),
963
+ void *userdata)
964
+ {
965
+ m->group_namelistchange = function;
966
+ m->group_namelistchange_userdata = userdata;
967
+ }
968
+
969
+ static int get_chat_num(const Messenger *m, const Group_Chat *chat)
970
+ {
971
+ uint32_t i;
972
+
973
+ for (i = 0; i < m->numchats; ++i) { //TODO: remove this
974
+ if (m->chats[i] == chat)
975
+ return i;
976
+ }
977
+
978
+ return -1;
979
+ }
980
+
981
+ static void group_message_function(Group_Chat *chat, int peer_number, const uint8_t *message, uint16_t length,
982
+ void *userdata)
983
+ {
984
+ Messenger *m = userdata;
985
+ int i = get_chat_num(m, chat);
986
+
987
+ if (i == -1)
988
+ return;
989
+
990
+ uint8_t message_terminated[length + 1];
991
+ memcpy(message_terminated, message, length);
992
+ message_terminated[length] = 0; /* Force NULL terminator */
993
+
994
+ if (m->group_message)
995
+ (*m->group_message)(m, i, peer_number, message_terminated, length, m->group_message_userdata);
996
+ }
997
+
998
+ static void group_action_function(Group_Chat *chat, int peer_number, const uint8_t *action, uint16_t length,
999
+ void *userdata)
1000
+ {
1001
+ Messenger *m = userdata;
1002
+ int i = get_chat_num(m, chat);
1003
+
1004
+ if (i == -1)
1005
+ return;
1006
+
1007
+ uint8_t action_terminated[length + 1];
1008
+ memcpy(action_terminated, action, length);
1009
+ action_terminated[length] = 0; /* Force NULL terminator */
1010
+
1011
+ if (m->group_action)
1012
+ (*m->group_action)(m, i, peer_number, action_terminated, length, m->group_action_userdata);
1013
+ }
1014
+
1015
+ static void group_namelistchange_function(Group_Chat *chat, int peer, uint8_t change, void *userdata)
1016
+ {
1017
+ Messenger *m = userdata;
1018
+ int i = get_chat_num(m, chat);
1019
+
1020
+ if (i == -1)
1021
+ return;
1022
+
1023
+ if (m->group_namelistchange)
1024
+ (*m->group_namelistchange)(m, i, peer, change, m->group_namelistchange_userdata);
1025
+ }
1026
+
1027
+
1028
+ /* Creates a new groupchat and puts it in the chats array.
1029
+ *
1030
+ * return group number on success.
1031
+ * return -1 on failure.
1032
+ */
1033
+ int add_groupchat(Messenger *m)
1034
+ {
1035
+ uint32_t i;
1036
+
1037
+ for (i = 0; i < m->numchats; ++i) {
1038
+ if (m->chats[i] == NULL) {
1039
+ Group_Chat *newchat = new_groupchat(m->net);
1040
+
1041
+ if (newchat == NULL)
1042
+ return -1;
1043
+
1044
+ callback_groupmessage(newchat, &group_message_function, m);
1045
+ callback_groupaction(newchat, &group_action_function, m);
1046
+ callback_namelistchange(newchat, &group_namelistchange_function, m);
1047
+ /* TODO: remove this (group nicks should not be tied to the global one) */
1048
+ set_nick(newchat, m->name, m->name_length);
1049
+ m->chats[i] = newchat;
1050
+ return i;
1051
+ }
1052
+ }
1053
+
1054
+ Group_Chat **temp;
1055
+ temp = realloc(m->chats, sizeof(Group_Chat *) * (m->numchats + 1));
1056
+
1057
+ if (temp == NULL)
1058
+ return -1;
1059
+
1060
+ m->chats = temp;
1061
+ temp[m->numchats] = new_groupchat(m->net);
1062
+
1063
+ if (temp[m->numchats] == NULL)
1064
+ return -1;
1065
+
1066
+ callback_groupmessage(temp[m->numchats], &group_message_function, m);
1067
+ callback_groupaction(temp[m->numchats], &group_action_function, m);
1068
+ callback_namelistchange(temp[m->numchats], &group_namelistchange_function, m);
1069
+ /* TODO: remove this (group nicks should not be tied to the global one) */
1070
+ set_nick(temp[m->numchats], m->name, m->name_length);
1071
+ ++m->numchats;
1072
+ return (m->numchats - 1);
1073
+ }
1074
+
1075
+ /* Delete a groupchat from the chats array.
1076
+ *
1077
+ * return 0 on success.
1078
+ * return -1 if failure.
1079
+ */
1080
+ int del_groupchat(Messenger *m, int groupnumber)
1081
+ {
1082
+ if ((unsigned int)groupnumber >= m->numchats)
1083
+ return -1;
1084
+
1085
+ if (m->chats == NULL)
1086
+ return -1;
1087
+
1088
+ if (m->chats[groupnumber] == NULL)
1089
+ return -1;
1090
+
1091
+ kill_groupchat(m->chats[groupnumber]);
1092
+ m->chats[groupnumber] = NULL;
1093
+
1094
+ uint32_t i;
1095
+
1096
+ for (i = m->numchats; i != 0; --i) {
1097
+ if (m->chats[i - 1] != NULL)
1098
+ break;
1099
+ }
1100
+
1101
+ m->numchats = i;
1102
+
1103
+ if (i == 0) {
1104
+ free(m->chats);
1105
+ m->chats = NULL;
1106
+ } else {
1107
+ Group_Chat **temp = realloc(m->chats, sizeof(Group_Chat *) * i);
1108
+
1109
+ if (temp != NULL)
1110
+ m->chats = temp;
1111
+ }
1112
+
1113
+ return 0;
1114
+ }
1115
+
1116
+ /* Copy the name of peernumber who is in groupnumber to name.
1117
+ * name must be at least MAX_NICK_BYTES long.
1118
+ *
1119
+ * return length of name if success
1120
+ * return -1 if failure
1121
+ */
1122
+ int m_group_peername(const Messenger *m, int groupnumber, int peernumber, uint8_t *name)
1123
+ {
1124
+ if ((unsigned int)groupnumber >= m->numchats)
1125
+ return -1;
1126
+
1127
+ if (m->chats == NULL)
1128
+ return -1;
1129
+
1130
+ if (m->chats[groupnumber] == NULL)
1131
+ return -1;
1132
+
1133
+ return group_peername(m->chats[groupnumber], peernumber, name);
1134
+ }
1135
+
1136
+ /* Store the fact that we invited a specific friend.
1137
+ */
1138
+ static void group_store_friendinvite(Messenger *m, int32_t friendnumber, int groupnumber)
1139
+ {
1140
+ /* Add 1 to the groupchat number because 0 (default value in invited_groups) is a valid groupchat number */
1141
+ m->friendlist[friendnumber].invited_groups[m->friendlist[friendnumber].invited_groups_num % MAX_INVITED_GROUPS] =
1142
+ groupnumber + 1;
1143
+ ++m->friendlist[friendnumber].invited_groups_num;
1144
+ }
1145
+
1146
+ /* return 1 if that friend was invited to the group
1147
+ * return 0 if the friend was not or error.
1148
+ */
1149
+ static uint8_t group_invited(const Messenger *m, int32_t friendnumber, int groupnumber)
1150
+ {
1151
+
1152
+ uint32_t i;
1153
+ uint16_t num = MAX_INVITED_GROUPS;
1154
+
1155
+ if (MAX_INVITED_GROUPS > m->friendlist[friendnumber].invited_groups_num)
1156
+ num = m->friendlist[friendnumber].invited_groups_num;
1157
+
1158
+ for (i = 0; i < num; ++i) {
1159
+ if (m->friendlist[friendnumber].invited_groups[i] == groupnumber + 1) {
1160
+ return 1;
1161
+ }
1162
+ }
1163
+
1164
+ return 0;
1165
+ }
1166
+
1167
+ /* invite friendnumber to groupnumber
1168
+ * return 0 on success
1169
+ * return -1 on failure
1170
+ */
1171
+ int invite_friend(Messenger *m, int32_t friendnumber, int groupnumber)
1172
+ {
1173
+ if (friend_not_valid(m, friendnumber) || (unsigned int)groupnumber >= m->numchats)
1174
+ return -1;
1175
+
1176
+ if (m->chats == NULL)
1177
+ return -1;
1178
+
1179
+ if (m->friendlist[friendnumber].status == NOFRIEND || m->chats[groupnumber] == NULL)
1180
+ return -1;
1181
+
1182
+ group_store_friendinvite(m, friendnumber, groupnumber);
1183
+
1184
+ if (write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, m->chats[groupnumber]->self_public_key,
1185
+ crypto_box_PUBLICKEYBYTES, 0) == 0)
1186
+ return -1;
1187
+
1188
+ return 0;
1189
+ }
1190
+
1191
+
1192
+ /* Join a group (you need to have been invited first.)
1193
+ *
1194
+ * returns group number on success
1195
+ * returns -1 on failure.
1196
+ */
1197
+ int join_groupchat(Messenger *m, int32_t friendnumber, const uint8_t *friend_group_public_key)
1198
+ {
1199
+ if (friend_not_valid(m, friendnumber))
1200
+ return -1;
1201
+
1202
+ uint8_t data[crypto_box_PUBLICKEYBYTES * 2];
1203
+ int groupnum = add_groupchat(m);
1204
+
1205
+ if (groupnum == -1)
1206
+ return -1;
1207
+
1208
+ IP_Port friend_ip = get_friend_ipport(m, friendnumber);
1209
+
1210
+ if (friend_ip.ip.family == 0) {
1211
+ del_groupchat(m, groupnum);
1212
+ return -1;
1213
+ }
1214
+
1215
+ id_copy(data, friend_group_public_key);
1216
+ id_copy(data + crypto_box_PUBLICKEYBYTES, m->chats[groupnum]->self_public_key);
1217
+
1218
+ if (write_cryptpacket_id(m, friendnumber, PACKET_ID_JOIN_GROUPCHAT, data, sizeof(data), 0)) {
1219
+ chat_bootstrap_nonlazy(m->chats[groupnum], get_friend_ipport(m, friendnumber),
1220
+ friend_group_public_key); //TODO: check if ip returned is zero?
1221
+ return groupnum;
1222
+ }
1223
+
1224
+ del_groupchat(m, groupnum);
1225
+ return -1;
1226
+ }
1227
+
1228
+
1229
+ /* send a group message
1230
+ * return 0 on success
1231
+ * return -1 on failure
1232
+ */
1233
+ int group_message_send(const Messenger *m, int groupnumber, const uint8_t *message, uint32_t length)
1234
+ {
1235
+ if (groupnumber_not_valid(m, groupnumber))
1236
+ return -1;
1237
+
1238
+ if (group_sendmessage(m->chats[groupnumber], message, length) > 0)
1239
+ return 0;
1240
+
1241
+ return -1;
1242
+ }
1243
+
1244
+ /* send a group action
1245
+ * return 0 on success
1246
+ * return -1 on failure
1247
+ */
1248
+ int group_action_send(const Messenger *m, int groupnumber, const uint8_t *action, uint32_t length)
1249
+ {
1250
+ if (groupnumber_not_valid(m, groupnumber))
1251
+ return -1;
1252
+
1253
+ if (group_sendaction(m->chats[groupnumber], action, length) > 0)
1254
+ return 0;
1255
+
1256
+ return -1;
1257
+ }
1258
+
1259
+ /* Return the number of peers in the group chat on success.
1260
+ * return -1 on failure
1261
+ */
1262
+ int group_number_peers(const Messenger *m, int groupnumber)
1263
+ {
1264
+ if (groupnumber_not_valid(m, groupnumber))
1265
+ return -1;
1266
+
1267
+ return group_numpeers(m->chats[groupnumber]);
1268
+ }
1269
+
1270
+ /* List all the peers in the group chat.
1271
+ *
1272
+ * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array.
1273
+ *
1274
+ * Copies the lengths of the names to lengths[length]
1275
+ *
1276
+ * returns the number of peers on success.
1277
+ *
1278
+ * return -1 on failure.
1279
+ */
1280
+ int group_names(const Messenger *m, int groupnumber, uint8_t names[][MAX_NICK_BYTES], uint16_t lengths[],
1281
+ uint16_t length)
1282
+ {
1283
+ if (groupnumber_not_valid(m, groupnumber))
1284
+ return -1;
1285
+
1286
+ return group_client_names(m->chats[groupnumber], names, lengths, length);
1287
+ }
1288
+
1289
+ static int handle_group(void *object, IP_Port source, const uint8_t *packet, uint32_t length)
1290
+ {
1291
+ Messenger *m = object;
1292
+
1293
+ if (length < crypto_box_PUBLICKEYBYTES + 1) {
1294
+ return 1;
1295
+ }
1296
+
1297
+ uint32_t i;
1298
+
1299
+ for (i = 0; i < m->numchats; ++i) {
1300
+ if (m->chats[i] == NULL)
1301
+ continue;
1302
+
1303
+ if (id_equal(packet + 1, m->chats[i]->self_public_key))
1304
+ return handle_groupchatpacket(m->chats[i], source, packet, length);
1305
+ }
1306
+
1307
+ return 1;
1308
+ }
1309
+
1310
+ static void do_allgroupchats(Messenger *m)
1311
+ {
1312
+ uint32_t i;
1313
+
1314
+ for (i = 0; i < m->numchats; ++i) {
1315
+ if (m->chats[i] != NULL)
1316
+ do_groupchat(m->chats[i]);
1317
+ }
1318
+ }
1319
+
1320
+ /****************FILE SENDING*****************/
1321
+
1322
+
1323
+ /* Set the callback for file send requests.
1324
+ *
1325
+ * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *filename, uint16_t filename_length, void *userdata)
1326
+ */
1327
+ void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint64_t, const uint8_t *,
1328
+ uint16_t, void *), void *userdata)
1329
+ {
1330
+ m->file_sendrequest = function;
1331
+ m->file_sendrequest_userdata = userdata;
1332
+ }
1333
+
1334
+ /* Set the callback for file control requests.
1335
+ *
1336
+ * Function(Tox *tox, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata)
1337
+ *
1338
+ */
1339
+ void callback_file_control(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, uint8_t, uint8_t,
1340
+ const uint8_t *, uint16_t, void *), void *userdata)
1341
+ {
1342
+ m->file_filecontrol = function;
1343
+ m->file_filecontrol_userdata = userdata;
1344
+ }
1345
+
1346
+ /* Set the callback for file data.
1347
+ *
1348
+ * Function(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata)
1349
+ *
1350
+ */
1351
+ void callback_file_data(Messenger *m, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t length,
1352
+ void *), void *userdata)
1353
+ {
1354
+ m->file_filedata = function;
1355
+ m->file_filedata_userdata = userdata;
1356
+ }
1357
+
1358
+ #define MAX_FILENAME_LENGTH 255
1359
+
1360
+ /* Send a file send request.
1361
+ * Maximum filename length is 255 bytes.
1362
+ * return 1 on success
1363
+ * return 0 on failure
1364
+ */
1365
+ int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
1366
+ const uint8_t *filename, uint16_t filename_length)
1367
+ {
1368
+ if (friend_not_valid(m, friendnumber))
1369
+ return 0;
1370
+
1371
+ if (filename_length > MAX_FILENAME_LENGTH)
1372
+ return 0;
1373
+
1374
+ uint8_t packet[MAX_FILENAME_LENGTH + 1 + sizeof(filesize)];
1375
+ packet[0] = filenumber;
1376
+ host_to_net((uint8_t *)&filesize, sizeof(filesize));
1377
+ memcpy(packet + 1, &filesize, sizeof(filesize));
1378
+ memcpy(packet + 1 + sizeof(filesize), filename, filename_length);
1379
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet,
1380
+ 1 + sizeof(filesize) + filename_length, 0);
1381
+ }
1382
+
1383
+ /* Send a file send request.
1384
+ * Maximum filename length is 255 bytes.
1385
+ * return file number on success
1386
+ * return -1 on failure
1387
+ */
1388
+ int new_filesender(const Messenger *m, int32_t friendnumber, uint64_t filesize, const uint8_t *filename,
1389
+ uint16_t filename_length)
1390
+ {
1391
+ if (friend_not_valid(m, friendnumber))
1392
+ return -1;
1393
+
1394
+ uint32_t i;
1395
+
1396
+ for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1397
+ if (m->friendlist[friendnumber].file_sending[i].status == FILESTATUS_NONE)
1398
+ break;
1399
+ }
1400
+
1401
+ if (i == MAX_CONCURRENT_FILE_PIPES)
1402
+ return -1;
1403
+
1404
+ if (file_sendrequest(m, friendnumber, i, filesize, filename, filename_length) == 0)
1405
+ return -1;
1406
+
1407
+ m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NOT_ACCEPTED;
1408
+ m->friendlist[friendnumber].file_sending[i].size = filesize;
1409
+ m->friendlist[friendnumber].file_sending[i].transferred = 0;
1410
+ return i;
1411
+ }
1412
+
1413
+ /* Send a file control request.
1414
+ * send_receive is 0 if we want the control packet to target a sending file, 1 if it targets a receiving file.
1415
+ *
1416
+ * return 0 on success
1417
+ * return -1 on failure
1418
+ */
1419
+ int file_control(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id,
1420
+ const uint8_t *data, uint16_t length)
1421
+ {
1422
+ if (length > MAX_CRYPTO_DATA_SIZE - 3)
1423
+ return -1;
1424
+
1425
+ if (friend_not_valid(m, friendnumber))
1426
+ return -1;
1427
+
1428
+ if (send_receive == 1) {
1429
+ if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE)
1430
+ return -1;
1431
+ } else {
1432
+ if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE)
1433
+ return -1;
1434
+ }
1435
+
1436
+ if (send_receive > 1)
1437
+ return -1;
1438
+
1439
+ uint8_t packet[MAX_CRYPTO_DATA_SIZE];
1440
+ packet[0] = send_receive;
1441
+ packet[1] = filenumber;
1442
+ packet[2] = message_id;
1443
+ uint64_t transferred = 0;
1444
+
1445
+ if (message_id == FILECONTROL_RESUME_BROKEN) {
1446
+ if (length != sizeof(uint64_t))
1447
+ return -1;
1448
+
1449
+ uint8_t remaining[sizeof(uint64_t)];
1450
+ memcpy(remaining, data, sizeof(uint64_t));
1451
+ host_to_net(remaining, sizeof(uint64_t));
1452
+ memcpy(packet + 3, remaining, sizeof(uint64_t));
1453
+ memcpy(&transferred, data, sizeof(uint64_t));
1454
+ } else {
1455
+ memcpy(packet + 3, data, length);
1456
+ }
1457
+
1458
+ if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, length + 3, 0)) {
1459
+ if (send_receive == 1)
1460
+ switch (message_id) {
1461
+ case FILECONTROL_ACCEPT:
1462
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TRANSFERRING;
1463
+ break;
1464
+
1465
+ case FILECONTROL_PAUSE:
1466
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_US;
1467
+ break;
1468
+
1469
+ case FILECONTROL_KILL:
1470
+ case FILECONTROL_FINISHED:
1471
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
1472
+ break;
1473
+
1474
+ case FILECONTROL_RESUME_BROKEN:
1475
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_OTHER;
1476
+ m->friendlist[friendnumber].file_receiving[filenumber].transferred = transferred;
1477
+ break;
1478
+ }
1479
+ else
1480
+ switch (message_id) {
1481
+ case FILECONTROL_ACCEPT:
1482
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TRANSFERRING;
1483
+ break;
1484
+
1485
+ case FILECONTROL_PAUSE:
1486
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_US;
1487
+ break;
1488
+
1489
+ case FILECONTROL_KILL:
1490
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
1491
+ break;
1492
+
1493
+ case FILECONTROL_FINISHED:
1494
+ break;
1495
+ }
1496
+
1497
+ return 0;
1498
+ } else {
1499
+ return -1;
1500
+ }
1501
+ }
1502
+
1503
+ #define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 2)
1504
+ /* Send file data.
1505
+ *
1506
+ * return 0 on success
1507
+ * return -1 on failure
1508
+ */
1509
+ int file_data(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length)
1510
+ {
1511
+ if (length > MAX_CRYPTO_DATA_SIZE - 1)
1512
+ return -1;
1513
+
1514
+ if (friend_not_valid(m, friendnumber))
1515
+ return -1;
1516
+
1517
+ if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_TRANSFERRING)
1518
+ return -1;
1519
+
1520
+ /* Prevent file sending from filling up the entire buffer preventing messages from being sent. */
1521
+ if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE)
1522
+ return -1;
1523
+
1524
+ uint8_t packet[MAX_CRYPTO_DATA_SIZE];
1525
+ packet[0] = filenumber;
1526
+ memcpy(packet + 1, data, length);
1527
+
1528
+ if (write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_DATA, packet, length + 1, 1)) {
1529
+ m->friendlist[friendnumber].file_sending[filenumber].transferred += length;
1530
+ return 0;
1531
+ }
1532
+
1533
+ return -1;
1534
+
1535
+ }
1536
+
1537
+ /* Give the number of bytes left to be sent/received.
1538
+ *
1539
+ * send_receive is 0 if we want the sending files, 1 if we want the receiving.
1540
+ *
1541
+ * return number of bytes remaining to be sent/received on success
1542
+ * return 0 on failure
1543
+ */
1544
+ uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive)
1545
+ {
1546
+ if (friend_not_valid(m, friendnumber))
1547
+ return 0;
1548
+
1549
+ if (send_receive == 0) {
1550
+ if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE)
1551
+ return 0;
1552
+
1553
+ return m->friendlist[friendnumber].file_sending[filenumber].size -
1554
+ m->friendlist[friendnumber].file_sending[filenumber].transferred;
1555
+ } else {
1556
+ if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE)
1557
+ return 0;
1558
+
1559
+ return m->friendlist[friendnumber].file_receiving[filenumber].size -
1560
+ m->friendlist[friendnumber].file_receiving[filenumber].transferred;
1561
+ }
1562
+ }
1563
+
1564
+ /* Run this when the friend disconnects.
1565
+ * Sets all current file transfers to broken.
1566
+ */
1567
+ static void break_files(const Messenger *m, int32_t friendnumber)
1568
+ {
1569
+ uint32_t i;
1570
+
1571
+ for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1572
+ if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE)
1573
+ m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_BROKEN;
1574
+
1575
+ if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE)
1576
+ m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_BROKEN;
1577
+ }
1578
+ }
1579
+
1580
+ static int handle_filecontrol(const Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
1581
+ uint8_t message_id, uint8_t *data,
1582
+ uint16_t length)
1583
+ {
1584
+ if (receive_send > 1)
1585
+ return -1;
1586
+
1587
+ if (receive_send == 0) {
1588
+ if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) {
1589
+ /* Tell the other to kill the file sending if we don't know this one. */
1590
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TEMPORARY;
1591
+ file_control(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, NULL, 0);
1592
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
1593
+ return -1;
1594
+
1595
+ }
1596
+
1597
+ switch (message_id) {
1598
+ case FILECONTROL_ACCEPT:
1599
+ if (m->friendlist[friendnumber].file_receiving[filenumber].status != FILESTATUS_PAUSED_BY_US) {
1600
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_TRANSFERRING;
1601
+ return 0;
1602
+ }
1603
+
1604
+ return -1;
1605
+
1606
+ case FILECONTROL_PAUSE:
1607
+ if (m->friendlist[friendnumber].file_receiving[filenumber].status != FILESTATUS_PAUSED_BY_US) {
1608
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_PAUSED_BY_OTHER;
1609
+ return 0;
1610
+ }
1611
+
1612
+ return -1;
1613
+
1614
+ case FILECONTROL_KILL:
1615
+ m->friendlist[friendnumber].file_receiving[filenumber].status = FILESTATUS_NONE;
1616
+
1617
+ case FILECONTROL_FINISHED:
1618
+ return 0;
1619
+ }
1620
+ } else {
1621
+ if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) {
1622
+ /* Tell the other to kill the file sending if we don't know this one. */
1623
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TEMPORARY;
1624
+ file_control(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, NULL, 0);
1625
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
1626
+ return -1;
1627
+ }
1628
+
1629
+ switch (message_id) {
1630
+ case FILECONTROL_ACCEPT:
1631
+ if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_PAUSED_BY_US) {
1632
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_TRANSFERRING;
1633
+ return 0;
1634
+ }
1635
+
1636
+ return -1;
1637
+
1638
+ case FILECONTROL_PAUSE:
1639
+ if (m->friendlist[friendnumber].file_sending[filenumber].status != FILESTATUS_PAUSED_BY_US) {
1640
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_OTHER;
1641
+ }
1642
+
1643
+ return 0;
1644
+
1645
+ case FILECONTROL_KILL:
1646
+ case FILECONTROL_FINISHED:
1647
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_NONE;
1648
+ return 0;
1649
+
1650
+ case FILECONTROL_RESUME_BROKEN: {
1651
+ if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_BROKEN && length == sizeof(uint64_t)) {
1652
+ m->friendlist[friendnumber].file_sending[filenumber].status = FILESTATUS_PAUSED_BY_US;
1653
+ net_to_host(data, sizeof(uint64_t));
1654
+ return 0;
1655
+ }
1656
+
1657
+ return -1;
1658
+ }
1659
+ }
1660
+ }
1661
+
1662
+ return -1;
1663
+ }
1664
+
1665
+ /**************************************/
1666
+
1667
+ /* Set the callback for msi packets.
1668
+ *
1669
+ * Function(Messenger *m, int friendnumber, uint8_t *data, uint16_t length, void *userdata)
1670
+ */
1671
+ void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, int32_t, const uint8_t *, uint16_t, void *),
1672
+ void *userdata)
1673
+ {
1674
+ m->msi_packet = function;
1675
+ m->msi_packet_userdata = userdata;
1676
+ }
1677
+
1678
+ /* Send an msi packet.
1679
+ *
1680
+ * return 1 on success
1681
+ * return 0 on failure
1682
+ */
1683
+ int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
1684
+ {
1685
+ return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length, 0);
1686
+ }
1687
+
1688
+ static int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length)
1689
+ {
1690
+ Messenger *m = object;
1691
+
1692
+ if (friend_not_valid(m, friend_num))
1693
+ return 1;
1694
+
1695
+ if (m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].function)
1696
+ return m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].function(
1697
+ m->friendlist[friend_num].lossy_packethandlers[packet[0] % PACKET_ID_LOSSY_RANGE_SIZE].object, packet, length);
1698
+
1699
+ return 1;
1700
+ }
1701
+
1702
+ int custom_lossy_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte,
1703
+ int (*packet_handler_callback)(void *object, const uint8_t *data, uint32_t len), void *object)
1704
+ {
1705
+ if (friend_not_valid(m, friendnumber))
1706
+ return -1;
1707
+
1708
+ if (byte < PACKET_ID_LOSSY_RANGE_START)
1709
+ return -1;
1710
+
1711
+ if (byte >= (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE))
1712
+ return -1;
1713
+
1714
+ m->friendlist[friendnumber].lossy_packethandlers[byte % PACKET_ID_LOSSY_RANGE_SIZE].function = packet_handler_callback;
1715
+ m->friendlist[friendnumber].lossy_packethandlers[byte % PACKET_ID_LOSSY_RANGE_SIZE].object = object;
1716
+ return 0;
1717
+ }
1718
+
1719
+ int send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)
1720
+ {
1721
+ if (friend_not_valid(m, friendnumber))
1722
+ return -1;
1723
+
1724
+ if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
1725
+ return -1;
1726
+
1727
+ if (m->friendlist[friendnumber].crypt_connection_id == -1)
1728
+ return -1;
1729
+
1730
+ return send_lossy_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length);
1731
+ }
1732
+
1733
+ static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length)
1734
+ {
1735
+ Messenger *m = object;
1736
+
1737
+ if (friend_not_valid(m, friend_num))
1738
+ return -1;
1739
+
1740
+ if (packet[0] < PACKET_ID_LOSSLESS_RANGE_START)
1741
+ return -1;
1742
+
1743
+ if (packet[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE))
1744
+ return -1;
1745
+
1746
+ if (m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].function)
1747
+ return m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].function(
1748
+ m->friendlist[friend_num].lossless_packethandlers[packet[0] % PACKET_ID_LOSSLESS_RANGE_SIZE].object, packet, length);
1749
+
1750
+ return 1;
1751
+ }
1752
+
1753
+ int custom_lossless_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8_t byte,
1754
+ int (*packet_handler_callback)(void *object, const uint8_t *data, uint32_t len), void *object)
1755
+ {
1756
+ if (friend_not_valid(m, friendnumber))
1757
+ return -1;
1758
+
1759
+ if (byte < PACKET_ID_LOSSLESS_RANGE_START)
1760
+ return -1;
1761
+
1762
+ if (byte >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE))
1763
+ return -1;
1764
+
1765
+ m->friendlist[friendnumber].lossless_packethandlers[byte % PACKET_ID_LOSSLESS_RANGE_SIZE].function =
1766
+ packet_handler_callback;
1767
+ m->friendlist[friendnumber].lossless_packethandlers[byte % PACKET_ID_LOSSLESS_RANGE_SIZE].object = object;
1768
+ return 0;
1769
+ }
1770
+
1771
+ int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)
1772
+ {
1773
+ if (friend_not_valid(m, friendnumber))
1774
+ return -1;
1775
+
1776
+ if (length == 0)
1777
+ return -1;
1778
+
1779
+ if (data[0] < PACKET_ID_LOSSLESS_RANGE_START)
1780
+ return -1;
1781
+
1782
+ if (data[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE))
1783
+ return -1;
1784
+
1785
+ if (m->friendlist[friendnumber].status != FRIEND_ONLINE)
1786
+ return -1;
1787
+
1788
+ if (m->friendlist[friendnumber].crypt_connection_id == -1)
1789
+ return -1;
1790
+
1791
+ if (write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, data, length, 1) == -1) {
1792
+ return -1;
1793
+ } else {
1794
+ return 0;
1795
+ }
1796
+ }
1797
+
1798
+ /* Function to filter out some friend requests*/
1799
+ static int friend_already_added(const uint8_t *client_id, void *data)
1800
+ {
1801
+ const Messenger *m = data;
1802
+
1803
+ if (getfriend_id(m, client_id) == -1)
1804
+ return 0;
1805
+
1806
+ return -1;
1807
+ }
1808
+
1809
+ /* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */
1810
+ static void LANdiscovery(Messenger *m)
1811
+ {
1812
+ if (m->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) {
1813
+ send_LANdiscovery(htons(TOX_PORT_DEFAULT), m->dht);
1814
+ m->last_LANdiscovery = unix_time();
1815
+ }
1816
+ }
1817
+
1818
+ static int handle_status(void *object, int i, uint8_t status);
1819
+ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len);
1820
+
1821
+ static int handle_new_connections(void *object, New_Connection *n_c)
1822
+ {
1823
+ Messenger *m = object;
1824
+ int friend_id = getfriend_id(m, n_c->public_key);
1825
+
1826
+ if (friend_id != -1) {
1827
+ if (m->friendlist[friend_id].crypt_connection_id != -1)
1828
+ return -1;
1829
+
1830
+ int id = accept_crypto_connection(m->net_crypto, n_c);
1831
+ connection_status_handler(m->net_crypto, id, &handle_status, m, friend_id);
1832
+ connection_data_handler(m->net_crypto, id, &handle_packet, m, friend_id);
1833
+ connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friend_id);
1834
+ m->friendlist[friend_id].crypt_connection_id = id;
1835
+ set_friend_status(m, friend_id, FRIEND_CONFIRMED);
1836
+ return 0;
1837
+ }
1838
+
1839
+ return -1;
1840
+ }
1841
+
1842
+
1843
+ /* Run this at startup. */
1844
+ Messenger *new_messenger(Messenger_Options *options)
1845
+ {
1846
+ Messenger *m = calloc(1, sizeof(Messenger));
1847
+
1848
+ if ( ! m )
1849
+ return NULL;
1850
+
1851
+ if (options->udp_disabled) {
1852
+ /* this is the easiest way to completely disable UDP without changing too much code. */
1853
+ m->net = calloc(1, sizeof(Networking_Core));
1854
+ } else {
1855
+ IP ip;
1856
+ ip_init(&ip, options->ipv6enabled);
1857
+ m->net = new_networking(ip, TOX_PORT_DEFAULT);
1858
+ }
1859
+
1860
+ if (m->net == NULL) {
1861
+ free(m);
1862
+ return NULL;
1863
+ }
1864
+
1865
+ m->dht = new_DHT(m->net);
1866
+
1867
+ if (m->dht == NULL) {
1868
+ kill_networking(m->net);
1869
+ free(m);
1870
+ return NULL;
1871
+ }
1872
+
1873
+ if (options->proxy_enabled) {
1874
+ m->net_crypto = new_net_crypto(m->dht, &options->proxy_info);
1875
+ } else {
1876
+ m->net_crypto = new_net_crypto(m->dht, 0);
1877
+ }
1878
+
1879
+ if (m->net_crypto == NULL) {
1880
+ kill_networking(m->net);
1881
+ kill_DHT(m->dht);
1882
+ free(m);
1883
+ return NULL;
1884
+ }
1885
+
1886
+ new_connection_handler(m->net_crypto, &handle_new_connections, m);
1887
+
1888
+ m->onion = new_onion(m->dht);
1889
+ m->onion_a = new_onion_announce(m->dht);
1890
+ m->onion_c = new_onion_client(m->net_crypto);
1891
+
1892
+ if (!(m->onion && m->onion_a && m->onion_c)) {
1893
+ kill_onion(m->onion);
1894
+ kill_onion_announce(m->onion_a);
1895
+ kill_onion_client(m->onion_c);
1896
+ kill_DHT(m->dht);
1897
+ kill_net_crypto(m->net_crypto);
1898
+ kill_networking(m->net);
1899
+ free(m);
1900
+ return NULL;
1901
+ }
1902
+
1903
+ m->options = *options;
1904
+ friendreq_init(&(m->fr), m->onion_c);
1905
+ LANdiscovery_init(m->dht);
1906
+ set_nospam(&(m->fr), random_int());
1907
+ set_filter_function(&(m->fr), &friend_already_added, m);
1908
+
1909
+ networking_registerhandler(m->net, NET_PACKET_GROUP_CHATS, &handle_group, m);
1910
+
1911
+ return m;
1912
+ }
1913
+
1914
+ /* Run this before closing shop. */
1915
+ void kill_messenger(Messenger *m)
1916
+ {
1917
+ /* FIXME TODO: ideally cleanupMessenger will mirror initMessenger.
1918
+ * This requires the other modules to expose cleanup functions.
1919
+ */
1920
+ uint32_t i, numchats = m->numchats;
1921
+
1922
+ for (i = 0; i < numchats; ++i)
1923
+ del_groupchat(m, i);
1924
+
1925
+ kill_onion(m->onion);
1926
+ kill_onion_announce(m->onion_a);
1927
+ kill_onion_client(m->onion_c);
1928
+ kill_net_crypto(m->net_crypto);
1929
+ kill_DHT(m->dht);
1930
+ kill_networking(m->net);
1931
+
1932
+ for (i = 0; i < m->numfriends; ++i) {
1933
+ if (m->friendlist[i].statusmessage)
1934
+ free(m->friendlist[i].statusmessage);
1935
+ }
1936
+
1937
+ free(m->friendlist);
1938
+ free(m);
1939
+ }
1940
+
1941
+ /* Check for and handle a timed-out friend request. If the request has
1942
+ * timed-out then the friend status is set back to FRIEND_ADDED.
1943
+ * i: friendlist index of the timed-out friend
1944
+ * t: time
1945
+ */
1946
+ static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t)
1947
+ {
1948
+ Friend *f = &m->friendlist[i];
1949
+
1950
+ if (f->friendrequest_lastsent + f->friendrequest_timeout < t) {
1951
+ set_friend_status(m, i, FRIEND_ADDED);
1952
+ /* Double the default timeout every time if friendrequest is assumed
1953
+ * to have been sent unsuccessfully.
1954
+ */
1955
+ f->friendrequest_timeout *= 2;
1956
+ }
1957
+ }
1958
+
1959
+ static int handle_status(void *object, int i, uint8_t status)
1960
+ {
1961
+ uint64_t temp_time = unix_time();
1962
+ Messenger *m = object;
1963
+
1964
+ if (status) { /* Went online. */
1965
+ set_friend_status(m, i, FRIEND_ONLINE);
1966
+ m->friendlist[i].name_sent = 0;
1967
+ m->friendlist[i].userstatus_sent = 0;
1968
+ m->friendlist[i].statusmessage_sent = 0;
1969
+ m->friendlist[i].ping_lastrecv = temp_time;
1970
+ } else { /* Went offline. */
1971
+ m->friendlist[i].crypt_connection_id = -1;
1972
+
1973
+ if (m->friendlist[i].status == FRIEND_ONLINE) {
1974
+ set_friend_status(m, i, FRIEND_CONFIRMED);
1975
+ }
1976
+ }
1977
+
1978
+ return 0;
1979
+ }
1980
+
1981
+ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
1982
+ {
1983
+ if (len == 0)
1984
+ return -1;
1985
+
1986
+ Messenger *m = object;
1987
+ uint64_t temp_time = unix_time();
1988
+ uint8_t packet_id = temp[0];
1989
+ uint8_t *data = temp + 1;
1990
+ uint32_t data_length = len - 1;
1991
+
1992
+ if (m->friendlist[i].status != FRIEND_ONLINE)
1993
+ return -1;
1994
+
1995
+ switch (packet_id) {
1996
+ case PACKET_ID_ALIVE: {
1997
+ m->friendlist[i].ping_lastrecv = temp_time;
1998
+ break;
1999
+ }
2000
+
2001
+ case PACKET_ID_NICKNAME: {
2002
+ if (data_length > MAX_NAME_LENGTH || data_length == 0)
2003
+ break;
2004
+
2005
+ /* Make sure the NULL terminator is present. */
2006
+ uint8_t data_terminated[data_length + 1];
2007
+ memcpy(data_terminated, data, data_length);
2008
+ data_terminated[data_length] = 0;
2009
+
2010
+ /* inform of namechange before we overwrite the old name */
2011
+ if (m->friend_namechange)
2012
+ m->friend_namechange(m, i, data_terminated, data_length, m->friend_namechange_userdata);
2013
+
2014
+ memcpy(m->friendlist[i].name, data_terminated, data_length);
2015
+ m->friendlist[i].name_length = data_length;
2016
+
2017
+ break;
2018
+ }
2019
+
2020
+ case PACKET_ID_STATUSMESSAGE: {
2021
+ if (data_length == 0 || data_length > MAX_STATUSMESSAGE_LENGTH)
2022
+ break;
2023
+
2024
+ /* Make sure the NULL terminator is present. */
2025
+ uint8_t data_terminated[data_length + 1];
2026
+ memcpy(data_terminated, data, data_length);
2027
+ data_terminated[data_length] = 0;
2028
+
2029
+ if (m->friend_statusmessagechange)
2030
+ m->friend_statusmessagechange(m, i, data_terminated, data_length,
2031
+ m->friend_statuschange_userdata);
2032
+
2033
+ set_friend_statusmessage(m, i, data_terminated, data_length);
2034
+ break;
2035
+ }
2036
+
2037
+ case PACKET_ID_USERSTATUS: {
2038
+ if (data_length != 1)
2039
+ break;
2040
+
2041
+ USERSTATUS status = data[0];
2042
+
2043
+ if (status >= USERSTATUS_INVALID)
2044
+ break;
2045
+
2046
+ if (m->friend_userstatuschange)
2047
+ m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata);
2048
+
2049
+ set_friend_userstatus(m, i, status);
2050
+ break;
2051
+ }
2052
+
2053
+ case PACKET_ID_TYPING: {
2054
+ if (data_length != 1)
2055
+ break;
2056
+
2057
+ uint8_t typing = data[0];
2058
+
2059
+ set_friend_typing(m, i, typing);
2060
+
2061
+ if (m->friend_typingchange)
2062
+ m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata);
2063
+
2064
+ break;
2065
+ }
2066
+
2067
+ case PACKET_ID_MESSAGE: {
2068
+ const uint8_t *message_id = data;
2069
+ uint8_t message_id_length = 4;
2070
+
2071
+ if (data_length <= message_id_length)
2072
+ break;
2073
+
2074
+ const uint8_t *message = data + message_id_length;
2075
+ uint16_t message_length = data_length - message_id_length;
2076
+
2077
+ /* Make sure the NULL terminator is present. */
2078
+ uint8_t message_terminated[message_length + 1];
2079
+ memcpy(message_terminated, message, message_length);
2080
+ message_terminated[message_length] = 0;
2081
+
2082
+ if (m->friendlist[i].receives_read_receipts) {
2083
+ write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length, 0);
2084
+ }
2085
+
2086
+ if (m->friend_message)
2087
+ (*m->friend_message)(m, i, message_terminated, message_length, m->friend_message_userdata);
2088
+
2089
+ break;
2090
+ }
2091
+
2092
+ case PACKET_ID_ACTION: {
2093
+ const uint8_t *message_id = data;
2094
+ uint8_t message_id_length = 4;
2095
+
2096
+ if (data_length <= message_id_length)
2097
+ break;
2098
+
2099
+ const uint8_t *action = data + message_id_length;
2100
+ uint16_t action_length = data_length - message_id_length;
2101
+
2102
+ /* Make sure the NULL terminator is present. */
2103
+ uint8_t action_terminated[action_length + 1];
2104
+ memcpy(action_terminated, action, action_length);
2105
+ action_terminated[action_length] = 0;
2106
+
2107
+ if (m->friendlist[i].receives_read_receipts) {
2108
+ write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length, 0);
2109
+ }
2110
+
2111
+ if (m->friend_action)
2112
+ (*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata);
2113
+
2114
+
2115
+ break;
2116
+ }
2117
+
2118
+ case PACKET_ID_RECEIPT: {
2119
+ uint32_t msgid;
2120
+
2121
+ if (data_length < sizeof(msgid))
2122
+ break;
2123
+
2124
+ memcpy(&msgid, data, sizeof(msgid));
2125
+ msgid = ntohl(msgid);
2126
+
2127
+ if (m->read_receipt)
2128
+ (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata);
2129
+
2130
+ break;
2131
+ }
2132
+
2133
+ case PACKET_ID_INVITE_GROUPCHAT: {
2134
+ if (data_length != crypto_box_PUBLICKEYBYTES)
2135
+ break;
2136
+
2137
+ if (m->group_invite)
2138
+ (*m->group_invite)(m, i, data, m->group_invite_userdata);
2139
+
2140
+ break;
2141
+ }
2142
+
2143
+ case PACKET_ID_JOIN_GROUPCHAT: {
2144
+ if (data_length != crypto_box_PUBLICKEYBYTES * 2)
2145
+ break;
2146
+
2147
+ int groupnum = group_num(m, data);
2148
+
2149
+ if (groupnum == -1)
2150
+ break;
2151
+
2152
+ if (!group_invited(m, i, groupnum))
2153
+ break;
2154
+
2155
+ group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES);
2156
+ /* This is just there to speedup joining. */
2157
+ chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES);
2158
+ break;
2159
+ }
2160
+
2161
+ case PACKET_ID_FILE_SENDREQUEST: {
2162
+ if (data_length < 1 + sizeof(uint64_t) + 1)
2163
+ break;
2164
+
2165
+ uint8_t filenumber = data[0];
2166
+ uint64_t filesize;
2167
+ memcpy(&filesize, data + 1, sizeof(filesize));
2168
+ net_to_host((uint8_t *) &filesize, sizeof(filesize));
2169
+ m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED;
2170
+ m->friendlist[i].file_receiving[filenumber].size = filesize;
2171
+ m->friendlist[i].file_receiving[filenumber].transferred = 0;
2172
+
2173
+ /* Force NULL terminate file name. */
2174
+ uint8_t filename_terminated[data_length - 1 - sizeof(uint64_t) + 1];
2175
+ memcpy(filename_terminated, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t));
2176
+ filename_terminated[data_length - 1 - sizeof(uint64_t)] = 0;
2177
+
2178
+ if (m->file_sendrequest)
2179
+ (*m->file_sendrequest)(m, i, filenumber, filesize, filename_terminated, data_length - 1 - sizeof(uint64_t),
2180
+ m->file_sendrequest_userdata);
2181
+
2182
+ break;
2183
+ }
2184
+
2185
+ case PACKET_ID_FILE_CONTROL: {
2186
+ if (data_length < 3)
2187
+ break;
2188
+
2189
+ uint8_t send_receive = data[0];
2190
+ uint8_t filenumber = data[1];
2191
+ uint8_t control_type = data[2];
2192
+
2193
+ if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1)
2194
+ break;
2195
+
2196
+ if (m->file_filecontrol)
2197
+ (*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3,
2198
+ m->file_filecontrol_userdata);
2199
+
2200
+ break;
2201
+ }
2202
+
2203
+ case PACKET_ID_FILE_DATA: {
2204
+ if (data_length < 2)
2205
+ break;
2206
+
2207
+ uint8_t filenumber = data[0];
2208
+
2209
+ if (m->friendlist[i].file_receiving[filenumber].status == FILESTATUS_NONE)
2210
+ break;
2211
+
2212
+ m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1);
2213
+
2214
+ if (m->file_filedata)
2215
+ (*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata);
2216
+
2217
+ break;
2218
+ }
2219
+
2220
+ case PACKET_ID_MSI: {
2221
+ if (data_length == 0)
2222
+ break;
2223
+
2224
+ if (m->msi_packet)
2225
+ (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata);
2226
+
2227
+ break;
2228
+ }
2229
+
2230
+ case PACKET_ID_SHARE_RELAYS: {
2231
+ Node_format nodes[MAX_SHARED_RELAYS];
2232
+ int n;
2233
+
2234
+ if ((n = unpack_nodes(nodes, MAX_SHARED_RELAYS, NULL, data, data_length, 1)) == -1)
2235
+ break;
2236
+
2237
+ int i;
2238
+
2239
+ for (i = 0; i < n; i++) {
2240
+ add_tcp_relay(m->net_crypto, nodes[i].ip_port, nodes[i].client_id);
2241
+ }
2242
+
2243
+ break;
2244
+ }
2245
+
2246
+ default: {
2247
+ handle_custom_lossless_packet(object, i, temp, len);
2248
+ break;
2249
+ }
2250
+ }
2251
+
2252
+ return 0;
2253
+ }
2254
+
2255
+ static int friend_new_connection(Messenger *m, int32_t friendnumber, const uint8_t *real_public_key)
2256
+ {
2257
+ if (friend_not_valid(m, friendnumber))
2258
+ return -1;
2259
+
2260
+ if (m->friendlist[friendnumber].crypt_connection_id != -1) {
2261
+ return -1;
2262
+ }
2263
+
2264
+ int id = new_crypto_connection(m->net_crypto, real_public_key);
2265
+
2266
+ if (id == -1)
2267
+ return -1;
2268
+
2269
+ m->friendlist[friendnumber].crypt_connection_id = id;
2270
+ connection_status_handler(m->net_crypto, id, &handle_status, m, friendnumber);
2271
+ connection_data_handler(m->net_crypto, id, &handle_packet, m, friendnumber);
2272
+ connection_lossy_data_handler(m->net_crypto, id, &handle_custom_lossy_packet, m, friendnumber);
2273
+ return 0;
2274
+ }
2275
+
2276
+ /* TODO: Make this function not suck. */
2277
+ void do_friends(Messenger *m)
2278
+ {
2279
+ uint32_t i;
2280
+ uint64_t temp_time = unix_time();
2281
+
2282
+ for (i = 0; i < m->numfriends; ++i) {
2283
+ if (m->friendlist[i].status == FRIEND_ADDED) {
2284
+ int fr = send_friendrequest(m->onion_c, m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam,
2285
+ m->friendlist[i].info,
2286
+ m->friendlist[i].info_size);
2287
+
2288
+ if (fr >= 0) {
2289
+ set_friend_status(m, i, FRIEND_REQUESTED);
2290
+ m->friendlist[i].friendrequest_lastsent = temp_time;
2291
+ }
2292
+ }
2293
+
2294
+ if (m->friendlist[i].status == FRIEND_REQUESTED
2295
+ || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */
2296
+ if (m->friendlist[i].status == FRIEND_REQUESTED) {
2297
+ /* If we didn't connect to friend after successfully sending him a friend request the request is deemed
2298
+ * unsuccessful so we set the status back to FRIEND_ADDED and try again.
2299
+ */
2300
+ check_friend_request_timed_out(m, i, temp_time);
2301
+ }
2302
+
2303
+ friend_new_connection(m, i, m->friendlist[i].client_id);
2304
+ }
2305
+
2306
+ if (m->friendlist[i].crypt_connection_id != -1) {
2307
+ uint8_t dht_public_key1[crypto_box_PUBLICKEYBYTES];
2308
+ uint64_t timestamp1 = onion_getfriend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key1);
2309
+ uint8_t dht_public_key2[crypto_box_PUBLICKEYBYTES];
2310
+ uint64_t timestamp2 = get_connection_dht_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key2);
2311
+
2312
+ if (timestamp1 > timestamp2) {
2313
+ set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key1, timestamp1);
2314
+ } else if (timestamp1 < timestamp2) {
2315
+ onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key2, timestamp2);
2316
+ }
2317
+
2318
+ uint8_t direct_connected;
2319
+ unsigned int status = crypto_connection_status(m->net_crypto, m->friendlist[i].crypt_connection_id, &direct_connected);
2320
+
2321
+ if (direct_connected == 0 || status == CRYPTO_CONN_COOKIE_REQUESTING) {
2322
+ IP_Port friendip;
2323
+
2324
+ if (onion_getfriendip(m->onion_c, m->friendlist[i].onion_friendnum, &friendip) == 1) {
2325
+ set_direct_ip_port(m->net_crypto, m->friendlist[i].crypt_connection_id, friendip);
2326
+ }
2327
+ }
2328
+ }
2329
+
2330
+ if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */
2331
+ if (m->friendlist[i].name_sent == 0) {
2332
+ if (m_sendname(m, i, m->name, m->name_length))
2333
+ m->friendlist[i].name_sent = 1;
2334
+ }
2335
+
2336
+ if (m->friendlist[i].statusmessage_sent == 0) {
2337
+ if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length))
2338
+ m->friendlist[i].statusmessage_sent = 1;
2339
+ }
2340
+
2341
+ if (m->friendlist[i].userstatus_sent == 0) {
2342
+ if (send_userstatus(m, i, m->userstatus))
2343
+ m->friendlist[i].userstatus_sent = 1;
2344
+ }
2345
+
2346
+ if (m->friendlist[i].user_istyping_sent == 0) {
2347
+ if (send_user_istyping(m, i, m->friendlist[i].user_istyping))
2348
+ m->friendlist[i].user_istyping_sent = 1;
2349
+ }
2350
+
2351
+ if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) {
2352
+ send_ping(m, i);
2353
+ }
2354
+
2355
+ if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) {
2356
+ /* If we stopped receiving ping packets, kill it. */
2357
+ crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id);
2358
+ m->friendlist[i].crypt_connection_id = -1;
2359
+ set_friend_status(m, i, FRIEND_CONFIRMED);
2360
+ }
2361
+
2362
+ if (m->friendlist[i].share_relays_lastsent + FRIEND_SHARE_RELAYS_INTERVAL < temp_time) {
2363
+ send_relays(m, i);
2364
+ }
2365
+ }
2366
+ }
2367
+ }
2368
+
2369
+
2370
+
2371
+
2372
+ #ifdef LOGGING
2373
+ #define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL
2374
+ static time_t lastdump = 0;
2375
+ static char IDString[CLIENT_ID_SIZE * 2 + 1];
2376
+ static char *ID2String(const uint8_t *client_id)
2377
+ {
2378
+ uint32_t i;
2379
+
2380
+ for (i = 0; i < CLIENT_ID_SIZE; i++)
2381
+ sprintf(&IDString[i * 2], "%02X", client_id[i]);
2382
+
2383
+ IDString[CLIENT_ID_SIZE * 2] = 0;
2384
+ return IDString;
2385
+ }
2386
+ #endif
2387
+
2388
+ /* Minimum messenger run interval in ms
2389
+ TODO: A/V */
2390
+ #define MIN_RUN_INTERVAL 50
2391
+
2392
+ /* Return the time in milliseconds before do_messenger() should be called again
2393
+ * for optimal performance.
2394
+ *
2395
+ * returns time (in ms) before the next do_messenger() needs to be run on success.
2396
+ */
2397
+ uint32_t messenger_run_interval(Messenger *m)
2398
+ {
2399
+ uint32_t crypto_interval = crypto_run_interval(m->net_crypto);
2400
+
2401
+ if (crypto_interval > MIN_RUN_INTERVAL) {
2402
+ return MIN_RUN_INTERVAL;
2403
+ } else {
2404
+ return crypto_interval;
2405
+ }
2406
+ }
2407
+
2408
+ /* The main loop that needs to be run at least 20 times per second. */
2409
+ void do_messenger(Messenger *m)
2410
+ {
2411
+ // Add the TCP relays, but only if this is the first time calling do_messenger
2412
+ if (m->has_added_relays == 0) {
2413
+ m->has_added_relays = 1;
2414
+
2415
+ int i;
2416
+
2417
+ for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) {
2418
+ add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].client_id);
2419
+ }
2420
+ }
2421
+
2422
+ unix_time_update();
2423
+
2424
+ if (!m->options.udp_disabled) {
2425
+ networking_poll(m->net);
2426
+ do_DHT(m->dht);
2427
+ }
2428
+
2429
+ do_net_crypto(m->net_crypto);
2430
+ do_onion_client(m->onion_c);
2431
+ do_friends(m);
2432
+ do_allgroupchats(m);
2433
+ LANdiscovery(m);
2434
+
2435
+ #ifdef LOGGING
2436
+
2437
+ if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
2438
+
2439
+ #ifdef ENABLE_ASSOC_DHT
2440
+ Assoc_status(m->dht->assoc);
2441
+ #endif
2442
+
2443
+ if (m->numchats > 0) {
2444
+ size_t c;
2445
+
2446
+ for (c = 0; c < m->numchats; c++) {
2447
+ if (m->chats[c])
2448
+ Assoc_status(m->chats[c]->assoc);
2449
+ }
2450
+ }
2451
+
2452
+
2453
+ lastdump = unix_time();
2454
+ uint32_t client, last_pinged;
2455
+
2456
+ for (client = 0; client < LCLIENT_LIST; client++) {
2457
+ Client_data *cptr = &m->dht->close_clientlist[client];
2458
+ IPPTsPng *assoc = NULL;
2459
+ uint32_t a;
2460
+
2461
+ for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6)
2462
+ if (ip_isset(&assoc->ip_port.ip)) {
2463
+ last_pinged = lastdump - assoc->last_pinged;
2464
+
2465
+ if (last_pinged > 999)
2466
+ last_pinged = 999;
2467
+
2468
+ LOGGER_INFO("C[%2u] %s:%u [%3u] %s",
2469
+ client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port),
2470
+ last_pinged, ID2String(cptr->client_id));
2471
+ }
2472
+ }
2473
+
2474
+
2475
+ uint32_t friend, dhtfriend;
2476
+
2477
+ /* dht contains additional "friends" (requests) */
2478
+ uint32_t num_dhtfriends = m->dht->num_friends;
2479
+ int32_t m2dht[num_dhtfriends];
2480
+ int32_t dht2m[num_dhtfriends];
2481
+
2482
+ for (friend = 0; friend < num_dhtfriends; friend++) {
2483
+ m2dht[friend] = -1;
2484
+ dht2m[friend] = -1;
2485
+
2486
+ if (friend >= m->numfriends)
2487
+ continue;
2488
+
2489
+ for (dhtfriend = 0; dhtfriend < m->dht->num_friends; dhtfriend++)
2490
+ if (id_equal(m->friendlist[friend].client_id, m->dht->friends_list[dhtfriend].client_id)) {
2491
+ m2dht[friend] = dhtfriend;
2492
+ break;
2493
+ }
2494
+ }
2495
+
2496
+ for (friend = 0; friend < num_dhtfriends; friend++)
2497
+ if (m2dht[friend] >= 0)
2498
+ dht2m[m2dht[friend]] = friend;
2499
+
2500
+ if (m->numfriends != m->dht->num_friends) {
2501
+ LOGGER_INFO("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends);
2502
+ }
2503
+
2504
+ uint32_t ping_lastrecv;
2505
+ Friend *msgfptr;
2506
+ DHT_Friend *dhtfptr;
2507
+
2508
+ for (friend = 0; friend < num_dhtfriends; friend++) {
2509
+ if (dht2m[friend] >= 0)
2510
+ msgfptr = &m->friendlist[dht2m[friend]];
2511
+ else
2512
+ msgfptr = NULL;
2513
+
2514
+ dhtfptr = &m->dht->friends_list[friend];
2515
+
2516
+ if (msgfptr) {
2517
+ ping_lastrecv = lastdump - msgfptr->ping_lastrecv;
2518
+
2519
+ if (ping_lastrecv > 999)
2520
+ ping_lastrecv = 999;
2521
+
2522
+ LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s",
2523
+ dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id,
2524
+ ping_lastrecv, ID2String(msgfptr->client_id));
2525
+ } else {
2526
+ LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id));
2527
+ }
2528
+
2529
+ for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
2530
+ Client_data *cptr = &dhtfptr->client_list[client];
2531
+ IPPTsPng *assoc = NULL;
2532
+ uint32_t a;
2533
+
2534
+ for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6)
2535
+ if (ip_isset(&assoc->ip_port.ip)) {
2536
+ last_pinged = lastdump - assoc->last_pinged;
2537
+
2538
+ if (last_pinged > 999)
2539
+ last_pinged = 999;
2540
+
2541
+ LOGGER_INFO("F[%2u] => C[%2u] %s:%u [%3u] %s",
2542
+ friend, client, ip_ntoa(&assoc->ip_port.ip),
2543
+ ntohs(assoc->ip_port.port), last_pinged,
2544
+ ID2String(cptr->client_id));
2545
+ }
2546
+ }
2547
+ }
2548
+ }
2549
+
2550
+ #endif /* LOGGING */
2551
+ }
2552
+
2553
+ /* new messenger format for load/save, more robust and forward compatible */
2554
+
2555
+ #define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1f
2556
+
2557
+ #define MESSENGER_STATE_COOKIE_TYPE 0x01ce
2558
+ #define MESSENGER_STATE_TYPE_NOSPAMKEYS 1
2559
+ #define MESSENGER_STATE_TYPE_DHT 2
2560
+ #define MESSENGER_STATE_TYPE_FRIENDS 3
2561
+ #define MESSENGER_STATE_TYPE_NAME 4
2562
+ #define MESSENGER_STATE_TYPE_STATUSMESSAGE 5
2563
+ #define MESSENGER_STATE_TYPE_STATUS 6
2564
+ #define MESSENGER_STATE_TYPE_TCP_RELAY 10
2565
+ #define MESSENGER_STATE_TYPE_PATH_NODE 11
2566
+
2567
+ #define SAVED_FRIEND_REQUEST_SIZE 1024
2568
+ #define NUM_SAVED_PATH_NODES 8
2569
+ struct SAVED_FRIEND {
2570
+ uint8_t status;
2571
+ uint8_t client_id[CLIENT_ID_SIZE];
2572
+ uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do.
2573
+ uint16_t info_size; // Length of the info.
2574
+ uint8_t name[MAX_NAME_LENGTH];
2575
+ uint16_t name_length;
2576
+ uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];
2577
+ uint16_t statusmessage_length;
2578
+ uint8_t userstatus;
2579
+ uint32_t friendrequest_nospam;
2580
+ uint64_t ping_lastrecv;
2581
+ };
2582
+
2583
+ static uint32_t saved_friendslist_size(const Messenger *m)
2584
+ {
2585
+ return count_friendlist(m) * sizeof(struct SAVED_FRIEND);
2586
+ }
2587
+
2588
+ static uint32_t friends_list_save(const Messenger *m, uint8_t *data)
2589
+ {
2590
+ uint32_t i;
2591
+ uint32_t num = 0;
2592
+
2593
+ for (i = 0; i < m->numfriends; i++) {
2594
+ if (m->friendlist[i].status > 0) {
2595
+ struct SAVED_FRIEND temp;
2596
+ memset(&temp, 0, sizeof(struct SAVED_FRIEND));
2597
+ temp.status = m->friendlist[i].status;
2598
+ memcpy(temp.client_id, m->friendlist[i].client_id, CLIENT_ID_SIZE);
2599
+
2600
+ if (temp.status < 3) {
2601
+ if (m->friendlist[i].info_size > SAVED_FRIEND_REQUEST_SIZE) {
2602
+ memcpy(temp.info, m->friendlist[i].info, SAVED_FRIEND_REQUEST_SIZE);
2603
+ } else {
2604
+ memcpy(temp.info, m->friendlist[i].info, m->friendlist[i].info_size);
2605
+ }
2606
+
2607
+ temp.info_size = htons(m->friendlist[i].info_size);
2608
+ temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam;
2609
+ } else {
2610
+ memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length);
2611
+ temp.name_length = htons(m->friendlist[i].name_length);
2612
+ memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length);
2613
+ temp.statusmessage_length = htons(m->friendlist[i].statusmessage_length);
2614
+ temp.userstatus = m->friendlist[i].userstatus;
2615
+
2616
+ uint8_t lastonline[sizeof(uint64_t)];
2617
+ memcpy(lastonline, &m->friendlist[i].ping_lastrecv, sizeof(uint64_t));
2618
+ host_to_net(lastonline, sizeof(uint64_t));
2619
+ memcpy(&temp.ping_lastrecv, lastonline, sizeof(uint64_t));
2620
+ }
2621
+
2622
+ memcpy(data + num * sizeof(struct SAVED_FRIEND), &temp, sizeof(struct SAVED_FRIEND));
2623
+ num++;
2624
+ }
2625
+ }
2626
+
2627
+ return num * sizeof(struct SAVED_FRIEND);
2628
+ }
2629
+
2630
+ static int friends_list_load(Messenger *m, const uint8_t *data, uint32_t length)
2631
+ {
2632
+ if (length % sizeof(struct SAVED_FRIEND) != 0) {
2633
+ return -1;
2634
+ }
2635
+
2636
+ uint32_t num = length / sizeof(struct SAVED_FRIEND);
2637
+ uint32_t i;
2638
+
2639
+ for (i = 0; i < num; ++i) {
2640
+ struct SAVED_FRIEND temp;
2641
+ memcpy(&temp, data + i * sizeof(struct SAVED_FRIEND), sizeof(struct SAVED_FRIEND));
2642
+
2643
+ if (temp.status >= 3) {
2644
+ int fnum = m_addfriend_norequest(m, temp.client_id);
2645
+
2646
+ if (fnum < 0)
2647
+ continue;
2648
+
2649
+ setfriendname(m, fnum, temp.name, ntohs(temp.name_length));
2650
+ set_friend_statusmessage(m, fnum, temp.statusmessage, ntohs(temp.statusmessage_length));
2651
+ set_friend_userstatus(m, fnum, temp.userstatus);
2652
+ uint8_t lastonline[sizeof(uint64_t)];
2653
+ memcpy(lastonline, &temp.ping_lastrecv, sizeof(uint64_t));
2654
+ net_to_host(lastonline, sizeof(uint64_t));
2655
+ memcpy(&m->friendlist[fnum].ping_lastrecv, lastonline, sizeof(uint64_t));
2656
+ } else if (temp.status != 0) {
2657
+ /* TODO: This is not a good way to do this. */
2658
+ uint8_t address[FRIEND_ADDRESS_SIZE];
2659
+ id_copy(address, temp.client_id);
2660
+ memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp.friendrequest_nospam), sizeof(uint32_t));
2661
+ uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
2662
+ memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));
2663
+ m_addfriend(m, address, temp.info, ntohs(temp.info_size));
2664
+ }
2665
+ }
2666
+
2667
+ return num;
2668
+ }
2669
+
2670
+ /* return size of the messenger data (for saving) */
2671
+ uint32_t messenger_size(const Messenger *m)
2672
+ {
2673
+ uint32_t size32 = sizeof(uint32_t), sizesubhead = size32 * 2;
2674
+ return size32 * 2 // global cookie
2675
+ + sizesubhead + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES
2676
+ + sizesubhead + DHT_size(m->dht) // DHT
2677
+ + sizesubhead + saved_friendslist_size(m) // Friendlist itself.
2678
+ + sizesubhead + m->name_length // Own nickname.
2679
+ + sizesubhead + m->statusmessage_length // status message
2680
+ + sizesubhead + 1 // status
2681
+ + sizesubhead + NUM_SAVED_TCP_RELAYS * sizeof(Node_format) //TCP relays
2682
+ + sizesubhead + NUM_SAVED_PATH_NODES * sizeof(Node_format) //saved path nodes
2683
+ ;
2684
+ }
2685
+
2686
+ static uint8_t *z_state_save_subheader(uint8_t *data, uint32_t len, uint16_t type)
2687
+ {
2688
+ uint32_t *data32 = (uint32_t *)data;
2689
+ data32[0] = len;
2690
+ data32[1] = (MESSENGER_STATE_COOKIE_TYPE << 16) | type;
2691
+ data += sizeof(uint32_t) * 2;
2692
+ return data;
2693
+ }
2694
+
2695
+
2696
+ /* Save the messenger in data of size Messenger_size(). */
2697
+ void messenger_save(const Messenger *m, uint8_t *data)
2698
+ {
2699
+ uint32_t len;
2700
+ uint16_t type;
2701
+ uint32_t *data32, size32 = sizeof(uint32_t);
2702
+
2703
+ data32 = (uint32_t *)data;
2704
+ data32[0] = 0;
2705
+ data32[1] = MESSENGER_STATE_COOKIE_GLOBAL;
2706
+ data += size32 * 2;
2707
+
2708
+ #ifdef DEBUG
2709
+ assert(sizeof(get_nospam(&(m->fr))) == sizeof(uint32_t));
2710
+ #endif
2711
+ len = size32 + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
2712
+ type = MESSENGER_STATE_TYPE_NOSPAMKEYS;
2713
+ data = z_state_save_subheader(data, len, type);
2714
+ *(uint32_t *)data = get_nospam(&(m->fr));
2715
+ save_keys(m->net_crypto, data + size32);
2716
+ data += len;
2717
+
2718
+ len = DHT_size(m->dht);
2719
+ type = MESSENGER_STATE_TYPE_DHT;
2720
+ data = z_state_save_subheader(data, len, type);
2721
+ DHT_save(m->dht, data);
2722
+ data += len;
2723
+
2724
+ len = saved_friendslist_size(m);
2725
+ type = MESSENGER_STATE_TYPE_FRIENDS;
2726
+ data = z_state_save_subheader(data, len, type);
2727
+ friends_list_save(m, data);
2728
+ data += len;
2729
+
2730
+ len = m->name_length;
2731
+ type = MESSENGER_STATE_TYPE_NAME;
2732
+ data = z_state_save_subheader(data, len, type);
2733
+ memcpy(data, m->name, len);
2734
+ data += len;
2735
+
2736
+ len = m->statusmessage_length;
2737
+ type = MESSENGER_STATE_TYPE_STATUSMESSAGE;
2738
+ data = z_state_save_subheader(data, len, type);
2739
+ memcpy(data, m->statusmessage, len);
2740
+ data += len;
2741
+
2742
+ len = 1;
2743
+ type = MESSENGER_STATE_TYPE_STATUS;
2744
+ data = z_state_save_subheader(data, len, type);
2745
+ *data = m->userstatus;
2746
+ data += len;
2747
+
2748
+ Node_format relays[NUM_SAVED_TCP_RELAYS];
2749
+ len = sizeof(relays);
2750
+ type = MESSENGER_STATE_TYPE_TCP_RELAY;
2751
+ data = z_state_save_subheader(data, len, type);
2752
+ memset(relays, 0, len);
2753
+ copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS);
2754
+ memcpy(data, relays, len);
2755
+ data += len;
2756
+
2757
+ Node_format nodes[NUM_SAVED_PATH_NODES];
2758
+ len = sizeof(nodes);
2759
+ type = MESSENGER_STATE_TYPE_PATH_NODE;
2760
+ data = z_state_save_subheader(data, len, type);
2761
+ memset(nodes, 0, len);
2762
+ onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES);
2763
+ memcpy(data, nodes, len);
2764
+ }
2765
+
2766
+ static int messenger_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)
2767
+ {
2768
+ Messenger *m = outer;
2769
+
2770
+ switch (type) {
2771
+ case MESSENGER_STATE_TYPE_NOSPAMKEYS:
2772
+ if (length == crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t)) {
2773
+ set_nospam(&(m->fr), *(uint32_t *)data);
2774
+ load_keys(m->net_crypto, &data[sizeof(uint32_t)]);
2775
+ #ifdef ENABLE_ASSOC_DHT
2776
+
2777
+ if (m->dht->assoc)
2778
+ Assoc_self_client_id_changed(m->dht->assoc, m->net_crypto->self_public_key);
2779
+
2780
+ #endif
2781
+ } else
2782
+ return -1; /* critical */
2783
+
2784
+ break;
2785
+
2786
+ case MESSENGER_STATE_TYPE_DHT:
2787
+ DHT_load(m->dht, data, length);
2788
+ break;
2789
+
2790
+ case MESSENGER_STATE_TYPE_FRIENDS:
2791
+ friends_list_load(m, data, length);
2792
+ break;
2793
+
2794
+ case MESSENGER_STATE_TYPE_NAME:
2795
+ if ((length > 0) && (length < MAX_NAME_LENGTH)) {
2796
+ setname(m, data, length);
2797
+ }
2798
+
2799
+ break;
2800
+
2801
+ case MESSENGER_STATE_TYPE_STATUSMESSAGE:
2802
+ if ((length > 0) && (length < MAX_STATUSMESSAGE_LENGTH)) {
2803
+ m_set_statusmessage(m, data, length);
2804
+ }
2805
+
2806
+ break;
2807
+
2808
+ case MESSENGER_STATE_TYPE_STATUS:
2809
+ if (length == 1) {
2810
+ m_set_userstatus(m, *data);
2811
+ }
2812
+
2813
+ break;
2814
+
2815
+ case MESSENGER_STATE_TYPE_TCP_RELAY: {
2816
+ if (length != sizeof(m->loaded_relays)) {
2817
+ return -1;
2818
+ }
2819
+
2820
+ memcpy(m->loaded_relays, data, length);
2821
+ m->has_added_relays = 0;
2822
+
2823
+ break;
2824
+ }
2825
+
2826
+ case MESSENGER_STATE_TYPE_PATH_NODE: {
2827
+ Node_format nodes[NUM_SAVED_PATH_NODES];
2828
+
2829
+ if (length != sizeof(nodes)) {
2830
+ return -1;
2831
+ }
2832
+
2833
+ memcpy(nodes, data, length);
2834
+ uint32_t i;
2835
+
2836
+ for (i = 0; i < NUM_SAVED_PATH_NODES; ++i) {
2837
+ onion_add_path_node(m->onion_c, nodes[i].ip_port, nodes[i].client_id);
2838
+ }
2839
+
2840
+ break;
2841
+ }
2842
+
2843
+ #ifdef DEBUG
2844
+
2845
+ default:
2846
+ fprintf(stderr, "Load state: contains unrecognized part (len %u, type %u)\n",
2847
+ length, type);
2848
+ break;
2849
+ #endif
2850
+ }
2851
+
2852
+ return 0;
2853
+ }
2854
+
2855
+ /* Load the messenger from data of size length. */
2856
+ int messenger_load(Messenger *m, const uint8_t *data, uint32_t length)
2857
+ {
2858
+ uint32_t data32[2];
2859
+ uint32_t cookie_len = sizeof(data32);
2860
+
2861
+ if (length < cookie_len)
2862
+ return -1;
2863
+
2864
+ memcpy(data32, data, sizeof(data32));
2865
+
2866
+ if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL))
2867
+ return load_state(messenger_load_state_callback, m, data + cookie_len,
2868
+ length - cookie_len, MESSENGER_STATE_COOKIE_TYPE);
2869
+ else
2870
+ return -1;
2871
+ }
2872
+
2873
+ /* Return the number of friends in the instance m.
2874
+ * You should use this to determine how much memory to allocate
2875
+ * for copy_friendlist. */
2876
+ uint32_t count_friendlist(const Messenger *m)
2877
+ {
2878
+ uint32_t ret = 0;
2879
+ uint32_t i;
2880
+
2881
+ for (i = 0; i < m->numfriends; i++) {
2882
+ if (m->friendlist[i].status > 0) {
2883
+ ret++;
2884
+ }
2885
+ }
2886
+
2887
+ return ret;
2888
+ }
2889
+
2890
+ /* Return the number of online friends in the instance m. */
2891
+ uint32_t get_num_online_friends(const Messenger *m)
2892
+ {
2893
+ return m->numonline_friends;
2894
+ }
2895
+
2896
+ /* Copy a list of valid friend IDs into the array out_list.
2897
+ * If out_list is NULL, returns 0.
2898
+ * Otherwise, returns the number of elements copied.
2899
+ * If the array was too small, the contents
2900
+ * of out_list will be truncated to list_size. */
2901
+ uint32_t copy_friendlist(Messenger const *m, int32_t *out_list, uint32_t list_size)
2902
+ {
2903
+ if (!out_list)
2904
+ return 0;
2905
+
2906
+ if (m->numfriends == 0) {
2907
+ return 0;
2908
+ }
2909
+
2910
+ uint32_t i;
2911
+ uint32_t ret = 0;
2912
+
2913
+ for (i = 0; i < m->numfriends; i++) {
2914
+ if (ret >= list_size) {
2915
+ break; /* Abandon ship */
2916
+ }
2917
+
2918
+ if (m->friendlist[i].status > 0) {
2919
+ out_list[ret] = i;
2920
+ ret++;
2921
+ }
2922
+ }
2923
+
2924
+ return ret;
2925
+ }
2926
+
2927
+ /* Allocate and return a list of valid friend id's. List must be freed by the
2928
+ * caller.
2929
+ *
2930
+ * retun 0 if success.
2931
+ * return -1 if failure.
2932
+ */
2933
+ int get_friendlist(const Messenger *m, int32_t **out_list, uint32_t *out_list_length)
2934
+ {
2935
+ uint32_t i;
2936
+
2937
+ *out_list_length = 0;
2938
+
2939
+ if (m->numfriends == 0) {
2940
+ *out_list = NULL;
2941
+ return 0;
2942
+ }
2943
+
2944
+ *out_list = malloc(m->numfriends * sizeof(int32_t));
2945
+
2946
+ if (*out_list == NULL) {
2947
+ return -1;
2948
+ }
2949
+
2950
+ for (i = 0; i < m->numfriends; i++) {
2951
+ if (m->friendlist[i].status > 0) {
2952
+ (*out_list)[i] = i;
2953
+ (*out_list_length)++;
2954
+ }
2955
+ }
2956
+
2957
+ return 0;
2958
+ }
2959
+
2960
+ /* Return the number of chats in the instance m.
2961
+ * You should use this to determine how much memory to allocate
2962
+ * for copy_chatlist. */
2963
+ uint32_t count_chatlist(const Messenger *m)
2964
+ {
2965
+ uint32_t ret = 0;
2966
+ uint32_t i;
2967
+
2968
+ for (i = 0; i < m->numchats; i++) {
2969
+ if (m->chats[i]) {
2970
+ ret++;
2971
+ }
2972
+ }
2973
+
2974
+ return ret;
2975
+ }
2976
+
2977
+ /* Copy a list of valid chat IDs into the array out_list.
2978
+ * If out_list is NULL, returns 0.
2979
+ * Otherwise, returns the number of elements copied.
2980
+ * If the array was too small, the contents
2981
+ * of out_list will be truncated to list_size. */
2982
+ uint32_t copy_chatlist(const Messenger *m, int *out_list, uint32_t list_size)
2983
+ {
2984
+ if (!out_list)
2985
+ return 0;
2986
+
2987
+ if (m->numchats == 0) {
2988
+ return 0;
2989
+ }
2990
+
2991
+ uint32_t i;
2992
+ uint32_t ret = 0;
2993
+
2994
+ for (i = 0; i < m->numchats; i++) {
2995
+ if (ret >= list_size) {
2996
+ break; /* Abandon ship */
2997
+ }
2998
+
2999
+ if (m->chats[i]) {
3000
+ out_list[ret] = i;
3001
+ ret++;
3002
+ }
3003
+ }
3004
+
3005
+ return ret;
3006
+ }