diff --git a/src/Makefile.am b/src/Makefile.am index 0ccd3539..c617421b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,6 +65,8 @@ utun_CORE_SOURCES = \ media_delivery/file_transfer.c \ media_delivery/file_transfer.h \ media_async/media_async.c \ + media_async/attachment.c \ + media_async/attachment.h \ video/video.c \ transport_layer/dummynet.c \ ntp_time.c \ @@ -177,6 +179,8 @@ libutun_a_SOURCES = \ media_delivery/file_transfer.c \ media_delivery/file_transfer.h \ media_async/media_async.c \ + media_async/attachment.c \ + media_async/attachment.h \ video/video.c \ transport_layer/dummynet.c \ ntp_time.c \ diff --git a/src/dm/dm_core.c b/src/dm/dm_core.c index 4762ded3..9fa839fd 100644 --- a/src/dm/dm_core.c +++ b/src/dm/dm_core.c @@ -306,6 +306,8 @@ static int dm_build_body(struct dm_state* dm, const struct dm_conv* c, uint64_t media = data; data += DM_MEDIA_DESC_SIZE; data_len -= DM_MEDIA_DESC_SIZE; + struct attachment_info info; + if (attachment_decode(data, data_len, &info)) return -1; } uint64_t conv_num = (uint64_t)strtoull(c->conv_id, NULL, 10); uint8_t nonce[DM_NONCE_SIZE]; @@ -465,6 +467,10 @@ int dm_accept_message(struct UTUN_INSTANCE* inst, const uint8_t* msg, size_t len size_t plain_len = 0; dm_build_nonce(conv, author, seq, nonce); if (dm_decrypt(c.content_key, nonce, msg + 35 + msg[32], enc_len, plain, &plain_len) != 0) return -1; + if (dm_message_media(msg, len)) { + struct attachment_info info; + if (attachment_decode(plain, plain_len, &info)) return -1; + } if (dm_exec(dm, "BEGIN IMMEDIATE") != 0) return -1; int inserted = dm_store_message(dm, conv_id, 0, msg, len); if (seq > c.last_in_seq) c.last_in_seq = seq; /* Только статистика; не курсор dedup. */ @@ -939,6 +945,12 @@ int dm_list_messages_json(struct UTUN_INSTANCE* inst, const char* conv_id, int c if (enc_len < DM_TAG_SIZE || enc_len > DM_DATA_MAX + DM_TAG_SIZE || dm_decrypt(c.content_key, nonce, enc, (size_t)enc_len, (uint8_t*)text, &plen)) goto fail; text[plen] = '\0'; + struct attachment_info attachment = {0}; + int file = ct && !strcmp(ct, "file"); + if (file) { + if (attachment_decode((const uint8_t*)text, plen, &attachment)) goto fail; + snprintf(text, sizeof(text), "%s", attachment.name); + } int ready = sqlite3_column_int(st, 7), downloading = sqlite3_column_int(st, 8); int delivered = sqlite3_column_bytes(st, 9) == DM_MEDIA_RECEIPT_SIZE; const char* path = ready == 1 ? (const char*)sqlite3_column_text(st, 10) : ""; @@ -948,10 +960,12 @@ int dm_list_messages_json(struct UTUN_INSTANCE* inst, const char* conv_id, int c json_escape(ct ? ct : "", esc_ct, sizeof(esc_ct)); json_escape(text, esc_data, sizeof(esc_data)); json_escape(path, esc_path, sizeof(esc_path)); if (strbuf_addf(&sb, "%s{\"dir\":%d,\"seq\":%llu,\"ts\":%llu,\"author\":\"%llu\",\"ct\":\"%s\",\"data\":\"%s\"," - "\"pending\":%s,\"media_status\":\"%s\",\"media_path\":\"%s\",\"media_size\":%llu}", first ? "" : ",", dir, + "\"pending\":%s,\"media_status\":\"%s\",\"media_path\":\"%s\",\"media_size\":%llu," + "\"content_type\":\"%s\",\"duration_ms\":%u,\"width\":%u,\"height\":%u,\"waveform\":\"%s\"}", first ? "" : ",", dir, (unsigned long long)seq, (unsigned long long)ts, (unsigned long long)author, esc_ct, esc_data, sqlite3_column_int(st, 6) ? "true" : "false", status, esc_path, - (unsigned long long)sqlite3_column_int64(st, 11)) < 0) goto fail; + (unsigned long long)sqlite3_column_int64(st, 11), file ? attachment_content_type(attachment.kind) : "text/plain", + attachment.duration_ms, attachment.width, attachment.height, attachment.waveform) < 0) goto fail; first = 0; } if (rc != SQLITE_DONE || strbuf_addf(&sb, "]") < 0 || sb.len + 1 > buf_size) goto fail;