Prepare Android JPEG and PNG attachments for fixed channel or PM targets

This commit is contained in:
evgeny committed 2026-10-28 12:08:06 +01:00
1 parent 23fecc2c11
commit e4af3907c2
2 files changed
+45 -16

No files matched your search

@@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,8 +15,10 @@
#include <libgen.h>
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);
@@ -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 <stdint.h>
@@ -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:<conv>, 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
}