mirror of
https://git.jabber.space/devs/cproof.git
synced 2026-07-31 05:16:21 +00:00
feat: Implement color coded status messages for file transfers
Introduce meaningful color feedback for background tasks like file downloads and uploads. Progress is displayed in a neutral color, while successful completions turn green and failures turn red. We reuse the existing THEME colors for now. Add new UI flags ENTRY_COMPLETED and ENTRY_ERROR to the buffer entry system. So we don't misuse delivery receipts anymore. Fixes: https://github.com/profanity-im/profanity/issues/1758 Signed-off-by: Michael Vetter <jubalh@iodoru.org>
This commit is contained in:
@@ -43,7 +43,7 @@ aesgcm_file_get(void* userdata)
|
|||||||
// and tag stored in the URL fragment.
|
// and tag stored in the URL fragment.
|
||||||
if (omemo_parse_aesgcm_url(aesgcm_dl->url, &https_url, &fragment) != 0) {
|
if (omemo_parse_aesgcm_url(aesgcm_dl->url, &https_url, &fragment) != 0) {
|
||||||
cons_show_error("Download failed: Cannot parse URL '%s'.", aesgcm_dl->url);
|
cons_show_error("Download failed: Cannot parse URL '%s'.", aesgcm_dl->url);
|
||||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Download failed: Cannot parse URL '%s'.",
|
"Download failed: Cannot parse URL '%s'.",
|
||||||
aesgcm_dl->url);
|
aesgcm_dl->url);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -54,7 +54,7 @@ aesgcm_file_get(void* userdata)
|
|||||||
auto_gchar gchar* tmpname = NULL;
|
auto_gchar gchar* tmpname = NULL;
|
||||||
auto_gfd gint tmpfd = 0;
|
auto_gfd gint tmpfd = 0;
|
||||||
if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmpname, NULL)) == -1) {
|
if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmpname, NULL)) == -1) {
|
||||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: Unable to create "
|
"Downloading '%s' failed: Unable to create "
|
||||||
"temporary ciphertext file for writing "
|
"temporary ciphertext file for writing "
|
||||||
"(%s).",
|
"(%s).",
|
||||||
@@ -65,7 +65,7 @@ aesgcm_file_get(void* userdata)
|
|||||||
// Open the target file for storing the cleartext.
|
// Open the target file for storing the cleartext.
|
||||||
auto_FILE FILE* outfh = fopen(aesgcm_dl->filename, "wb");
|
auto_FILE FILE* outfh = fopen(aesgcm_dl->filename, "wb");
|
||||||
if (outfh == NULL) {
|
if (outfh == NULL) {
|
||||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: Unable to open "
|
"Downloading '%s' failed: Unable to open "
|
||||||
"output file at '%s' for writing (%s).",
|
"output file at '%s' for writing (%s).",
|
||||||
https_url, aesgcm_dl->filename,
|
https_url, aesgcm_dl->filename,
|
||||||
@@ -97,7 +97,7 @@ aesgcm_file_get(void* userdata)
|
|||||||
|
|
||||||
FILE* tmpfh = fopen(tmpname, "rb");
|
FILE* tmpfh = fopen(tmpname, "rb");
|
||||||
if (tmpfh == NULL) {
|
if (tmpfh == NULL) {
|
||||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: Unable to open "
|
"Downloading '%s' failed: Unable to open "
|
||||||
"temporary file at '%s' for reading (%s).",
|
"temporary file at '%s' for reading (%s).",
|
||||||
aesgcm_dl->url, tmpname,
|
aesgcm_dl->url, tmpname,
|
||||||
@@ -112,12 +112,12 @@ aesgcm_file_get(void* userdata)
|
|||||||
remove(tmpname);
|
remove(tmpname);
|
||||||
|
|
||||||
if (crypt_res != GPG_ERR_NO_ERROR) {
|
if (crypt_res != GPG_ERR_NO_ERROR) {
|
||||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: Failed to decrypt "
|
"Downloading '%s' failed: Failed to decrypt "
|
||||||
"file (%s).",
|
"file (%s).",
|
||||||
aesgcm_dl->url, gcry_strerror(crypt_res));
|
aesgcm_dl->url, gcry_strerror(crypt_res));
|
||||||
} else {
|
} else {
|
||||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ONLINE, ENTRY_COMPLETED,
|
||||||
"Downloading '%s': done\nSaved to '%s'",
|
"Downloading '%s': done\nSaved to '%s'",
|
||||||
aesgcm_dl->url, aesgcm_dl->filename);
|
aesgcm_dl->url, aesgcm_dl->filename);
|
||||||
win_mark_received(aesgcm_dl->window, aesgcm_dl->id);
|
win_mark_received(aesgcm_dl->window, aesgcm_dl->id);
|
||||||
@@ -130,7 +130,7 @@ aesgcm_file_get(void* userdata)
|
|||||||
|
|
||||||
// TODO: Log the error.
|
// TODO: Log the error.
|
||||||
if (!call_external(argv)) {
|
if (!call_external(argv)) {
|
||||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: Unable to call "
|
"Downloading '%s' failed: Unable to call "
|
||||||
"command '%s' with file at '%s' (%s).",
|
"command '%s' with file at '%s' (%s).",
|
||||||
aesgcm_dl->url,
|
aesgcm_dl->url,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#define FALLBACK_MSG ""
|
#define FALLBACK_MSG ""
|
||||||
|
|
||||||
void
|
void
|
||||||
http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...)
|
http_print_transfer_update(ProfWin* window, char* id, theme_item_t theme_item, int flags, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...)
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
if (window->type != WIN_CONSOLE) {
|
if (window->type != WIN_CONSOLE) {
|
||||||
win_update_entry_message(window, id, msg->str);
|
win_update_entry(window, id, msg->str, theme_item, flags);
|
||||||
} else {
|
} else {
|
||||||
cons_show("%s", msg->str);
|
cons_show("%s", msg->str);
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
http_print_transfer(ProfWin* window, char* id, const char* fmt, ...)
|
http_print_transfer(ProfWin* window, char* id, theme_item_t theme_item, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ http_print_transfer(ProfWin* window, char* id, const char* fmt, ...)
|
|||||||
g_string_vprintf(msg, fmt, args);
|
g_string_vprintf(msg, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
win_print_http_transfer(window, msg->str, id);
|
win_print_status_with_id(window, msg->str, id, theme_item, 0);
|
||||||
|
|
||||||
g_string_free(msg, TRUE);
|
g_string_free(msg, TRUE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#include "ui/window.h"
|
#include "ui/window.h"
|
||||||
|
|
||||||
void http_print_transfer(ProfWin* window, char* id, const char* fmt, ...);
|
void http_print_transfer(ProfWin* window, char* id, theme_item_t theme_item, const char* fmt, ...);
|
||||||
void http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...);
|
void http_print_transfer_update(ProfWin* window, char* id, theme_item_t theme_item, int flags, const char* fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -60,10 +60,12 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot
|
|||||||
if (!download->silent) {
|
if (!download->silent) {
|
||||||
const char* url = download->display_url ? download->display_url : download->url;
|
const char* url = download->display_url ? download->display_url : download->url;
|
||||||
if (dlnow == dltotal && dltotal > 0) {
|
if (dlnow == dltotal && dltotal > 0) {
|
||||||
http_print_transfer_update(download->window, download->id,
|
if (!download->silent_done) {
|
||||||
"Downloading '%s': done", url);
|
http_print_transfer_update(download->window, download->id, THEME_ONLINE, ENTRY_COMPLETED,
|
||||||
|
"Downloading '%s': done", url);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
http_print_transfer_update(download->window, download->id,
|
http_print_transfer_update(download->window, download->id, THEME_DEFAULT, 0,
|
||||||
"Downloading '%s': %d%%", url, dlperc);
|
"Downloading '%s': %d%%", url, dlperc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,13 +100,13 @@ http_file_get(void* userdata)
|
|||||||
pthread_mutex_lock(&lock);
|
pthread_mutex_lock(&lock);
|
||||||
const char* display_url = download->display_url ? download->display_url : download->url;
|
const char* display_url = download->display_url ? download->display_url : download->url;
|
||||||
if (!download->silent) {
|
if (!download->silent) {
|
||||||
http_print_transfer(download->window, download->id,
|
http_print_transfer(download->window, download->id, THEME_DEFAULT,
|
||||||
"Downloading '%s': 0%%", display_url);
|
"Downloading '%s': 0%%", display_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* outfh = fopen(download->filename, "wb");
|
FILE* outfh = fopen(download->filename, "wb");
|
||||||
if (outfh == NULL) {
|
if (outfh == NULL) {
|
||||||
http_print_transfer_update(download->window, download->id,
|
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: Unable to open "
|
"Downloading '%s' failed: Unable to open "
|
||||||
"output file at '%s' for writing (%s).",
|
"output file at '%s' for writing (%s).",
|
||||||
download->url, download->filename,
|
download->url, download->filename,
|
||||||
@@ -175,22 +177,24 @@ http_file_get(void* userdata)
|
|||||||
g_free(cert_path);
|
g_free(cert_path);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (download->cancel) {
|
if (download->cancel) {
|
||||||
http_print_transfer_update(download->window, download->id,
|
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: "
|
"Downloading '%s' failed: "
|
||||||
"Download was canceled",
|
"Download was canceled",
|
||||||
display_url);
|
display_url);
|
||||||
} else {
|
} else {
|
||||||
http_print_transfer_update(download->window, download->id,
|
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: %s",
|
"Downloading '%s' failed: %s",
|
||||||
display_url, err);
|
display_url, err);
|
||||||
}
|
}
|
||||||
free(err);
|
free(err);
|
||||||
} else {
|
} else {
|
||||||
if (!download->cancel && !download->silent && !download->silent_done) {
|
if (!download->cancel) {
|
||||||
http_print_transfer_update(download->window, download->id,
|
if (!download->silent && !download->silent_done) {
|
||||||
"Downloading '%s': done\nSaved to '%s'",
|
http_print_transfer_update(download->window, download->id, THEME_ONLINE, ENTRY_COMPLETED,
|
||||||
display_url, download->filename);
|
"Downloading '%s': done\nSaved to '%s'",
|
||||||
win_mark_received(download->window, download->id);
|
display_url, download->filename);
|
||||||
|
win_mark_received(download->window, download->id);
|
||||||
|
}
|
||||||
if (download->return_bytes_received) {
|
if (download->return_bytes_received) {
|
||||||
ret = malloc(sizeof(*ret));
|
ret = malloc(sizeof(*ret));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -207,7 +211,7 @@ http_file_get(void* userdata)
|
|||||||
|
|
||||||
// TODO: Log the error.
|
// TODO: Log the error.
|
||||||
if (!call_external(argv)) {
|
if (!call_external(argv)) {
|
||||||
http_print_transfer_update(download->window, download->id,
|
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
|
||||||
"Downloading '%s' failed: Unable to call "
|
"Downloading '%s' failed: Unable to call "
|
||||||
"command '%s' with file at '%s' (%s).",
|
"command '%s' with file at '%s' (%s).",
|
||||||
display_url,
|
display_url,
|
||||||
|
|||||||
@@ -66,8 +66,12 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot
|
|||||||
}
|
}
|
||||||
|
|
||||||
gchar* msg = NULL;
|
gchar* msg = NULL;
|
||||||
|
theme_item_t theme = THEME_DEFAULT;
|
||||||
|
int flags = 0;
|
||||||
if (ulnow == ultotal && ultotal > 0) {
|
if (ulnow == ultotal && ultotal > 0) {
|
||||||
msg = g_strdup_printf("Uploading '%s': done", upload->filename);
|
msg = g_strdup_printf("Uploading '%s': done", upload->filename);
|
||||||
|
theme = THEME_ONLINE;
|
||||||
|
flags = ENTRY_COMPLETED;
|
||||||
} else {
|
} else {
|
||||||
msg = g_strdup_printf("Uploading '%s': %d%%", upload->filename, ulperc);
|
msg = g_strdup_printf("Uploading '%s': %d%%", upload->filename, ulperc);
|
||||||
}
|
}
|
||||||
@@ -75,7 +79,7 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot
|
|||||||
if (!msg) {
|
if (!msg) {
|
||||||
msg = g_strdup(FALLBACK_MSG);
|
msg = g_strdup(FALLBACK_MSG);
|
||||||
}
|
}
|
||||||
win_update_entry_message(upload->window, upload->put_url, msg);
|
win_update_entry(upload->window, upload->put_url, msg, theme, flags);
|
||||||
g_free(msg);
|
g_free(msg);
|
||||||
|
|
||||||
pthread_mutex_unlock(&lock);
|
pthread_mutex_unlock(&lock);
|
||||||
@@ -156,7 +160,7 @@ http_file_put(void* userdata)
|
|||||||
if (!msg) {
|
if (!msg) {
|
||||||
msg = g_strdup(FALLBACK_MSG);
|
msg = g_strdup(FALLBACK_MSG);
|
||||||
}
|
}
|
||||||
win_print_http_transfer(upload->window, msg, upload->put_url);
|
win_print_status_with_id(upload->window, msg, upload->put_url, THEME_DEFAULT, 0);
|
||||||
|
|
||||||
auto_gchar gchar* cert_path = prefs_get_string(PREF_TLS_CERTPATH);
|
auto_gchar gchar* cert_path = prefs_get_string(PREF_TLS_CERTPATH);
|
||||||
auto_gchar gchar* cafile = cafile_get_name();
|
auto_gchar gchar* cafile = cafile_get_name();
|
||||||
@@ -284,12 +288,13 @@ http_file_put(void* userdata)
|
|||||||
if (!err_msg) {
|
if (!err_msg) {
|
||||||
err_msg = g_strdup(FALLBACK_MSG);
|
err_msg = g_strdup(FALLBACK_MSG);
|
||||||
}
|
}
|
||||||
|
win_update_entry(upload->window, upload->put_url, err_msg, THEME_ERROR, ENTRY_ERROR);
|
||||||
} else {
|
} else {
|
||||||
err_msg = g_strdup_printf("Uploading '%s' failed: %s", upload->filename, err);
|
err_msg = g_strdup_printf("Uploading '%s' failed: %s", upload->filename, err);
|
||||||
if (!err_msg) {
|
if (!err_msg) {
|
||||||
err_msg = g_strdup(FALLBACK_MSG);
|
err_msg = g_strdup(FALLBACK_MSG);
|
||||||
}
|
}
|
||||||
win_update_entry_message(upload->window, upload->put_url, err_msg);
|
win_update_entry(upload->window, upload->put_url, err_msg, THEME_ERROR, ENTRY_ERROR);
|
||||||
}
|
}
|
||||||
cons_show_error(err_msg);
|
cons_show_error(err_msg);
|
||||||
} else {
|
} else {
|
||||||
@@ -298,7 +303,7 @@ http_file_put(void* userdata)
|
|||||||
if (!status_msg) {
|
if (!status_msg) {
|
||||||
status_msg = g_strdup(FALLBACK_MSG);
|
status_msg = g_strdup(FALLBACK_MSG);
|
||||||
}
|
}
|
||||||
win_update_entry_message(upload->window, upload->put_url, status_msg);
|
win_update_entry(upload->window, upload->put_url, status_msg, THEME_ONLINE, ENTRY_COMPLETED);
|
||||||
win_mark_received(upload->window, upload->put_url);
|
win_mark_received(upload->window, upload->put_url);
|
||||||
|
|
||||||
char* url = NULL;
|
char* url = NULL;
|
||||||
|
|||||||
14
src/ui/ui.h
14
src/ui/ui.h
@@ -25,12 +25,14 @@
|
|||||||
#include "otr/otr.h"
|
#include "otr/otr.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NO_ME 1
|
#define NO_ME 1
|
||||||
#define NO_DATE 2
|
#define NO_DATE 2
|
||||||
#define NO_EOL 4
|
#define NO_EOL 4
|
||||||
#define NO_COLOUR_FROM 8
|
#define NO_COLOUR_FROM 8
|
||||||
#define NO_COLOUR_DATE 16
|
#define NO_COLOUR_DATE 16
|
||||||
#define UNTRUSTED 32
|
#define UNTRUSTED 32
|
||||||
|
#define ENTRY_COMPLETED 64
|
||||||
|
#define ENTRY_ERROR 128
|
||||||
|
|
||||||
// core UI
|
// core UI
|
||||||
void ui_init(void);
|
void ui_init(void);
|
||||||
|
|||||||
@@ -1659,7 +1659,7 @@ win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const char* con
|
|||||||
void
|
void
|
||||||
win_print_http_transfer(ProfWin* window, const char* const message, char* id)
|
win_print_http_transfer(ProfWin* window, const char* const message, char* id)
|
||||||
{
|
{
|
||||||
win_print_outgoing_with_receipt(window, "!", NULL, message, id, NULL);
|
win_print_status_with_id(window, message, id, THEME_DEFAULT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1708,6 +1708,33 @@ win_update_entry_message(ProfWin* window, const char* const id, const char* cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
win_update_entry(ProfWin* window, const char* const id, const char* const message, theme_item_t theme_item, int flags)
|
||||||
|
{
|
||||||
|
if (window->type == WIN_CONSOLE)
|
||||||
|
return;
|
||||||
|
ProfBuffEntry* entry = buffer_get_entry_by_id(window->layout->buffer, id);
|
||||||
|
if (entry) {
|
||||||
|
if (message) {
|
||||||
|
free(entry->message);
|
||||||
|
entry->message = strdup(message);
|
||||||
|
}
|
||||||
|
entry->theme_item = theme_item;
|
||||||
|
entry->flags |= flags;
|
||||||
|
win_redraw(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
win_print_status_with_id(ProfWin* window, const char* const message, char* id, theme_item_t theme_item, int flags)
|
||||||
|
{
|
||||||
|
GDateTime* time = g_date_time_new_now_local();
|
||||||
|
int y_start_pos = getcury(window->layout->win);
|
||||||
|
_win_print_internal(window, "!", 0, time, flags, theme_item, NULL, message, NULL);
|
||||||
|
buffer_append(window->layout->buffer, "!", 0, time, flags, theme_item, NULL, NULL, message, NULL, id, y_start_pos, getcury(window->layout->win));
|
||||||
|
g_date_time_unref(time);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
win_remove_entry_message(ProfWin* window, const char* const id)
|
win_remove_entry_message(ProfWin* window, const char* const id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ void win_sub_print(WINDOW* win, char* msg, gboolean newline, gboolean wrap, int
|
|||||||
void win_sub_newline_lazy(WINDOW* win);
|
void win_sub_newline_lazy(WINDOW* win);
|
||||||
void win_mark_received(ProfWin* window, const char* const id);
|
void win_mark_received(ProfWin* window, const char* const id);
|
||||||
void win_update_entry_message(ProfWin* window, const char* const id, const char* const message);
|
void win_update_entry_message(ProfWin* window, const char* const id, const char* const message);
|
||||||
|
void win_update_entry(ProfWin* window, const char* const id, const char* const message, theme_item_t theme_item, int flags);
|
||||||
|
void win_print_status_with_id(ProfWin* window, const char* const message, char* id, theme_item_t theme_item, int flags);
|
||||||
|
|
||||||
gboolean win_has_active_subwin(ProfWin* window);
|
gboolean win_has_active_subwin(ProfWin* window);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user