This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/src/email.c
Dan Cross 359a190ee9 Remove the last of the sprintf() calls.
sprintf() is unsafe since it may overflow the bounds
of its destination buffers.  Remove the last of the
calls to it; all the logic has either been rewritten
to use snprintf() or other forms of string copying
such as strlcpy().

Signed-off-by: Dan Cross <patchdev@fat-dragon.org>
2018-10-17 13:11:33 +10:00

656 lines
19 KiB
C

#include <sqlite3.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "bbs.h"
extern struct bbs_config conf;
extern struct user_record *gUser;
struct email_msg {
int id;
char *from;
char *subject;
int seen;
time_t date;
char *body;
};
void commit_email(char *recipient, char *subject, char *msg) {
char buffer[PATH_MAX];
sqlite3 *db;
sqlite3_stmt *res;
int rc;
char *csql = "CREATE TABLE IF NOT EXISTS email ("
"id INTEGER PRIMARY KEY,"
"sender TEXT COLLATE NOCASE,"
"recipient TEXT COLLATE NOCASE,"
"subject TEXT,"
"body TEXT,"
"date INTEGER,"
"seen INTEGER);";
char *isql = "INSERT INTO email (sender, recipient, subject, body, date, seen) VALUES(?, ?, ?, ?, ?, 0)";
char *err_msg = 0;
snprintf(buffer, PATH_MAX, "%s/email.sq3", conf.bbs_path);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
return;
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_exec(db, csql, 0, 0, &err_msg);
if (rc != SQLITE_OK) {
dolog("SQL error: %s", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
return;
}
rc = sqlite3_prepare_v2(db, isql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, gUser->loginname, -1, 0);
sqlite3_bind_text(res, 2, recipient, -1, 0);
sqlite3_bind_text(res, 3, subject, -1, 0);
sqlite3_bind_text(res, 4, msg, -1, 0);
sqlite3_bind_int(res, 5, time(NULL));
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
return;
}
sqlite3_step(res);
sqlite3_finalize(res);
sqlite3_close(db);
}
void send_email(struct user_record *user) {
char buffer[26];
char *recipient;
char *subject;
char *msg;
s_printf(get_string(54));
s_readstring(buffer, 16);
if (strlen(buffer) == 0) {
s_printf(get_string(39));
return;
}
if (check_user(buffer)) {
s_printf(get_string(55));
return;
}
recipient = strdup(buffer);
s_printf(get_string(56));
s_readstring(buffer, 25);
if (strlen(buffer) == 0) {
free(recipient);
s_printf(get_string(39));
return;
}
subject = strdup(buffer);
// post a message
msg = external_editor(user, user->loginname, recipient, NULL, 0, NULL, subject, 1, 0);
if (msg != NULL) {
commit_email(recipient, subject, msg);
free(msg);
}
free(subject);
free(recipient);
}
void show_email(struct user_record *user, int msgno, int email_count, struct email_msg **emails) {
char buffer[256];
sqlite3 *db;
sqlite3_stmt *res;
int rc;
char *dsql = "DELETE FROM email WHERE id=?";
char *isql = "INSERT INTO email (sender, recipient, subject, body, date, seen) VALUES(?, ?, ?, ?, ?, 0)";
char *ssql = "UPDATE email SET seen=1 WHERE id=?";
int id;
char *sender;
char *subject;
time_t date;
struct tm msg_date;
int z;
int lines;
char c;
char *replybody;
int chars;
int start_line;
int msg_line_count;
char **msg_lines;
int i, j;
int position;
int should_break;
int quit = 0;
while (!quit) {
struct ptr_vector lines_vec;
char *line;
s_printf(get_string(57), emails[msgno]->from);
s_printf(get_string(58), emails[msgno]->subject);
localtime_r(&emails[msgno]->date, &msg_date);
strlcpy(buffer, asctime(&msg_date), sizeof buffer);
buffer[strlen(buffer) - 1] = '\0';
s_printf(get_string(59), buffer);
s_printf(get_string(60));
lines = 0;
chars = 0;
msg_line_count = 0;
start_line = 0;
init_ptr_vector(&lines_vec);
// count the number of lines...
for (z = 0; z < strlen(emails[msgno]->body); z++) {
if (emails[msgno]->body[z] == '\r' || chars == 79) {
line = (char *)malloz(z - start_line + 1);
ptr_vector_append(&lines_vec, line);
if (z == start_line) {
line[0] = '\0';
} else {
strlcpy(line, &emails[msgno]->body[start_line], z - start_line + 1);
line[z - start_line] = '\0';
}
if (emails[msgno]->body[z] == '\r') {
start_line = z + 1;
} else {
start_line = z;
}
chars = 0;
} else {
chars++;
}
}
msg_line_count = ptr_vector_len(&lines_vec);
msg_lines = (char **)consume_ptr_vector(&lines_vec);
lines = 0;
position = 0;
should_break = 0;
while (!should_break) {
s_printf("\e[5;1H");
for (z = position; z < msg_line_count; z++) {
s_printf("%s\e[K\r\n", msg_lines[z]);
if (z - position >= 17) {
break;
}
}
s_printf(get_string(187));
s_printf(get_string(191));
c = s_getchar();
if (tolower(c) == 'r') {
should_break = 1;
} else if (tolower(c) == 'q') {
should_break = 1;
quit = 1;
} else if (tolower(c) == 'd') {
should_break = 1;
} else if (c == '\e') {
c = s_getchar();
if (c == 91) {
c = s_getchar();
if (c == 65) {
position--;
if (position < 0) {
position = 0;
}
} else if (c == 66) {
position++;
if (position + 17 >= msg_line_count) {
position--;
}
} else if (c == 67) {
c = ' ';
should_break = 1;
} else if (c == 68) {
c = 'b';
should_break = 1;
}
}
}
}
for (i = 0; i < msg_line_count; i++) {
free(msg_lines[i]);
}
free(msg_lines);
msg_line_count = 0;
snprintf(buffer, sizeof buffer, "%s/email.sq3", conf.bbs_path);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_prepare_v2(db, ssql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_int(res, 1, emails[msgno]->id);
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
return;
}
sqlite3_step(res);
sqlite3_finalize(res);
sqlite3_close(db);
if (tolower(c) == 'r') {
if (emails[msgno]->subject != NULL) {
if (strncasecmp(emails[msgno]->subject, "RE:", 3) != 0) {
snprintf(buffer, 256, "RE: %s", emails[msgno]->subject);
} else {
snprintf(buffer, 256, "%s", emails[msgno]->subject);
}
}
subject = strdup(buffer);
replybody = external_editor(user, user->loginname, emails[msgno]->from, emails[msgno]->body, strlen(emails[msgno]->body), emails[msgno]->from, subject, 1, 0);
if (replybody != NULL) {
snprintf(buffer, sizeof buffer, "%s/email.sq3", conf.bbs_path);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_prepare_v2(db, isql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, user->loginname, -1, 0);
sqlite3_bind_text(res, 2, emails[msgno]->from, -1, 0);
sqlite3_bind_text(res, 3, subject, -1, 0);
sqlite3_bind_text(res, 4, replybody, -1, 0);
sqlite3_bind_int(res, 5, time(NULL));
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
free(replybody);
free(subject);
return;
}
sqlite3_step(res);
sqlite3_finalize(res);
sqlite3_close(db);
free(replybody);
}
free(subject);
} else if (tolower(c) == 'd') {
snprintf(buffer, sizeof buffer, "%s/email.sq3", conf.bbs_path);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_prepare_v2(db, dsql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_int(res, 1, emails[msgno]->id);
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
return;
}
sqlite3_step(res);
sqlite3_finalize(res);
sqlite3_close(db);
quit = 1;
} else if (tolower(c) == ' ') {
msgno++;
if (msgno == email_count) {
quit = 1;
}
} else if (tolower(c) == 'b') {
msgno--;
if (msgno < 0) {
quit = 1;
}
}
}
}
void list_emails(struct user_record *user) {
char buffer[PATH_MAX];
sqlite3 *db;
sqlite3_stmt *res;
int rc;
char *sql = "SELECT sender,subject,seen,date,body,id FROM email WHERE recipient LIKE ?";
struct email_msg **emails;
struct ptr_vector emails_vec;
int email_count;
int msgid;
int msgtoread;
struct tm msg_date;
int redraw;
int start;
int position;
int i;
char c;
int closed = 0;
snprintf(buffer, PATH_MAX, "%s/email.sq3", conf.bbs_path);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, user->loginname, -1, 0);
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
s_printf(get_string(62));
return;
}
msgid = 0;
s_printf(get_string(63));
init_ptr_vector(&emails_vec);
while (sqlite3_step(res) == SQLITE_ROW) {
struct email_msg *email = (struct email_msg *)malloz(sizeof(struct email_msg));
ptr_vector_append(&emails_vec, email);
email->from = strdup((char *)sqlite3_column_text(res, 0));
email->subject = strdup((char *)sqlite3_column_text(res, 1));
email->seen = sqlite3_column_int(res, 2);
email->date = (time_t)sqlite3_column_int(res, 3);
email->body = strdup((char *)sqlite3_column_text(res, 4));
email->id = sqlite3_column_int(res, 5);
}
email_count = ptr_vector_len(&emails_vec);
emails = (struct email_msg **)consume_ptr_vector(&emails_vec);
sqlite3_finalize(res);
sqlite3_close(db);
if (email_count == 0) {
s_printf(get_string(194));
return;
}
redraw = 1;
start = 0;
position = 0;
while (!closed) {
if (redraw) {
s_printf("\e[2J\e[1;1H");
s_printf(get_string(126));
for (i = start; i < start + 22 && i < email_count; i++) {
localtime_r((time_t *)&emails[i]->date, &msg_date);
if (i == position) {
if (!emails[i]->seen) {
if (conf.date_style == 1) {
s_printf(get_string(192), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(192), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
} else {
if (conf.date_style == 1) {
s_printf(get_string(193), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(193), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
}
} else {
if (!emails[i]->seen) {
if (conf.date_style == 1) {
s_printf(get_string(64), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(64), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
} else {
if (conf.date_style == 1) {
s_printf(get_string(65), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(65), i + 1, emails[i]->subject, emails[i]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
}
}
}
s_printf(get_string(190));
s_printf("\e[%d;5H", position - start + 2);
redraw = 0;
}
c = s_getchar();
if (tolower(c) == 'q') {
closed = 1;
} else if (c == 27) {
c = s_getchar();
if (c == 91) {
c = s_getchar();
if (c == 66) {
// down
position++;
if (position >= start + 22) {
start += 22;
if (start >= email_count) {
start = email_count - 22;
}
redraw = 1;
}
if (position == email_count) {
position--;
s_printf("\e[%d;5H", position - start + 2);
} else if (!redraw) {
s_printf("\e[%d;1H", position - start + 1);
localtime_r((time_t *)&emails[position - 1]->date, &msg_date);
if (!emails[position - 1]->seen) {
if (conf.date_style == 1) {
s_printf(get_string(64), position, emails[position - 1]->subject, emails[position - 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(64), position, emails[position - 1]->subject, emails[position - 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
} else {
if (conf.date_style == 1) {
s_printf(get_string(65), position, emails[position - 1]->subject, emails[position - 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(65), position, emails[position - 1]->subject, emails[position - 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
}
s_printf("\e[%d;1H", position - start + 2);
localtime_r((time_t *)&emails[position]->date, &msg_date);
if (!emails[position]->seen) {
if (conf.date_style == 1) {
s_printf(get_string(192), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(192), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
} else {
if (conf.date_style == 1) {
s_printf(get_string(193), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(193), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
}
s_printf("\e[%d;5H", position - start + 2);
}
} else if (c == 65) {
// up
position--;
if (position < start) {
start -= 22;
if (start < 0) {
start = 0;
}
redraw = 1;
}
if (position <= 0) {
start = 0;
position = 0;
redraw = 1;
} else if (!redraw) {
s_printf("\e[%d;1H", position - start + 3);
localtime_r((time_t *)&emails[position + 1]->date, &msg_date);
if (!emails[position + 1]->seen) {
if (conf.date_style == 1) {
s_printf(get_string(64), position + 2, emails[position + 1]->subject, emails[position + 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(64), position + 2, emails[position + 1]->subject, emails[position + 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
} else {
if (conf.date_style == 1) {
s_printf(get_string(65), position + 2, emails[position + 1]->subject, emails[position + 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(65), position + 2, emails[position + 1]->subject, emails[position + 1]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
}
s_printf("\e[%d;1H", position - start + 2);
localtime_r((time_t *)&emails[position]->date, &msg_date);
if (!emails[position]->seen) {
if (conf.date_style == 1) {
s_printf(get_string(192), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(192), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
} else {
if (conf.date_style == 1) {
s_printf(get_string(193), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mon + 1, msg_date.tm_mday, msg_date.tm_year - 100);
} else {
s_printf(get_string(193), position + 1, emails[position]->subject, emails[position]->from, msg_date.tm_hour, msg_date.tm_min, msg_date.tm_mday, msg_date.tm_mon + 1, msg_date.tm_year - 100);
}
}
s_printf("\e[%d;5H", position - start + 3);
}
} else if (c == 75) {
// END KEY
position = email_count - 1;
start = email_count - 22;
if (start < 0) {
start = 0;
}
redraw = 1;
} else if (c == 72) {
// HOME KEY
position = 0;
start = 0;
redraw = 1;
} else if (c == 86 || c == '5') {
if (c == '5') {
s_getchar();
}
// PAGE UP
position = position - 22;
if (position < 0) {
position = 0;
}
start = position;
redraw = 1;
} else if (c == 85 || c == '6') {
if (c == '6') {
s_getchar();
}
// PAGE DOWN
position = position + 22;
if (position >= email_count) {
position = email_count - 1;
}
start = position;
redraw = 1;
}
}
} else if (c == 13) {
closed = 1;
show_email(user, position, email_count, emails);
}
}
for (i = 0; i < email_count; i++) {
free(emails[i]->from);
free(emails[i]->subject);
free(emails[i]->body);
free(emails[i]);
}
free(emails);
}
int mail_getemailcount(struct user_record *user) {
char *sql = "SELECT COUNT(*) FROM email WHERE recipient LIKE ?";
int count;
char buffer[256];
sqlite3 *db;
sqlite3_stmt *res;
int rc;
snprintf(buffer, sizeof buffer, "%s/email.sq3", conf.bbs_path);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, user->loginname, -1, 0);
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
return 0;
}
count = 0;
if (sqlite3_step(res) == SQLITE_ROW) {
count = sqlite3_column_int(res, 0);
}
sqlite3_finalize(res);
sqlite3_close(db);
return count;
}