diff options
| author | Anders Betts <anders.betts@gmail.com> | 2026-09-21 11:45:54 +0200 |
|---|---|---|
| committer | Anders Betts <anders.betts@gmail.com> | 2026-09-21 11:45:54 +0200 |
| commit | e1dd7112e0346914710566660625da0f6b866e8a (patch) | |
| tree | c4b0d5c7f6f62c1c4c38245e7c001b3fd4b03e74 /clients/ui.c | |
| parent | 182f0a592b6fe97fc1ff87add227f9d52a4ef902 (diff) | |
| download | bokf-0.1.55.tar.gz bokf-0.1.55.zip | |
tui: payroll screens, Företag/System menu and settings splitv0.1.55
Diffstat (limited to 'clients/ui.c')
| -rw-r--r-- | clients/ui.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/clients/ui.c b/clients/ui.c index ff573c9..a95ce44 100644 --- a/clients/ui.c +++ b/clients/ui.c @@ -442,6 +442,91 @@ static int bytes_look_text(const unsigned char *p, size_t n) return 1; } +/* Directory for generated PDFs. */ +static void pdf_cache_dir(char *buf, size_t n) +{ + const char *cache = getenv("XDG_CACHE_HOME"); + if (cache && *cache) { + snprintf(buf, n, "%s/bokf", cache); + return; + } + snprintf(buf, n, "/tmp"); +} + +/* Keep a user-supplied name from escaping the directory. */ +static void safe_fname(const char *in, char *out, size_t n) +{ + size_t o = 0; + for (const char *p = in ? in : ""; *p && o + 1 < n; p++) { + unsigned char c = (unsigned char)*p; + if (c < 32 || c == '/') + c = '-'; + out[o++] = (char)c; + } + out[o] = '\0'; +} + +static int write_pdf_b64(const char *b64, const char *path) +{ + unsigned char *data = NULL; + size_t len = 0; + if (!b64 || util_b64_decode(b64, strlen(b64), &data, &len) != 0) + return -1; + FILE *fp = fopen(path, "wb"); + if (!fp) { + free(data); + return -1; + } + size_t wrote = fwrite(data, 1, len, fp); + fclose(fp); + free(data); + return wrote == len ? 0 : -1; +} + +/* Open a saved PDF with xdg-open when a desktop session is present; + otherwise (or on fork failure) show where it was saved. */ +static void open_pdf(const char *path, const char *title) +{ + const char *display = getenv("DISPLAY"); + const char *wayland = getenv("WAYLAND_DISPLAY"); + if ((!display || !*display) && (!wayland || !*wayland)) { + tui_message(title, "Sparad: %s", path); + return; + } + pid_t pid = fork(); + if (pid == 0) { + pid_t gc = fork(); + if (gc == 0) { + setsid(); + execlp("xdg-open", "xdg-open", path, (char *)NULL); + _exit(127); + } + _exit(gc < 0 ? 1 : 0); + } + if (pid > 0) + waitpid(pid, NULL, 0); + else + tui_message(title, "Sparad: %s", path); +} + +void pdf_save_and_open(const char *b64, const char *filename, + const char *title) +{ + char dir[512], path[700], safe[600]; + pdf_cache_dir(dir, sizeof dir); + safe_fname(filename, safe, sizeof safe); + if (snprintf(path, sizeof path, "%s/%s", dir, safe) >= (int)sizeof path) { + tui_message(title, "Sökvägen blir för lång."); + return; + } + config_mkdirs(path); + if (write_pdf_b64(b64, path) != 0) { + tui_message(title, "Kunde inte spara %s", path); + return; + } + open_pdf(path, title); +} + /* Fetch one attachment, save it to a prompted path and verify its hash. Text attachments are shown inline after saving. */ void attachment_download(struct app *a, int64_t att_id) |
