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:
204
src/mail.c
204
src/mail.c
@ -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 *_) {
|
||||
|
Reference in New Issue
Block a user