#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "client.h" #include "tui.h" #include "formula.h" #include "util.h" #include "version.h" #include "yyjson.h" #include "ui.h" static void inbox_upload(struct app *a) { char *path = file_browser(a, a->attachment_dir); if (!path) return; struct stat sb; if (stat(path, &sb) == 0 && (long)sb.st_size > a->max_attachment_bytes) { tui_message("Bilaga", "Filen är %.1f MB, max %ld MB.", (double)sb.st_size / (1024 * 1024), a->max_attachment_bytes / (1024 * 1024)); free(path); return; } char *b64 = read_file_b64(path); if (!b64) { tui_message("Fel", "Kunde inte läsa %s", path); free(path); return; } const char *base = strrchr(path, '/'); base = base ? base + 1 : path; yyjson_mut_doc *d = yyjson_mut_doc_new(NULL); yyjson_mut_val *o = yyjson_mut_obj(d); yyjson_mut_doc_set_root(d, o); yyjson_mut_obj_add_strcpy(d, o, "filename", base); yyjson_mut_obj_add_strcpy(d, o, "content_base64", b64); char *args = yyjson_mut_write(d, 0, NULL); yyjson_mut_doc_free(d); free(b64); size_t reqlen = strlen(args) + 256; char *raw = xmalloc(reqlen); snprintf(raw, reqlen, "{\"v\":1,\"id\":\"tui\",\"cmd\":\"attachment.put\"," "\"session\":\"%s\",\"org\":%lld,\"args\":%s}", a->session, (long long)a->org, args); free(args); char *r = NULL; if (client_send_line(&a->conn, raw) == 0) r = client_read_line(&a->conn); free(raw); if (r && client_ok(r)) tui_message("Underlag", "Sparat."); else show_error("Kunde inte spara", r); free(r); free(path); } struct inboxctx { struct app *a; int64_t *ids; size_t n; int cursor; }; static int inbox_key(void *ud, int ch) { struct inboxctx *ctx = ud; struct app *a = ctx->a; int64_t sel_id = (ctx->cursor >= 0 && (size_t)ctx->cursor < ctx->n) ? ctx->ids[ctx->cursor] : 0; if (ch == 'k' && sel_id) { int64_t vid = pick_voucher(a); if (vid) { char kargs[64]; snprintf(kargs, sizeof kargs, "{\"id\":%lld,\"voucher_id\":%lld}", (long long)sel_id, (long long)vid); char *r = client_rpc(&a->conn, "attachment.link", a->session, a->org, kargs); if (r && client_ok(r)) tui_message("Underlag", "Kopplat till verifikatet."); else show_error("Kunde inte koppla", r); free(r); } return TUI_HOOK_REFRESH; } if (ch == 'a' || ch == 'A') { inbox_upload(a); return TUI_HOOK_REFRESH; } return TUI_HOOK_NONE; } void inbox_screen(struct app *a) { int cursor = 0; for (;;) { if (g_quit) return; char *resp = client_rpc(&a->conn, "attachment.list", a->session, a->org, "{\"unlinked\":true,\"limit\":200}"); if (!resp || !client_ok(resp)) { show_error("Underlag", resp); free(resp); return; } size_t n = jarr_size(resp, "result.items"); char **items = xcalloc(n ? n : 1, sizeof(char *)); int64_t *ids = xcalloc(n ? n : 1, sizeof(int64_t)); for (size_t i = 0; i < n; i++) { char path[64], line[512]; snprintf(path, sizeof path, "result.items.%zu.id", i); ids[i] = jint_val(resp, path, 0); snprintf(path, sizeof path, "result.items.%zu.filename", i); char *fn = jstr_dup(resp, path); snprintf(path, sizeof path, "result.items.%zu.size_bytes", i); int64_t size = jint_val(resp, path, 0); char fnbuf[256]; snprintf(fnbuf, sizeof fnbuf, "%s", fn ? fn : ""); tui_pad_field(fnbuf, sizeof fnbuf, 40); snprintf(line, sizeof line, "%s %8lld byte", fnbuf, (long long)size); items[i] = xstrdup(line); free(fn); } struct inboxctx ctx = { a, ids, n, cursor }; int sel = tui_select_list_hook("Underlag (inkorg)", items, (int)n, cursor, 1, &cursor, 1, NULL, 0, inbox_key, &ctx); int64_t sel_id = (sel >= 0 && (size_t)sel < n) ? ids[sel] : 0; for (size_t i = 0; i < n; i++) free(items[i]); free(items); free(ids); free(resp); if (sel == -1) return; if (sel == -2) continue; if (sel == -4) { inbox_upload(a); continue; } if (sel_id) attachment_download(a, sel_id); } }