1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-12-22 22:43:25 +01:00

implement avatars (setting only) and generalize path tab-complete

This commit is contained in:
Jfreegman 2014-09-26 03:10:44 -04:00
parent cee9e624b8
commit 544c402f78
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
17 changed files with 169 additions and 29 deletions

View File

@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2014-08-26
.\" Date: 2014-09-19
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2014\-08\-26" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC\&.CONF" "5" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -138,6 +138,11 @@ Configuration related to paths\&.
Default path for downloads\&. String value\&. Absolute path for downloaded files\&.
.RE
.PP
\fBavatar_path\fR
.RS 4
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
.RE
.PP
\fBchatlogs_path\fR
.RS 4
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.

View File

@ -87,6 +87,9 @@ OPTIONS
Default path for downloads. String value. Absolute path for downloaded
files.
*avatar_path*;;
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
*chatlogs_path*;;
Default path for chatlogs. String value. Absolute path for chatlog files.

View File

@ -104,7 +104,9 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
return -1;
bool dir_search = strncmp(ubuf, "/sendfile", strlen("/sendfile")) == 0;
/* TODO: generalize this */
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
@ -202,8 +204,8 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
return diff;
}
/* transforms a sendfile tab complete contaning the shorthand "~/" into the full home directory.*/
static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
/* transforms a tab complete starting with the shorthand "~" into the full home directory.*/
static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
{
ChatContext *ctx = self->chatwin;
@ -211,8 +213,8 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
get_home_dir(homedir, sizeof(homedir));
char newline[MAX_STR_SIZE];
snprintf(newline, sizeof(newline), "/sendfile \"%s%s", homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[11]);
snprintf(newline, sizeof(newline), "%s \"%s%s", cmd, homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[cmdlen]);
wchar_t wline[MAX_STR_SIZE];
@ -229,23 +231,27 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
ctx->len = ctx->pos;
}
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
/* attempts to match /command "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
#define MAX_DIRS 512
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
{
char b_path[MAX_STR_SIZE];
char b_name[MAX_STR_SIZE];
const wchar_t *tmpline = &line[11]; /* start after "/sendfile \"" */
char b_cmd[MAX_STR_SIZE];
const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
return -1;
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1)
return -1;
if (b_path[0] == '~')
complt_home_dir(self, b_path, sizeof(b_path));
complt_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
int si = char_rfind(b_path, '/', strlen(b_path));
@ -261,7 +267,6 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
strcpy(b_name, &b_path[si + 1]);
b_path[si + 1] = '\0';
int b_name_len = strlen(b_name);
DIR *dp = opendir(b_path);
if (dp == NULL)

View File

@ -33,10 +33,10 @@
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size);
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
/* attempts to match /command "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line);
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd);
#endif /* #define AUTOCOMPLETE_H */

View File

@ -64,15 +64,16 @@ static void kill_infobox(ToxWindow *self);
#endif /* AUDIO */
#ifdef AUDIO
#define AC_NUM_CHAT_COMMANDS 26
#define AC_NUM_CHAT_COMMANDS 27
#else
#define AC_NUM_CHAT_COMMANDS 19
#define AC_NUM_CHAT_COMMANDS 20
#endif /* AUDIO */
/* Array of chat command names used for tab completion. */
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/accept" },
{ "/add" },
{ "/avatar" },
{ "/cancel" },
{ "/clear" },
{ "/close" },
@ -879,8 +880,11 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
int diff = -1;
/* TODO: make this not suck */
if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) {
diff = dir_match(self, m, ctx->line);
diff = dir_match(self, m, ctx->line, L"/sendfile");
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar");
} else {
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
}

View File

@ -41,6 +41,7 @@ struct cmd_func {
static struct cmd_func global_commands[] = {
{ "/accept", cmd_accept },
{ "/add", cmd_add },
{ "/avatar", cmd_avatar },
{ "/clear", cmd_clear },
{ "/connect", cmd_connect },
{ "/decline", cmd_decline },

View File

@ -184,6 +184,73 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
}
}
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied.");
return;
}
if (string_is_empty(argv[1]))
return;
if (argv[1][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
return;
}
/* remove opening and closing quotes */
char path[MAX_STR_SIZE];
snprintf(path, sizeof(path), "%s", &argv[1][1]);
int len = strlen(path) - 1;
path[len] = '\0';
off_t sz = file_size(path);
if (sz <= 8) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file.");
return;
}
if (sz > TOX_AVATAR_MAX_DATA_LENGTH) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File is too large.");
return;
}
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file.");
return;
}
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);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported.");
return;
}
char *avatar = malloc(sz);
if (avatar == NULL)
exit_toxic_err("Failed in set_avatar", FATALERR_MEMORY);
if (fread(avatar, sz, 1, fp) == -1) {
fclose(fp);
free(avatar);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail.");
return;
}
if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Core error.");
fclose(fp);
free(avatar);
}
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
line_info_clear(self->chatwin->hst);

View File

@ -28,6 +28,7 @@
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);

View File

@ -372,11 +372,15 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ctx->len > 0) {
int diff;
if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
diff = complete_line(self, groupchats[self->num].peer_names,
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
else
/* TODO: make this not suck */
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
diff = complete_line(self, groupchats[self->num].peer_names, groupchats[self->num].num_peers,
TOX_MAX_NAME_LENGTH);
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar");
} else {
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
}
if (diff != -1) {
if (x + diff > x2 - 1) {

View File

@ -138,6 +138,7 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /add <addr> <msg> : Add contact with optional message\n");
wprintw(win, " /accept <id> : Accept friend request\n");
wprintw(win, " /avatar <path> : Set a personal avatar\n");
wprintw(win, " /decline <id> : Decline friend request\n");
wprintw(win, " /requests : List pending friend requests\n");
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
@ -266,9 +267,9 @@ void help_onKey(ToxWindow *self, wint_t key)
case 'g':
#ifdef AUDIO
help_init_window(self, 23, 80);
help_init_window(self, 24, 80);
#else
help_init_window(self, 19, 80);
help_init_window(self, 20, 80);
#endif
self->help->type = HELP_GLOBAL;
break;

View File

@ -322,3 +322,22 @@ off_t file_size(const char *path)
return st.st_size;
}
/* compares the first size bytes of fp to signature.
Returns 0 if they are the same, 1 if they differ, and -1 on error.
On success this function will seek back to the beginning of fp */
int check_file_signature(const char *signature, size_t size, FILE *fp)
{
char buf[size];
if (fread(buf, size, 1, fp) == -1)
return -1;
int ret = memcmp(signature, buf, size);
if (fseek(fp, 0L, SEEK_SET) == -1)
return -1;
return ret == 0 ? 0 : 1;
}

View File

@ -115,4 +115,10 @@ bool file_exists(const char *path);
/* returns file size or -1 on error */
off_t file_size(const char *path);
/* compares the first size bytes of fp and signature.
Returns 0 if they are the same, 1 if they differ, and -1 on error.
On success this function will seek back to the beginning of fp and will not close fp */
int check_file_signature(const char *signature, size_t size, FILE *fp);
#endif /* #define MISC_TOOLS_H */

View File

@ -52,6 +52,7 @@ _FriendRequests FriendRequests;
const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/accept" },
{ "/add" },
{ "/avatar" },
{ "/clear" },
{ "/close" }, /* rm /close when groupchats gets its own list */
{ "/connect" },
@ -183,7 +184,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (key == '\t') { /* TAB key: auto-completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
int diff = -1;
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
diff = dir_match(self, m, ctx->line, L"/avatar");
else
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {

View File

@ -27,9 +27,9 @@
#include "windows.h"
#ifdef AUDIO
#define AC_NUM_GLOB_COMMANDS 18
#define AC_NUM_GLOB_COMMANDS 19
#else
#define AC_NUM_GLOB_COMMANDS 16
#define AC_NUM_GLOB_COMMANDS 17
#endif /* AUDIO */
#define MAX_FRIEND_REQUESTS 32

View File

@ -123,16 +123,19 @@ static const struct tox_strings {
const char* self;
const char* download_path;
const char* chatlogs_path;
const char* avatar_path;
} tox_strings = {
"tox",
"download_path",
"chatlogs_path",
"avatar_path",
};
static void tox_defaults(struct user_settings* settings)
{
strcpy(settings->download_path, "");
strcpy(settings->chatlogs_path, "");
strcpy(settings->avatar_path, "");
}
#ifdef AUDIO
@ -280,6 +283,14 @@ int settings_load(struct user_settings *s, const char *patharg)
else if (s->chatlogs_path[len - 1] != '/')
strcat(&s->chatlogs_path[len - 1], "/");
}
if ( config_setting_lookup_string(setting, tox_strings.avatar_path, &str) ) {
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
int len = strlen(s->avatar_path);
if (len >= sizeof(s->avatar_path))
s->avatar_path[0] = '\0';
}
}
/* keys */

View File

@ -39,9 +39,10 @@ struct user_settings {
char download_path[PATH_MAX];
char chatlogs_path[PATH_MAX];
char avatar_path[PATH_MAX];
int key_next_tab; /* character code */
int key_prev_tab; /* character code */
int key_next_tab;
int key_prev_tab;
int key_scroll_line_up;
int key_scroll_line_down;
int key_half_page_up;
@ -49,6 +50,7 @@ struct user_settings {
int key_page_bottom;
int key_peer_list_up;
int key_peer_list_down;
#ifdef AUDIO
int audio_in_dev;
int audio_out_dev;

View File

@ -56,6 +56,7 @@
#include "notify.h"
#include "device.h"
#include "message_queue.h"
#include "execute.h"
#ifdef AUDIO
#include "audio_call.h"
@ -1004,7 +1005,7 @@ int main(int argc, char *argv[])
Tox *m = init_tox();
if (m == NULL)
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
if (!arg_opts.ignore_data_file) {
if (arg_opts.encrypt_data && !datafile_exists)
@ -1061,6 +1062,10 @@ int main(int argc, char *argv[])
print_init_messages(prompt);
cleanup_init_messages();
char avatarstr[MAX_STR_SIZE];
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
uint64_t last_save = (uint64_t) time(NULL);
uint64_t looptimer = last_save;
useconds_t msleepval = 40000;