diff --git a/doc/toxic.1 b/doc/toxic.1
index 79d06a5..9878cb1 100644
--- a/doc/toxic.1
+++ b/doc/toxic.1
@@ -2,12 +2,12 @@
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" Date: 2015-07-08
+.\" Date: 2015-12-07
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
-.TH "TOXIC" "1" "2015\-07\-08" "toxic __VERSION__" "Toxic Manual"
+.TH "TOXIC" "1" "2015\-12\-07" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -70,7 +70,7 @@ Encrypt an unencrypted data file\&. An error will occur if this option is used w
Use specified
\fIdata\-file\fR
instead of
-\fI~/\&.config/tox/data\fR
+\fI~/\&.config/tox/toxic_profile\&.tox\fR
.RE
.PP
\-h, \-\-help
@@ -127,7 +127,7 @@ __DATADIR__/DHTnodes
Default list of DHT bootstrap nodes\&.
.RE
.PP
-~/\&.config/tox/data
+~/\&.config/tox/toxic_profile\&.tox
.RS 4
Savestate which contains your personal info (nickname, Tox ID, contacts, etc)
.RE
@@ -144,7 +144,11 @@ Configuration example\&.
.RE
.SH "BUGS"
.sp
-Unicode characters with a width larger than 1 column may cause strange behaviour\&. Expect more bugs and bad behaviour: this software is in a pre\-alpha stage\&.
+\-Unicode characters with a width larger than 1 column may cause strange behaviour\&.
+.sp
+\-Text occasionally fails to auto\-scroll to the bottom\&.
+.sp
+\-Screen flickering sometimes occurs on certain terminals\&.
.SH "AUTHORS"
.sp
JFreegman
@@ -153,6 +157,6 @@ JFreegman
\fBtoxic\&.conf\fR(5)
.SH "LINKS"
.sp
-Project page: https://github\&.com/Tox/toxic
+Project page: https://github\&.com/JFreegman/toxic
.sp
IRC channel: chat\&.freenode\&.net#tox
diff --git a/doc/toxic.1.asc b/doc/toxic.1.asc
index 8384091..20d3c00 100644
--- a/doc/toxic.1.asc
+++ b/doc/toxic.1.asc
@@ -35,7 +35,7 @@ OPTIONS
is used with an encrypted data file.
-f, --file data-file::
- Use specified 'data-file' instead of '~/.config/tox/data'
+ Use specified 'data-file' instead of '~/.config/tox/toxic_profile.tox'
-h, --help::
Show help message
@@ -71,7 +71,7 @@ FILES
{datadir}/DHTnodes::
Default list of DHT bootstrap nodes.
-~/.config/tox/data::
+~/.config/tox/toxic_profile.tox::
Savestate which contains your personal info (nickname, Tox ID, contacts,
etc)
@@ -83,9 +83,12 @@ FILES
BUGS
----
-Unicode characters with a width larger than 1 column may cause strange
-behaviour. Expect more bugs and bad behaviour: this software is in a
-pre-alpha stage.
+-Unicode characters with a width larger than 1 column may cause strange
+behaviour.
+
+-Text occasionally fails to auto-scroll to the bottom.
+
+-Screen flickering sometimes occurs on certain terminals.
AUTHORS
-------
@@ -97,6 +100,6 @@ SEE ALSO
LINKS
-----
-Project page:
+Project page:
IRC channel: chat.freenode.net#tox
diff --git a/doc/toxic.conf.5 b/doc/toxic.conf.5
index 70da6d6..f8d28ee 100644
--- a/doc/toxic.conf.5
+++ b/doc/toxic.conf.5
@@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" Date: 2015-03-28
+.\" Date: 2016-02-28
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
-.TH "TOXIC\&.CONF" "5" "2015\-03\-28" "toxic __VERSION__" "Toxic Manual"
+.TH "TOXIC\&.CONF" "5" "2016\-02\-28" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -113,6 +113,11 @@ Show others when you\(cqre typing in a 1\-on\-1 chat\&. true or false
Show welcome message on startup\&. true or false
.RE
.PP
+\fBshow_connection_msg\fR
+.RS 4
+Enable friend connection change notifications\&. true or false
+.RE
+.PP
\fBhistory_size\fR
.RS 4
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
@@ -194,6 +199,11 @@ Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
.RS 4
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
.RE
+.PP
+\fBpassword_eval\fR
+.RS 4
+Replace password prompt by running this command and using its output as the password\&.
+.RE
.RE
.PP
\fBsounds\fR
@@ -308,6 +318,11 @@ Key combination to scroll contacts list down\&.
.RS 4
Toggle the peer list on and off\&.
.RE
+.PP
+\fBtoggle_paste_mode\fR
+.RS 4
+Toggle treating linebreaks as enter key press\&.
+.RE
.RE
.SH "FILES"
.PP
@@ -325,7 +340,7 @@ Configuration example\&.
\fBtoxic\fR(1)
.SH "RESOURCES"
.sp
-Project page: https://github\&.com/Tox/toxic
+Project page: https://github\&.com/JFreegman/toxic
.sp
IRC channel: chat\&.freenode\&.net#tox
.SH "AUTHORS"
diff --git a/doc/toxic.conf.5.asc b/doc/toxic.conf.5.asc
index 267918f..03e83e1 100644
--- a/doc/toxic.conf.5.asc
+++ b/doc/toxic.conf.5.asc
@@ -72,6 +72,9 @@ OPTIONS
*show_welcome_msg*;;
Show welcome message on startup. true or false
+ *show_connection_msg*;;
+ Enable friend connection change notifications. true or false
+
*history_size*;;
Maximum lines for chat window history. Integer value. (for example: 700)
@@ -126,6 +129,10 @@ OPTIONS
*chatlogs_path*;;
Default path for chatlogs. String value. Absolute path for chatlog files.
+ *password_eval*;;
+ Replace password prompt by running this command and using its output as
+ the password.
+
*sounds*::
Configuration related to notification sounds.
Special value "silent" can be used to disable a specific notification. +
@@ -197,6 +204,9 @@ OPTIONS
*toggle_peerlist*;;
Toggle the peer list on and off.
+ *toggle_paste_mode*;;
+ Toggle treating linebreaks as enter key press.
+
FILES
-----
@@ -214,7 +224,7 @@ SEE ALSO
RESOURCES
---------
-Project page:
+Project page:
IRC channel: chat.freenode.net#tox
diff --git a/misc/DHTnodes b/misc/DHTnodes
index 6dbe066..2384706 100644
--- a/misc/DHTnodes
+++ b/misc/DHTnodes
@@ -1,2 +1,24 @@
173.230.153.129 33445 A992ED1E7E8C6A4C71B12347D9BFA67DD896CF7D5689E20DD94CA066EE384758
cerberus.zodiaclabs.org 33450 B139D5A0280AFA8CD2E5E866226397771F80F9A84967558AD740AE056CB63E58
+46.101.197.175 443 CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707
+95.215.46.114 33445 5823FB947FF24CF83DDFAC3F3BAA18F96EA2018B16CC08429CB97FA502F40C23
+5.189.176.217 5190 2B2137E094F743AC8BD44652C55F41DFACC502F125E99E4FE24D40537489E32F
+148.251.23.146 2306 7AED21F94D82B05774F697B209628CD5A9AD17E0C073D9329076A4C28ED28147
+104.223.122.15 33445 0FB96EEBFB1650DDB52E70CF773DDFCABE25A95CC3BB50FC251082E4B63EF82A
+78.47.114.252 33445 1C5293AEF2114717547B39DA8EA6F1E331E5E358B35F9B6B5F19317911C5F976
+d4rk4.ru 1813 53737F6D47FA6BD2808F378E339AF45BF86F39B64E79D6D491C53A1D522E7039
+81.4.110.149 33445 9E7BD4793FFECA7F32238FA2361040C09025ED3333744483CA6F3039BFF0211E
+95.31.20.151 33445 9CA69BB74DE7C056D1CC6B16AB8A0A38725C0349D187D8996766958584D39340
+104.233.104.126 33445 EDEE8F2E839A57820DE3DA4156D88350E53D4161447068A3457EE8F59F362414
+51.254.84.212 33445 AEC204B9A4501412D5F0BB67D9C81B5DB3EE6ADA64122D32A3E9B093D544327D
+home.vikingmakt.com.br 33445 188E072676404ED833A4E947DC1D223DF8EFEBE5F5258573A236573688FB9761
+5.135.59.163 33445 2D320F971EF2CA18004416C2AAE7BA52BF7949DB34EA8E2E21AF67BD367BE211
+185.58.206.164 33445 24156472041E5F220D1FA11D9DF32F7AD697D59845701CDD7BE7D1785EB9DB39
+188.244.38.183 33445 15A0F9684E2423F9F46CFA5A50B562AE42525580D840CC50E518192BF333EE38
+mrflibble.c4.ee 33445 FAAB17014F42F7F20949F61E55F66A73C230876812A9737F5F6D2DCE4D9E4207
+82.211.31.116 33445 AF97B76392A6474AF2FD269220FDCF4127D86A42EF3A242DF53A40A268A2CD7C
+128.199.199.197 33445 B05C8869DBB4EDDD308F43C1A974A20A725A36EACCA123862FDE9945BF9D3E09
+103.230.156.174 33445 5C4C7A60183D668E5BD8B3780D1288203E2F1BAE4EEF03278019E21F86174C1D
+91.121.66.124 33445 4E3F7D37295664BBD0741B6DBCB6431D6CD77FC4105338C2FC31567BF5C8224A
+92.54.84.70 33445 5625A62618CB4FCA70E147A71B29695F38CC65FF0CBD68AD46254585BE564802
+tox1.privacydragon.me 33445 31910C0497D347FF160D6F3A6C0E317BAFA71E8E03BC4CBB2A185C9D4FB8B31E
diff --git a/misc/nameservers b/misc/nameservers
index 94f6aab..e7a4222 100644
--- a/misc/nameservers
+++ b/misc/nameservers
@@ -1,2 +1 @@
toxme.io 1A39E7A5D5FA9CF155C751570A32E625698A60A55F6D88028F949F66144F4F25
-
diff --git a/misc/toxic.conf.example b/misc/toxic.conf.example
index 063551f..97228e0 100644
--- a/misc/toxic.conf.example
+++ b/misc/toxic.conf.example
@@ -29,6 +29,9 @@ ui = {
// true to show the welcome message on startup
show_welcome_msg=true;
+ // true to show friend connection change messages on the home screen
+ show_connection_msg=true;
+
// maximum lines for chat window history
history_size=700;
@@ -90,6 +93,7 @@ sounds = {
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
// Note: All printable keys register as input
+// Note2: Ctrl+M does not work
keys = {
next_tab="Ctrl+P";
prev_tab="Ctrl+O";
@@ -101,5 +105,6 @@ keys = {
peer_list_up="Ctrl+[";
peer_list_down="Ctrl+]";
toggle_peerlist="Ctrl+b";
+ toggle_paste_mode="Ctrl+T";
};
diff --git a/src/audio_call.c b/src/audio_call.c
index 86abb05..2fd4024 100644
--- a/src/audio_call.c
+++ b/src/audio_call.c
@@ -103,7 +103,8 @@ void callback_call_canceled ( uint32_t friend_number );
void callback_call_rejected ( uint32_t friend_number );
void callback_call_ended ( uint32_t friend_number );
-void write_device_callback( uint32_t friend_number, const int16_t* PCM, uint16_t size );
+void write_device_callback( uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
+ uint32_t sample_rate );
static void print_err (ToxWindow *self, const char *error_str)
{
@@ -120,9 +121,9 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
CallControl.av = toxav_new(tox, &error);
CallControl.audio_enabled = true;
- CallControl.audio_bit_rate = 48;
+ CallControl.audio_bit_rate = 64;
CallControl.audio_sample_rate = 48000;
- CallControl.audio_frame_duration = 10;
+ CallControl.audio_frame_duration = 20;
CallControl.audio_channels = 1;
#ifndef VIDEO
@@ -180,10 +181,11 @@ void read_device_callback(const int16_t* captured, uint32_t size, void* data)
{}
}
-void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t size)
+void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
+ uint32_t sample_rate)
{
if ( CallControl.calls[friend_number].ttas )
- write_out(CallControl.calls[friend_number].out_idx, PCM, size, CallControl.audio_channels);
+ write_out(CallControl.calls[friend_number].out_idx, PCM, sample_count, channels, sample_rate);
}
int start_transmission(ToxWindow *self, Call *call)
@@ -328,7 +330,7 @@ void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
int16_t const *pcm, size_t sample_count,
uint8_t channels, uint32_t sampling_rate, void *user_data)
{
- write_device_callback(friend_number, pcm, frame_size);
+ write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
}
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
diff --git a/src/audio_device.c b/src/audio_device.c
index fabed10..c74e8ea 100644
--- a/src/audio_device.c
+++ b/src/audio_device.c
@@ -357,7 +357,8 @@ DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx
return de_None;
}
-inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels)
+inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t sample_count, uint8_t channels,
+ uint32_t sample_rate)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
@@ -386,7 +387,7 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_
}
- alBufferData(bufid, device->sound_mode, data, length * 2 * channels, device->sample_rate);
+ alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data, sample_count * 2 * channels, sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid);
ALint state;
diff --git a/src/audio_device.h b/src/audio_device.h
index cc1b268..34d1ecc 100644
--- a/src/audio_device.h
+++ b/src/audio_device.h
@@ -22,7 +22,7 @@
/*
* You can have multiple sources (Input devices) but only one output device.
- * Pass buffers to output device via write();
+ * Pass buffers to output device via write();
* Read from running input device(s) via select()/callback combo.
*/
@@ -82,7 +82,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
DeviceError close_device(DeviceType type, uint32_t device_idx);
/* Write data to device */
-DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels);
+DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels, uint32_t sample_rate);
void print_devices(ToxWindow* self, DeviceType type);
void get_primary_device_name(DeviceType type, char *buf, int size);
diff --git a/src/autocomplete.c b/src/autocomplete.c
index d3ea7a4..4c0113d 100644
--- a/src/autocomplete.c
+++ b/src/autocomplete.c
@@ -53,12 +53,14 @@ static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items
}
/* puts match in match buffer. if more than one match, add first n chars that are identical.
- e.g. if matches contains: [foo, foobar, foe] we put fo in matches. */
-static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_SIZE], int n)
+ * e.g. if matches contains: [foo, foobar, foe] we put fo in match.
+ *
+ * Returns the length of the match.
+ */
+static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char (*matches)[MAX_STR_SIZE], int n)
{
if (n == 1) {
- strcpy(match, matches[0]);
- return;
+ return snprintf(match, match_sz, "%s", matches[0]);
}
int i;
@@ -71,14 +73,14 @@ static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_
char ch2 = matches[j][i];
if (ch1 != ch2 || !ch1) {
- strcpy(match, matches[0]);
+ snprintf(match, match_sz, "%s", matches[0]);
match[i] = '\0';
- return;
+ return i;
}
}
}
- strcpy(match, matches[0]);
+ return snprintf(match, match_sz, "%s", matches[0]);
}
/* looks for all instances in list that begin with the last entered word in line according to pos,
@@ -164,8 +166,11 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
char match[MAX_STR_SIZE];
- get_str_match(self, match, matches, n_matches);
- size_t match_len = strlen(match);
+ size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);
+
+ if (match_len == 0) {
+ return 0;
+ }
if (dir_search) {
if (n_matches == 1)
@@ -180,15 +185,15 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
int n_endchrs = strlen(endchrs);
int strt = ctx->pos - s_len;
int diff = match_len - s_len + n_endchrs;
-
if (ctx->len + diff >= MAX_STR_SIZE)
return -1;
char tmpend[MAX_STR_SIZE];
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
- if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf))
+ if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf)) {
return -1;
+ }
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + match_len], endchrs);
@@ -197,8 +202,9 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
/* convert to widechar and copy back to original buf */
wchar_t newbuf[MAX_STR_SIZE];
- if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1)
+ if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1) {
return -1;
+ }
wcscpy(ctx->line, newbuf);
diff --git a/src/chat.c b/src/chat.c
index e241b56..89e6ed5 100644
--- a/src/chat.c
+++ b/src/chat.c
@@ -216,7 +216,14 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
- if (connection_status != TOX_CONNECTION_NONE && statusbar->connection == TOX_CONNECTION_NONE) {
+ TOX_CONNECTION prev_status = statusbar->connection;
+ statusbar->connection = connection_status;
+
+ if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
+ return;
+ }
+
+ if (prev_status == TOX_CONNECTION_NONE) {
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
? tox_friend_get_typing(m, num, NULL) : false;
chat_resume_file_senders(self, m, num);
@@ -236,8 +243,6 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true);
}
-
- statusbar->connection = connection_status;
}
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
@@ -764,33 +769,6 @@ void chat_onEnd (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
#endif /* SOUND_NOTIFY */
}
-void chat_onRequestTimeout (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
-{
- if (!self || self->num != friend_number)
- return;
-
- self->is_call = false;
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No answer!");
-
-#ifdef SOUND_NOTIFY
- stop_sound(self->ringing_sound);
-#endif /* SOUND_NOTIFY */
-}
-
-void chat_onPeerTimeout (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
-{
- if (!self || self->num != friend_number)
- return;
-
- self->is_call = false;
- kill_infobox(self);
- line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer disconnected; call ended!");
-
-#ifdef SOUND_NOTIFY
- stop_sound(self->ringing_sound);
-#endif /* SOUND_NOTIFY */
-}
-
static void init_infobox(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
@@ -899,7 +877,6 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
-
ChatContext *ctx = self->chatwin;
StatusBar *statusbar = self->stb;
@@ -910,12 +887,15 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (y2 <= 0 || x2 <= 0)
return;
+ if (ctx->pastemode && key == '\r')
+ key = '\n';
+
if (self->help->active) {
help_onKey(self, key);
return;
}
- if (ltr) { /* char is printable */
+ if (ltr || key == '\n') { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE)
@@ -957,38 +937,42 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
sound_notify(self, notif_error, 0, NULL);
}
- } else if (key == '\n') {
+ } else if (key == '\r') {
rm_trailing_spaces_buf(ctx);
- char line[MAX_STR_SIZE];
-
- if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
- memset(&line, 0, sizeof(line));
-
- if (!string_is_empty(line))
+ if (!wstring_is_empty(ctx->line))
+ {
add_line_to_hist(ctx);
- if (line[0] == '/') {
- if (strcmp(line, "/close") == 0) {
- kill_chat_window(self, m);
- return;
- } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
- send_action(self, ctx, m, line + strlen("/me "));
+ wstrsubst(ctx->line, L'¶', L'\n');
+
+ char line[MAX_STR_SIZE] = {0};
+
+ if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
+ memset(&line, 0, sizeof(line));
+
+ if (line[0] == '/') {
+ if (strcmp(line, "/close") == 0) {
+ kill_chat_window(self, m);
+ return;
+ } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
+ send_action(self, ctx, m, line + strlen("/me "));
+ } else {
+ execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
+ }
} else {
- execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
+ char selfname[TOX_MAX_NAME_LENGTH];
+ tox_self_get_name(m, (uint8_t *) selfname);
+
+ size_t len = tox_self_get_name_size(m);
+ selfname[len] = '\0';
+
+ char timefrmt[TIME_STR_SIZE];
+ get_time_str(timefrmt, sizeof(timefrmt));
+
+ line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
+ cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1);
}
- } else if (!string_is_empty(line)) {
- char selfname[TOX_MAX_NAME_LENGTH];
- tox_self_get_name(m, (uint8_t *) selfname);
-
- size_t len = tox_self_get_name_size(m);
- selfname[len] = '\0';
-
- char timefrmt[TIME_STR_SIZE];
- get_time_str(timefrmt, sizeof(timefrmt));
-
- line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
- cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1);
}
wclear(ctx->linewin);
diff --git a/src/configdir.c b/src/configdir.c
index db63b6f..d1e5f8d 100644
--- a/src/configdir.c
+++ b/src/configdir.c
@@ -99,11 +99,6 @@ char *get_user_config_dir(void)
# endif /* __APPLE__ */
- if (!file_exists(user_config_dir)) {
- free(user_config_dir);
- return NULL;
- }
-
return user_config_dir;
}
diff --git a/src/file_transfers.c b/src/file_transfers.c
index 3a06742..ad71c9e 100644
--- a/src/file_transfers.c
+++ b/src/file_transfers.c
@@ -38,47 +38,6 @@ extern FriendsList Friends;
/* 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.
Assumes progline has room for at least MAX_STR_SIZE bytes */
void init_progress_bar(char *progline)
diff --git a/src/file_transfers.h b/src/file_transfers.h
index f5181a6..aaf081e 100644
--- a/src/file_transfers.h
+++ b/src/file_transfers.h
@@ -34,7 +34,6 @@
#define GiB 1073741824 /* 1024^3 */
#define MAX_FILES 32
-#define TIMEOUT_FILESENDER 120
typedef enum FILE_TRANSFER_STATE {
FILE_TRANSFER_INACTIVE,
@@ -68,9 +67,6 @@ struct FileTransfer {
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.
progline must be at lesat MAX_STR_SIZE bytes */
void init_progress_bar(char *progline);
diff --git a/src/friendlist.c b/src/friendlist.c
index 85411b9..7d3851f 100644
--- a/src/friendlist.c
+++ b/src/friendlist.c
@@ -133,17 +133,24 @@ void kill_friendlist(void)
#define TEMP_BLOCKLIST_EXT ".tmp"
static int save_blocklist(char *path)
{
- if (path == NULL)
+ if (path == NULL) {
return -1;
+ }
int len = sizeof(BlockedFriend) * Blocked.num_blocked;
- char data[len];
+ char *data = malloc(len * sizeof(char));
+
+ if (data == NULL) {
+ return -1;
+ }
int i, count = 0;
for (i = 0; i < Blocked.max_idx; ++i) {
- if (count > Blocked.num_blocked)
+ if (count > Blocked.num_blocked) {
+ free(data);
return -1;
+ }
if (Blocked.list[i].active) {
BlockedFriend tmp;
@@ -164,8 +171,11 @@ static int save_blocklist(char *path)
/* Blocklist is empty, we can remove the empty file */
if (count == 0) {
- if (remove(path) != 0)
+ free(data);
+
+ if (remove(path) != 0) {
return -1;
+ }
return 0;
}
@@ -175,19 +185,24 @@ static int save_blocklist(char *path)
FILE *fp = fopen(temp_path, "wb");
- if (fp == NULL)
+ if (fp == NULL) {
+ free(data);
return -1;
+ }
if (fwrite(data, len, 1, fp) != 1) {
fprintf(stderr, "Failed to write blocklist data.\n");
fclose(fp);
+ free(data);
return -1;
}
fclose(fp);
+ free(data);
- if (rename(temp_path, path) != 0)
+ if (rename(temp_path, path) != 0) {
return -1;
+ }
return 0;
}
@@ -753,7 +768,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return;
switch (key) {
- case '\n':
+ case '\r':
if (blocklist_view)
break;
diff --git a/src/global_commands.c b/src/global_commands.c
index 9f5dbd9..e3588b1 100644
--- a/src/global_commands.c
+++ b/src/global_commands.c
@@ -36,6 +36,7 @@
#include "avatars.h"
#include "name_lookup.h"
#include "qr_code.h"
+#include "toxic_strings.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
diff --git a/src/groupchat.c b/src/groupchat.c
index aaf50ac..db78b1d 100644
--- a/src/groupchat.c
+++ b/src/groupchat.c
@@ -1090,7 +1090,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return;
}
- if (ltr) { /* char is printable */
+ if (ctx->pastemode && key == '\r')
+ key = '\n';
+
+ if (ltr || key == '\n') { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
return;
}
@@ -1133,40 +1136,43 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else if (key == user_settings->key_peer_list_up) {
if (chat->side_pos > 0)
--chat->side_pos;
- } else if (key == '\n') {
+ } else if (key == '\r') {
rm_trailing_spaces_buf(ctx);
- char line[MAX_STR_SIZE];
-
- if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
- memset(&line, 0, sizeof(line));
-
- if (!string_is_empty(line))
+ if (!wstring_is_empty(ctx->line)) {
add_line_to_hist(ctx);
- if (line[0] == '/') {
- if (strncmp(line, "/close", strlen("/close")) == 0) {
- int offset = 6;
+ wstrsubst(ctx->line, L'¶', L'\n');
- if (line[offset] != '\0')
- ++offset;
+ char line[MAX_STR_SIZE];
- exit_groupchat(self, m, self->num, line + offset, ctx->len - offset);
- return;
- } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
- send_group_message(self, m, self->num, line + 4, TOX_MESSAGE_TYPE_ACTION);
- } else if (strncmp(line, "/whisper ", strlen("/whisper ")) == 0) {
- send_group_prvt_message(self, m, self->num, line + 9, ctx->len - 9);
+ if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
+ memset(&line, 0, sizeof(line));
+
+ if (line[0] == '/') {
+ if (strncmp(line, "/close", strlen("/close")) == 0) {
+ int offset = 6;
+
+ if (line[offset] != '\0')
+ ++offset;
+
+ exit_groupchat(self, m, self->num, line + offset, ctx->len - offset);
+ return;
+ } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
+ send_group_message(self, m, self->num, line + 4, TOX_MESSAGE_TYPE_ACTION);
+ } else if (strncmp(line, "/whisper ", strlen("/whisper ")) == 0) {
+ send_group_prvt_message(self, m, self->num, line + 9, ctx->len - 9);
+ } else {
+ execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
+ }
} else {
- execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
+ send_group_message(self, m, self->num, line, TOX_MESSAGE_TYPE_NORMAL);
}
- } else if (!string_is_empty(line)) {
- send_group_message(self, m, self->num, line, TOX_MESSAGE_TYPE_NORMAL);
- }
- wclear(ctx->linewin);
- wmove(self->window, y2 - CURS_Y_OFFSET, 0);
- reset_buf(ctx);
+ wclear(ctx->linewin);
+ wmove(self->window, y2 - CURS_Y_OFFSET, 0);
+ reset_buf(ctx);
+ }
}
}
diff --git a/src/help.c b/src/help.c
index 57895a4..90a9486 100644
--- a/src/help.c
+++ b/src/help.c
@@ -245,7 +245,9 @@ static void help_draw_keys(ToxWindow *self)
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n");
- wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n\n");
+ wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n");
+ wprintw(win, " Ctrl+J : Insert new line\n");
+ wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
help_draw_bottom_menu(win);
@@ -360,7 +362,7 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'k':
- help_init_window(self, 13, 80);
+ help_init_window(self, 15, 80);
self->help->type = HELP_KEYS;
break;
diff --git a/src/input.c b/src/input.c
index 4186c4d..649dad9 100644
--- a/src/input.c
+++ b/src/input.c
@@ -42,9 +42,12 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
{
ChatContext *ctx = self->chatwin;
+ /* this is the only place we need to do this check */
+ if (key == '\n')
+ key = L'¶';
+
int cur_len = wcwidth(key);
- /* this is the only place we need to do this check */
if (cur_len == -1) {
sound_notify(self, notif_error, 0, NULL);
return;
@@ -266,15 +269,19 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
/* TODO: this special case is ugly.
maybe convert entire function to if/else and make them all customizable keys? */
- if (!match && key == user_settings->key_toggle_peerlist) {
- if (self->is_groupchat) {
- self->show_peerlist ^= 1;
- redraw_groupchat_win(self);
+ if (!match) {
+ if (key == user_settings->key_toggle_peerlist) {
+ if (self->is_groupchat) {
+ self->show_peerlist ^= 1;
+ redraw_groupchat_win(self);
+ }
+ match = true;
+ }
+ else if (key == user_settings->key_toggle_pastemode) {
+ self->chatwin->pastemode ^= 1;
+ match = true;
}
-
- match = true;
}
-
return match;
}
diff --git a/src/line_info.c b/src/line_info.c
index 67a6715..ddc1af2 100644
--- a/src/line_info.c
+++ b/src/line_info.c
@@ -333,17 +333,27 @@ void line_info_print(ToxWindow *self)
line->name1);
wattroff(win, COLOR_PAIR(nameclr));
- if (line->msg[0] == '>')
- wattron(win, COLOR_PAIR(GREEN));
- else if (line->msg[0] == '<')
- wattron(win, COLOR_PAIR(RED));
+ char* msg = line->msg;
+ while (msg)
+ {
+ char* line = strsep(&msg, "\n");
- wprintw(win, "%s", line->msg);
+ if (line[0] == '>')
+ wattron(win, COLOR_PAIR(GREEN));
+ else if (line[0] == '<')
+ wattron(win, COLOR_PAIR(RED));
- if (line->msg[0] == '>')
- wattroff(win, COLOR_PAIR(GREEN));
- else if (line->msg[0] == '<')
- wattroff(win, COLOR_PAIR(RED));
+ wprintw(win, "%s%c", line, msg ? '\n' : '\0');
+
+ if (line[0] == '>')
+ wattroff(win, COLOR_PAIR(GREEN));
+ else if (line[0] == '<')
+ wattroff(win, COLOR_PAIR(RED));
+
+ // change the \0 set by strsep back to \n
+ if (msg)
+ msg[-1] = '\n';
+ }
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
wattron(win, COLOR_PAIR(RED));
diff --git a/src/misc_tools.c b/src/misc_tools.c
index c3ddf73..eee59db 100644
--- a/src/misc_tools.c
+++ b/src/misc_tools.c
@@ -194,6 +194,15 @@ int string_is_empty(const char *string)
return string[0] == '\0';
}
+/* Returns 1 if the string is empty, 0 otherwise */
+int wstring_is_empty(const wchar_t *string)
+{
+ if (!string)
+ return true;
+
+ return string[0] == L'\0';
+}
+
/* convert a multibyte string to a wide character string and puts in buf. */
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
{
diff --git a/src/misc_tools.h b/src/misc_tools.h
index d4c22f7..79b7af1 100644
--- a/src/misc_tools.h
+++ b/src/misc_tools.h
@@ -81,6 +81,9 @@ void update_unix_time(void);
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(const char *string);
+/* Same as above but for wide character strings */
+int wstring_is_empty(const wchar_t *string);
+
/* convert a multibyte string to a wide character string (must provide buffer) */
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
diff --git a/src/notify.c b/src/notify.c
index f6a2fcf..093ad95 100644
--- a/src/notify.c
+++ b/src/notify.c
@@ -234,17 +234,17 @@ void* do_playing(void* _p)
}
bool has_looping = false;
+ bool test_active_notify = false;
int i;
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].looping) has_looping = true;
-
- if (actives[i].active && !actives[i].looping
- #ifdef BOX_NOTIFY
- && !actives[i].box
- #endif
- ) {
+ test_active_notify = actives[i].active && !actives[i].looping;
+ #ifdef BOX_NOTIFY
+ test_active_notify = test_active_notify && !actives[i].box;
+ #endif
+ if (test_active_notify) {
if(actives[i].id_indicator)
*actives[i].id_indicator = -1; /* reset indicator value */
@@ -580,7 +580,6 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
alDeleteSources(1, &actives[id].source);
alDeleteBuffers(1,&actives[id].buffer);
-
alGenSources(1, &actives[id].source);
alGenBuffers(1, &actives[id].buffer);
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
diff --git a/src/prompt.c b/src/prompt.c
index b349143..77e48d1 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -190,13 +190,16 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (x2 <= 0 || y2 <= 0)
return;
+ if (ctx->pastemode && key == '\r')
+ key = '\n';
+
/* ignore non-menu related input if active */
if (self->help->active) {
help_onKey(self, key);
return;
}
- if (ltr) { /* char is printable */
+ if (ltr || key == '\n') { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
return;
}
@@ -233,19 +236,22 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else {
sound_notify(self, notif_error, 0, NULL);
}
- } else if (key == '\n') {
+ } else if (key == '\r') {
rm_trailing_spaces_buf(ctx);
- char line[MAX_STR_SIZE] = {0};
-
- if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
- memset(&line, 0, sizeof(line));
-
- if (!string_is_empty(line))
+ if (!wstring_is_empty(ctx->line))
+ {
add_line_to_hist(ctx);
+ wstrsubst(ctx->line, L'¶', L'\n');
- line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
- execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
+ char line[MAX_STR_SIZE] = {0};
+
+ if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
+ memset(&line, 0, sizeof(line));
+
+ line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
+ execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
+ }
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
@@ -384,6 +390,10 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
get_time_str(timefrmt, sizeof(timefrmt));
const char *msg;
+ if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
+ return;
+ }
+
if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) {
msg = "has come online";
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
diff --git a/src/settings.c b/src/settings.c
index 7c4ac36..47b1af8 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -57,6 +57,7 @@ static struct ui_strings {
const char* show_typing_self;
const char* show_typing_other;
const char* show_welcome_msg;
+ const char* show_connection_msg;
const char* line_join;
const char* line_quit;
@@ -79,6 +80,7 @@ static struct ui_strings {
"show_typing_self",
"show_typing_other",
"show_welcome_msg",
+ "show_connection_msg",
"line_join",
"line_quit",
"line_alert",
@@ -101,6 +103,7 @@ static void ui_defaults(struct user_settings* settings)
settings->show_typing_self = SHOW_TYPING_ON;
settings->show_typing_other = SHOW_TYPING_ON;
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
+ settings->show_connection_msg = SHOW_CONNECTION_MSG_ON;
snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN);
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
@@ -127,6 +130,7 @@ static const struct keys_strings {
const char* peer_list_up;
const char* peer_list_down;
const char* toggle_peerlist;
+ const char* toggle_pastemode;
} key_strings = {
"keys",
"next_tab",
@@ -139,6 +143,7 @@ static const struct keys_strings {
"peer_list_up",
"peer_list_down",
"toggle_peerlist",
+ "toggle_paste_mode",
};
/* defines from toxic.h */
@@ -154,6 +159,7 @@ static void key_defaults(struct user_settings* settings)
settings->key_peer_list_up = T_KEY_C_LB;
settings->key_peer_list_down = T_KEY_C_RB;
settings->key_toggle_peerlist = T_KEY_C_B;
+ settings->key_toggle_pastemode = T_KEY_C_T;
}
static const struct tox_strings {
@@ -161,11 +167,13 @@ static const struct tox_strings {
const char* download_path;
const char* chatlogs_path;
const char* avatar_path;
+ const char* password_eval;
} tox_strings = {
"tox",
"download_path",
"chatlogs_path",
"avatar_path",
+ "password_eval",
};
static void tox_defaults(struct user_settings* settings)
@@ -173,6 +181,7 @@ static void tox_defaults(struct user_settings* settings)
strcpy(settings->download_path, "");
strcpy(settings->chatlogs_path, "");
strcpy(settings->avatar_path, "");
+ strcpy(settings->password_eval, "");
}
#ifdef AUDIO
@@ -224,11 +233,11 @@ static const struct sound_strings {
};
#endif
-static int key_parse(const char** bind){
+static int key_parse(const char **bind) {
int len = strlen(*bind);
if (len > 5) {
- if(strncasecmp(*bind, "ctrl+", 5) == 0)
+ if(strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
return toupper(bind[0][5]) - 'A' + 1;
}
@@ -241,6 +250,14 @@ static int key_parse(const char** bind){
return -1;
}
+static void set_key_binding(int *key, const char **bind) {
+ int code = key_parse(bind);
+
+ if (code != -1) {
+ *key = code;
+ }
+}
+
int settings_load(struct user_settings *s, const char *patharg)
{
config_t cfg[1];
@@ -311,6 +328,7 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_bool(setting, ui_strings.show_typing_self, &s->show_typing_self);
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg);
+ config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg);
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
@@ -365,31 +383,41 @@ int settings_load(struct user_settings *s, const char *patharg)
if (len >= sizeof(s->avatar_path))
s->avatar_path[0] = '\0';
}
+
+ if ( config_setting_lookup_string(setting, tox_strings.password_eval, &str) ) {
+ snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
+ int len = strlen(str);
+
+ if (len >= sizeof(s->password_eval))
+ s->password_eval[0] = '\0';
+ }
}
/* keys */
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
const char* tmp = NULL;
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
- s->key_next_tab = key_parse(&tmp);
+ set_key_binding(&s->key_next_tab, &tmp);
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
- s->key_prev_tab = key_parse(&tmp);
+ set_key_binding(&s->key_prev_tab, &tmp);
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
- s->key_scroll_line_up = key_parse(&tmp);
+ set_key_binding(&s->key_scroll_line_up, &tmp);
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
- s->key_scroll_line_down= key_parse(&tmp);
+ set_key_binding(&s->key_scroll_line_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
- s->key_half_page_up = key_parse(&tmp);
+ set_key_binding(&s->key_half_page_up, &tmp);
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
- s->key_half_page_down = key_parse(&tmp);
+ set_key_binding(&s->key_half_page_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
- s->key_page_bottom = key_parse(&tmp);
+ set_key_binding(&s->key_page_bottom, &tmp);
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
- s->key_peer_list_up = key_parse(&tmp);
+ set_key_binding(&s->key_peer_list_up, &tmp);
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
- s->key_peer_list_down = key_parse(&tmp);
+ set_key_binding(&s->key_peer_list_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
- s->key_toggle_peerlist = key_parse(&tmp);
+ set_key_binding(&s->key_toggle_peerlist, &tmp);
+ if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
+ set_key_binding(&s->key_toggle_pastemode, &tmp);
}
#ifdef AUDIO
diff --git a/src/settings.h b/src/settings.h
index 1e51c7b..9bc9353 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -30,6 +30,8 @@
/* Represents line_* hints max strlen */
#define LINE_HINT_MAX 3
+#define PASSWORD_EVAL_MAX 512
+
/* holds user setting values */
struct user_settings {
int autolog; /* boolean */
@@ -44,6 +46,7 @@ struct user_settings {
int show_typing_self; /* boolean */
int show_typing_other; /* boolean */
int show_welcome_msg; /* boolean */
+ int show_connection_msg; /* boolean */
char line_join[LINE_HINT_MAX + 1];
char line_quit[LINE_HINT_MAX + 1];
@@ -54,6 +57,7 @@ struct user_settings {
char download_path[PATH_MAX];
char chatlogs_path[PATH_MAX];
char avatar_path[PATH_MAX];
+ char password_eval[PASSWORD_EVAL_MAX];
int key_next_tab;
int key_prev_tab;
@@ -65,6 +69,7 @@ struct user_settings {
int key_peer_list_up;
int key_peer_list_down;
int key_toggle_peerlist;
+ int key_toggle_pastemode;
int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */
char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH];
@@ -95,6 +100,9 @@ enum {
SHOW_WELCOME_MSG_OFF = 0,
SHOW_WELCOME_MSG_ON = 1,
+ SHOW_CONNECTION_MSG_OFF = 0,
+ SHOW_CONNECTION_MSG_ON = 1,
+
DFLT_HST_SIZE = 700,
MPLEX_OFF = 0,
diff --git a/src/toxic.c b/src/toxic.c
index fc59f64..f4aeb4b 100644
--- a/src/toxic.c
+++ b/src/toxic.c
@@ -39,6 +39,7 @@
#include
#include
#include
+#include
#include
#include
@@ -200,6 +201,7 @@ static void init_term(void)
cbreak();
keypad(stdscr, 1);
noecho();
+ nonl();
timeout(100);
if (has_colors()) {
@@ -484,6 +486,45 @@ static int password_prompt(char *buf, int size)
return len;
}
+/* Get the password from the eval command.
+ * return length of password on success, 0 on failure
+ */
+static int password_eval(char *buf, int size)
+{
+ buf[0] = '\0';
+
+ /* Run password_eval command */
+ FILE *f = popen(user_settings->password_eval, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Executing password_eval failed\n");
+ return 0;
+ }
+
+ /* Get output from command */
+ char *ret = fgets(buf, size, f);
+ if (ret == NULL) {
+ fprintf(stderr, "Reading password from password_eval command failed\n");
+ pclose(f);
+ return 0;
+ }
+
+ /* Get exit status */
+ int status = pclose(f);
+ if (status != 0) {
+ fprintf(stderr, "password_eval command returned error %d\n", status);
+ return 0;
+ }
+
+ /* Removez whitespace or \n at end */
+ int i, len = strlen(buf);
+ for (i = len - 1; i > 0 && isspace(buf[i]); i--) {
+ buf[i] = 0;
+ len--;
+ }
+
+ return len;
+}
+
/* Ask user if they would like to encrypt the data file and set password */
static void first_time_encrypt(const char *msg)
{
@@ -555,25 +596,36 @@ static void first_time_encrypt(const char *msg)
#define TEMP_PROFILE_EXT ".tmp"
int store_data(Tox *m, const char *path)
{
- if (path == NULL)
+ if (path == NULL) {
return -1;
+ }
char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1];
snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT);
FILE *fp = fopen(temp_path, "wb");
- if (fp == NULL)
+ if (fp == NULL) {
return -1;
+ }
size_t data_len = tox_get_savedata_size(m);
- char data[data_len];
+ char *data = malloc(data_len * sizeof(char));
+
+ if (data == NULL) {
+ return -1;
+ }
tox_get_savedata(m, (uint8_t *) data);
if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
size_t enc_len = data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
- char enc_data[enc_len];
+ char *enc_data = malloc(enc_len * sizeof(char));
+
+ if (enc_data == NULL) {
+ free(data);
+ return -1;
+ }
TOX_ERR_ENCRYPTION err;
tox_pass_encrypt((uint8_t *) data, data_len, (uint8_t *) user_password.pass, user_password.len,
@@ -582,26 +634,33 @@ int store_data(Tox *m, const char *path)
if (err != TOX_ERR_ENCRYPTION_OK) {
fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err);
fclose(fp);
+ free(data);
+ free(enc_data);
return -1;
}
if (fwrite(enc_data, enc_len, 1, fp) != 1) {
fprintf(stderr, "Failed to write profile data.\n");
fclose(fp);
+ free(data);
+ free(enc_data);
return -1;
}
} else { /* data will not be encrypted */
if (fwrite(data, data_len, 1, fp) != 1) {
fprintf(stderr, "Failed to write profile data.\n");
fclose(fp);
+ free(data);
return -1;
}
}
fclose(fp);
+ free(data);
- if (rename(temp_path, path) != 0)
+ if (rename(temp_path, path) != 0) {
return -1;
+ }
return 0;
}
@@ -714,14 +773,21 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
user_password.data_is_encrypted = true;
size_t pwlen = 0;
- system("clear"); // TODO: is this portable?
- printf("Enter password (q to quit) ");
+ int pweval = user_settings->password_eval[0];
+ if (!pweval) {
+ system("clear"); // TODO: is this portable?
+ printf("Enter password (q to quit) ");
+ }
size_t plain_len = len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
char plain[plain_len];
while (true) {
- pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
+ if (pweval) {
+ pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
+ } else {
+ pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
+ }
user_password.len = pwlen;
if (strcasecmp(user_password.pass, "q") == 0) {
@@ -733,6 +799,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
system("clear");
sleep(1);
printf("Invalid password. Try again. ");
+ pweval = 0;
continue;
}
@@ -757,6 +824,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
system("clear");
sleep(1);
printf("Invalid password. Try again. ");
+ pweval = 0;
} else {
fclose(fp);
exit_toxic_err("tox_pass_decrypt() failed", pwerr);
@@ -859,7 +927,6 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
tox_iterate(m);
do_bootstrap(m);
- check_file_transfer_timeouts(m);
pthread_mutex_unlock(&Winthread.lock);
}
@@ -1198,25 +1265,6 @@ static void init_default_data_files(void)
free(user_config_dir);
}
-#define REC_TOX_DO_LOOPS_PER_SEC 25
-
-/* 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)
-{
- useconds_t new_sleep = MAX(msleepval, 3);
- ++(*loopcount);
-
- if (*looptimer == cur_time)
- return new_sleep;
-
- if (*loopcount != REC_TOX_DO_LOOPS_PER_SEC)
- new_sleep *= (double) *loopcount / REC_TOX_DO_LOOPS_PER_SEC;
-
- *looptimer = cur_time;
- *loopcount = 0;
- return new_sleep;
-}
-
// this doesn't do anything (yet)
#ifdef X11
void DnD_callback(const char* asdv, DropType dt)
@@ -1350,9 +1398,6 @@ int main(int argc, char **argv)
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
uint64_t last_save = (uint64_t) time(NULL);
- uint64_t looptimer = last_save;
- useconds_t msleepval = 40000;
- uint64_t loopcount = 0;
while (true) {
do_toxic(m, prompt);
@@ -1368,8 +1413,7 @@ int main(int argc, char **argv)
last_save = cur_time;
}
- msleepval = optimal_msleepval(&looptimer, &loopcount, cur_time, msleepval);
- usleep(msleepval);
+ usleep(tox_iteration_interval(m) * 1000);
}
return 0;
diff --git a/src/toxic.h b/src/toxic.h
index 1111aae..7758e2a 100644
--- a/src/toxic.h
+++ b/src/toxic.h
@@ -70,6 +70,7 @@
#define T_KEY_C_L 0x0C /* ctrl-l */
#define T_KEY_C_W 0x17 /* ctrl-w */
#define T_KEY_C_B 0x02 /* ctrl-b */
+#define T_KEY_C_T 0x14 /* ctrl-t */
#define T_KEY_TAB 0x09 /* TAB key */
#define ONLINE_CHAR "*"
diff --git a/src/toxic_strings.c b/src/toxic_strings.c
index e2417ba..e17c5bb 100644
--- a/src/toxic_strings.c
+++ b/src/toxic_strings.c
@@ -166,19 +166,19 @@ void reset_buf(ChatContext *ctx)
ctx->start = 0;
}
-/* Removes trailing spaces from line. */
+/* Removes trailing spaces and newlines from line. */
void rm_trailing_spaces_buf(ChatContext *ctx)
{
if (ctx->len <= 0)
return;
- if (ctx->line[ctx->len - 1] != ' ')
+ if (ctx->line[ctx->len - 1] != ' ' && ctx->line[ctx->len - 1] != L'¶')
return;
int i;
for (i = ctx->len - 1; i >= 0; --i) {
- if (ctx->line[i] != ' ')
+ if (ctx->line[i] != ' ' && ctx->line[i] != L'¶')
break;
}
@@ -242,3 +242,19 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
ctx->pos = h_len;
ctx->len = h_len;
}
+
+void strsubst(char* str, char old, char new)
+{
+ int i;
+ for (i = 0; str[i] != '\0'; ++i)
+ if (str[i] == old)
+ str[i] = new;
+}
+
+void wstrsubst(wchar_t* str, wchar_t old, wchar_t new)
+{
+ int i;
+ for (i = 0; str[i] != L'\0'; ++i)
+ if (str[i] == old)
+ str[i] = new;
+}
diff --git a/src/toxic_strings.h b/src/toxic_strings.h
index 3c957ef..c9e402c 100644
--- a/src/toxic_strings.h
+++ b/src/toxic_strings.h
@@ -66,4 +66,8 @@ void add_line_to_hist(ChatContext *ctx);
resets line if at end of history */
void fetch_hist_item(ChatContext *ctx, int key_dir);
+/* Substitutes all occurrences of old with new. */
+void strsubst(char *str, char old, char new);
+void wstrsubst(wchar_t *str, wchar_t old, wchar_t new);
+
#endif /* #define TOXIC_STRINGS_H */
diff --git a/src/windows.h b/src/windows.h
index cffb747..ad49525 100644
--- a/src/windows.h
+++ b/src/windows.h
@@ -247,6 +247,7 @@ struct ChatContext {
#endif
uint8_t self_is_typing;
+ uint8_t pastemode; /* whether to translate \r to \n */
WINDOW *history;
WINDOW *linewin;