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;