You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

461 lines
14 KiB

7 years ago
7 years ago
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <tox/tox.h>
  6. #include <unistd.h>
  7. /* SETUP */
  8. #define SLEEP_TIME_ISNOTCONNECTED 100000
  9. #define SLEEP_TIME_MAINLOOP 10000
  10. #define BOOTSTRAP_ADDRESS "192.254.75.98"
  11. #define BOOTSTRAP_PORT 33445
  12. #define BOOTSTRAP_KEY "951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F"
  13. #define MY_NAME "Toxbot"
  14. #define STATUS_MSG "Write 'help' if you dont know what to do!"
  15. #define SAVEFILE "savetox.bin"
  16. #define MSG_INVITE "invite"
  17. #define RETURN_MSG_INVITE "I have invited you to a groupchat!"
  18. #define RETURN_MSG_NOTINVITE "Dude, dunno what you want..."
  19. #define GROUPCHAT_NUMBER 0
  20. #define SAVEFILE_MSG "savemsg.txt"
  21. #define MSG_LOG "log"
  22. #define MSG_LOG_DEFAULT_LINES 2
  23. #define MSG_LOG_MAX_LINES 1000
  24. #define MSG_LOG_DEFAULT_LINE_LENGTH 256
  25. #define MSG_HELP "help"
  26. #define RETURN_MSG_HELP \
  27. "Valid commands:\ninvite\tinvites to groupchat\nlog\tsends log\nlog " \
  28. "n\tsends log with length n\nhelp\tgives help\n"
  29. /* CONVERT HEX TO BINARY */
  30. char *hex_string_to_bin(const char *hex_string)
  31. {
  32. size_t len = strlen(hex_string);
  33. char *val = malloc(len);
  34. if (val == NULL)
  35. printf("failed in hex_string_to_bin");
  36. size_t i;
  37. for (i = 0; i < len; ++i, hex_string += 2)
  38. sscanf(hex_string, "%2hhx", &val[i]);
  39. return val;
  40. }
  41. /* CONVERT DATA TO HEX ID */
  42. void id_from_data(const uint8_t *address, uint8_t *id)
  43. {
  44. size_t i;
  45. for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
  46. char xx[3];
  47. snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
  48. strcat(id, xx);
  49. }
  50. }
  51. /* GET MY ID */
  52. void get_myid(Tox *m)
  53. {
  54. char id[TOX_ADDRESS_SIZE * 2 + 1] = { 0 };
  55. const char address[TOX_ADDRESS_SIZE];
  56. tox_self_get_address(m, (uint8_t *)address);
  57. id_from_data(address, id);
  58. printf("My ID: %s\n", id);
  59. }
  60. /* STORE TOX DATA */
  61. int store_data(Tox *m)
  62. {
  63. int len = tox_get_savedata_size(m);
  64. char *buf = malloc(len);
  65. tox_get_savedata(m, (uint8_t *)buf);
  66. FILE *fd = fopen(SAVEFILE, "wb");
  67. fwrite(buf, len, 1, fd);
  68. free(buf);
  69. fclose(fd);
  70. return 0;
  71. }
  72. /* LOAD TOX DATA */
  73. int load_data(Tox *m)
  74. {
  75. FILE *fd;
  76. if ((fd = fopen(SAVEFILE, "rb")) != NULL) {
  77. fseek(fd, 0, SEEK_END);
  78. int len = ftell(fd);
  79. fseek(fd, 0, SEEK_SET);
  80. char *buf = malloc(len);
  81. fread(buf, len, 1, fd);
  82. int load_status;
  83. tox_get_savedata(m, (uint8_t *)buf);
  84. if (load_status == 0) {
  85. printf("Loaded savefile successfully.\n");
  86. }
  87. if (load_status == -1) {
  88. printf("Failed to load savefile.\n");
  89. return -1;
  90. }
  91. free(buf);
  92. fclose(fd);
  93. return 0;
  94. } else {
  95. printf("No savefile found, writing new one.\n");
  96. store_data(m);
  97. return 1;
  98. }
  99. }
  100. /* CALLBACK AND FUNCTIONS: ON REQUEST */
  101. void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
  102. {
  103. printf("Got friend request.\n");
  104. // Get friend id and send message
  105. char id[TOX_ADDRESS_SIZE * 2 + 1] = { 0 };
  106. char address[TOX_ADDRESS_SIZE];
  107. id_from_data(public_key, id);
  108. printf("Friend ID [Msg]: %s [%s]\n", id, data);
  109. // Answer friend request positive
  110. char key_answer[TOX_PUBLIC_KEY_SIZE];
  111. memcpy(key_answer, public_key, TOX_PUBLIC_KEY_SIZE);
  112. int friendnumber;
  113. TOX_ERR_FRIEND_ADD status;
  114. friendnumber = tox_friend_add_norequest(m, key_answer, status);
  115. printf("Friend accepted, Friendnumber: %i\n", friendnumber);
  116. }
  117. /* CALLBACK AND FUNCTIONS: ON MESSAGE */
  118. void send_log(Tox *m, int32_t friendnumber, int32_t lines)
  119. {
  120. printf("Send log to [%i] with %i lines.\n", friendnumber, lines);
  121. FILE *fd = fopen(SAVEFILE_MSG, "r");
  122. if (fd != NULL) {
  123. ; // jump out if there is no file
  124. fseek(fd, 0, SEEK_END);
  125. int len = ftell(fd);
  126. fseek(fd, 0, SEEK_SET);
  127. // Check if enough data is available for lines msg parts, else pointer
  128. // remains on first char
  129. if (len - lines * MSG_LOG_DEFAULT_LINE_LENGTH >= 0) {
  130. fseek(fd, len - lines * MSG_LOG_DEFAULT_LINE_LENGTH, SEEK_SET);
  131. len = lines * MSG_LOG_DEFAULT_LINE_LENGTH;
  132. }
  133. char *buf = malloc(len);
  134. fread(buf, len, 1, fd);
  135. TOX_ERR_FRIEND_SEND_MESSAGE stat;
  136. // Send log to friend
  137. if (len > TOX_MAX_MESSAGE_LENGTH) { // split msg if it is too long
  138. char buf_split[TOX_MAX_MESSAGE_LENGTH];
  139. int len_split, i;
  140. // Send full packages
  141. for (i = 0; i < len / (int)TOX_MAX_MESSAGE_LENGTH; i++) {
  142. memcpy(
  143. buf_split,
  144. buf + i * TOX_MAX_MESSAGE_LENGTH,
  145. TOX_MAX_MESSAGE_LENGTH * sizeof(uint8_t));
  146. len_split = TOX_MAX_MESSAGE_LENGTH;
  147. tox_friend_send_message(
  148. m,
  149. friendnumber,
  150. TOX_MESSAGE_TYPE_NORMAL,
  151. buf_split,
  152. len_split,
  153. stat);
  154. }
  155. // Send last package
  156. memcpy(
  157. buf_split,
  158. buf + (len / (int)TOX_MAX_MESSAGE_LENGTH) * TOX_MAX_MESSAGE_LENGTH,
  159. (len - (len / (int)TOX_MAX_MESSAGE_LENGTH) * TOX_MAX_MESSAGE_LENGTH) *
  160. sizeof(uint8_t));
  161. len_split = len - (len / (int)TOX_MAX_MESSAGE_LENGTH) * TOX_MAX_MESSAGE_LENGTH;
  162. if (len > 0)
  163. tox_friend_send_message(
  164. m,
  165. friendnumber,
  166. TOX_MESSAGE_TYPE_NORMAL,
  167. buf_split,
  168. len_split,
  169. stat);
  170. } else {
  171. tox_friend_send_message(m, friendnumber, TOX_MESSAGE_TYPE_NORMAL, buf, len, stat);
  172. }
  173. free(buf);
  174. }
  175. }
  176. void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
  177. {
  178. printf("Msg [%i]: %s\n", friendnumber, string);
  179. uint8_t *msg_invite, *msg_log, *msg_help, *m_msg_log;
  180. msg_invite = MSG_INVITE;
  181. msg_log = MSG_LOG;
  182. msg_help = MSG_HELP;
  183. m_msg_log = malloc(strlen(MSG_LOG) * sizeof(uint8_t)); // copy only chars of MSG_LOG to string
  184. // for checking of numbers behind MSG_LOG
  185. memcpy(m_msg_log, string, strlen(MSG_LOG) * sizeof(uint8_t));
  186. TOX_ERR_CONFERENCE_INVITE stat;
  187. TOX_ERR_FRIEND_SEND_MESSAGE sstat;
  188. // Take aktion based on string
  189. if (!memcmp(msg_invite, string,
  190. length * sizeof(uint8_t))) { // if msg is MSG_INVITE
  191. send_log(m, friendnumber, MSG_LOG_DEFAULT_LINES);
  192. tox_conference_invite(m, friendnumber, GROUPCHAT_NUMBER, stat);
  193. tox_friend_send_message(
  194. m,
  195. friendnumber,
  196. TOX_MESSAGE_TYPE_ACTION,
  197. RETURN_MSG_INVITE,
  198. strlen(RETURN_MSG_INVITE),
  199. sstat);
  200. printf("Invited [%i] to groupchat.\n", friendnumber);
  201. } else if (!memcmp(
  202. msg_log,
  203. m_msg_log,
  204. strlen(MSG_LOG) * sizeof(uint8_t))) { // if msg is MSG_LOG
  205. int32_t lines;
  206. if (length - strlen(MSG_LOG) > 1) { // if string is long enough that there can be a number
  207. uint8_t *lines_string = malloc(length - strlen(MSG_LOG) - 1); // take care of whitespace!
  208. memcpy(
  209. lines_string,
  210. string + strlen(MSG_LOG) + 1,
  211. (length - strlen(MSG_LOG) - 1) * sizeof(uint8_t));
  212. lines = atoi(lines_string);
  213. if (lines > MSG_LOG_MAX_LINES)
  214. lines = MSG_LOG_DEFAULT_LINES; // fallback
  215. } else { // if string is only len(MSG_LOG) length long, set number to
  216. // default
  217. lines = MSG_LOG_DEFAULT_LINES;
  218. }
  219. send_log(m, friendnumber, lines); // send log with lines lines to friend
  220. } else if (!memcmp(msg_help, string, length * sizeof(uint8_t))) {
  221. tox_friend_send_message(
  222. m,
  223. friendnumber,
  224. TOX_MESSAGE_TYPE_ACTION,
  225. RETURN_MSG_HELP,
  226. strlen(RETURN_MSG_HELP),
  227. sstat);
  228. } else { // fallback
  229. tox_friend_send_message(
  230. m,
  231. friendnumber,
  232. TOX_MESSAGE_TYPE_ACTION,
  233. RETURN_MSG_NOTINVITE,
  234. strlen(RETURN_MSG_NOTINVITE),
  235. sstat);
  236. printf("Unknown command from [%i].\n", friendnumber);
  237. }
  238. free(m_msg_log);
  239. }
  240. /* CALLBACK AND FUNCTIONS: ON CONNECTION STATUS CHANGE */
  241. void on_connection_status(Tox *m, int32_t friendnumber, uint8_t status, void *userdata)
  242. {
  243. if (status) {
  244. printf("Friend %i comes online.\n", friendnumber);
  245. } else {
  246. printf("Friend %i gone offline.\n", friendnumber);
  247. }
  248. }
  249. /* CALLBACK AND FUNCTIONS: ON GROUP MESSAGE */
  250. void store_group_message(Tox *m, uint8_t *name, uint16_t name_len, const uint8_t *msg, uint16_t msg_len)
  251. {
  252. // Get time
  253. time_t rawtime;
  254. struct tm *timeinfo;
  255. uint8_t buffer[100];
  256. uint8_t time_string[100];
  257. time(&rawtime);
  258. timeinfo = localtime(&rawtime);
  259. strftime(buffer, 100, "%R %a %b %d", timeinfo);
  260. int time_len = sprintf(time_string, "[%s]", buffer);
  261. // Set string
  262. int len = name_len + 1 + time_len + 1 + msg_len + 2;
  263. uint8_t *buf = malloc(len * sizeof(uint8_t));
  264. memcpy(buf, name, name_len * sizeof(uint8_t)); // copy name
  265. memset(buf + name_len, ' ', sizeof(uint8_t)); // set whitespace
  266. memcpy(buf + name_len + 1, time_string,
  267. time_len * sizeof(uint8_t)); // copy time
  268. memset(buf + name_len + 1 + time_len, '\n', sizeof(uint8_t)); // set newline
  269. memcpy(buf + name_len + 1 + time_len + 1, msg,
  270. msg_len * sizeof(uint8_t)); // copy msg
  271. memset(buf + name_len + 1 + time_len + 1 + msg_len, '\n',
  272. sizeof(uint8_t)); // set newline
  273. memset(buf + name_len + 1 + time_len + 1 + msg_len + 1, '\n',
  274. sizeof(uint8_t)); // set newline
  275. // Save string
  276. FILE *fd = fopen(SAVEFILE_MSG, "a");
  277. fwrite(buf, len, 1, fd);
  278. free(buf);
  279. fclose(fd);
  280. }
  281. // void
  282. // on_group_message(Tox *m, int groupnum, int peernum, const uint8_t *msg,
  283. // uint16_t msg_len, void* userdata){ uint8_t buf_name[TOX_MAX_NAME_LENGTH];
  284. // uint8_t *name;
  285. // uint16_t name_len;
  286. // name_len = tox_group_peername(m, groupnum, peernum, buf_name);
  287. // if(name_len!=-1){
  288. // name = malloc(name_len*sizeof(uint8_t));
  289. // memcpy(name,buf_name,name_len*sizeof(uint8_t));
  290. // printf("Group msg [%s]: %s\n", name, msg);
  291. // // Store msg
  292. // store_group_message(m, name, name_len, msg, msg_len);
  293. // }
  294. // else printf("Cant resolve peername!\n");
  295. // }
  296. /* INIT TOX */
  297. static Tox *init_tox(void)
  298. {
  299. struct Tox_Options *opts = tox_options_new(NULL);
  300. tox_options_set_proxy_type(opts, TOX_PROXY_TYPE_NONE);
  301. tox_options_set_ipv6_enabled(opts, false);
  302. tox_options_set_udp_enabled(opts, false);
  303. TOX_ERR_NEW err;
  304. Tox *m = tox_new(&opts, err);
  305. // tox_options_free(opts);
  306. // Register callback
  307. tox_callback_friend_request(m, on_request);
  308. tox_callback_friend_message(m, on_message);
  309. tox_callback_self_connection_status(m, on_connection_status);
  310. // tox_callback_group_message(m, on_group_message, NULL);
  311. // Return tox object
  312. return m;
  313. }
  314. /* MAIN */
  315. int main(int argc, const char *argv[])
  316. {
  317. // Start toxbot
  318. printf("// TOXBOT\n");
  319. // Convert public keyto binary data
  320. char *pub_key = hex_string_to_bin(BOOTSTRAP_KEY);
  321. // Setup mytox
  322. Tox *m = init_tox();
  323. int load_status;
  324. load_status = load_data(m);
  325. if (load_status == -1)
  326. return 1;
  327. TOX_ERR_SET_INFO e_setinfo;
  328. tox_self_set_name(m, (uint8_t *)MY_NAME, strlen(MY_NAME),
  329. e_setinfo); // set name
  330. tox_self_set_status_message(m, STATUS_MSG, strlen(STATUS_MSG),
  331. e_setinfo); // set status
  332. // Init connection
  333. int bootstrap;
  334. int i;
  335. TOX_ERR_BOOTSTRAP e_bs;
  336. bootstrap = tox_bootstrap(m, BOOTSTRAP_ADDRESS, BOOTSTRAP_PORT, (uint8_t *)pub_key, e_bs);
  337. if (bootstrap) {
  338. printf("Boostrap done.\n");
  339. } else {
  340. printf("Boostrap crashed.\n");
  341. return 1;
  342. }
  343. // Main loop
  344. TOX_CONNECTION is_connected = 0;
  345. int first_connect = 1;
  346. while (1) {
  347. is_connected = tox_self_get_connection_status(m);
  348. tox_iterate(m, NULL);
  349. // Do loop of first connect
  350. if ((is_connected != TOX_CONNECTION_NONE) && first_connect) {
  351. first_connect = 0;
  352. printf("Connected to DHT.\n");
  353. get_myid(m); // get my id
  354. // int groupchat_num;
  355. // groupchat_num = tox_add_groupchat(m);
  356. // if(groupchat_num == -1){
  357. // printf("Creating groupchat failed.\n");
  358. // return 1;
  359. // }
  360. // if(groupchat_num == GROUPCHAT_NUMBER){
  361. // printf("Setup groupchat
  362. //[%i].\n",GROUPCHAT_NUMBER);
  363. // }
  364. // else{
  365. // printf("Setup groupchat with undefined
  366. //number.\n"); return 1;
  367. // }
  368. usleep(SLEEP_TIME_MAINLOOP);
  369. }
  370. // Do loops after first connect (save data and do short sleep)
  371. else if (is_connected && !first_connect) {
  372. store_data(m);
  373. usleep(SLEEP_TIME_MAINLOOP);
  374. }
  375. // Catch error if connection is lost
  376. else if (!is_connected && !first_connect) {
  377. printf("Lost connection to DHT.\n");
  378. return 1;
  379. }
  380. // Wait for connection
  381. else {
  382. usleep(SLEEP_TIME_ISNOTCONNECTED);
  383. }
  384. }
  385. // Kill tox
  386. tox_kill(m);
  387. return 0;
  388. }