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:
parent
cee9e624b8
commit
544c402f78
@ -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\&.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
10
src/chat.c
10
src/chat.c
@ -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);
|
||||
}
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user