summaryrefslogtreecommitdiff
path: root/src/mail.c
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-21 09:56:01 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-21 09:56:01 +0200
commit4488b6c2eb1a3ddf20e190ebd28953e4f3f01042 (patch)
treeb52812145147669d04f23a57d41b3f604104963f /src/mail.c
parente692f0fbe16342195297048534ad1be227493107 (diff)
downloadbokf-4488b6c2eb1a3ddf20e190ebd28953e4f3f01042.tar.gz
bokf-4488b6c2eb1a3ddf20e190ebd28953e4f3f01042.zip
payroll: lönebesked PDF and mail (schema v11)
Diffstat (limited to 'src/mail.c')
-rw-r--r--src/mail.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/mail.c b/src/mail.c
new file mode 100644
index 0000000..52d429c
--- /dev/null
+++ b/src/mail.c
@@ -0,0 +1,168 @@
+#include "mail.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "secret.h"
+#include "smtp.h"
+#include "util.h"
+
+struct mail_cfg {
+ char *host;
+ char *port;
+ char *from;
+ char *reply_to;
+ char *security;
+ char *user;
+ char *password;
+ char from_name[256];
+};
+
+static void mail_cfg_free(struct mail_cfg *c)
+{
+ free(c->host);
+ free(c->port);
+ free(c->from);
+ free(c->reply_to);
+ free(c->security);
+ free(c->user);
+ free(c->password);
+ memset(c, 0, sizeof *c);
+}
+
+static void set_err(char *err, size_t errlen, const char *msg)
+{
+ if (err && errlen)
+ snprintf(err, errlen, "%s", msg);
+}
+
+static int mail_cfg_load(sqlite3 *db, int64_t org_id, struct mail_cfg *c,
+ char *err, size_t errlen)
+{
+ memset(c, 0, sizeof *c);
+ c->host = db_setting(db, org_id, "smtp_host");
+ c->port = db_setting(db, org_id, "smtp_port");
+ c->from = db_setting(db, org_id, "smtp_from");
+ c->reply_to = db_setting(db, org_id, "smtp_reply_to");
+ c->security = db_setting(db, org_id, "smtp_security");
+ c->user = db_setting(db, org_id, "smtp_user");
+ c->password = db_setting(db, org_id, "smtp_password");
+
+ if (!c->host || !*c->host || !c->from || !*c->from) {
+ set_err(err, errlen, "smtp_host and smtp_from must be set");
+ goto fail;
+ }
+ if (c->user && *c->user) {
+ if (!c->password || !*c->password) {
+ set_err(err, errlen,
+ "smtp_user is set but smtp_password is missing");
+ goto fail;
+ }
+ if (!secret_available()) {
+ set_err(err, errlen,
+ "smtp_password is set but BOKFD_SECRET_KEY is missing or"
+ " invalid");
+ goto fail;
+ }
+ char *plain = NULL;
+ if (secret_decrypt(c->password, &plain) != 0 || !plain) {
+ free(plain);
+ set_err(err, errlen,
+ "cannot decrypt smtp_password, check BOKFD_SECRET_KEY");
+ goto fail;
+ }
+ free(c->password);
+ c->password = plain;
+ }
+
+ sqlite3_stmt *st = NULL;
+ int ok = 0;
+ if (sqlite3_prepare_v2(db, "SELECT name FROM orgs WHERE id=?1", -1, &st,
+ NULL) == SQLITE_OK) {
+ sqlite3_bind_int64(st, 1, org_id);
+ if (sqlite3_step(st) == SQLITE_ROW) {
+ const unsigned char *name = sqlite3_column_text(st, 0);
+ snprintf(c->from_name, sizeof c->from_name, "%s",
+ name ? (const char *)name : "");
+ ok = 1;
+ }
+ }
+ sqlite3_finalize(st);
+ if (!ok) {
+ set_err(err, errlen, "org not found");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ mail_cfg_free(c);
+ return -1;
+}
+
+static int mail_cfg_port(const char *s)
+{
+ if (s && *s) {
+ long v = strtol(s, NULL, 10);
+ if (v >= 1 && v <= 65535)
+ return (int)v;
+ }
+ return 587;
+}
+
+int mail_config_check(sqlite3 *db, int64_t org_id, char *err, size_t errlen)
+{
+ struct mail_cfg c;
+ if (err && errlen)
+ err[0] = '\0';
+ if (!db) {
+ set_err(err, errlen, "no database");
+ return -1;
+ }
+ if (mail_cfg_load(db, org_id, &c, err, errlen) != 0)
+ return -1;
+ mail_cfg_free(&c);
+ return 0;
+}
+
+int mail_send_pdf(sqlite3 *db, int64_t org_id, const struct mail_message *m,
+ char *err, size_t errlen)
+{
+ if (err && errlen)
+ err[0] = '\0';
+ if (!m || !m->to || !*m->to) {
+ set_err(err, errlen, "no recipient");
+ return -2;
+ }
+ struct mail_cfg c;
+ if (mail_cfg_load(db, org_id, &c, err, errlen) != 0)
+ return -1;
+
+ struct smtp_message sm;
+ memset(&sm, 0, sizeof sm);
+ sm.host = c.host;
+ sm.port = mail_cfg_port(c.port);
+ sm.security = c.security && *c.security ? c.security : "starttls";
+ sm.user = c.user && *c.user ? c.user : "";
+ sm.password = c.password ? c.password : "";
+ sm.from = c.from;
+ sm.from_name = c.from_name;
+ sm.to = m->to;
+ sm.subject = m->subject;
+ sm.body = m->body;
+ sm.attach_name = m->attach_name;
+ sm.attach = m->attach;
+ sm.attach_len = m->attach_len;
+
+ char send_err[512];
+ send_err[0] = '\0';
+ int rc = smtp_send(&sm, send_err, sizeof send_err);
+ mail_cfg_free(&c);
+ if (rc != 0) {
+ set_err(err, errlen,
+ send_err[0] ? send_err : "smtp send failed");
+ return -2;
+ }
+ return 0;
+}