mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-23 01:53:02 +01:00
Merge with upstream
This commit is contained in:
commit
ed1429afa1
16
README.md
16
README.md
@ -4,23 +4,9 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
|
|||||||
[![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png)
|
[![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
[Use our repositories](https://wiki.tox.chat/doku.php?id=developers:binaries#other_linux)<br />
|
[Use our repositories](https://wiki.tox.chat/binaries#other_linux)<br />
|
||||||
[Compile it yourself](/INSTALL.md)
|
[Compile it yourself](/INSTALL.md)
|
||||||
|
|
||||||
## Downloads
|
|
||||||
If you don't like installation methods listed above, you can still download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so):
|
|
||||||
* [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_i386/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz)
|
|
||||||
* [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz) [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
|
|
||||||
* [~~Linux ARMv6~~](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) **CURRENTLY DISABLED** [![Build Status](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/badge/icon)](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz)
|
|
||||||
|
|
||||||
#### DEBs packages
|
|
||||||
* [toxic-i386.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.deb)
|
|
||||||
* [toxic-x86_64.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-x86_64.deb)
|
|
||||||
|
|
||||||
#### RPMs packages
|
|
||||||
* [toxic-i386.rpm](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.rpm)
|
|
||||||
* [toxic-x86_64.rpm](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-x86_64.rpm)
|
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
|
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
|
||||||
You can view our example config file [here](misc/toxic.conf.example).
|
You can view our example config file [here](misc/toxic.conf.example).
|
||||||
|
@ -93,7 +93,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
|
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
const char *L = (char *) list;
|
const char *L = (char *) list;
|
||||||
@ -136,7 +136,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string_is_empty(sub)) {
|
if (!sub[0]) {
|
||||||
free(sub);
|
free(sub);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -185,7 +185,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
char tmpend[MAX_STR_SIZE];
|
char tmpend[MAX_STR_SIZE];
|
||||||
strcpy(tmpend, &ubuf[ctx->pos]);
|
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
|
||||||
strcpy(&ubuf[strt], match);
|
strcpy(&ubuf[strt], match);
|
||||||
strcpy(&ubuf[strt + m_len], endchrs);
|
strcpy(&ubuf[strt + m_len], endchrs);
|
||||||
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
|
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
|
||||||
@ -193,7 +193,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
/* convert to widechar and copy back to original buf */
|
/* convert to widechar and copy back to original buf */
|
||||||
wchar_t newbuf[MAX_STR_SIZE];
|
wchar_t newbuf[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
|
if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
wcscpy(ctx->line, newbuf);
|
wcscpy(ctx->line, newbuf);
|
||||||
@ -218,7 +218,7 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const cha
|
|||||||
|
|
||||||
wchar_t wline[MAX_STR_SIZE];
|
wchar_t wline[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (mbs_to_wcs_buf(wline, newline, sizeof(wline)) == -1)
|
if (mbs_to_wcs_buf(wline, newline, sizeof(wline) / sizeof(wchar_t)) == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int newlen = wcslen(wline);
|
int newlen = wcslen(wline);
|
||||||
@ -261,10 +261,10 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
||||||
char tmp[MAX_STR_SIZE];
|
char tmp[MAX_STR_SIZE];
|
||||||
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
||||||
strcpy(b_path, tmp);
|
snprintf(b_path, sizeof(b_path), "%s", tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(b_name, &b_path[si + 1]);
|
snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
|
||||||
b_path[si + 1] = '\0';
|
b_path[si + 1] = '\0';
|
||||||
int b_name_len = strlen(b_name);
|
int b_name_len = strlen(b_name);
|
||||||
DIR *dp = opendir(b_path);
|
DIR *dp = opendir(b_path);
|
||||||
|
@ -63,7 +63,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = get_new_file_sender(friendnum);
|
struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft)
|
||||||
return -1;
|
return -1;
|
||||||
@ -75,11 +75,6 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
|||||||
|
|
||||||
snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
|
snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
|
||||||
ft->file_size = Avatar.size;
|
ft->file_size = Avatar.size;
|
||||||
ft->state = FILE_TRANSFER_PENDING;
|
|
||||||
ft->filenum = filenum;
|
|
||||||
ft->friendnum = friendnum;
|
|
||||||
ft->direction = FILE_TRANSFER_SEND;
|
|
||||||
ft->file_type = TOX_FILE_KIND_AVATAR;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -206,4 +201,5 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position,
|
|||||||
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
|
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
|
||||||
|
|
||||||
ft->position += send_length;
|
ft->position += send_length;
|
||||||
|
ft->last_keep_alive = get_unix_time();
|
||||||
}
|
}
|
||||||
|
136
src/chat.c
136
src/chat.c
@ -189,8 +189,8 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TY
|
|||||||
return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
|
return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_resume_file_transfers(Tox *m, uint32_t fnum);
|
static void chat_pause_file_transfers(Tox *m, uint32_t friendnum);
|
||||||
static void chat_stop_file_senders(Tox *m, uint32_t friendnum);
|
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t fnum);
|
||||||
|
|
||||||
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
@ -210,7 +210,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
if (connection_status != TOX_CONNECTION_NONE && statusbar->connection == TOX_CONNECTION_NONE) {
|
if (connection_status != TOX_CONNECTION_NONE && statusbar->connection == TOX_CONNECTION_NONE) {
|
||||||
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
||||||
? tox_friend_get_typing(m, num, NULL) : false;
|
? tox_friend_get_typing(m, num, NULL) : false;
|
||||||
chat_resume_file_transfers(m, num);
|
chat_resume_file_senders(self, m, num);
|
||||||
|
|
||||||
msg = "has come online";
|
msg = "has come online";
|
||||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
||||||
@ -221,7 +221,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
if (self->chatwin->self_is_typing)
|
if (self->chatwin->self_is_typing)
|
||||||
set_self_typingstatus(self, m, 0);
|
set_self_typingstatus(self, m, 0);
|
||||||
|
|
||||||
chat_stop_file_senders(m, num);
|
chat_pause_file_transfers(m, num);
|
||||||
|
|
||||||
msg = "has gone offline";
|
msg = "has gone offline";
|
||||||
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
||||||
@ -278,17 +278,44 @@ static void chat_onReadReceipt(ToxWindow *self, Tox *m, uint32_t num, uint32_t r
|
|||||||
cqueue_remove(self, m, receipt);
|
cqueue_remove(self, m, receipt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stops active file senders for this friend. Call when a friend goes offline */
|
/* Stops active file transfers for this friend. Called when a friend goes offline */
|
||||||
static void chat_stop_file_senders(Tox *m, uint32_t friendnum)
|
static void chat_pause_file_transfers(Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
// TODO: core purges file transfers when a friend goes offline. Ideally we want to repair/resume
|
ToxicFriend *friend = &Friends.list[friendnum];
|
||||||
kill_all_file_transfers_friend(m, friendnum);
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED)
|
||||||
|
friend->file_sender[i].state = FILE_TRANSFER_PAUSED;
|
||||||
|
|
||||||
|
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED)
|
||||||
|
friend->file_receiver[i].state = FILE_TRANSFER_PAUSED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tries to resume broken file transfers. Call when a friend comes online */
|
/* Tries to resume broken file senders. Called when a friend comes online */
|
||||||
static void chat_resume_file_transfers(Tox *m, uint32_t fnum)
|
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
// TODO
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
||||||
|
|
||||||
|
if (ft->state != FILE_TRANSFER_PAUSED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TOX_ERR_FILE_SEND err;
|
||||||
|
ft->filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, ft->file_size, ft->file_id,
|
||||||
|
(uint8_t *) ft->file_name, strlen(ft->file_name), &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_FILE_SEND_OK) {
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||||
@ -347,6 +374,7 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
|
|||||||
|
|
||||||
ft->position += send_length;
|
ft->position += send_length;
|
||||||
ft->bps += send_length;
|
ft->bps += send_length;
|
||||||
|
ft->last_keep_alive = get_unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||||
@ -386,6 +414,7 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui
|
|||||||
|
|
||||||
ft->bps += length;
|
ft->bps += length;
|
||||||
ft->position += length;
|
ft->position += length;
|
||||||
|
ft->last_keep_alive = get_unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control)
|
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control)
|
||||||
@ -401,14 +430,16 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
|||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
|
|
||||||
switch (control) {
|
switch (control) {
|
||||||
case TOX_FILE_CONTROL_RESUME:
|
case TOX_FILE_CONTROL_RESUME: {
|
||||||
|
ft->last_keep_alive = get_unix_time();
|
||||||
|
|
||||||
/* transfer is accepted */
|
/* transfer is accepted */
|
||||||
if (ft->state == FILE_TRANSFER_PENDING) {
|
if (ft->state == FILE_TRANSFER_PENDING) {
|
||||||
ft->state = FILE_TRANSFER_STARTED;
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
||||||
ft->index, ft->file_name);
|
ft->index, ft->file_name);
|
||||||
char progline[MAX_STR_SIZE];
|
char progline[MAX_STR_SIZE];
|
||||||
prep_prog_line(progline);
|
init_progress_bar(progline);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
||||||
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
|
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
|
||||||
ft->line_id = self->chatwin->hst->line_end->id + 2;
|
ft->line_id = self->chatwin->hst->line_end->id + 2;
|
||||||
@ -417,25 +448,78 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case TOX_FILE_CONTROL_PAUSE:
|
case TOX_FILE_CONTROL_PAUSE: {
|
||||||
ft->state = FILE_TRANSFER_PAUSED;
|
ft->state = FILE_TRANSFER_PAUSED;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case TOX_FILE_CONTROL_CANCEL:
|
case TOX_FILE_CONTROL_CANCEL: {
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
||||||
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Attempts to resume a broken inbound file transfer.
|
||||||
|
*
|
||||||
|
* Returns true if resume is successful.
|
||||||
|
*/
|
||||||
|
static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum)
|
||||||
|
{
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
||||||
|
|
||||||
|
if (!tox_file_get_file_id(m, friendnum, filenum, file_id, NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool resuming = false;
|
||||||
|
struct FileTransfer *ft = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
ft = &Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
|
if (ft->state == FILE_TRANSFER_INACTIVE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
|
||||||
|
ft->filenum = filenum;
|
||||||
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
|
ft->last_keep_alive = get_unix_time();
|
||||||
|
resuming = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resuming || !ft)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!tox_file_seek(m, ft->friendnum, ft->filenum, ft->position, NULL))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL))
|
||||||
|
goto on_error;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", ft->file_name);
|
||||||
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
|
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
|
||||||
const char *filename, size_t name_length)
|
const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (self->num != friendnum)
|
if (self->num != friendnum)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct FileTransfer *ft = get_new_file_receiver(friendnum);
|
/* first check if we need to resume a broken transfer */
|
||||||
|
if (chat_resume_broken_ft(self, m, friendnum, filenum))
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct FileTransfer *ft = new_file_transfer(self, friendnum, filenum, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA);
|
||||||
|
|
||||||
if (!ft) {
|
if (!ft) {
|
||||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
@ -458,7 +542,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
|||||||
snprintf(file_path, sizeof(file_path), "%s", filename);
|
snprintf(file_path, sizeof(file_path), "%s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
|
if (path_len >= sizeof(file_path) || path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) {
|
||||||
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long.");
|
||||||
return;
|
return;
|
||||||
@ -493,14 +577,10 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
|||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", ft->index);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", ft->index);
|
||||||
|
|
||||||
ft->state = FILE_TRANSFER_PENDING;
|
|
||||||
ft->direction = FILE_TRANSFER_RECV;
|
|
||||||
ft->file_size = file_size;
|
ft->file_size = file_size;
|
||||||
ft->friendnum = friendnum;
|
|
||||||
ft->filenum = filenum;
|
|
||||||
ft->file_type = TOX_FILE_KIND_DATA;
|
|
||||||
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
|
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
|
||||||
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
|
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
|
||||||
|
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
|
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
|
||||||
@ -851,7 +931,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
if (diff != -1) {
|
if (diff != -1) {
|
||||||
if (x + diff > x2 - 1) {
|
if (x + diff > x2 - 1) {
|
||||||
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
|
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
|
||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1005,7 +1085,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int y, x;
|
int y, x;
|
||||||
getyx(self->window, y, x);
|
getyx(self->window, y, x);
|
||||||
(void) x;
|
(void) x;
|
||||||
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
|
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
||||||
wmove(self->window, y + 1, new_x);
|
wmove(self->window, y + 1, new_x);
|
||||||
|
|
||||||
wrefresh(self->window);
|
wrefresh(self->window);
|
||||||
@ -1072,11 +1152,13 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
char myid[TOX_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
||||||
load_chat_history(self, ctx->log);
|
load_chat_history(self, ctx->log);
|
||||||
|
|
||||||
if (!Friends.list[self->num].logging_on)
|
if (!Friends.list[self->num].logging_on)
|
||||||
log_disable(ctx->log);
|
log_disable(ctx->log);
|
||||||
|
else if (log_ret == -1)
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
|
|
||||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
|
|
||||||
/* prep progress bar line */
|
/* prep progress bar line */
|
||||||
char progline[MAX_STR_SIZE];
|
char progline[MAX_STR_SIZE];
|
||||||
prep_prog_line(progline);
|
init_progress_bar(progline);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
||||||
|
|
||||||
ft->line_id = self->chatwin->hst->line_end->id + 2;
|
ft->line_id = self->chatwin->hst->line_end->id + 2;
|
||||||
@ -265,7 +265,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
if (err != TOX_ERR_FILE_SEND_OK)
|
if (err != TOX_ERR_FILE_SEND_OK)
|
||||||
goto on_send_error;
|
goto on_send_error;
|
||||||
|
|
||||||
struct FileTransfer *ft = get_new_file_sender(self->num);
|
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
|
||||||
|
|
||||||
if (!ft) {
|
if (!ft) {
|
||||||
err = TOX_ERR_FILE_SEND_TOO_MANY;
|
err = TOX_ERR_FILE_SEND_TOO_MANY;
|
||||||
@ -273,13 +273,9 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
}
|
}
|
||||||
|
|
||||||
memcpy(ft->file_name, file_name, namelen + 1);
|
memcpy(ft->file_name, file_name, namelen + 1);
|
||||||
ft->state = FILE_TRANSFER_PENDING;
|
|
||||||
ft->file = file_to_send;
|
ft->file = file_to_send;
|
||||||
ft->file_size = filesize;
|
ft->file_size = filesize;
|
||||||
ft->filenum = filenum;
|
tox_file_get_file_id(m, self->num, filenum, ft->file_id, NULL);
|
||||||
ft->friendnum = self->num;
|
|
||||||
ft->direction = FILE_TRANSFER_SEND;
|
|
||||||
ft->file_type = TOX_FILE_KIND_DATA;
|
|
||||||
|
|
||||||
char sizestr[32];
|
char sizestr[32];
|
||||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
||||||
|
162
src/device.c
162
src/device.c
@ -58,14 +58,14 @@ typedef struct Device {
|
|||||||
DataHandleCallback cb; /* Use this to handle data from input device usually */
|
DataHandleCallback cb; /* Use this to handle data from input device usually */
|
||||||
void* cb_data; /* Data to be passed to callback */
|
void* cb_data; /* Data to be passed to callback */
|
||||||
int32_t call_idx; /* ToxAv call index */
|
int32_t call_idx; /* ToxAv call index */
|
||||||
|
|
||||||
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
|
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
|
||||||
uint32_t ref_count;
|
uint32_t ref_count;
|
||||||
int32_t selection;
|
int32_t selection;
|
||||||
bool enable_VAD;
|
bool enable_VAD;
|
||||||
bool muted;
|
bool muted;
|
||||||
pthread_mutex_t mutex[1];
|
pthread_mutex_t mutex[1];
|
||||||
uint32_t sample_rate;
|
uint32_t sample_rate;
|
||||||
uint32_t frame_duration;
|
uint32_t frame_duration;
|
||||||
int32_t sound_mode;
|
int32_t sound_mode;
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -89,7 +89,7 @@ static ToxAv* av = NULL;
|
|||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
|
||||||
bool thread_running = true,
|
bool thread_running = true,
|
||||||
thread_paused = true; /* Thread control */
|
thread_paused = true; /* Thread control */
|
||||||
|
|
||||||
void* thread_poll(void*);
|
void* thread_poll(void*);
|
||||||
@ -105,19 +105,19 @@ DeviceError init_devices()
|
|||||||
size[input] = 0;
|
size[input] = 0;
|
||||||
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
|
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
|
||||||
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
|
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
|
||||||
|
|
||||||
for ( ; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input] ) {
|
for ( ; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input] ) {
|
||||||
devices_names[input][size[input]] = stringed_device_list;
|
devices_names[input][size[input]] = stringed_device_list;
|
||||||
stringed_device_list += strlen( stringed_device_list ) + 1;
|
stringed_device_list += strlen( stringed_device_list ) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size[output] = 0;
|
size[output] = 0;
|
||||||
if ( (stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER)) ) {
|
if ( (stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER)) ) {
|
||||||
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||||
|
|
||||||
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
|
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
|
||||||
devices_names[output][size[output]] = stringed_device_list;
|
devices_names[output][size[output]] = stringed_device_list;
|
||||||
stringed_device_list += strlen( stringed_device_list ) + 1;
|
stringed_device_list += strlen( stringed_device_list ) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,27 +125,30 @@ DeviceError init_devices()
|
|||||||
// Start poll thread
|
// Start poll thread
|
||||||
if (pthread_mutex_init(&mutex, NULL) != 0)
|
if (pthread_mutex_init(&mutex, NULL) != 0)
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
|
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
|
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
av = av_;
|
av = av_;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
return (DeviceError) de_None;
|
return (DeviceError) de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceError terminate_devices()
|
DeviceError terminate_devices()
|
||||||
{
|
{
|
||||||
/* Cleanup if needed */
|
/* Cleanup if needed */
|
||||||
|
lock;
|
||||||
thread_running = false;
|
thread_running = false;
|
||||||
|
unlock;
|
||||||
|
|
||||||
usleep(20000);
|
usleep(20000);
|
||||||
|
|
||||||
if (pthread_mutex_destroy(&mutex) != 0)
|
if (pthread_mutex_destroy(&mutex) != 0)
|
||||||
return (DeviceError) de_InternalError;
|
return (DeviceError) de_InternalError;
|
||||||
|
|
||||||
return (DeviceError) de_None;
|
return (DeviceError) de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,16 +156,16 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
|||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
Device* device = running[type][device_idx];
|
Device* device = running[type][device_idx];
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
unlock;
|
unlock;
|
||||||
return de_DeviceNotActive;
|
return de_DeviceNotActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->muted = !device->muted;
|
device->muted = !device->muted;
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
@ -175,7 +178,7 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
|||||||
|
|
||||||
Device* device = running[input][device_idx];
|
Device* device = running[input][device_idx];
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
unlock;
|
unlock;
|
||||||
return de_DeviceNotActive;
|
return de_DeviceNotActive;
|
||||||
}
|
}
|
||||||
@ -192,7 +195,7 @@ DeviceError set_primary_device(DeviceType type, int32_t selection)
|
|||||||
{
|
{
|
||||||
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
||||||
primary_device[type] = selection;
|
primary_device[type] = selection;
|
||||||
|
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,88 +215,88 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
||||||
|
|
||||||
if (channels != 1 && channels != 2) return de_UnsupportedMode;
|
if (channels != 1 && channels != 2) return de_UnsupportedMode;
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
|
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
|
||||||
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
|
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
|
||||||
|
|
||||||
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
|
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
|
||||||
else *device_idx = i;
|
else *device_idx = i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
|
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
|
||||||
if ( running[type][i] && running[type][i]->selection == selection ) {
|
if ( running[type][i] && running[type][i]->selection == selection ) {
|
||||||
// printf("a%d-%d:%p ", selection, i, running[type][i]->dhndl);
|
// printf("a%d-%d:%p ", selection, i, running[type][i]->dhndl);
|
||||||
|
|
||||||
running[type][*device_idx] = running[type][i];
|
running[type][*device_idx] = running[type][i];
|
||||||
running[type][i]->ref_count ++;
|
running[type][i]->ref_count ++;
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));
|
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));
|
||||||
device->selection = selection;
|
device->selection = selection;
|
||||||
|
|
||||||
device->sample_rate = sample_rate;
|
device->sample_rate = sample_rate;
|
||||||
device->frame_duration = frame_duration;
|
device->frame_duration = frame_duration;
|
||||||
device->sound_mode = channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
device->sound_mode = channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
||||||
|
|
||||||
if (pthread_mutex_init(device->mutex, NULL) != 0) {
|
if (pthread_mutex_init(device->mutex, NULL) != 0) {
|
||||||
free(device);
|
free(device);
|
||||||
unlock;
|
unlock;
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == input) {
|
if (type == input) {
|
||||||
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
|
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
|
||||||
sample_rate, device->sound_mode, frame_size * 2);
|
sample_rate, device->sound_mode, frame_size * 2);
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
device->VAD_treshold = user_settings->VAD_treshold;
|
device->VAD_treshold = user_settings->VAD_treshold;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
device->dhndl = alcOpenDevice(devices_names[type][selection]);
|
device->dhndl = alcOpenDevice(devices_names[type][selection]);
|
||||||
if ( !device->dhndl ) {
|
if ( !device->dhndl ) {
|
||||||
free(device);
|
free(device);
|
||||||
running[type][*device_idx] = NULL;
|
running[type][*device_idx] = NULL;
|
||||||
unlock;
|
unlock;
|
||||||
return de_FailedStart;
|
return de_FailedStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->ctx = alcCreateContext(device->dhndl, NULL);
|
device->ctx = alcCreateContext(device->dhndl, NULL);
|
||||||
alcMakeContextCurrent(device->ctx);
|
alcMakeContextCurrent(device->ctx);
|
||||||
|
|
||||||
alGenBuffers(OPENAL_BUFS, device->buffers);
|
alGenBuffers(OPENAL_BUFS, device->buffers);
|
||||||
alGenSources((uint32_t)1, &device->source);
|
alGenSources((uint32_t)1, &device->source);
|
||||||
alSourcei(device->source, AL_LOOPING, AL_FALSE);
|
alSourcei(device->source, AL_LOOPING, AL_FALSE);
|
||||||
|
|
||||||
uint16_t zeros[frame_size];
|
uint16_t zeros[frame_size];
|
||||||
memset(zeros, 0, frame_size*2);
|
memset(zeros, 0, frame_size*2);
|
||||||
|
|
||||||
for ( i = 0; i < OPENAL_BUFS; ++i ) {
|
for ( i = 0; i < OPENAL_BUFS; ++i ) {
|
||||||
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate);
|
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
|
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
|
||||||
alSourcePlay(device->source);
|
alSourcePlay(device->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alcGetError(device->dhndl) != AL_NO_ERROR) {
|
if (alcGetError(device->dhndl) != AL_NO_ERROR) {
|
||||||
free(device);
|
free(device);
|
||||||
running[type][*device_idx] = NULL;
|
running[type][*device_idx] = NULL;
|
||||||
unlock;
|
unlock;
|
||||||
return de_FailedStart;
|
return de_FailedStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == input) {
|
if (type == input) {
|
||||||
alcCaptureStart(device->dhndl);
|
alcCaptureStart(device->dhndl);
|
||||||
thread_paused = false;
|
thread_paused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
@ -301,47 +304,47 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
DeviceError close_device(DeviceType type, uint32_t device_idx)
|
DeviceError close_device(DeviceType type, uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
Device* device = running[type][device_idx];
|
Device* device = running[type][device_idx];
|
||||||
DeviceError rc = de_None;
|
DeviceError rc = de_None;
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
unlock;
|
unlock;
|
||||||
return de_DeviceNotActive;
|
return de_DeviceNotActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
running[type][device_idx] = NULL;
|
running[type][device_idx] = NULL;
|
||||||
|
|
||||||
if ( !device->ref_count ) {
|
if ( !device->ref_count ) {
|
||||||
|
|
||||||
// printf("Closed device ");
|
// printf("Closed device ");
|
||||||
|
|
||||||
if (type == input) {
|
if (type == input) {
|
||||||
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
|
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
|
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
|
||||||
|
|
||||||
alDeleteSources(1, &device->source);
|
alDeleteSources(1, &device->source);
|
||||||
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
||||||
|
|
||||||
alcMakeContextCurrent(NULL);
|
alcMakeContextCurrent(NULL);
|
||||||
if ( device->ctx ) alcDestroyContext(device->ctx);
|
if ( device->ctx ) alcDestroyContext(device->ctx);
|
||||||
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
|
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
}
|
}
|
||||||
else device->ref_count--;
|
else device->ref_count--;
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceError register_device_callback( int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD)
|
DeviceError register_device_callback( int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD)
|
||||||
{
|
{
|
||||||
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
||||||
return de_InvalidSelection;
|
return de_InvalidSelection;
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
@ -375,9 +378,9 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_
|
|||||||
alSourceUnqueueBuffers(device->source, processed, bufids);
|
alSourceUnqueueBuffers(device->source, processed, bufids);
|
||||||
alDeleteBuffers(processed - 1, bufids + 1);
|
alDeleteBuffers(processed - 1, bufids + 1);
|
||||||
bufid = bufids[0];
|
bufid = bufids[0];
|
||||||
}
|
}
|
||||||
else if(queued < 16) alGenBuffers(1, &bufid);
|
else if(queued < 16) alGenBuffers(1, &bufid);
|
||||||
else {
|
else {
|
||||||
pthread_mutex_unlock(device->mutex);
|
pthread_mutex_unlock(device->mutex);
|
||||||
return de_Busy;
|
return de_Busy;
|
||||||
}
|
}
|
||||||
@ -404,44 +407,51 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
(void)arg;
|
(void)arg;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int32_t sample = 0;
|
int32_t sample = 0;
|
||||||
|
|
||||||
|
|
||||||
while (thread_running)
|
while (true)
|
||||||
{
|
{
|
||||||
|
lock;
|
||||||
|
if (!thread_running) {
|
||||||
|
unlock;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unlock;
|
||||||
|
|
||||||
if (thread_paused) usleep(10000); /* Wait for unpause. */
|
if (thread_paused) usleep(10000); /* Wait for unpause. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < size[input]; ++i)
|
for (i = 0; i < size[input]; ++i)
|
||||||
{
|
{
|
||||||
lock;
|
lock;
|
||||||
if (running[input][i] != NULL)
|
if (running[input][i] != NULL)
|
||||||
{
|
{
|
||||||
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
|
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
|
||||||
|
|
||||||
int f_size = (running[input][i]->sample_rate * running[input][i]->frame_duration / 1000);
|
int f_size = (running[input][i]->sample_rate * running[input][i]->frame_duration / 1000);
|
||||||
|
|
||||||
if (sample < f_size) {
|
if (sample < f_size) {
|
||||||
unlock;
|
unlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Device* device = running[input][i];
|
Device* device = running[input][i];
|
||||||
|
|
||||||
int16_t frame[16000];
|
int16_t frame[16000];
|
||||||
alcCaptureSamples(device->dhndl, frame, f_size);
|
alcCaptureSamples(device->dhndl, frame, f_size);
|
||||||
|
|
||||||
if (device->muted) {
|
if (device->muted) {
|
||||||
unlock;
|
unlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
|
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
|
||||||
}
|
}
|
||||||
unlock;
|
unlock;
|
||||||
}
|
}
|
||||||
usleep(5000);
|
usleep(5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,8 +472,8 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
|
|||||||
|
|
||||||
void* get_device_callback_data(uint32_t device_idx)
|
void* get_device_callback_data(uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return running[input][device_idx]->cb_data;
|
return running[input][device_idx]->cb_data;
|
||||||
}
|
}
|
||||||
|
18
src/dns.c
18
src/dns.c
@ -234,12 +234,16 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
|||||||
and the domain in dombuf.
|
and the domain in dombuf.
|
||||||
|
|
||||||
return length of username on success, -1 on failure */
|
return length of username on success, -1 on failure */
|
||||||
static int parse_addr(const char *addr, char *namebuf, char *dombuf)
|
static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
|
||||||
{
|
{
|
||||||
char tmpaddr[MAX_STR_SIZE];
|
if (strlen(addr) >= MAX_STR_SIZE)
|
||||||
char *tmpname, *tmpdom;
|
return -1;
|
||||||
|
|
||||||
strcpy(tmpaddr, addr);
|
char tmpaddr[MAX_STR_SIZE];
|
||||||
|
char *tmpname = NULL;
|
||||||
|
char *tmpdom = NULL;
|
||||||
|
|
||||||
|
snprintf(tmpaddr, sizeof(tmpaddr), "%s", addr);
|
||||||
tmpname = strtok(tmpaddr, "@");
|
tmpname = strtok(tmpaddr, "@");
|
||||||
tmpdom = strtok(NULL, "");
|
tmpdom = strtok(NULL, "");
|
||||||
|
|
||||||
@ -247,8 +251,8 @@ static int parse_addr(const char *addr, char *namebuf, char *dombuf)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
str_to_lower(tmpdom);
|
str_to_lower(tmpdom);
|
||||||
strcpy(namebuf, tmpname);
|
snprintf(namebuf, namebuf_sz, "%s", tmpname);
|
||||||
strcpy(dombuf, tmpdom);
|
snprintf(dombuf, dombuf_sz, "%s", tmpdom);
|
||||||
|
|
||||||
return strlen(namebuf);
|
return strlen(namebuf);
|
||||||
}
|
}
|
||||||
@ -295,7 +299,7 @@ void *dns3_lookup_thread(void *data)
|
|||||||
char inputdomain[MAX_STR_SIZE];
|
char inputdomain[MAX_STR_SIZE];
|
||||||
char name[MAX_STR_SIZE];
|
char name[MAX_STR_SIZE];
|
||||||
|
|
||||||
int namelen = parse_addr(t_data.addr, name, inputdomain);
|
int namelen = parse_addr(t_data.addr, name, sizeof(name), inputdomain, sizeof(inputdomain));
|
||||||
|
|
||||||
if (namelen == -1) {
|
if (namelen == -1) {
|
||||||
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
|
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
|
||||||
|
@ -35,11 +35,52 @@
|
|||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||||
|
#define NUM_PROG_MARKS 50
|
||||||
|
|
||||||
|
/* Checks for timed out file transfers and closes them. */
|
||||||
|
#define CHECK_FILE_TIMEOUT_INTERAVAL 5
|
||||||
|
void check_file_transfer_timeouts(Tox *m)
|
||||||
|
{
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
static uint64_t last_check = 0;
|
||||||
|
|
||||||
|
if (!timed_out(last_check, CHECK_FILE_TIMEOUT_INTERAVAL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
last_check = get_unix_time();
|
||||||
|
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < Friends.max_idx; ++i) {
|
||||||
|
if (!Friends.list[i].active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; j < MAX_FILES; ++j) {
|
||||||
|
struct FileTransfer *ft_send = &Friends.list[i].file_sender[j];
|
||||||
|
|
||||||
|
if (ft_send->state > FILE_TRANSFER_PAUSED) {
|
||||||
|
if (timed_out(ft_send->last_keep_alive, TIMEOUT_FILESENDER)) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_send->file_name);
|
||||||
|
close_file_transfer(ft_send->window, m, ft_send, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileTransfer *ft_recv = &Friends.list[i].file_receiver[j];
|
||||||
|
|
||||||
|
if (ft_recv->state > FILE_TRANSFER_PAUSED) {
|
||||||
|
if (timed_out(ft_recv->last_keep_alive, TIMEOUT_FILESENDER)) {
|
||||||
|
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_recv->file_name);
|
||||||
|
close_file_transfer(ft_recv->window, m, ft_recv, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
Assumes progline is of size MAX_STR_SIZE */
|
Assumes progline is of size MAX_STR_SIZE */
|
||||||
void prep_prog_line(char *progline)
|
void init_progress_bar(char *progline)
|
||||||
{
|
{
|
||||||
strcpy(progline, "0.0 B/s [");
|
strcpy(progline, "0.0 B/s [");
|
||||||
int i;
|
int i;
|
||||||
@ -80,13 +121,13 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
|
|||||||
line_info_set(self, line_id, msg);
|
line_info_set(self, line_id, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft, uint64_t curtime)
|
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
|
||||||
{
|
{
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE)
|
if (ft->state == FILE_TRANSFER_INACTIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Timeout must be set to 1 second to show correct bytes per second */
|
/* Timeout must be set to 1 second to show correct bytes per second */
|
||||||
if (!timed_out(ft->last_progress, curtime, 1))
|
if (!timed_out(ft->last_line_progress, 1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double remain = ft->file_size - ft->position;
|
double remain = ft->file_size - ft->position;
|
||||||
@ -94,18 +135,17 @@ static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft, ui
|
|||||||
print_progress_bar(self, ft->bps, pct_done, ft->line_id);
|
print_progress_bar(self, ft->bps, pct_done, ft->line_id);
|
||||||
|
|
||||||
ft->bps = 0;
|
ft->bps = 0;
|
||||||
ft->last_progress = curtime;
|
ft->last_line_progress = get_unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* refreshes active file receiver status bars for friendnum */
|
/* refreshes active file transfer status bars. */
|
||||||
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
|
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
uint64_t curtime = get_unix_time();
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i], curtime);
|
refresh_progress_helper(self, m, &Friends.list[friendnum].file_receiver[i]);
|
||||||
refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i], curtime);
|
refresh_progress_helper(self, m, &Friends.list[friendnum].file_sender[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +197,7 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
|
|||||||
/* Returns a pointer to an unused file sender.
|
/* Returns a pointer to an unused file sender.
|
||||||
* Returns NULL if all file senders are in use.
|
* Returns NULL if all file senders are in use.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_new_file_sender(uint32_t friendnum)
|
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -165,7 +205,15 @@ struct FileTransfer *get_new_file_sender(uint32_t friendnum)
|
|||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
|
memset(ft, 0, sizeof(struct FileTransfer));
|
||||||
|
ft->window = window;
|
||||||
ft->index = i;
|
ft->index = i;
|
||||||
|
ft->friendnum = friendnum;
|
||||||
|
ft->filenum = filenum;
|
||||||
|
ft->file_type = type;
|
||||||
|
ft->last_keep_alive = get_unix_time();
|
||||||
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
|
ft->direction = FILE_TRANSFER_SEND;
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,7 +224,7 @@ struct FileTransfer *get_new_file_sender(uint32_t friendnum)
|
|||||||
/* Returns a pointer to an unused file receiver.
|
/* Returns a pointer to an unused file receiver.
|
||||||
* Returns NULL if all file receivers are in use.
|
* Returns NULL if all file receivers are in use.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_new_file_receiver(uint32_t friendnum)
|
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -184,7 +232,15 @@ struct FileTransfer *get_new_file_receiver(uint32_t friendnum)
|
|||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
|
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
|
memset(ft, 0, sizeof(struct FileTransfer));
|
||||||
|
ft->window = window;
|
||||||
ft->index = i;
|
ft->index = i;
|
||||||
|
ft->friendnum = friendnum;
|
||||||
|
ft->filenum = filenum;
|
||||||
|
ft->file_type = type;
|
||||||
|
ft->last_keep_alive = get_unix_time();
|
||||||
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
|
ft->direction = FILE_TRANSFER_RECV;
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,6 +248,22 @@ struct FileTransfer *get_new_file_receiver(uint32_t friendnum)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initializes an unused file transfer and returns its pointer.
|
||||||
|
* Returns NULL on failure.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
||||||
|
FILE_TRANSFER_DIRECTION direction, uint8_t type)
|
||||||
|
{
|
||||||
|
if (direction == FILE_TRANSFER_RECV)
|
||||||
|
return new_file_receiver(window, friendnum, filenum, type);
|
||||||
|
|
||||||
|
if (direction == FILE_TRANSFER_SEND)
|
||||||
|
return new_file_sender(window, friendnum, filenum, type);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Closes file transfer ft.
|
/* Closes file transfer ft.
|
||||||
*
|
*
|
||||||
* Set CTRL to -1 if we don't want to send a control signal.
|
* Set CTRL to -1 if we don't want to send a control signal.
|
||||||
@ -209,19 +281,19 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
|
|||||||
if (ft->file)
|
if (ft->file)
|
||||||
fclose(ft->file);
|
fclose(ft->file);
|
||||||
|
|
||||||
memset(ft, 0, sizeof(struct FileTransfer));
|
|
||||||
|
|
||||||
if (CTRL >= 0)
|
if (CTRL >= 0)
|
||||||
tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
|
tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
|
||||||
|
|
||||||
if (message && self) {
|
if (message && self) {
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1 && sound_type != silent)
|
||||||
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
|
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
|
||||||
else
|
else
|
||||||
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
|
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(ft, 0, sizeof(struct FileTransfer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kills all active file transfers for friendnum */
|
/* Kills all active file transfers for friendnum */
|
||||||
|
@ -30,17 +30,17 @@
|
|||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
#define KiB 1024
|
#define KiB 1024
|
||||||
#define MiB 1048576 /* 1024 ^ 2 */
|
#define MiB 1048576 /* 1024^2 */
|
||||||
#define GiB 1073741824 /* 1024 ^ 3 */
|
#define GiB 1073741824 /* 1024^3 */
|
||||||
|
|
||||||
#define MAX_FILES 32
|
#define MAX_FILES 32
|
||||||
#define TIMEOUT_FILESENDER 120
|
#define TIMEOUT_FILESENDER 120
|
||||||
|
|
||||||
typedef enum FILE_TRANSFER_STATE {
|
typedef enum FILE_TRANSFER_STATE {
|
||||||
FILE_TRANSFER_INACTIVE,
|
FILE_TRANSFER_INACTIVE,
|
||||||
|
FILE_TRANSFER_PAUSED,
|
||||||
FILE_TRANSFER_PENDING,
|
FILE_TRANSFER_PENDING,
|
||||||
FILE_TRANSFER_STARTED,
|
FILE_TRANSFER_STARTED,
|
||||||
FILE_TRANSFER_PAUSED
|
|
||||||
} FILE_TRANSFER_STATE;
|
} FILE_TRANSFER_STATE;
|
||||||
|
|
||||||
typedef enum FILE_TRANSFER_DIRECTION {
|
typedef enum FILE_TRANSFER_DIRECTION {
|
||||||
@ -49,30 +49,36 @@ typedef enum FILE_TRANSFER_DIRECTION {
|
|||||||
} FILE_TRANSFER_DIRECTION;
|
} FILE_TRANSFER_DIRECTION;
|
||||||
|
|
||||||
struct FileTransfer {
|
struct FileTransfer {
|
||||||
|
ToxWindow *window;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
FILE_TRANSFER_STATE state;
|
FILE_TRANSFER_STATE state;
|
||||||
FILE_TRANSFER_DIRECTION direction;
|
FILE_TRANSFER_DIRECTION direction;
|
||||||
uint8_t file_type;
|
uint8_t file_type;
|
||||||
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
||||||
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
||||||
double bps;
|
double bps;
|
||||||
uint32_t filenum;
|
uint32_t filenum;
|
||||||
uint32_t friendnum;
|
uint32_t friendnum;
|
||||||
size_t index;
|
size_t index;
|
||||||
uint64_t file_size;
|
uint64_t file_size;
|
||||||
uint64_t position;
|
uint64_t position;
|
||||||
uint64_t last_progress;
|
uint64_t last_line_progress; /* The last time we updated the progress bar */
|
||||||
|
uint64_t last_keep_alive; /* The last time we sent or received data */
|
||||||
uint32_t line_id;
|
uint32_t line_id;
|
||||||
|
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Checks for timed out file transfers and closes them. */
|
||||||
|
void check_file_transfer_timeouts(Tox *m);
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
progline must be at lesat MAX_STR_SIZE bytes */
|
progline must be at lesat MAX_STR_SIZE bytes */
|
||||||
void prep_prog_line(char *progline);
|
void init_progress_bar(char *progline);
|
||||||
|
|
||||||
/* prints a progress bar for file transfers */
|
/* prints a progress bar for file transfers */
|
||||||
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
||||||
|
|
||||||
/* refreshes active file transfer status bars for friendnum */
|
/* refreshes active file transfer status bars. */
|
||||||
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
||||||
|
|
||||||
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
||||||
@ -87,15 +93,11 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
|
|||||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||||
FILE_TRANSFER_DIRECTION direction);
|
FILE_TRANSFER_DIRECTION direction);
|
||||||
|
|
||||||
/* Returns a pointer to an unused file sender.
|
/* Initializes an unused file transfer and returns its pointer.
|
||||||
* Returns NULL if all file senders are in use.
|
* Returns NULL on failure.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_new_file_sender(uint32_t friendnum);
|
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
||||||
|
FILE_TRANSFER_DIRECTION direction, uint8_t type);
|
||||||
/* Returns a pointer to an unused file receiver.
|
|
||||||
* Returns NULL if all file receivers are in use.
|
|
||||||
*/
|
|
||||||
struct FileTransfer *get_new_file_receiver(uint32_t friendnum);
|
|
||||||
|
|
||||||
/* Closes file transfer ft.
|
/* Closes file transfer ft.
|
||||||
*
|
*
|
||||||
|
@ -139,8 +139,10 @@ static int save_blocklist(char *path)
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||||
if (count > Blocked.num_blocked)
|
if (count > Blocked.num_blocked) {
|
||||||
goto on_error;
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (Blocked.list[i].active) {
|
if (Blocked.list[i].active) {
|
||||||
BlockedFriend tmp;
|
BlockedFriend tmp;
|
||||||
@ -161,19 +163,20 @@ static int save_blocklist(char *path)
|
|||||||
|
|
||||||
FILE *fp = fopen(path, "wb");
|
FILE *fp = fopen(path, "wb");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
goto on_error;
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (fwrite(data, len, 1, fp) != 1)
|
if (fwrite(data, len, 1, fp) != 1) {
|
||||||
goto on_error;
|
fclose(fp);
|
||||||
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
on_error:
|
|
||||||
free(data);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sort_blocklist_index(void);
|
static void sort_blocklist_index(void);
|
||||||
@ -221,9 +224,10 @@ int load_blocklist(char *path)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < num; ++i) {
|
for (i = 0; i < num; ++i) {
|
||||||
|
BlockedFriend tmp;
|
||||||
|
memset(&tmp, 0, sizeof(BlockedFriend));
|
||||||
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
|
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
|
||||||
|
|
||||||
BlockedFriend tmp;
|
|
||||||
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
|
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
|
||||||
Blocked.list[i].active = true;
|
Blocked.list[i].active = true;
|
||||||
Blocked.list[i].num = i;
|
Blocked.list[i].num = i;
|
||||||
@ -616,10 +620,12 @@ static void draw_del_popup(void)
|
|||||||
wprintw(PendingDelete.popup, "Delete contact ");
|
wprintw(PendingDelete.popup, "Delete contact ");
|
||||||
wattron(PendingDelete.popup, A_BOLD);
|
wattron(PendingDelete.popup, A_BOLD);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
if (blocklist_view == 0)
|
if (blocklist_view == 0)
|
||||||
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
||||||
else
|
else
|
||||||
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
wattroff(PendingDelete.popup, A_BOLD);
|
wattroff(PendingDelete.popup, A_BOLD);
|
||||||
wprintw(PendingDelete.popup, "? y/n");
|
wprintw(PendingDelete.popup, "? y/n");
|
||||||
@ -880,12 +886,13 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t cur_time = get_unix_time();
|
uint64_t cur_time = time(NULL);
|
||||||
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
wprintw(self->window, " Online: ");
|
wprintw(self->window, " Online: ");
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
|
|
||||||
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
|
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
|
||||||
|
|
||||||
if ((y2 - FLIST_OFST) <= 0)
|
if ((y2 - FLIST_OFST) <= 0)
|
||||||
@ -894,18 +901,30 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
uint32_t selected_num = 0;
|
uint32_t selected_num = 0;
|
||||||
|
|
||||||
/* Determine which portion of friendlist to draw based on current position */
|
/* Determine which portion of friendlist to draw based on current position */
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int page = Friends.num_selected / (y2 - FLIST_OFST);
|
int page = Friends.num_selected / (y2 - FLIST_OFST);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
int start = (y2 - FLIST_OFST) * page;
|
int start = (y2 - FLIST_OFST) * page;
|
||||||
int end = y2 - FLIST_OFST + start;
|
int end = y2 - FLIST_OFST + start;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
size_t num_friends = Friends.num_friends;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = start; i < Friends.num_friends && i < end; ++i) {
|
for (i = start; i < num_friends && i < end; ++i) {
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
uint32_t f = Friends.index[i];
|
uint32_t f = Friends.index[i];
|
||||||
|
bool is_active = Friends.list[f].active;
|
||||||
|
int num_selected = Friends.num_selected;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
bool f_selected = false;
|
bool f_selected = false;
|
||||||
|
|
||||||
if (Friends.list[f].active) {
|
if (is_active) {
|
||||||
if (i == Friends.num_selected) {
|
if (i == num_selected) {
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
wprintw(self->window, " > ");
|
wprintw(self->window, " > ");
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
@ -915,8 +934,12 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wprintw(self->window, " ");
|
wprintw(self->window, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Friends.list[f].connection_status != TOX_CONNECTION_NONE) {
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
TOX_USER_STATUS status = Friends.list[f].status;
|
TOX_CONNECTION connection_status = Friends.list[f].connection_status;
|
||||||
|
TOX_USER_STATUS status = Friends.list[f].status;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
if (connection_status != TOX_CONNECTION_NONE) {
|
||||||
int colour = MAGENTA;
|
int colour = MAGENTA;
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -939,7 +962,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wattron(self->window, COLOR_PAIR(BLUE));
|
wattron(self->window, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
wprintw(self->window, "%s", Friends.list[f].name);
|
wprintw(self->window, "%s", Friends.list[f].name);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected)
|
||||||
@ -952,17 +977,23 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, NULL);
|
tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, NULL);
|
||||||
size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL);
|
size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL);
|
||||||
statusmsg[s_len] = '\0';
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
statusmsg[s_len] = '\0';
|
||||||
|
|
||||||
filter_str(statusmsg, s_len);
|
filter_str(statusmsg, s_len);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
snprintf(Friends.list[f].statusmsg, sizeof(Friends.list[f].statusmsg), "%s", statusmsg);
|
snprintf(Friends.list[f].statusmsg, sizeof(Friends.list[f].statusmsg), "%s", statusmsg);
|
||||||
Friends.list[f].statusmsg_len = strlen(Friends.list[f].statusmsg);
|
Friends.list[f].statusmsg_len = strlen(Friends.list[f].statusmsg);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Truncate note if it doesn't fit on one line */
|
/* Truncate note if it doesn't fit on one line */
|
||||||
size_t maxlen = x2 - getcurx(self->window) - 2;
|
size_t maxlen = x2 - getcurx(self->window) - 2;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (Friends.list[f].statusmsg_len > maxlen) {
|
if (Friends.list[f].statusmsg_len > maxlen) {
|
||||||
Friends.list[f].statusmsg[maxlen - 3] = '\0';
|
Friends.list[f].statusmsg[maxlen - 3] = '\0';
|
||||||
strcat(Friends.list[f].statusmsg, "...");
|
strcat(Friends.list[f].statusmsg, "...");
|
||||||
@ -973,6 +1004,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
if (Friends.list[f].statusmsg_len > 0)
|
if (Friends.list[f].statusmsg_len > 0)
|
||||||
wprintw(self->window, " %s", Friends.list[f].statusmsg);
|
wprintw(self->window, " %s", Friends.list[f].statusmsg);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
wprintw(self->window, "\n");
|
wprintw(self->window, "\n");
|
||||||
} else {
|
} else {
|
||||||
wprintw(self->window, "%s ", OFFLINE_CHAR);
|
wprintw(self->window, "%s ", OFFLINE_CHAR);
|
||||||
@ -981,21 +1014,29 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wattron(self->window, COLOR_PAIR(BLUE));
|
wattron(self->window, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
wprintw(self->window, "%s", Friends.list[f].name);
|
wprintw(self->window, "%s", Friends.list[f].name);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected)
|
||||||
wattroff(self->window, COLOR_PAIR(BLUE));
|
wattroff(self->window, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
uint64_t last_seen = Friends.list[f].last_online.last_on;
|
uint64_t last_seen = Friends.list[f].last_online.last_on;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
if (last_seen != 0) {
|
if (last_seen != 0) {
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
int day_dist = (
|
int day_dist = (
|
||||||
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
||||||
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
||||||
);
|
);
|
||||||
const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
switch (day_dist) {
|
switch (day_dist) {
|
||||||
case 0:
|
case 0:
|
||||||
wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
||||||
@ -1018,7 +1059,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
self->x = x2;
|
self->x = x2;
|
||||||
|
|
||||||
if (Friends.num_friends) {
|
if (num_friends) {
|
||||||
wmove(self->window, y2 - 1, 1);
|
wmove(self->window, y2 - 1, 1);
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
|
@ -249,19 +249,22 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
|
|
||||||
const char *ip = argv[1];
|
const char *ip = argv[1];
|
||||||
const char *port = argv[2];
|
const char *port = argv[2];
|
||||||
const char *key = argv[3];
|
const char *ascii_key = argv[3];
|
||||||
|
|
||||||
if (atoi(port) == 0) {
|
if (atoi(port) == 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *binary_string = hex_string_to_bin(key);
|
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||||
|
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TOX_ERR_BOOTSTRAP err;
|
TOX_ERR_BOOTSTRAP err;
|
||||||
tox_bootstrap(m, ip, atoi(port), (uint8_t *) binary_string, &err);
|
tox_bootstrap(m, ip, atoi(port), (uint8_t *) key_binary, &err);
|
||||||
tox_add_tcp_relay(m, ip, atoi(port), (uint8_t *) binary_string, &err);
|
tox_add_tcp_relay(m, ip, atoi(port), (uint8_t *) key_binary, &err);
|
||||||
free(binary_string);
|
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TOX_ERR_BOOTSTRAP_BAD_HOST:
|
case TOX_ERR_BOOTSTRAP_BAD_HOST:
|
||||||
@ -457,16 +460,18 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
char myid[TOX_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
|
int log_ret = -1;
|
||||||
|
|
||||||
if (self->is_chat) {
|
if (self->is_chat) {
|
||||||
Friends.list[self->num].logging_on = true;
|
Friends.list[self->num].logging_on = true;
|
||||||
log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
|
log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
|
||||||
} else if (self->is_prompt) {
|
} else if (self->is_prompt) {
|
||||||
log_enable(self->name, myid, NULL, log, LOG_PROMPT);
|
log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT);
|
||||||
} else if (self->is_groupchat) {
|
} else if (self->is_groupchat) {
|
||||||
log_enable(self->name, myid, NULL, log, LOG_GROUP);
|
log_ret = log_enable(self->name, myid, NULL, log, LOG_GROUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = "Logging enabled";
|
msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
return;
|
return;
|
||||||
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
|
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
|
||||||
@ -475,7 +480,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
|
|
||||||
log_disable(log);
|
log_disable(log);
|
||||||
|
|
||||||
msg = "Logging disabled";
|
msg = "Logging disabled.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -914,7 +914,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
if (diff != -1) {
|
if (diff != -1) {
|
||||||
if (x + diff > x2 - 1) {
|
if (x + diff > x2 - 1) {
|
||||||
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
|
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
|
||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1056,7 +1056,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int y, x;
|
int y, x;
|
||||||
getyx(self->window, y, x);
|
getyx(self->window, y, x);
|
||||||
(void) x;
|
(void) x;
|
||||||
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
|
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
||||||
wmove(self->window, y + 1, new_x);
|
wmove(self->window, y + 1, new_x);
|
||||||
|
|
||||||
wrefresh(self->window);
|
wrefresh(self->window);
|
||||||
@ -1087,7 +1087,9 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP);
|
|
||||||
|
if (log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP) == -1)
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||||
|
@ -125,7 +125,7 @@ static void input_yank(ToxWindow *self, int x, int mx_x)
|
|||||||
|
|
||||||
if (x + yank_cols >= mx_x) {
|
if (x + yank_cols >= mx_x) {
|
||||||
int rmdr = MAX(0, (x + yank_cols) - mx_x);
|
int rmdr = MAX(0, (x + yank_cols) - mx_x);
|
||||||
int s_len = wcswidth(&ctx->line[ctx->start], rmdr);
|
int s_len = MAX(0, wcswidth(&ctx->line[ctx->start], rmdr));
|
||||||
ctx->start += s_len + 1;
|
ctx->start += s_len + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,7 +137,7 @@ static void input_mv_end(ToxWindow *self, int y, int mx_x)
|
|||||||
|
|
||||||
ctx->pos = ctx->len;
|
ctx->pos = ctx->len;
|
||||||
|
|
||||||
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
|
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
|
||||||
ctx->start = MAX(0, 1 + (mx_x * (wlen / mx_x) - mx_x) + (wlen % mx_x));
|
ctx->start = MAX(0, 1 + (mx_x * (wlen / mx_x) - mx_x) + (wlen % mx_x));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ static void input_history(ToxWindow *self, wint_t key, int mx_x)
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
fetch_hist_item(ctx, key);
|
fetch_hist_item(ctx, key);
|
||||||
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
|
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
|
||||||
ctx->start = wlen < mx_x ? 0 : wlen - mx_x + 1;
|
ctx->start = wlen < mx_x ? 0 : wlen - mx_x + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,9 @@ static struct line_info *line_info_ret_queue(struct history *hst)
|
|||||||
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
||||||
uint8_t bold, uint8_t colour, const char *msg, ...)
|
uint8_t bold, uint8_t colour, const char *msg, ...)
|
||||||
{
|
{
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
|
||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
|
|
||||||
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
|
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
|
||||||
@ -332,13 +335,17 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
if (line->msg[0] == '>')
|
if (line->msg[0] == '>')
|
||||||
wattron(win, COLOR_PAIR(GREEN));
|
wattron(win, COLOR_PAIR(GREEN));
|
||||||
|
else if (line->msg[0] == '<')
|
||||||
|
wattron(win, COLOR_PAIR(RED));
|
||||||
|
|
||||||
wprintw(win, "%s", line->msg);
|
wprintw(win, "%s", line->msg);
|
||||||
|
|
||||||
if (line->msg[0] == '>')
|
if (line->msg[0] == '>')
|
||||||
wattroff(win, COLOR_PAIR(GREEN));
|
wattroff(win, COLOR_PAIR(GREEN));
|
||||||
|
else if (line->msg[0] == '<')
|
||||||
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
|
||||||
if (type == OUT_MSG && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
|
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
wprintw(win, " x", line->msg);
|
wprintw(win, " x", line->msg);
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
@ -365,7 +372,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
|
wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
|
||||||
wattroff(win, COLOR_PAIR(YELLOW));
|
wattroff(win, COLOR_PAIR(YELLOW));
|
||||||
|
|
||||||
if (type == OUT_ACTION && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
|
if (type == OUT_ACTION && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
wprintw(win, " x", line->msg);
|
wprintw(win, " x", line->msg);
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
20
src/log.c
20
src/log.c
@ -139,11 +139,9 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
|
|||||||
strftime(s, MAX_STR_SIZE, t, get_time());
|
strftime(s, MAX_STR_SIZE, t, get_time());
|
||||||
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);
|
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);
|
||||||
|
|
||||||
uint64_t curtime = get_unix_time();
|
if (timed_out(log->lastwrite, LOG_FLUSH_LIMIT)) {
|
||||||
|
|
||||||
if (timed_out(log->lastwrite, curtime, LOG_FLUSH_LIMIT)) {
|
|
||||||
fflush(log->file);
|
fflush(log->file);
|
||||||
log->lastwrite = curtime;
|
log->lastwrite = get_unix_time();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,15 +153,19 @@ void log_disable(struct chatlog *log)
|
|||||||
memset(log, 0, sizeof(struct chatlog));
|
memset(log, 0, sizeof(struct chatlog));
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
||||||
{
|
{
|
||||||
log->log_on = true;
|
log->log_on = true;
|
||||||
|
|
||||||
if (log->file != NULL)
|
if (log->file != NULL)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1)
|
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
|
||||||
log_disable(log);
|
log_disable(log);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loads previous history from chat log */
|
/* Loads previous history from chat log */
|
||||||
@ -177,7 +179,7 @@ void load_chat_history(ToxWindow *self, struct chatlog *log)
|
|||||||
if (sz <= 0)
|
if (sz <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char *hstbuf = malloc(sz);
|
char *hstbuf = malloc(sz + 1);
|
||||||
|
|
||||||
if (hstbuf == NULL)
|
if (hstbuf == NULL)
|
||||||
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
|
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
|
||||||
@ -194,6 +196,8 @@ void load_chat_history(ToxWindow *self, struct chatlog *log)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hstbuf[sz] = '\0';
|
||||||
|
|
||||||
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
|
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
|
||||||
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
|
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
|
||||||
int start, count = 0;
|
int start, count = 0;
|
||||||
|
@ -39,8 +39,12 @@ enum {
|
|||||||
/* formats/writes line to log file */
|
/* formats/writes line to log file */
|
||||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
|
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
|
||||||
|
|
||||||
/* enables logging for specified log and creates/fetches file if necessary */
|
/* enables logging for specified log and creates/fetches file if necessary.
|
||||||
void log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
|
||||||
|
|
||||||
/* disables logging for specified log and closes file */
|
/* disables logging for specified log and closes file */
|
||||||
void log_disable(struct chatlog *log);
|
void log_disable(struct chatlog *log);
|
||||||
|
@ -140,9 +140,7 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
|
|||||||
if (!msg)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint64_t curtime = get_unix_time();
|
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL))
|
||||||
|
|
||||||
if (msg->receipt != 0 && !timed_out(msg->last_send_try, curtime, CQUEUE_TRY_SEND_INTERVAL))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t receipt = 0;
|
uint32_t receipt = 0;
|
||||||
@ -150,7 +148,7 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
|
|||||||
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
||||||
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
||||||
|
|
||||||
msg->last_send_try = curtime;
|
msg->last_send_try = get_unix_time();
|
||||||
msg->receipt = receipt;
|
msg->receipt = receipt;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ void hst_to_net(uint8_t *num, uint16_t numbytes)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note: The time functions are not thread safe */
|
||||||
void update_unix_time(void)
|
void update_unix_time(void)
|
||||||
{
|
{
|
||||||
current_unix_time = (uint64_t) time(NULL);
|
current_unix_time = (uint64_t) time(NULL);
|
||||||
@ -65,9 +66,9 @@ uint64_t get_unix_time(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 1 if connection has timed out, 0 otherwise */
|
/* Returns 1 if connection has timed out, 0 otherwise */
|
||||||
int timed_out(uint64_t timestamp, uint64_t curtime, uint64_t timeout)
|
int timed_out(uint64_t timestamp, uint64_t timeout)
|
||||||
{
|
{
|
||||||
return timestamp + timeout <= curtime;
|
return timestamp + timeout <= get_unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the current local time */
|
/* Get the current local time */
|
||||||
@ -109,20 +110,24 @@ void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs)
|
|||||||
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
|
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *hex_string_to_bin(const char *hex_string)
|
/*
|
||||||
|
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
|
||||||
|
* output_size must be exactly half of hex_len.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size)
|
||||||
{
|
{
|
||||||
size_t len = strlen(hex_string);
|
if (output_size == 0 || hex_len != output_size * 2)
|
||||||
char *val = malloc(len);
|
return -1;
|
||||||
|
|
||||||
if (val == NULL)
|
for (size_t i = 0; i < output_size; ++i) {
|
||||||
exit_toxic_err("failed in hex_string_to_bin", FATALERR_MEMORY);
|
sscanf(hex_string, "%2hhx", &output[i]);
|
||||||
|
hex_string += 2;
|
||||||
|
}
|
||||||
|
|
||||||
size_t i;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < len; ++i, hex_string += 2)
|
|
||||||
sscanf(hex_string, "%2hhx", &val[i]);
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
||||||
@ -147,6 +152,9 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
|||||||
/* Returns 1 if the string is empty, 0 otherwise */
|
/* Returns 1 if the string is empty, 0 otherwise */
|
||||||
int string_is_empty(const char *string)
|
int string_is_empty(const char *string)
|
||||||
{
|
{
|
||||||
|
if (!string)
|
||||||
|
return true;
|
||||||
|
|
||||||
return string[0] == '\0';
|
return string[0] == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +225,7 @@ void filter_str(char *str, size_t len)
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v')
|
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0')
|
||||||
str[i] = ' ';
|
str[i] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,22 +41,28 @@
|
|||||||
|
|
||||||
void hst_to_net(uint8_t *num, uint16_t numbytes);
|
void hst_to_net(uint8_t *num, uint16_t numbytes);
|
||||||
|
|
||||||
/* convert a hex string to binary */
|
/*
|
||||||
char *hex_string_to_bin(const char *hex_string);
|
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
|
||||||
|
* output_size must be exactly half of hex_len.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size);
|
||||||
|
|
||||||
/* convert a hex string to bytes. returns 0 on success, -1 on failure */
|
/* convert a hex string to bytes. returns 0 on success, -1 on failure */
|
||||||
int hex_string_to_bytes(char *buf, int size, const char *keystr);
|
int hex_string_to_bytes(char *buf, int size, const char *keystr);
|
||||||
|
|
||||||
/* get the current unix time */
|
/* get the current unix time (not thread safe) */
|
||||||
uint64_t get_unix_time(void);
|
uint64_t get_unix_time(void);
|
||||||
|
|
||||||
/* Puts the current time in buf in the format of [HH:mm:ss] */
|
/* Puts the current time in buf in the format of [HH:mm:ss] (not thread safe) */
|
||||||
void get_time_str(char *buf, int bufsize);
|
void get_time_str(char *buf, int bufsize);
|
||||||
|
|
||||||
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
|
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
|
||||||
void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs);
|
void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs);
|
||||||
|
|
||||||
/* get the current local time */
|
/* get the current local time (not thread safe) */
|
||||||
struct tm *get_time(void);
|
struct tm *get_time(void);
|
||||||
|
|
||||||
/* updates current unix time (should be run once per do_toxic loop) */
|
/* updates current unix time (should be run once per do_toxic loop) */
|
||||||
@ -75,7 +81,7 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n);
|
|||||||
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
||||||
|
|
||||||
/* Returns 1 if connection has timed out, 0 otherwise */
|
/* Returns 1 if connection has timed out, 0 otherwise */
|
||||||
int timed_out(uint64_t timestamp, uint64_t timeout, uint64_t curtime);
|
int timed_out(uint64_t timestamp, uint64_t timeout);
|
||||||
|
|
||||||
/* Colours the window tab according to type. Beeps if is_beep is true */
|
/* Colours the window tab according to type. Beeps if is_beep is true */
|
||||||
void alert_window(ToxWindow *self, int type, bool is_beep);
|
void alert_window(ToxWindow *self, int type, bool is_beep);
|
||||||
|
85
src/notify.c
85
src/notify.c
@ -90,7 +90,7 @@ struct _ActiveNotifications {
|
|||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
NotifyNotification* box;
|
NotifyNotification* box;
|
||||||
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
|
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
|
||||||
char title[24];
|
char title[64];
|
||||||
size_t size;
|
size_t size;
|
||||||
time_t n_timeout;
|
time_t n_timeout;
|
||||||
#endif
|
#endif
|
||||||
@ -117,9 +117,12 @@ static void tab_notify(ToxWindow *self, uint64_t flags)
|
|||||||
|
|
||||||
static bool notifications_are_disabled(uint64_t flags)
|
static bool notifications_are_disabled(uint64_t flags)
|
||||||
{
|
{
|
||||||
bool res = flags & NT_RESTOL && Control.cooldown > get_unix_time();
|
if (user_settings->alerts != ALERTS_ENABLED)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool res = (flags & NT_RESTOL) && (Control.cooldown > get_unix_time());
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
return res || (flags & NT_NOFOCUS && is_focused());
|
return res || ((flags & NT_NOFOCUS) && is_focused());
|
||||||
#else
|
#else
|
||||||
return res;
|
return res;
|
||||||
#endif
|
#endif
|
||||||
@ -153,33 +156,36 @@ bool is_playing(int source)
|
|||||||
static bool device_opened = false;
|
static bool device_opened = false;
|
||||||
time_t last_opened_update = 0;
|
time_t last_opened_update = 0;
|
||||||
|
|
||||||
bool m_open_device()
|
/* Opens primary device. Returns true on succe*/
|
||||||
|
void m_open_device()
|
||||||
{
|
{
|
||||||
last_opened_update = get_unix_time();
|
last_opened_update = get_unix_time();
|
||||||
|
|
||||||
if (device_opened) return true;
|
if (device_opened) return;
|
||||||
|
|
||||||
/* Blah error check */
|
/* Blah error check */
|
||||||
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
||||||
|
|
||||||
return (device_opened = true);
|
device_opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool m_close_device()
|
void m_close_device()
|
||||||
{
|
{
|
||||||
if (!device_opened) return true;
|
if (!device_opened) return;
|
||||||
|
|
||||||
close_device(output, Control.device_idx);
|
close_device(output, Control.device_idx);
|
||||||
|
|
||||||
return !(device_opened = false);
|
device_opened = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terminate all sounds but wait for them to finish first */
|
/* Terminate all sounds but wait for them to finish first */
|
||||||
void graceful_clear()
|
void graceful_clear()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].active) {
|
if (actives[i].active) {
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
@ -211,18 +217,24 @@ void graceful_clear()
|
|||||||
|
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
control_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* do_playing(void* _p)
|
void* do_playing(void* _p)
|
||||||
{
|
{
|
||||||
(void)_p;
|
(void)_p;
|
||||||
int i;
|
|
||||||
|
|
||||||
bool has_looping = false;
|
while(true) {
|
||||||
|
|
||||||
while(Control.poll_active) {
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
|
if (!Control.poll_active) {
|
||||||
|
control_unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_looping = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
|
|
||||||
@ -245,7 +257,7 @@ void* do_playing(void* _p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
else if (actives[i].box && get_unix_time() >= actives[i].n_timeout)
|
else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
||||||
{
|
{
|
||||||
GError* ignore;
|
GError* ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
@ -266,7 +278,7 @@ void* do_playing(void* _p)
|
|||||||
|
|
||||||
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
||||||
if (device_opened && !has_looping &&
|
if (device_opened && !has_looping &&
|
||||||
(get_unix_time() - last_opened_update) > DEVICE_COOLDOWN) {
|
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
|
||||||
m_close_device();
|
m_close_device();
|
||||||
}
|
}
|
||||||
has_looping = false;
|
has_looping = false;
|
||||||
@ -299,11 +311,19 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
|
|||||||
void* do_playing(void* _p)
|
void* do_playing(void* _p)
|
||||||
{
|
{
|
||||||
(void)_p;
|
(void)_p;
|
||||||
int i;
|
|
||||||
while(Control.poll_active) {
|
while(true) {
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
|
if (!Control.poll_active) {
|
||||||
|
control_unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].box && get_unix_time() >= actives[i].n_timeout)
|
if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
||||||
{
|
{
|
||||||
GError* ignore;
|
GError* ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
@ -361,16 +381,17 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
Control.poll_active = 1;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
|
||||||
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
|
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
|
||||||
pthread_mutex_destroy(Control.poll_mutex);
|
pthread_mutex_destroy(Control.poll_mutex);
|
||||||
|
Control.poll_active = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Control.poll_active = 1;
|
|
||||||
#endif
|
#endif
|
||||||
Control.cooldown = get_unix_time() + login_cooldown;
|
Control.cooldown = time(NULL) + login_cooldown;
|
||||||
|
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
@ -383,8 +404,15 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
void terminate_notify()
|
void terminate_notify()
|
||||||
{
|
{
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
if ( !Control.poll_active ) return;
|
control_lock();
|
||||||
|
|
||||||
|
if ( !Control.poll_active ) {
|
||||||
|
control_unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Control.poll_active = 0;
|
Control.poll_active = 0;
|
||||||
|
control_unlock();
|
||||||
|
|
||||||
graceful_clear();
|
graceful_clear();
|
||||||
#endif
|
#endif
|
||||||
@ -503,7 +531,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
|||||||
int id = -1;
|
int id = -1;
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED)
|
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY))
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
else if (flags & NT_ALWAYS)
|
else if (flags & NT_ALWAYS)
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
@ -598,9 +626,12 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
if (id_indicator) *id_indicator = id;
|
if (id_indicator) *id_indicator = id;
|
||||||
}
|
}
|
||||||
#endif
|
#else
|
||||||
|
if (id == -1)
|
||||||
|
return -1;
|
||||||
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
strncpy(actives[id].title, title, 24);
|
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
||||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__; va_start (__ARGS__, format);
|
||||||
@ -623,7 +654,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
return sound_notify(self, notif, flags, id_indicator);
|
return sound_notify(self, notif, flags, id_indicator);
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
|
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
|
||||||
@ -699,7 +730,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
*id_indicator = id;
|
*id_indicator = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(actives[id].title, title, 24);
|
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
||||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__; va_start (__ARGS__, format);
|
||||||
|
32
src/prompt.c
32
src/prompt.c
@ -213,7 +213,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
if (diff != -1) {
|
if (diff != -1) {
|
||||||
if (x + diff > x2 - 1) {
|
if (x + diff > x2 - 1) {
|
||||||
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
|
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
|
||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -261,14 +261,23 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
||||||
|
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
|
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
|
||||||
wmove(statusbar->topline, 0, 0);
|
wmove(statusbar->topline, 0, 0);
|
||||||
|
|
||||||
if (statusbar->connection != TOX_CONNECTION_NONE) {
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
TOX_CONNECTION connection = statusbar->connection;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
if (connection != TOX_CONNECTION_NONE) {
|
||||||
int colour = MAGENTA;
|
int colour = MAGENTA;
|
||||||
const char *status_text = "ERROR";
|
const char *status_text = "ERROR";
|
||||||
|
|
||||||
switch (statusbar->status) {
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
TOX_USER_STATUS status = statusbar->status;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
case TOX_USER_STATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
status_text = "Online";
|
status_text = "Online";
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
@ -288,12 +297,16 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||||
|
|
||||||
wattron(statusbar->topline, A_BOLD);
|
wattron(statusbar->topline, A_BOLD);
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
wprintw(statusbar->topline, " %s", statusbar->nick);
|
wprintw(statusbar->topline, " %s", statusbar->nick);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
wattroff(statusbar->topline, A_BOLD);
|
wattroff(statusbar->topline, A_BOLD);
|
||||||
} else {
|
} else {
|
||||||
wprintw(statusbar->topline, " [Offline]");
|
wprintw(statusbar->topline, " [Offline]");
|
||||||
wattron(statusbar->topline, A_BOLD);
|
wattron(statusbar->topline, A_BOLD);
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
wprintw(statusbar->topline, " %s", statusbar->nick);
|
wprintw(statusbar->topline, " %s", statusbar->nick);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
wattroff(statusbar->topline, A_BOLD);
|
wattroff(statusbar->topline, A_BOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,10 +318,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
size_t slen = tox_self_get_status_message_size(m);
|
size_t slen = tox_self_get_status_message_size(m);
|
||||||
tox_self_get_status_message (m, (uint8_t*) statusmsg);
|
tox_self_get_status_message (m, (uint8_t*) statusmsg);
|
||||||
statusmsg[slen] = '\0';
|
statusmsg[slen] = '\0';
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->x = x2;
|
self->x = x2;
|
||||||
@ -316,6 +328,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
/* Truncate note if it doesn't fit in statusbar */
|
/* Truncate note if it doesn't fit in statusbar */
|
||||||
uint16_t maxlen = x2 - getcurx(statusbar->topline) - 3;
|
uint16_t maxlen = x2 - getcurx(statusbar->topline) - 3;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (statusbar->statusmsg_len > maxlen) {
|
if (statusbar->statusmsg_len > maxlen) {
|
||||||
statusbar->statusmsg[maxlen - 3] = '\0';
|
statusbar->statusmsg[maxlen - 3] = '\0';
|
||||||
strcat(statusbar->statusmsg, "...");
|
strcat(statusbar->statusmsg, "...");
|
||||||
@ -325,13 +339,15 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
if (statusbar->statusmsg[0])
|
if (statusbar->statusmsg[0])
|
||||||
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
|
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
|
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
|
||||||
|
|
||||||
int y, x;
|
int y, x;
|
||||||
getyx(self->window, y, x);
|
getyx(self->window, y, x);
|
||||||
(void) x;
|
(void) x;
|
||||||
|
|
||||||
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
|
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
||||||
wmove(self->window, y + 1, new_x);
|
wmove(self->window, y + 1, new_x);
|
||||||
|
|
||||||
wrefresh(self->window);
|
wrefresh(self->window);
|
||||||
@ -478,7 +494,9 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
|||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT);
|
|
||||||
|
if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1)
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollok(ctx->history, 0);
|
scrollok(ctx->history, 0);
|
||||||
|
@ -41,6 +41,7 @@ typedef struct {
|
|||||||
} FriendRequests;
|
} FriendRequests;
|
||||||
|
|
||||||
ToxWindow new_prompt(void);
|
ToxWindow new_prompt(void);
|
||||||
|
|
||||||
void prep_prompt_win(void);
|
void prep_prompt_win(void);
|
||||||
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
||||||
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
||||||
|
@ -167,6 +167,10 @@ static int detect_gnu_screen ()
|
|||||||
|
|
||||||
free (dyn_buffer);
|
free (dyn_buffer);
|
||||||
dyn_buffer = NULL;
|
dyn_buffer = NULL;
|
||||||
|
|
||||||
|
if (strlen(socket_path) + strlen(PATH_SEP_S) + strlen(socket_name) >= sizeof(mplex_data))
|
||||||
|
goto nomplex;
|
||||||
|
|
||||||
strcpy (mplex_data, socket_path);
|
strcpy (mplex_data, socket_path);
|
||||||
strcat (mplex_data, PATH_SEP_S);
|
strcat (mplex_data, PATH_SEP_S);
|
||||||
strcat (mplex_data, socket_name);
|
strcat (mplex_data, socket_name);
|
||||||
@ -181,6 +185,8 @@ nomplex:
|
|||||||
pclose (session_info_stream);
|
pclose (session_info_stream);
|
||||||
if (dyn_buffer)
|
if (dyn_buffer)
|
||||||
free (dyn_buffer);
|
free (dyn_buffer);
|
||||||
|
if (socket_path)
|
||||||
|
free(socket_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +202,7 @@ static int detect_tmux ()
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* store the session number string for later use */
|
/* store the session number string for later use */
|
||||||
strcpy (mplex_data, pos + 1);
|
snprintf (mplex_data, sizeof(mplex_data), "%s", pos + 1);
|
||||||
mplex = MPLEX_TMUX;
|
mplex = MPLEX_TMUX;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
103
src/toxic.c
103
src/toxic.c
@ -78,6 +78,9 @@ char *DATA_FILE = NULL;
|
|||||||
char *BLOCK_FILE = NULL;
|
char *BLOCK_FILE = NULL;
|
||||||
ToxWindow *prompt = NULL;
|
ToxWindow *prompt = NULL;
|
||||||
|
|
||||||
|
#define DATANAME "data"
|
||||||
|
#define BLOCKNAME "data-blocklist"
|
||||||
|
|
||||||
#define AUTOSAVE_FREQ 60
|
#define AUTOSAVE_FREQ 60
|
||||||
#define MIN_PASSWORD_LEN 6
|
#define MIN_PASSWORD_LEN 6
|
||||||
#define MAX_PASSWORD_LEN 64
|
#define MAX_PASSWORD_LEN 64
|
||||||
@ -120,6 +123,24 @@ static void init_signal_catchers(void)
|
|||||||
signal(SIGSEGV, catch_SIGSEGV);
|
signal(SIGSEGV, catch_SIGSEGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void free_global_data(void)
|
||||||
|
{
|
||||||
|
if (DATA_FILE) {
|
||||||
|
free(DATA_FILE);
|
||||||
|
DATA_FILE = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BLOCK_FILE) {
|
||||||
|
free(BLOCK_FILE);
|
||||||
|
BLOCK_FILE = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings) {
|
||||||
|
free(user_settings);
|
||||||
|
user_settings = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void exit_toxic_success(Tox *m)
|
void exit_toxic_success(Tox *m)
|
||||||
{
|
{
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
@ -132,10 +153,7 @@ void exit_toxic_success(Tox *m)
|
|||||||
terminate_audio();
|
terminate_audio();
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
free(DATA_FILE);
|
free_global_data();
|
||||||
free(BLOCK_FILE);
|
|
||||||
free(user_settings);
|
|
||||||
|
|
||||||
tox_kill(m);
|
tox_kill(m);
|
||||||
endwin();
|
endwin();
|
||||||
|
|
||||||
@ -151,6 +169,7 @@ void exit_toxic_success(Tox *m)
|
|||||||
|
|
||||||
void exit_toxic_err(const char *errmsg, int errcode)
|
void exit_toxic_err(const char *errmsg, int errcode)
|
||||||
{
|
{
|
||||||
|
free_global_data();
|
||||||
freopen("/dev/tty", "w", stderr);
|
freopen("/dev/tty", "w", stderr);
|
||||||
endwin();
|
endwin();
|
||||||
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
||||||
@ -277,22 +296,36 @@ static int load_nodelist(const char *filename)
|
|||||||
char line[MAX_NODE_LINE];
|
char line[MAX_NODE_LINE];
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
|
while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
|
||||||
if (strlen(line) > MIN_NODE_LINE) {
|
size_t line_len = strlen(line);
|
||||||
|
|
||||||
|
if (line_len >= MIN_NODE_LINE && line_len <= MAX_NODE_LINE) {
|
||||||
const char *name = strtok(line, " ");
|
const char *name = strtok(line, " ");
|
||||||
const char *port = strtok(NULL, " ");
|
const char *port = strtok(NULL, " ");
|
||||||
const char *key_ascii = strtok(NULL, " ");
|
const char *key_ascii = strtok(NULL, " ");
|
||||||
|
|
||||||
/* invalid line */
|
|
||||||
if (name == NULL || port == NULL || key_ascii == NULL)
|
if (name == NULL || port == NULL || key_ascii == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
size_t key_len = strlen(key_ascii);
|
||||||
|
size_t name_len = strlen(name);
|
||||||
|
|
||||||
|
if (key_len < TOX_PUBLIC_KEY_SIZE * 2 || name_len >= NODELEN)
|
||||||
|
continue;
|
||||||
|
|
||||||
snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
|
snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
|
||||||
toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
|
toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
|
||||||
toxNodes.ports[toxNodes.lines] = atoi(port);
|
toxNodes.ports[toxNodes.lines] = atoi(port);
|
||||||
|
|
||||||
char *key_binary = hex_string_to_bin(key_ascii);
|
/* remove possible trailing newline from key string */
|
||||||
|
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||||
|
memcpy(key_binary, key_ascii, TOX_PUBLIC_KEY_SIZE * 2);
|
||||||
|
key_len = TOX_PUBLIC_KEY_SIZE * 2;
|
||||||
|
key_binary[key_len] = '\0';
|
||||||
|
|
||||||
|
if (hex_string_to_bin(key_ascii, key_len, key_binary, TOX_PUBLIC_KEY_SIZE) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_PUBLIC_KEY_SIZE);
|
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_PUBLIC_KEY_SIZE);
|
||||||
free(key_binary);
|
|
||||||
|
|
||||||
toxNodes.lines++;
|
toxNodes.lines++;
|
||||||
}
|
}
|
||||||
@ -777,9 +810,8 @@ static uint64_t last_bootstrap_time = 0;
|
|||||||
static void do_bootstrap(Tox *m)
|
static void do_bootstrap(Tox *m)
|
||||||
{
|
{
|
||||||
static int conn_err = 0;
|
static int conn_err = 0;
|
||||||
uint64_t curtime = get_unix_time();
|
|
||||||
|
|
||||||
if (!timed_out(last_bootstrap_time, curtime, TRY_BOOTSTRAP_INTERVAL))
|
if (!timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (tox_self_get_connection_status(m) != TOX_CONNECTION_NONE)
|
if (tox_self_get_connection_status(m) != TOX_CONNECTION_NONE)
|
||||||
@ -788,7 +820,7 @@ static void do_bootstrap(Tox *m)
|
|||||||
if (conn_err != 0)
|
if (conn_err != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
last_bootstrap_time = curtime;
|
last_bootstrap_time = get_unix_time();
|
||||||
conn_err = init_connection(m);
|
conn_err = init_connection(m);
|
||||||
|
|
||||||
if (conn_err != 0)
|
if (conn_err != 0)
|
||||||
@ -797,12 +829,17 @@ static void do_bootstrap(Tox *m)
|
|||||||
|
|
||||||
static void do_toxic(Tox *m, ToxWindow *prompt)
|
static void do_toxic(Tox *m, ToxWindow *prompt)
|
||||||
{
|
{
|
||||||
if (arg_opts.no_connect)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
update_unix_time();
|
||||||
|
|
||||||
|
if (arg_opts.no_connect) {
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tox_iterate(m);
|
tox_iterate(m);
|
||||||
do_bootstrap(m);
|
do_bootstrap(m);
|
||||||
|
check_file_transfer_timeouts(m);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,6 +848,7 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
|
|||||||
void *thread_winref(void *data)
|
void *thread_winref(void *data)
|
||||||
{
|
{
|
||||||
Tox *m = (Tox *) data;
|
Tox *m = (Tox *) data;
|
||||||
|
|
||||||
uint8_t draw_count = 0;
|
uint8_t draw_count = 0;
|
||||||
init_signal_catchers();
|
init_signal_catchers();
|
||||||
|
|
||||||
@ -955,10 +993,22 @@ static void parse_args(int argc, char *argv[])
|
|||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
arg_opts.use_custom_data = 1;
|
arg_opts.use_custom_data = 1;
|
||||||
DATA_FILE = strdup(optarg);
|
|
||||||
|
if (DATA_FILE)
|
||||||
|
free(DATA_FILE);
|
||||||
|
|
||||||
|
if (BLOCK_FILE)
|
||||||
|
free(BLOCK_FILE);
|
||||||
|
|
||||||
|
DATA_FILE = malloc(strlen(optarg) + 1);
|
||||||
|
strcpy(DATA_FILE, optarg);
|
||||||
|
|
||||||
|
if (DATA_FILE == NULL)
|
||||||
|
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||||
|
|
||||||
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
||||||
|
|
||||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
if (BLOCK_FILE == NULL)
|
||||||
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||||
|
|
||||||
strcpy(BLOCK_FILE, optarg);
|
strcpy(BLOCK_FILE, optarg);
|
||||||
@ -1029,8 +1079,6 @@ static void parse_args(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DATANAME "data"
|
|
||||||
#define BLOCKNAME "data-blocklist"
|
|
||||||
static int init_default_data_files(void)
|
static int init_default_data_files(void)
|
||||||
{
|
{
|
||||||
if (arg_opts.use_custom_data)
|
if (arg_opts.use_custom_data)
|
||||||
@ -1070,7 +1118,7 @@ static int init_default_data_files(void)
|
|||||||
/* Adjusts usleep value so that tox_do runs close to the recommended number of times per second */
|
/* Adjusts usleep value so that tox_do runs close to the recommended number of times per second */
|
||||||
static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, uint64_t cur_time, useconds_t msleepval)
|
static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, uint64_t cur_time, useconds_t msleepval)
|
||||||
{
|
{
|
||||||
useconds_t new_sleep = msleepval;
|
useconds_t new_sleep = MAX(msleepval, 3);
|
||||||
++(*loopcount);
|
++(*loopcount);
|
||||||
|
|
||||||
if (*looptimer == cur_time)
|
if (*looptimer == cur_time)
|
||||||
@ -1084,14 +1132,16 @@ static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, ui
|
|||||||
return new_sleep;
|
return new_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this doesn't do anything (yet)
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
// FIXME
|
|
||||||
void DnD_callback(const char* asdv, DropType dt)
|
void DnD_callback(const char* asdv, DropType dt)
|
||||||
{
|
{
|
||||||
if (dt != DT_plain)
|
// if (dt != DT_plain)
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
|
// pthread_mutex_lock(&Winthread.lock);
|
||||||
|
// line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
#endif /* X11 */
|
#endif /* X11 */
|
||||||
|
|
||||||
@ -1160,6 +1210,7 @@ int main(int argc, char *argv[])
|
|||||||
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
|
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
|
||||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||||
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
av = init_audio(prompt, m);
|
av = init_audio(prompt, m);
|
||||||
@ -1193,8 +1244,11 @@ int main(int argc, char *argv[])
|
|||||||
if (init_mplex_away_timer(m) == -1)
|
if (init_mplex_away_timer(m) == -1)
|
||||||
queue_init_message("Failed to init mplex auto-away.");
|
queue_init_message("Failed to init mplex auto-away.");
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
load_groups(m);
|
load_groups(m);
|
||||||
print_init_messages(prompt);
|
print_init_messages(prompt);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
cleanup_init_messages();
|
cleanup_init_messages();
|
||||||
|
|
||||||
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
|
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
|
||||||
@ -1208,11 +1262,10 @@ int main(int argc, char *argv[])
|
|||||||
uint64_t loopcount = 0;
|
uint64_t loopcount = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
update_unix_time();
|
|
||||||
do_toxic(m, prompt);
|
do_toxic(m, prompt);
|
||||||
uint64_t cur_time = get_unix_time();
|
uint64_t cur_time = get_unix_time();
|
||||||
|
|
||||||
if (timed_out(last_save, cur_time, AUTOSAVE_FREQ)) {
|
if (timed_out(last_save, AUTOSAVE_FREQ)) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
if (store_data(m, DATA_FILE) != 0)
|
if (store_data(m, DATA_FILE) != 0)
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
|
||||||
|
@ -569,10 +569,16 @@ void on_window_resize(void)
|
|||||||
|
|
||||||
static void draw_window_tab(ToxWindow *toxwin)
|
static void draw_window_tab(ToxWindow *toxwin)
|
||||||
{
|
{
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
|
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
clrtoeol();
|
clrtoeol();
|
||||||
printw(" [%s]", toxwin->name);
|
printw(" [%s]", toxwin->name);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
|
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_bar(void)
|
static void draw_bar(void)
|
||||||
@ -620,7 +626,10 @@ static void draw_bar(void)
|
|||||||
void draw_active_window(Tox *m)
|
void draw_active_window(Tox *m)
|
||||||
{
|
{
|
||||||
ToxWindow *a = active_window;
|
ToxWindow *a = active_window;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
a->alert = WINDOW_ALERT_NONE;
|
a->alert = WINDOW_ALERT_NONE;
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
wint_t ch = 0;
|
wint_t ch = 0;
|
||||||
|
|
||||||
@ -683,7 +692,7 @@ ToxWindow *get_window_ptr(int i)
|
|||||||
{
|
{
|
||||||
ToxWindow *toxwin = NULL;
|
ToxWindow *toxwin = NULL;
|
||||||
|
|
||||||
if (i >= 0 && i <= MAX_WINDOWS_NUM && windows[i].active)
|
if (i >= 0 && i < MAX_WINDOWS_NUM && windows[i].active)
|
||||||
toxwin = &windows[i];
|
toxwin = &windows[i];
|
||||||
|
|
||||||
return toxwin;
|
return toxwin;
|
||||||
|
110
src/xtra.c
110
src/xtra.c
@ -72,24 +72,24 @@ Property read_property(Window s, Atom p)
|
|||||||
unsigned long read_num;
|
unsigned long read_num;
|
||||||
unsigned long left_bytes;
|
unsigned long left_bytes;
|
||||||
unsigned char *data = NULL;
|
unsigned char *data = NULL;
|
||||||
|
|
||||||
int read_bytes = 1024;
|
int read_bytes = 1024;
|
||||||
|
|
||||||
/* Keep trying to read the property until there are no bytes unread */
|
/* Keep trying to read the property until there are no bytes unread */
|
||||||
do {
|
do {
|
||||||
if (data) XFree(data);
|
if (data) XFree(data);
|
||||||
|
|
||||||
XGetWindowProperty(Xtra.display, s,
|
XGetWindowProperty(Xtra.display, s,
|
||||||
p, 0,
|
p, 0,
|
||||||
read_bytes,
|
read_bytes,
|
||||||
False, AnyPropertyType,
|
False, AnyPropertyType,
|
||||||
&read_type, &read_format,
|
&read_type, &read_format,
|
||||||
&read_num, &left_bytes,
|
&read_num, &left_bytes,
|
||||||
&data);
|
&data);
|
||||||
|
|
||||||
read_bytes *= 2;
|
read_bytes *= 2;
|
||||||
} while (left_bytes != 0);
|
} while (left_bytes != 0);
|
||||||
|
|
||||||
Property property = {data, read_format, read_num, read_type};
|
Property property = {data, read_format, read_num, read_type};
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ Atom get_dnd_type(long *a, int l)
|
|||||||
static void handle_xdnd_enter(XClientMessageEvent* e)
|
static void handle_xdnd_enter(XClientMessageEvent* e)
|
||||||
{
|
{
|
||||||
Xtra.handling_version = (e->data.l[1] >> 24);
|
Xtra.handling_version = (e->data.l[1] >> 24);
|
||||||
|
|
||||||
if ((e->data.l[1] & 1)) {
|
if ((e->data.l[1] & 1)) {
|
||||||
// Fetch the list of possible conversions
|
// Fetch the list of possible conversions
|
||||||
Property p = read_property(e->data.l[0], XdndTypeList);
|
Property p = read_property(e->data.l[0], XdndTypeList);
|
||||||
@ -120,7 +120,7 @@ static void handle_xdnd_enter(XClientMessageEvent* e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void handle_xdnd_position(XClientMessageEvent* e)
|
static void handle_xdnd_position(XClientMessageEvent* e)
|
||||||
{
|
{
|
||||||
XEvent ev = {
|
XEvent ev = {
|
||||||
.xclient = {
|
.xclient = {
|
||||||
.type = ClientMessage,
|
.type = ClientMessage,
|
||||||
@ -130,15 +130,15 @@ static void handle_xdnd_position(XClientMessageEvent* e)
|
|||||||
.format = 32,
|
.format = 32,
|
||||||
.data = {
|
.data = {
|
||||||
.l = {
|
.l = {
|
||||||
Xtra.proxy_window,
|
Xtra.proxy_window,
|
||||||
(Xtra.expecting_type != XtraNil),
|
(Xtra.expecting_type != XtraNil),
|
||||||
0, 0,
|
0, 0,
|
||||||
XdndActionCopy
|
XdndActionCopy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
||||||
XFlush(Xtra.display);
|
XFlush(Xtra.display);
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ static void handle_xdnd_drop(XClientMessageEvent* e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
||||||
} else {
|
} else {
|
||||||
Xtra.source_window = e->data.l[0];
|
Xtra.source_window = e->data.l[0];
|
||||||
@ -188,57 +188,57 @@ static void handle_xdnd_selection(XSelectionEvent* e)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
XSendEvent(Xtra.display, Xtra.source_window, False, NoEventMask, &ev);
|
XSendEvent(Xtra.display, Xtra.source_window, False, NoEventMask, &ev);
|
||||||
|
|
||||||
Property p = read_property(Xtra.proxy_window, XdndSelection);
|
Property p = read_property(Xtra.proxy_window, XdndSelection);
|
||||||
DropType dt;
|
DropType dt;
|
||||||
|
|
||||||
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0)
|
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0)
|
||||||
dt = DT_file_list;
|
dt = DT_file_list;
|
||||||
else /* text/uri-list */
|
else /* text/uri-list */
|
||||||
dt = DT_plain;
|
dt = DT_plain;
|
||||||
|
|
||||||
|
|
||||||
/* Call callback for every entry */
|
/* Call callback for every entry */
|
||||||
if (Xtra.on_drop && p.read_num)
|
if (Xtra.on_drop && p.read_num)
|
||||||
{
|
{
|
||||||
char *sptr;
|
char *sptr;
|
||||||
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
||||||
|
|
||||||
if (str) Xtra.on_drop(str, dt);
|
if (str) Xtra.on_drop(str, dt);
|
||||||
while ((str = strtok_r(NULL, "\n\r", &sptr)))
|
while ((str = strtok_r(NULL, "\n\r", &sptr)))
|
||||||
Xtra.on_drop(str, dt);
|
Xtra.on_drop(str, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.data) XFree(p.data);
|
if (p.data) XFree(p.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *event_loop(void* p)
|
void *event_loop(void* p)
|
||||||
{
|
{
|
||||||
/* Handle events like a real nigga */
|
/* Handle events like a real nigga */
|
||||||
|
|
||||||
(void) p; /* DINDUNOTHIN */
|
(void) p; /* DINDUNOTHIN */
|
||||||
|
|
||||||
XEvent event;
|
XEvent event;
|
||||||
int pending;
|
int pending;
|
||||||
|
|
||||||
while (Xtra.display)
|
while (Xtra.display)
|
||||||
{
|
{
|
||||||
/* NEEDMOEVENTSFODEMPROGRAMS */
|
/* NEEDMOEVENTSFODEMPROGRAMS */
|
||||||
|
|
||||||
XLockDisplay(Xtra.display);
|
XLockDisplay(Xtra.display);
|
||||||
if((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
|
if((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
|
||||||
|
|
||||||
if (!pending)
|
if (!pending)
|
||||||
{
|
{
|
||||||
XUnlockDisplay(Xtra.display);
|
XUnlockDisplay(Xtra.display);
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type == ClientMessage)
|
if (event.type == ClientMessage)
|
||||||
{
|
{
|
||||||
Atom type = event.xclient.message_type;
|
Atom type = event.xclient.message_type;
|
||||||
|
|
||||||
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
|
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
|
||||||
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
|
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
|
||||||
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
|
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
|
||||||
@ -247,11 +247,11 @@ void *event_loop(void* p)
|
|||||||
else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
|
else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
|
||||||
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
||||||
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
||||||
|
|
||||||
XUnlockDisplay(Xtra.display);
|
XUnlockDisplay(Xtra.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actual XTRA termination
|
/* Actual XTRA termination
|
||||||
* Please call xtra_terminate() at exit
|
* Please call xtra_terminate() at exit
|
||||||
* otherwise HEWUSAGUDBOI happens
|
* otherwise HEWUSAGUDBOI happens
|
||||||
*/
|
*/
|
||||||
@ -262,23 +262,23 @@ void *event_loop(void* p)
|
|||||||
int init_xtra(drop_callback d)
|
int init_xtra(drop_callback d)
|
||||||
{
|
{
|
||||||
memset(&Xtra, 0, sizeof(Xtra));
|
memset(&Xtra, 0, sizeof(Xtra));
|
||||||
|
|
||||||
if (!d) return -1;
|
if (!d) return -1;
|
||||||
else Xtra.on_drop = d;
|
else Xtra.on_drop = d;
|
||||||
|
|
||||||
XInitThreads();
|
XInitThreads();
|
||||||
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
|
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
|
||||||
|
|
||||||
Xtra.terminal_window = focused_window_id();
|
Xtra.terminal_window = focused_window_id();
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Create an invisible window which will act as proxy for the DnD operation. */
|
/* Create an invisible window which will act as proxy for the DnD operation. */
|
||||||
XSetWindowAttributes attr = {0};
|
XSetWindowAttributes attr = {0};
|
||||||
attr.event_mask = EnterWindowMask |
|
attr.event_mask = EnterWindowMask |
|
||||||
LeaveWindowMask |
|
LeaveWindowMask |
|
||||||
ButtonMotionMask |
|
ButtonMotionMask |
|
||||||
ButtonPressMask |
|
ButtonPressMask |
|
||||||
ButtonReleaseMask |
|
ButtonReleaseMask |
|
||||||
ResizeRedirectMask;
|
ResizeRedirectMask;
|
||||||
|
|
||||||
attr.do_not_propagate_mask = NoEventMask;
|
attr.do_not_propagate_mask = NoEventMask;
|
||||||
@ -286,14 +286,14 @@ int init_xtra(drop_callback d)
|
|||||||
Window root;
|
Window root;
|
||||||
int x, y;
|
int x, y;
|
||||||
unsigned int wht, hht, b, d;
|
unsigned int wht, hht, b, d;
|
||||||
|
|
||||||
/* Since we cannot capture resize events for parent window we will have to create
|
/* Since we cannot capture resize events for parent window we will have to create
|
||||||
* this window to have maximum size as defined in root window
|
* this window to have maximum size as defined in root window
|
||||||
*/
|
*/
|
||||||
XGetGeometry(Xtra.display,
|
XGetGeometry(Xtra.display,
|
||||||
XDefaultRootWindow(Xtra.display),
|
XDefaultRootWindow(Xtra.display),
|
||||||
&root, &x, &y, &wht, &hht, &b, &d);
|
&root, &x, &y, &wht, &hht, &b, &d);
|
||||||
|
|
||||||
if (! (Xtra.proxy_window = XCreateWindow
|
if (! (Xtra.proxy_window = XCreateWindow
|
||||||
(Xtra.display, Xtra.terminal_window, /* Parent */
|
(Xtra.display, Xtra.terminal_window, /* Parent */
|
||||||
0, 0, /* Position */
|
0, 0, /* Position */
|
||||||
@ -306,7 +306,7 @@ int init_xtra(drop_callback d)
|
|||||||
&attr)) ) /* Attributes for value mask */
|
&attr)) ) /* Attributes for value mask */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
|
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
|
||||||
XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
|
XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ int init_xtra(drop_callback d)
|
|||||||
XdndTypeList = XInternAtom(Xtra.display, "XdndTypeList", False);
|
XdndTypeList = XInternAtom(Xtra.display, "XdndTypeList", False);
|
||||||
XdndActionCopy = XInternAtom(Xtra.display, "XdndActionCopy", False);
|
XdndActionCopy = XInternAtom(Xtra.display, "XdndActionCopy", False);
|
||||||
XdndFinished = XInternAtom(Xtra.display, "XdndFinished", False);
|
XdndFinished = XInternAtom(Xtra.display, "XdndFinished", False);
|
||||||
|
|
||||||
/* Inform my nigga windows that we are aware of dnd */
|
/* Inform my nigga windows that we are aware of dnd */
|
||||||
Atom XdndVersion = 3;
|
Atom XdndVersion = 3;
|
||||||
XChangeProperty(Xtra.display,
|
XChangeProperty(Xtra.display,
|
||||||
@ -331,18 +331,20 @@ int init_xtra(drop_callback d)
|
|||||||
32,
|
32,
|
||||||
PropModeReplace,
|
PropModeReplace,
|
||||||
(unsigned char*)&XdndVersion, 1);
|
(unsigned char*)&XdndVersion, 1);
|
||||||
|
|
||||||
pthread_t id;
|
pthread_t id;
|
||||||
pthread_create(&id, NULL, event_loop, NULL);
|
if (pthread_create(&id, NULL, event_loop, NULL) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
pthread_detach(id);
|
pthread_detach(id);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminate_xtra()
|
void terminate_xtra()
|
||||||
{
|
{
|
||||||
if (!Xtra.display) return;
|
if (!Xtra.display) return;
|
||||||
|
|
||||||
XEvent terminate = {
|
XEvent terminate = {
|
||||||
.xclient = {
|
.xclient = {
|
||||||
.type = ClientMessage,
|
.type = ClientMessage,
|
||||||
@ -350,19 +352,19 @@ void terminate_xtra()
|
|||||||
.message_type = XtraTerminate,
|
.message_type = XtraTerminate,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XLockDisplay(Xtra.display);
|
XLockDisplay(Xtra.display);
|
||||||
XDeleteProperty(Xtra.display, Xtra.proxy_window, XdndAware);
|
XDeleteProperty(Xtra.display, Xtra.proxy_window, XdndAware);
|
||||||
XSendEvent(Xtra.display, Xtra.proxy_window, 0, NoEventMask, &terminate);
|
XSendEvent(Xtra.display, Xtra.proxy_window, 0, NoEventMask, &terminate);
|
||||||
XUnlockDisplay(Xtra.display);
|
XUnlockDisplay(Xtra.display);
|
||||||
|
|
||||||
while (Xtra.display); /* Wait for termination */
|
while (Xtra.display); /* Wait for termination */
|
||||||
}
|
}
|
||||||
|
|
||||||
long unsigned int focused_window_id()
|
long unsigned int focused_window_id()
|
||||||
{
|
{
|
||||||
if (!Xtra.display) return 0;
|
if (!Xtra.display) return 0;
|
||||||
|
|
||||||
Window focus;
|
Window focus;
|
||||||
int revert;
|
int revert;
|
||||||
XLockDisplay(Xtra.display);
|
XLockDisplay(Xtra.display);
|
||||||
|
Loading…
Reference in New Issue
Block a user