diff --git a/tools/chatgui-android/libutun_lite/photo_sender.c b/tools/chatgui-android/libutun_lite/photo_sender.c index 242a4acd..e475dcf2 100644 --- a/tools/chatgui-android/libutun_lite/photo_sender.c +++ b/tools/chatgui-android/libutun_lite/photo_sender.c @@ -4,6 +4,7 @@ #include "../../../lib/mem.h" #include "../../../lib/u_async.h" #include "../../../src/chat/chat_core.h" +#include "../../../src/media_async/attachment_send.h" #include #include #include @@ -14,8 +15,10 @@ #include int photo_send(const char* channel_id, const char* src_file_path, const char* db_path, - int width, int height, const uint8_t reply_to[32], uint64_t request_id) { - if (!channel_id || !src_file_path || !db_path) { + int width, int height, const uint8_t reply_to[32], uint64_t request_id, + const char* content_type, uint64_t generation) { + if (!channel_id || !src_file_path || !db_path || !content_type || !reply_to || + width <= 0 || height <= 0 || width > 16384 || height > 16384 || strlen(src_file_path) >= 1024) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "photo_send: invalid args"); return -1; } @@ -29,6 +32,34 @@ int photo_send(const char* channel_id, const char* src_file_path, const char* db return -1; } + if (!strcmp(content_type, "image/jpeg") || !strcmp(content_type, "image/png")) { + struct attachment_send_req* req = u_calloc(1, sizeof(*req)); + struct posted_task* post = u_calloc(1, sizeof(*post)); + if (!req || !post) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "photo_send: allocation failed"); u_free(req); u_free(post); return -1; } + req->inst = instance_lite_get_instance(); req->is_dm = !strncmp(channel_id, "dm:", 3); + const char* target = channel_id + (req->is_dm ? 3 : 0); + const char* name = strrchr(src_file_path, '/'); name = name ? name + 1 : src_file_path; + if (strlen(target) >= sizeof(req->target) || strlen(name) >= sizeof(req->info.name) || (req->is_dm && !generation)) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "photo_send: invalid target/name/generation"); u_free(req); u_free(post); return -1; + } + req->dm_generation = generation; req->temporary_source = 1; + req->info.kind = !strcmp(content_type, "image/png") ? ATTACHMENT_PNG : ATTACHMENT_JPEG; + req->info.width = (uint16_t)width; req->info.height = (uint16_t)height; + snprintf(req->target, sizeof(req->target), "%s", target); + snprintf(req->source, sizeof(req->source), "%s", src_file_path); + snprintf(req->info.name, sizeof(req->info.name), "%s", name); + if (attachment_validate(&req->info)) { u_free(req); u_free(post); return -1; } + if (!req->is_dm) { memcpy(req->reply_to, reply_to, 32); req->request_id = request_id; } + DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "photo_send: target=%s mime=%s dimensions=%dx%d bytes=%lld generation=%llu", + channel_id, content_type, width, height, (long long)st.st_size, (unsigned long long)generation); + post->callback = attachment_send_trampoline; post->arg = req; + uasync_post_reserved(ua, post); return 0; + } + if (strncmp(channel_id, "dm:", 3) == 0 || + (strcmp(content_type, "image/gif") && strcmp(content_type, "image/bmp") && strcmp(content_type, "image/webp"))) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "photo_send: unsupported image target=%s mime=%s", channel_id, content_type); return -1; + } + char path_copy[1024]; snprintf(path_copy, sizeof(path_copy), "%s", src_file_path); char* fname = basename(path_copy); @@ -39,13 +70,10 @@ int photo_send(const char* channel_id, const char* src_file_path, const char* db if (dot) { snprintf(ext, sizeof(ext), "%s", dot + 1); *dot = '\0'; } for (char* p = ext; *p; p++) *p = (char)tolower((unsigned char)*p); - const char* content_type = "image/jpeg"; const char* use_ext = "jpg"; - if (strcmp(ext, "png") == 0) { content_type = "image/png"; use_ext = "png"; } - else if (strcmp(ext, "gif") == 0) { content_type = "image/gif"; use_ext = "gif"; } - else if (strcmp(ext, "bmp") == 0) { content_type = "image/bmp"; use_ext = "bmp"; } - else if (strcmp(ext, "webp") == 0) { content_type = "image/webp"; use_ext = "webp"; } - else if (strcmp(ext, "jpeg") == 0) { use_ext = "jpeg"; } + if (!strcmp(content_type, "image/gif")) use_ext = "gif"; + else if (!strcmp(content_type, "image/bmp")) use_ext = "bmp"; + else if (!strcmp(content_type, "image/webp")) use_ext = "webp"; time_t t = time(NULL); struct tm tm_buf; localtime_r(&t, &tm_buf); diff --git a/tools/chatgui-android/libutun_lite/photo_sender.h b/tools/chatgui-android/libutun_lite/photo_sender.h index 54905c3b..5d315575 100644 --- a/tools/chatgui-android/libutun_lite/photo_sender.h +++ b/tools/chatgui-android/libutun_lite/photo_sender.h @@ -1,7 +1,7 @@ -/* Отправка уже подготовленного изображения в канал: MIME выбирается по расширению, width/height даёт caller. - * Не декодирует и не масштабирует изображение; ставит копирование/индексацию в chat_core/media_index. - * 0 = запрос поставлен в uasync, -1 = отказ; результат — CHAT_EVT_MSG_SUBMITTED. - * Вызовы сериализовать со stop/restart; неизменный src_file_path нужен до завершения задачи, здесь не удаляется. */ +/* Отправка подготовленного изображения: JPEG/PNG в канал/PM через attachment_send, другие форматы — только в канал. + * MIME и размеры с учётом EXIF определяет Android по содержимому. JPEG/PNG забирает собственный cache-файл caller. + * 0 = запрос поставлен в uasync, -1 = отказ (cache остаётся caller); для канала результат — CHAT_EVT_MSG_SUBMITTED. + * Вызовы сериализовать со stop/restart; для дополнительных форматов источник живёт до результата и удаляется caller. */ #ifndef PHOTO_SENDER_H #define PHOTO_SENDER_H #include @@ -10,11 +10,12 @@ extern "C" { #endif -/* channel_id — десятичный ID канала, db_path — каталог БД, width/height — размеры подготовленного файла. - * PNG/GIF/BMP/WebP определяются по расширению без учёта регистра, остальное считается JPEG. - * reply_to — обязательные 32 байта (нули = без ответа), request_id — корреляция результата с UI. */ +/* channel_id — ID канала либо dm:, generation — зафиксированное поколение PM (для канала 0). + * db_path нужен только дополнительным форматам канала; content_type — проверенный MIME. + * reply_to — обязательные 32 байта (нули = без ответа), request_id — корреляция канального результата с UI. */ int photo_send(const char* channel_id, const char* src_file_path, const char* db_path, - int width, int height, const uint8_t reply_to[32], uint64_t request_id); + int width, int height, const uint8_t reply_to[32], uint64_t request_id, + const char* content_type, uint64_t generation); #ifdef __cplusplus }