/* avatars.c * * * Copyright (C) 2015 Toxic All Rights Reserved. * * This file is part of Toxic. * * Toxic is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Toxic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Toxic. If not, see . * */ #include #include #include #include "misc_tools.h" #include "file_transfers.h" #include "friendlist.h" #include "avatars.h" extern FriendsList Friends; static struct Avatar { char name[TOX_MAX_FILENAME_LENGTH + 1]; size_t name_len; char path[PATH_MAX + 1]; size_t path_len; off_t size; } Avatar; static void avatar_clear(void) { memset(&Avatar, 0, sizeof(struct Avatar)); } /* Sends avatar to friendnum. * * Returns 0 on success. * Returns -1 on failure. */ int avatar_send(Tox *m, uint32_t friendnum) { TOX_ERR_FILE_SEND err; uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size, NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err); if (Avatar.size == 0) return 0; if (err != TOX_ERR_FILE_SEND_OK) { fprintf(stderr, "tox_file_send failed for friendnumber %d (error %d)\n", friendnum, err); return -1; } struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR); if (!ft) return -1; ft->file = fopen(Avatar.path, "r"); if (ft->file == NULL) return -1; snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name); ft->file_size = Avatar.size; return 0; } /* Sends avatar to all friends */ static void avatar_send_all(Tox *m) { size_t i; for (i = 0; i < Friends.max_idx; ++i) { if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) avatar_send(m, Friends.list[i].num); } } /* Sets avatar to path and sends it to all online contacts. * * Returns 0 on success. * Returns -1 on failure. */ int avatar_set(Tox *m, const char *path, size_t path_len) { if (path_len == 0 || path_len >= sizeof(Avatar.path)) return -1; FILE *fp = fopen(path, "rb"); if (fp == NULL) return -1; char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) { fclose(fp); return -1; } fclose(fp); off_t size = file_size(path); if (size == 0 || size > MAX_AVATAR_FILE_SIZE) return -1; get_file_name(Avatar.name, sizeof(Avatar.name), path); Avatar.name_len = strlen(Avatar.name); snprintf(Avatar.path, sizeof(Avatar.path), "%s", path); Avatar.path_len = path_len; Avatar.size = size; avatar_send_all(m); return 0; } /* Unsets avatar and sends to all online contacts. * * Returns 0 on success. * Returns -1 on failure. */ void avatar_unset(Tox *m) { avatar_clear(); avatar_send_all(m); } void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL control) { switch (control) { case TOX_FILE_CONTROL_RESUME: if (ft->state == FILE_TRANSFER_PENDING) { ft->state = FILE_TRANSFER_STARTED; } else if (ft->state == FILE_TRANSFER_PAUSED) { ft->state = FILE_TRANSFER_STARTED; } break; case TOX_FILE_CONTROL_PAUSE: ft->state = FILE_TRANSFER_PAUSED; break; case TOX_FILE_CONTROL_CANCEL: close_file_transfer(NULL, m, ft, -1, NULL, silent); break; } } void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length) { if (ft->state != FILE_TRANSFER_STARTED) return; if (length == 0) { close_file_transfer(NULL, m, ft, -1, NULL, silent); return; } if (ft->file == NULL) { close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent); return; } if (ft->position != position) { if (fseek(ft->file, position, SEEK_SET) == -1) { close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent); return; } ft->position = position; } uint8_t send_data[length]; size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file); if (send_length != length) { close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent); return; } TOX_ERR_FILE_SEND_CHUNK err; tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err); if (err != TOX_ERR_FILE_SEND_CHUNK_OK) fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err); ft->position += send_length; ft->last_keep_alive = get_unix_time(); }