diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index c37cc51b..23f0b98d 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -4811,7 +4811,6 @@ cmd_sendfile(ProfWin* window, const char* const command, gchar** args) { jabber_conn_status_t conn_status = connection_get_status(); char *filename = args[0]; - char *filepath = NULL; unsigned char *key = NULL; // expand ~ to $HOME @@ -4823,7 +4822,15 @@ cmd_sendfile(ProfWin* window, const char* const command, gchar** args) filename = strdup(filename); } - filepath = strdup(filename); + if (access(filename, R_OK) != 0) { + cons_show_error("Uploading '%s' failed: File not found!", filename); + goto out; + } + + if (!is_regular_file(filename)) { + cons_show_error("Uploading '%s' failed: Not a file!", filename); + goto out; + } if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); @@ -4835,6 +4842,14 @@ cmd_sendfile(ProfWin* window, const char* const command, gchar** args) goto out; } + int fd; + if ((fd = open(filename, O_RDONLY)) == -1) { + cons_show_error("Unable to open file descriptor for '%s'.", filename); + goto out; + } + + FILE *fh = fdopen(fd, "rb"); + switch (window->type) { case WIN_MUC: case WIN_CHAT: @@ -4844,37 +4859,14 @@ cmd_sendfile(ProfWin* window, const char* const command, gchar** args) if (chatwin->is_omemo && !prefs_get_boolean(PREF_OMEMO_SENDFILE)) { int tmpfd; - GError *err = NULL; - char *tmppath = NULL; - - tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmppath, &err); - if (err != NULL) { + if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", NULL, NULL)) == -1) { cons_show_error("Unable to create temporary file for encrypted transfer."); win_println(window, THEME_ERROR, "-", "Unable to create temporary file for encrypted transfer."); + fclose(fh); goto out; } - struct stat tmpst; - if (fstat(tmpfd, &tmpst)) { - cons_show_error("Cannot determine file size."); - win_println(window, THEME_ERROR, "-", "Cannot determine file size."); - goto out; - } - - FILE *tmpfile = fdopen(tmpfd, "wb"); - if (tmpfile == NULL) { - cons_show_error("Unable to open temporary file."); - win_println(window, THEME_ERROR, "-", "Unable to open temporary file."); - goto out; - } - - FILE *infile = fopen(filepath, "rb"); - if (infile == NULL) { - cons_show_error("Unable to open file."); - win_println(window, THEME_ERROR, "-", "Unable to open file."); - close(tmpfd); - goto out; - } + FILE *tmpfh = fdopen(tmpfd, "wb"); int crypt_res = GPG_ERR_NO_ERROR; @@ -4884,22 +4876,33 @@ cmd_sendfile(ProfWin* window, const char* const command, gchar** args) if (key == NULL) { cons_show_error("Cannot allocate secure memory for encryption."); win_println(window, THEME_ERROR, "-", "Cannot allocate secure memory for encryption."); + fclose(fh); + fclose(tmpfh); goto out; } key = gcry_random_bytes_secure(AES256_GCM_KEY_LENGTH, GCRY_VERY_STRONG_RANDOM); gcry_create_nonce(nonce, AES256_GCM_NONCE_LENGTH); - crypt_res = aes256gcm_encrypt_file(infile, tmpfile, tmpst.st_size, key, nonce); + crypt_res = aes256gcm_encrypt_file(fh, tmpfh, file_size(fd), key, nonce); if (crypt_res != 0) { cons_show_error("Failed to encrypt file."); win_println(window, THEME_ERROR, "-", "Failed to encrypt file."); + fclose(fh); + fclose(tmpfh); goto out; } - free(filepath); - filepath = tmppath; + // Force flush as the upload will read from the same stream. + fflush(tmpfh); + rewind(tmpfh); + + fclose(fh); + + // Switch original stream with temporary encrypted stream. + fd = tmpfd; + fh = tmpfh; break; } @@ -4934,21 +4937,12 @@ cmd_sendfile(ProfWin* window, const char* const command, gchar** args) return TRUE; } - if (access(filename, R_OK) != 0) { - cons_show_error("Uploading '%s' failed: File not found!", filename); - goto out; - } - - if (!is_regular_file(filename)) { - cons_show_error("Uploading '%s' failed: Not a file!", filename); - goto out; - } - - HTTPUpload* upload = malloc(sizeof(HTTPUpload)); + HTTPUpload *upload = malloc(sizeof(HTTPUpload)); upload->window = window; - upload->filename = filename; - upload->filesize = file_size(filename); + upload->filename = strdup(filename); + upload->filehandle = fh; + upload->filesize = file_size(fd); upload->mime_type = file_mime_type(filename); iq_http_upload_request(upload); @@ -4958,8 +4952,6 @@ out: gcry_free(key); if (filename != NULL) free(filename); - if (filepath != NULL) - free(filepath); return TRUE; } diff --git a/src/tools/http_upload.c b/src/tools/http_upload.c index 68de57ed..5f725851 100644 --- a/src/tools/http_upload.c +++ b/src/tools/http_upload.c @@ -133,7 +133,7 @@ http_file_put(void* userdata) { HTTPUpload* upload = (HTTPUpload*)userdata; - FILE* fd = NULL; + FILE *fh = NULL; char* err = NULL; char* content_type_header; @@ -146,7 +146,7 @@ http_file_put(void* userdata) pthread_mutex_lock(&lock); char* msg; - if (asprintf(&msg, "Uploading '%s': 0%%", upload->filepath) == -1) { + if (asprintf(&msg, "Uploading '%s': 0%%", upload->filename) == -1) { msg = strdup(FALLBACK_MSG); } win_print_http_upload(upload->window, msg, upload->put_url); @@ -186,18 +186,13 @@ http_file_put(void* userdata) curl_easy_setopt(curl, CURLOPT_USERAGENT, "profanity"); - if (!(fd = fopen(upload->filepath, "rb"))) { - if (asprintf(&err, "failed to open '%s'", upload->filepath) == -1) { - err = NULL; - } - goto end; - } + fh = upload->filehandle; if (cert_path) { curl_easy_setopt(curl, CURLOPT_CAPATH, cert_path); } - curl_easy_setopt(curl, CURLOPT_READDATA, fd); + curl_easy_setopt(curl, CURLOPT_READDATA, fh); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)(upload->filesize)); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); @@ -225,12 +220,11 @@ http_file_put(void* userdata) #endif } -end: curl_easy_cleanup(curl); curl_global_cleanup(); curl_slist_free_all(headers); - if (fd) { - fclose(fd); + if (fh) { + fclose(fh); } free(content_type_header); free(output.buffer); @@ -294,7 +288,6 @@ end: pthread_mutex_unlock(&lock); free(upload->filename); - free(upload->filepath); free(upload->mime_type); free(upload->get_url); free(upload->put_url); @@ -304,18 +297,18 @@ end: } char* -file_mime_type(const char* const filepath) +file_mime_type(const char* const filename) { char* out_mime_type; char file_header[FILE_HEADER_BYTES]; - FILE *fd; - if (!(fd = fopen(filepath, "rb"))) { + FILE *fh; + if (!(fh = fopen(filename, "rb"))) { return strdup(FALLBACK_MIMETYPE); } - size_t file_header_size = fread(file_header, 1, FILE_HEADER_BYTES, fd); - fclose(fd); + size_t file_header_size = fread(file_header, 1, FILE_HEADER_BYTES, fh); + fclose(fh); - char *content_type = g_content_type_guess(filepath, (unsigned char*)file_header, file_header_size, NULL); + char *content_type = g_content_type_guess(filename, (unsigned char*)file_header, file_header_size, NULL); if (content_type != NULL) { char* mime_type = g_content_type_get_mime_type(content_type); out_mime_type = strdup(mime_type); @@ -327,10 +320,10 @@ file_mime_type(const char* const filepath) return out_mime_type; } -off_t file_size(const char* const filepath) +off_t file_size(int filedes) { struct stat st; - stat(filepath, &st); + fstat(filedes, &st); return st.st_size; } diff --git a/src/tools/http_upload.h b/src/tools/http_upload.h index cbab96ed..5b3b4754 100644 --- a/src/tools/http_upload.h +++ b/src/tools/http_upload.h @@ -47,7 +47,7 @@ typedef struct http_upload_t { char *filename; - char *filepath; + FILE *filehandle; off_t filesize; curl_off_t bytes_sent; char* mime_type; @@ -60,8 +60,8 @@ typedef struct http_upload_t { void* http_file_put(void* userdata); -char* file_mime_type(const char* const filepath); -off_t file_size(const char* const filepath); +char* file_mime_type(const char* const filename); +off_t file_size(int filedes); void http_upload_cancel_processes(ProfWin* window); void http_upload_add_upload(HTTPUpload* upload); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 1c7d16e7..07acdf14 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -2401,9 +2401,9 @@ _http_upload_response_id_handler(xmpp_stanza_t* const stanza, void* const userda if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char* error_message = stanza_get_error_message(stanza); if (from) { - cons_show_error("Uploading '%s' failed for %s: %s", upload->filepath, from, error_message); + cons_show_error("Uploading '%s' failed for %s: %s", upload->filename, from, error_message); } else { - cons_show_error("Uploading '%s' failed: %s", upload->filepath, error_message); + cons_show_error("Uploading '%s' failed: %s", upload->filename, error_message); } free(error_message); return 0;