aboutsummaryrefslogtreecommitdiff
path: root/clients
diff options
context:
space:
mode:
Diffstat (limited to 'clients')
-rw-r--r--clients/bokftui.c10
-rw-r--r--clients/client.c3
-rw-r--r--clients/screens_bokslut.c2
-rw-r--r--clients/screens_dashboard.c53
-rw-r--r--clients/screens_ib.c2
-rw-r--r--clients/screens_invoices.c2
-rw-r--r--clients/screens_payroll.c5
-rw-r--r--clients/screens_settings.c97
-rw-r--r--clients/screens_templates.c2
-rw-r--r--clients/screens_vouchers.c2
-rw-r--r--clients/tui.c35
-rw-r--r--clients/ui.c19
-rw-r--r--clients/ui.h3
13 files changed, 145 insertions, 90 deletions
diff --git a/clients/bokftui.c b/clients/bokftui.c
index a047ef5..69d6690 100644
--- a/clients/bokftui.c
+++ b/clients/bokftui.c
@@ -45,7 +45,7 @@ static const struct scene SCENES[] = {
{ "audit", audit_screen },
{ "company", company_screen },
{ "settings", company_screen }, /* ^R/--screen compatibility */
- { "system", system_settings_screen },
+ { "system", system_screen },
{ "bokslut", bokslut_screen },
{ "yearinfo", bokslut_screen }, /* ^R compatibility */
};
@@ -146,11 +146,14 @@ static void config_load(struct app *a)
snprintf(a->socket, sizeof a->socket, "%s", val);
else if (strcmp(line, "user") == 0 && !a->username[0])
snprintf(a->username, sizeof a->username, "%s", val);
+ else if (strcmp(line, "attachment_dir") == 0 &&
+ !a->attachment_dir[0])
+ snprintf(a->attachment_dir, sizeof a->attachment_dir, "%s", val);
}
fclose(f);
}
-static void config_save(const struct app *a)
+void config_save(struct app *a)
{
char path[512];
config_path(path, sizeof path);
@@ -161,6 +164,8 @@ static void config_save(const struct app *a)
fprintf(f, "server=%s\n", a->socket);
if (a->username[0])
fprintf(f, "user=%s\n", a->username);
+ if (a->attachment_dir[0])
+ fprintf(f, "attachment_dir=%s\n", a->attachment_dir);
fclose(f);
chmod(path, 0600);
}
@@ -341,6 +346,7 @@ static void usage(FILE *f)
static void reset_modify_keys(void)
{
+ putp("\033[<u");
putp("\033[>4m");
fflush(stdout);
}
diff --git a/clients/client.c b/clients/client.c
index fd119f1..30f2a67 100644
--- a/clients/client.c
+++ b/clients/client.c
@@ -1,4 +1,5 @@
#include "client.h"
+#include "tls_ca.h"
#include <arpa/inet.h>
#include <errno.h>
@@ -126,7 +127,7 @@ static int tls_connect_addr(const char *addrport, struct client_conn *out)
}
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
- SSL_CTX_set_default_verify_paths(ctx);
+ tls_load_default_cas(ctx);
const char *ca = getenv("BOKFD_TLS_CA");
if (ca && *ca && SSL_CTX_load_verify_locations(ctx, ca, NULL) != 1) {
set_tls_error("TLS CA file");
diff --git a/clients/screens_bokslut.c b/clients/screens_bokslut.c
index df47196..3f69982 100644
--- a/clients/screens_bokslut.c
+++ b/clients/screens_bokslut.c
@@ -242,7 +242,7 @@ void bokslut_screen(struct app *a)
ff[7].cap = sizeof rate;
ff[7].kind = TUI_F_TEXT;
tui_form_hint("upp/ned/Tab = flytta Enter = ändra/utför F5 = visa"
- " bokslutsplan ^Enter = bokför planen (frågar"
+ " bokslutsplan ^Enter/F9 = bokför planen (frågar"
" först) Esc/q = tillbaka ^C = avsluta");
int r = tui_form_run_actions("Bokslut", ff, nf + 2, can_edit, acts, 5,
NULL, &sel);
diff --git a/clients/screens_dashboard.c b/clients/screens_dashboard.c
index a386dae..83b4f6a 100644
--- a/clients/screens_dashboard.c
+++ b/clients/screens_dashboard.c
@@ -268,19 +268,11 @@ static void select_fiscal_year(struct app *a)
}
}
static const char *const MAIN_ITEMS[] = {
- MK_SECTION "Bokföring",
"Verifikat", "Underlag (inkorg)", "Bankavstämning", "Mallar",
- MK_SECTION "Fakturering",
"Fakturor",
- MK_SECTION "Lön",
"Lönekörningar",
- MK_SECTION "Rapporter & bokslut",
"Rapporter", "Bokslut",
- MK_SECTION "Företag",
- "Anställda", "Kunder", "Bolaget", "Momsregler",
- MK_SECTION "System",
- "Skattetabeller", "Revision", "Systeminställningar",
- MK_SECTION "Räkenskapsår",
+ "Bolaget", "System",
"Ingående balans", "Räkenskapsår",
"Logga ut / avsluta",
};
@@ -306,61 +298,46 @@ void dashboard(struct app *a)
if (sel < 0)
continue; /* Esc/back at the top level never exits */
switch (sel) {
- case 1:
+ case 0:
open_scene(a, "vouchers");
break;
- case 2:
+ case 1:
open_scene(a, "inbox");
break;
- case 3:
+ case 2:
open_scene(a, "bank");
break;
- case 4:
+ case 3:
open_scene(a, "templates");
break;
- case 6:
+ case 4:
open_scene(a, "invoices");
break;
- case 8:
+ case 5:
open_scene(a, "payroll");
break;
- case 10:
+ case 6:
open_scene(a, "reports");
break;
- case 11:
+ case 7:
open_scene(a, "bokslut");
break;
- case 13:
- open_scene(a, "employees");
- break;
- case 14:
- open_scene(a, "customers");
- break;
- case 15:
+ case 8:
open_scene(a, "company");
break;
- case 16:
- open_scene(a, "rules");
- break;
- case 18:
- open_scene(a, "tax_tables");
- break;
- case 19:
- open_scene(a, "audit");
- break;
- case 20:
+ case 9:
open_scene(a, "system");
break;
- case 22:
+ case 10:
open_scene(a, "ib");
break;
- case 23:
+ case 11:
select_fiscal_year(a);
break;
- case 24:
+ case 12:
return;
default:
- break; /* section header */
+ break;
}
}
}
diff --git a/clients/screens_ib.c b/clients/screens_ib.c
index ca35562..8950667 100644
--- a/clients/screens_ib.c
+++ b/clients/screens_ib.c
@@ -272,7 +272,7 @@ static int ib_form(struct app *a, char **old_acc, int64_t *old_amt, int nold)
for (;;) {
int rr = tui_rt_run("Ingående balans", &ib.rt,
"Tab = byta fält F5 = validera ^X = rensa rad"
- " ^Enter = spara Esc = avbryt");
+ " ^Enter/F9 = spara Esc = avbryt");
if (rr == -1)
return 0;
char msg[256];
diff --git a/clients/screens_invoices.c b/clients/screens_invoices.c
index b8cc8dd..ca59eef 100644
--- a/clients/screens_invoices.c
+++ b/clients/screens_invoices.c
@@ -1092,7 +1092,7 @@ static int64_t invoices_new(struct app *a)
tui_rt_set_fields(&f.rt, ff, 7);
const char *hint =
"Enter = välj/ändra Tab = byta fält F5 = förhandsvisa"
- " ^Enter = utfärda Esc = avbryt";
+ " ^Enter/F9 = utfärda Esc = avbryt";
int64_t out = 0;
for (;;) {
int rr = tui_rt_run("Ny faktura", &f.rt, hint);
diff --git a/clients/screens_payroll.c b/clients/screens_payroll.c
index 9bfaf38..23d765f 100644
--- a/clients/screens_payroll.c
+++ b/clients/screens_payroll.c
@@ -1101,7 +1101,8 @@ static int64_t payroll_run_screen(struct app *a, int64_t id)
{ status, -1, NULL },
{ totals, -1, NULL },
{ "Förhandsvisa (F5)", 1, NULL },
- { "Bokför körning (^Enter)", post_reason ? 0 : 1, post_reason },
+ { "Bokför körning (^Enter/F9)", post_reason ? 0 : 1,
+ post_reason },
{ "Lönebesked (PDF)", payslip_reason ? 0 : 1, payslip_reason },
{ "AGI-underlag", agi_reason ? 0 : 1, agi_reason },
{ "Betala skatt & avgifter", pay_reason ? 0 : 1, pay_reason },
@@ -1123,7 +1124,7 @@ static int64_t payroll_run_screen(struct app *a, int64_t id)
snprintf(title, sizeof title, "Ny lönekörning");
int editable = can_write && !posted;
tui_form_hint("upp/ned/Tab = flytta Enter = ändra/utför"
- " F5 = förhandsvisa ^Enter = bokför"
+ " F5 = förhandsvisa ^Enter/F9 = bokför"
" Esc/q = tillbaka ^C = avsluta");
int ret = tui_form_run_actions(title, ff, 2, editable, acts, 7, NULL,
&focus);
diff --git a/clients/screens_settings.c b/clients/screens_settings.c
index c6a46c5..8a31620 100644
--- a/clients/screens_settings.c
+++ b/clients/screens_settings.c
@@ -321,10 +321,6 @@ static const struct setting_field SMTP_SETTINGS[] = {
{ "smtp_password", "SMTP-lösenord", NULL, 0, 1 },
};
-static const struct setting_field SYSTEM_SETTINGS[] = {
- { "attachment_dir", "Bilagornas mapp", NULL, 0, 0 },
-};
-
static int settings_can_write(struct app *a)
{
return a->role[0] && (strcmp(a->role, "owner") == 0 ||
@@ -347,27 +343,40 @@ static void smtp_settings_screen(struct app *a)
settings_can_write(a), 1, &sel);
}
-void system_settings_screen(struct app *a)
+static const char *const SYSTEM_ITEMS[] = {
+ "Skattetabeller",
+ "Revision",
+};
+
+void system_screen(struct app *a)
{
static int sel = 0;
- settings_form(a, "Systeminställningar", SYSTEM_SETTINGS,
- (int)(sizeof SYSTEM_SETTINGS / sizeof SYSTEM_SETTINGS[0]),
- settings_can_write(a), 0, &sel);
+ for (;;) {
+ if (g_quit)
+ return;
+ int r = tui_menu("System", SYSTEM_ITEMS,
+ (int)(sizeof SYSTEM_ITEMS / sizeof SYSTEM_ITEMS[0]),
+ 0, &sel);
+ if (r < 0)
+ return;
+ if (r == 0)
+ payroll_tax_tables_screen(a);
+ else if (r == 1)
+ audit_screen(a);
+ }
}
-void company_screen(struct app *a)
+static void company_data_screen(struct app *a)
{
static int sel = 0;
const int nf = (int)(sizeof COMPANY_FIELDS / sizeof COMPANY_FIELDS[0]);
int owner = a->role[0] && strcmp(a->role, "owner") == 0;
- int writer = settings_can_write(a);
- const char *settings_reason = writer ? NULL : "du har inte behörighet";
for (;;) {
if (g_quit)
return;
char *resp = client_rpc(&a->conn, "org.get", a->session, a->org, "{}");
if (!resp || !client_ok(resp)) {
- show_error("Bolaget", resp);
+ show_error("Företagsuppgifter", resp);
free(resp);
return;
}
@@ -392,15 +401,7 @@ void company_screen(struct app *a)
ff[i].kind = TUI_F_TEXT;
}
free(resp);
- struct tui_form_action acts[3] = {
- { "Fakturauppgifter…", writer ? 1 : 0, settings_reason },
- { "E-post (SMTP)…", writer ? 1 : 0, settings_reason },
- { "Styrelseledamöter", 1, NULL },
- };
- tui_form_hint("upp/ned/Tab = flytta Enter = ändra/utför"
- " F5 = uppdatera Esc/q = tillbaka ^C = avsluta");
- int r = tui_form_run_actions("Bolaget", ff, nf, owner, acts, 3, NULL,
- &sel);
+ int r = tui_form_run("Företagsuppgifter", ff, nf, owner, &sel);
if (r >= 0 && r < nf) {
if (!company_field_valid(&COMPANY_FIELDS[r], vals[r])) {
tui_message("Ogiltigt värde", "%s", COMPANY_FIELDS[r].label);
@@ -426,14 +427,58 @@ void company_screen(struct app *a)
}
for (int i = 0; i < nf; i++)
free(vals[i]);
- if (r == TUI_FORM_ACTION + 0)
+ if (r == TUI_FORM_BACK)
+ return;
+ }
+}
+
+static const char *const COMPANY_ITEMS[] = {
+ "Företagsuppgifter",
+ "Fakturauppgifter",
+ "E-post (SMTP)",
+ "Styrelseledamöter",
+ MK_SECTION "Register",
+ "Anställda",
+ "Kunder",
+ "Momsregler",
+};
+
+void company_screen(struct app *a)
+{
+ static int sel = 0;
+ for (;;) {
+ if (g_quit)
+ return;
+ int r = tui_menu("Bolaget", COMPANY_ITEMS,
+ (int)(sizeof COMPANY_ITEMS / sizeof COMPANY_ITEMS[0]),
+ 0, &sel);
+ if (r < 0)
+ return;
+ switch (r) {
+ case 0:
+ company_data_screen(a);
+ break;
+ case 1:
invoice_settings_screen(a);
- else if (r == TUI_FORM_ACTION + 1)
+ break;
+ case 2:
smtp_settings_screen(a);
- else if (r == TUI_FORM_ACTION + 2)
+ break;
+ case 3:
board_screen(a);
- else if (r == TUI_FORM_BACK)
- return;
+ break;
+ case 5:
+ employees_screen(a);
+ break;
+ case 6:
+ customers_screen(a);
+ break;
+ case 7:
+ rules_screen(a);
+ break;
+ default:
+ break;
+ }
}
}
diff --git a/clients/screens_templates.c b/clients/screens_templates.c
index b2cd7ab..5777742 100644
--- a/clients/screens_templates.c
+++ b/clients/screens_templates.c
@@ -234,7 +234,7 @@ static int template_form(struct app *a, const char *load_name)
tui_rt_set_fields(&tf.rt, ff, 3);
const char *title = load_name ? "Redigera mall" : "Ny mall";
const char *hint = "Enter = ändra fält Tab = byta fält F5 = validera"
- " ^X = rensa rad ^Enter = spara Esc = avbryt";
+ " ^X = rensa rad ^Enter/F9 = spara Esc = avbryt";
for (;;) {
int rr = tui_rt_run(title, &tf.rt, hint);
if (rr == -1)
diff --git a/clients/screens_vouchers.c b/clients/screens_vouchers.c
index fedffe9..5e1b006 100644
--- a/clients/screens_vouchers.c
+++ b/clients/screens_vouchers.c
@@ -836,7 +836,7 @@ int64_t vouchers_new_prefill(struct app *a, const struct voucher_prefill *p)
tui_rt_normalize(&vf.rt);
const char *hint = "Enter = ändra fält Tab = byta fält F4 = mall"
" ^F = bifoga fil F5 = validera ^X = rensa rad"
- " ^Enter = bokför Esc = avbryt";
+ " ^Enter/F9 = bokför Esc = avbryt";
for (;;) {
int rr = tui_rt_run("Nytt verifikat", &vf.rt, hint);
if (rr == -1)
diff --git a/clients/tui.c b/clients/tui.c
index 031fad0..30761a8 100644
--- a/clients/tui.c
+++ b/clients/tui.c
@@ -159,9 +159,34 @@ int tui_sticky_split(char **lines, int n, char **head, int *nhead)
void tui_keys_setup(void)
{
- /* ^Enter has no control code; enable xterm modifyOtherKeys and bind the
- sequence it produces. Terminals without it ignore the request. */
+ /* ^Enter has no control code; enable xterm modifyOtherKeys level 2 (level
+ 1 leaves control+Enter alone) and the Kitty keyboard protocol, then bind
+ the sequences they produce. Terminals with neither keep F9 working. */
+ putp("\033[>4;2m");
+ putp("\033[>1u");
+ fflush(stdout);
define_key("\033[27;5;13~", TUI_KEY_CTRL_ENTER);
+ define_key("\033[13;5u", TUI_KEY_CTRL_ENTER);
+ define_key("\033[27;2;9~", KEY_BTAB);
+ define_key("\033[9;2u", KEY_BTAB);
+ define_key("\033[27u", 27);
+ define_key("\033[27;1u", 27);
+ define_key("\033[27;5;97~", 1);
+ define_key("\033[97;5u", 1);
+ define_key("\033[27;5;99~", 3);
+ define_key("\033[99;5u", 3);
+ define_key("\033[27;5;101~", 5);
+ define_key("\033[101;5u", 5);
+ define_key("\033[27;5;102~", 6);
+ define_key("\033[102;5u", 6);
+ define_key("\033[27;5;110~", 14);
+ define_key("\033[110;5u", 14);
+ define_key("\033[27;5;114~", 18);
+ define_key("\033[114;5u", 18);
+ define_key("\033[27;5;117~", 21);
+ define_key("\033[117;5u", 21);
+ define_key("\033[27;5;120~", 24);
+ define_key("\033[120;5u", 24);
/* Home/End arrive as CSI or SS3 depending on the terminal */
define_key("\033[1~", KEY_HOME);
define_key("\033OH", KEY_HOME);
@@ -184,8 +209,6 @@ void tui_keys_setup(void)
init_pair(TUI_CP_RULE, COLOR_BLUE, -1);
init_pair(TUI_CP_STATUS, COLOR_CYAN, -1);
}
- putp("\033[>4;1m");
- fflush(stdout);
}
@@ -1592,7 +1615,7 @@ static int form_run(const char *title, struct tui_form_field *f, int nf,
h = na > 0
? (can_edit
? "upp/ned/Tab = flytta Enter = ändra/utför"
- " F5 = uppdatera ^Enter = spara"
+ " F5 = uppdatera ^Enter/F9 = spara"
" Esc/q = tillbaka ^C = avsluta"
: "upp/ned/Tab = flytta Enter = utför"
" F5 = uppdatera Esc/q = tillbaka"
@@ -1600,7 +1623,7 @@ static int form_run(const char *title, struct tui_form_field *f, int nf,
" (endast behöriga kan ändra)")
: (can_edit
? "upp/ned/Home/End Enter = ändra"
- " F5 = uppdatera ^Enter = spara"
+ " F5 = uppdatera ^Enter/F9 = spara"
" Esc/q = tillbaka ^C = avsluta"
: "upp/ned/Home/End F5 = uppdatera"
" Esc/q = tillbaka ^C = avsluta"
diff --git a/clients/ui.c b/clients/ui.c
index a95ce44..ca6906f 100644
--- a/clients/ui.c
+++ b/clients/ui.c
@@ -217,17 +217,12 @@ void app_refresh_context(struct app *a)
free(resp);
snprintf(a->default_series, sizeof a->default_series, "%s", "A");
- a->attachment_dir[0] = '\0';
resp = client_rpc(&a->conn, "settings.get", a->session, a->org, "{}");
if (resp && client_ok(resp)) {
char *ser = jstr_dup(resp, "result.default_series");
if (ser && *ser)
snprintf(a->default_series, sizeof a->default_series, "%s", ser);
free(ser);
- char *dir = jstr_dup(resp, "result.attachment_dir");
- if (dir && *dir)
- snprintf(a->attachment_dir, sizeof a->attachment_dir, "%s", dir);
- free(dir);
}
free(resp);
@@ -332,14 +327,18 @@ static void expand_path(const char *in, char *out, size_t n)
Returns a malloc'd path, or NULL on cancel. */
char *file_browser(struct app *a, const char *start_dir)
{
- (void)a;
if (g_quit)
return NULL;
char dir[1024];
- const char *start = (start_dir && *start_dir) ? start_dir : getenv("HOME");
+ const char *home = getenv("HOME");
+ const char *start = (start_dir && *start_dir) ? start_dir : home;
expand_path(start, dir, sizeof dir);
- if (!dir[0])
- snprintf(dir, sizeof dir, ".");
+ struct stat sb;
+ if (!dir[0] || stat(dir, &sb) != 0 || !S_ISDIR(sb.st_mode)) {
+ expand_path(home && *home ? home : ".", dir, sizeof dir);
+ if (!dir[0])
+ snprintf(dir, sizeof dir, ".");
+ }
for (;;) {
DIR *d = opendir(dir);
if (!d) {
@@ -408,6 +407,8 @@ char *file_browser(struct app *a, const char *start_dir)
continue;
}
free(ents);
+ snprintf(a->attachment_dir, sizeof a->attachment_dir, "%.255s", dir);
+ config_save(a);
return xstrdup(full);
}
}
diff --git a/clients/ui.h b/clients/ui.h
index 2b93106..b37eb4f 100644
--- a/clients/ui.h
+++ b/clients/ui.h
@@ -102,6 +102,7 @@ extern const struct is_group IS_GROUPS[IS_GROUPS_N];
/* defined in bokftui.c, used by screens */
void open_scene(struct app *a, const char *name);
void config_mkdirs(const char *path);
+void config_save(struct app *a);
/* Optional prefill for the new-voucher form (bank reconciliation). */
struct voucher_prefill {
@@ -130,12 +131,12 @@ void audit_screen(struct app *a);
void templates_screen(struct app *a);
void ib_screen(struct app *a);
void company_screen(struct app *a);
-void system_settings_screen(struct app *a);
void invoices_screen(struct app *a);
void customers_screen(struct app *a);
void bokslut_screen(struct app *a);
void employees_screen(struct app *a);
void payroll_screen(struct app *a);
void payroll_tax_tables_screen(struct app *a);
+void system_screen(struct app *a);
#endif