add func to (get all/N lines of a mail) + (wipe a mail) + use st.Mail for SMTP

Signed-off-by: AGentooCat <agentoocat@mail.i2p>
This commit is contained in:
2025-04-18 10:56:46 +00:00
parent 38868055cd
commit bc0485fa57

View File

@ -456,14 +456,7 @@ hostcommitfail:
#undef RETPATH
}
struct InTransit {
char *from;
char *data;
long len;
struct Header *heads;
long headl;
};
int sendmsgid_tohost(struct I2Host *host, struct InTransit *thand, char **err) {
int sendmsgid_tohost(struct I2Host *host, struct Mail *thand, char **err) {
*err = NULL;
int cfd = -1;
@ -530,12 +523,12 @@ smtpbadresp:
WANTRET(354, "DATA");
for (long i = 0; i < thand->headl; i++) {
if (sendfmtline(cfd, "%s: %s", thand->heads[i].key, thand->heads[i].val) < 1)
for (long i = 0; i < thand->hdrl; i++) {
if (sendfmtline(cfd, "%s: %s", thand->hdrs[i].key, thand->hdrs[i].val) < 1)
goto midsendlinefail;
}
if (sendline(cfd, "", 1) < 2) goto midsendlinefail;
if (write(cfd, thand->data, thand->len) < thand->len)
if (write(cfd, thand->lines, thand->size) < thand->size)
goto midsendlinefail;
if (!(line = readline(cfd, &llen))) goto midsendlinefail;
if (strncmp(line, "220 ", 4) != 0) goto smtpbadresp;
@ -546,67 +539,33 @@ smtpbadresp:
return 1;
}
int sendmsgid(char *msgid) {
struct Header *heads = NULL;
char *from_resolved = NULL;
char *maildata = NULL;
long mailen = 0, headl = 0;
log(INFO, "will send mail %s...", msgid);
int getmaillines(struct Mail *mail, char *msgid, long max_lines, char **perr) {
memset(mail, 0, sizeof(*mail));
int ret = sqlite3_bind_text(cached_getmail, 1, msgid, -1, SQLITE_STATIC);
char *err;
if (ret != SQLITE_OK) {
#define RETPATH mailsendfail
mailsendfail:
#define RETPATH pullmailfail
pullmailfail:
CLEARSQL(cached_getmail);
CLEARSQL(cached_gethead);
CLEARSQL(cached_getline);
CLEARSQL(cached_pick_2);
for (long i = 0; i < headl; i++)
xfree2(heads[i].key, heads[i].alen);
if (heads) free(heads);
xfree(maildata);
xfree(from_resolved);
if (ret == SQLITE_OK)
log(ERROR, "preparing to send mail %s failed", msgid);
else
log(ERROR, "preparing to send mail %s failed: %d/%s", msgid, ret, sqlite3_errstr(ret));
freemail(mail);
return -ret;
}
ret = sqlite3_step(cached_getmail);
if (ret == SQLITE_ROW) {
if (!(from_resolved = strdup((const char*)sqlite3_column_text(cached_getmail, 0)))) {
if (!(mail->from = strdup((const char*)sqlite3_column_text(cached_getmail, 0)))) {
ret = SQLITE_NOMEM;
goto mailsendfail;
goto pullmailfail;
}
} else if (ret == SQLITE_DONE) {
log(ERROR, "...no wait can't send details are missing from database");
goto mailsendfail;
} else goto mailsendfail;
CLEARSQL(cached_getmail);
log(INFO, "...from <%s>", from_resolved);
BINDSTR(cached_getline, 1, msgid);
while ((ret = sqlite3_step(cached_getline)) == SQLITE_ROW) {
char *ptr = sqlite3_column_text(cached_getline, 0);
char *ndat = realloc(maildata, mailen + strlen(ptr) + 5);
if (!ndat) {
ret = SQLITE_NOMEM;
goto mailsendfail;
}
maildata = ndat;
sprintf(&maildata[mailen], "%s\r\n", ptr);
mailen += strlen(ptr) + 2;
}
if (ret != SQLITE_DONE) goto mailsendfail;
if (mailen < 5 || strcmp(&maildata[mailen - 5], "\r\n.\r\n") != 0) {
log(ERROR, "incomplete mail data in database; sorry");
*perr = "mail msgid missing from database";
ret = SQLITE_OK;
goto mailsendfail;
}
CLEARSQL(cached_getline);
goto pullmailfail;
} else goto pullmailfail;
CLEARSQL(cached_getmail);
BINDSTR(cached_gethead, 1, msgid);
while ((ret = sqlite3_step(cached_gethead)) == SQLITE_ROW) {
@ -616,34 +575,110 @@ mailsendfail:
char *ptr = malloc(alen);
if (!ptr) {
ret = SQLITE_NOMEM;
goto mailsendfail;
goto pullmailfail;
}
sprintf(ptr, "%s%c%s", key, 0, val);
char *vptr = ptr + strlen(key) + 1;
struct Header *nhead = realloc(heads, (headl + 1) * sizeof(struct Header));
struct Header *nhead = realloc(mail->hdrs, (mail->hdrl + 1) * sizeof(struct Header));
if (!nhead) {
xfree2(ptr, alen);
ret = SQLITE_NOMEM;
goto mailsendfail;
goto pullmailfail;
}
heads = nhead;
heads[headl].key = ptr;
heads[headl].val = vptr;
heads[headl].alen = alen;
heads[headl].koff = strlen(key) + 1;
headl++;
mail->hdrs = nhead;
mail->hdrs[mail->hdrl].key = ptr;
mail->hdrs[mail->hdrl].val = vptr;
mail->hdrs[mail->hdrl].alen = alen;
mail->hdrs[mail->hdrl].koff = strlen(key) + 1;
mail->hdrl++;
}
if (ret != SQLITE_DONE) goto mailsendfail;
if (ret != SQLITE_DONE) goto pullmailfail;
CLEARSQL(cached_gethead);
struct InTransit transhand = {
.heads = heads,
.headl = headl,
.data = maildata,
.len = mailen,
.from = from_resolved,
};
BINDSTR(cached_getline, 1, msgid);
while ((ret = sqlite3_step(cached_getline)) == SQLITE_ROW) {
char *ptr = sqlite3_column_text(cached_getline, 0);
char *ndat = realloc(mail->lines, mail->size + strlen(ptr) + 16);
if (!ndat) {
ret = SQLITE_NOMEM;
goto pullmailfail;
}
mail->lines = ndat;
sprintf(&mail->lines[mail->size], "%s\r\n", ptr);
mail->size += strlen(ptr) + 2;
mail->line_count++;
if (max_lines > 0 && mail->line_count == max_lines) {
if (strcmp(ptr, ".") != 0) {
strcpy(&mail->lines[mail->size], ".\r\n");
mail->size += 3;
mail->line_count++;
}
break;
}
}
if (ret != SQLITE_DONE) goto pullmailfail;
if (mail->size < 5 || strcmp(&mail->lines[mail->size - 5], "\r\n.\r\n") != 0) {
ret = SQLITE_OK;
*perr = "incomplete mail data in database";
goto pullmailfail;
}
CLEARSQL(cached_getline);
mail->line_count--;
return 1;
#undef RETPATH
}
int wipemail(char *msgid) {
int ret;
char *err = NULL;
if ((ret = sqlite3_exec(conn, "BEGIN TRANSACTION", NULL, NULL, &err)) != SQLITE_OK) {
wipemailfail:
#define RETPATH wipemailfail
log(WARN, "attempting to wipe mail %s failed: %d/%s", msgid, ret, err ? err : sqlite3_errstr(ret));
CLEARSQL(cached_popmail);
CLEARSQL(cached_popline);
CLEARSQL(cached_pophead);
CLEARSQL(cached_popfail);
CLEARSQL(cached_popwhoqu);
return -ret;
}
#define BINDSTEP(stmt) \
BINDSTR(stmt, 1, msgid); \
CHKSQL(sqlite3_step(stmt)); \
CLEARSQL(stmt);
BINDSTEP(cached_popmail);
BINDSTEP(cached_popline);
BINDSTEP(cached_pophead);
BINDSTEP(cached_popfail);
BINDSTEP(cached_popwhoqu);
CHKSQL(sqlite3_exec(conn, "COMMIT", NULL, NULL, &err));
#undef RETPATH
return 1;
}
int sendmsgid(char *msgid) {
log(INFO, "will send mail %s...", msgid);
struct Mail transhand;
char *err;
int ret = getmaillines(&transhand, msgid, 0, &err);
if (ret < 1) {
ret = -ret;
#define RETPATH mailsendfail
mailsendfail:
CLEARSQL(cached_pick_2);
freemail(&transhand);
if (ret == SQLITE_OK)
log(ERROR, "preparing to send mail %s failed: %s", msgid, err);
else
log(ERROR, "preparing to send mail %s failed: %d/%s", msgid, ret, sqlite3_errstr(ret));
return -ret;
}
log(INFO, "...from <%s>", transhand.from);
long tol = 0;
BINDSTR(cached_pick_2, 1, msgid);
@ -717,6 +752,7 @@ mailsendfail:
}
}
if (ret != SQLITE_DONE) goto mailsendfail;
CLEARSQL(cached_pick_2);
#undef RETPATH
@ -734,8 +770,6 @@ mailsendfail:
// on success
sqlite3_bind_parameter_index(cached_popqueue, ":msgid"),
sqlite3_bind_parameter_index(cached_popqueue, ":addr"),
sqlite3_bind_parameter_index(cached_popmail, ":msgid"),
};
int all_good = 1;
for (long i = 0; i < tol; i++) {
@ -822,29 +856,13 @@ hostsenddone:
xfree(rerr);
}
if (all_good && gloconf->delete_outgoing_mails) {
if ((ret = sqlite3_exec(conn, "BEGIN TRANSACTION", NULL, NULL, &err)) != SQLITE_OK) {
allsentdeletefail:
#define RETPATH allsentdeletefail
log(WARN, "attempting to wipe successful sent mail failed: %d/%s", ret, sqlite3_errstr(ret));
CLEARSQL(cached_popmail);
goto allsentafter;
}
BINDSTR(cached_popmail, idx[9], msgid);
CHKSQL(sqlite3_step(cached_popmail));
CHKSQL(sqlite3_exec(conn, "COMMIT", NULL, NULL, &err));
CLEARSQL(cached_popmail);
#undef RETPATH
wipemail(msgid); // it does it's own error logging
}
allsentafter:
free(tos);
CLEARSQL(cached_pick_2);
xfree(maildata);
xfree(from_resolved);
for (long i = 0; i < headl; i++)
xfree2(heads[i].key, heads[i].alen);
if (heads) free(heads);
freemail(&transhand);
return 0;
}
void *mailpicker(void *_) {