diff options
Diffstat (limited to 'src/mail.c')
| -rw-r--r-- | src/mail.c | 168 |
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; +} |
