Skip to content

Commit 572df90

Browse files
Fix email attachment collisions causing email send failure (#312)
1 parent 8d0587d commit 572df90

File tree

1 file changed

+27
-10
lines changed

1 file changed

+27
-10
lines changed

src/db/email.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,18 +196,16 @@ void Database::updateEmailContent(EmailData* data) {
196196
sqlite3_finalize(stmt);
197197
}
198198

199-
void Database::deleteEmailAttachments(int playerID, int index, int slot) {
200-
std::lock_guard<std::mutex> lock(dbCrit);
201-
199+
static void _deleteEmailAttachments(int playerID, int index, int slot) {
202200
sqlite3_stmt* stmt;
203201

204202
std::string sql(R"(
205203
DELETE FROM EmailItems
206-
WHERE PlayerID = ? AND MsgIndex = ?;
204+
WHERE PlayerID = ? AND MsgIndex = ?
207205
)");
208206

209207
if (slot != -1)
210-
sql += " AND \"Slot\" = ? ";
208+
sql += " AND \"Slot\" = ?";
211209
sql += ";";
212210

213211
sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL);
@@ -221,6 +219,11 @@ void Database::deleteEmailAttachments(int playerID, int index, int slot) {
221219
sqlite3_finalize(stmt);
222220
}
223221

222+
void Database::deleteEmailAttachments(int playerID, int index, int slot) {
223+
std::lock_guard<std::mutex> lock(dbCrit);
224+
_deleteEmailAttachments(playerID, index, slot);
225+
}
226+
224227
void Database::deleteEmails(int playerID, int64_t* indices) {
225228
std::lock_guard<std::mutex> lock(dbCrit);
226229

@@ -234,12 +237,15 @@ void Database::deleteEmails(int playerID, int64_t* indices) {
234237
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
235238

236239
for (int i = 0; i < 5; i++) {
240+
int64_t msgIndex = indices[i];
237241
sqlite3_bind_int(stmt, 1, playerID);
238-
sqlite3_bind_int64(stmt, 2, indices[i]);
242+
sqlite3_bind_int64(stmt, 2, msgIndex);
239243
if (sqlite3_step(stmt) != SQLITE_DONE) {
240244
std::cout << "[WARN] Database: Failed to delete an email: " << sqlite3_errmsg(db) << std::endl;
241245
}
242246
sqlite3_reset(stmt);
247+
// delete all attachments
248+
_deleteEmailAttachments(playerID, msgIndex, -1);
243249
}
244250
sqlite3_finalize(stmt);
245251

@@ -323,12 +329,23 @@ bool Database::sendEmail(EmailData* data, std::vector<sItemBase> attachments, Pl
323329
sqlite3_bind_int(stmt, 7, item.iTimeLimit);
324330

325331
if (sqlite3_step(stmt) != SQLITE_DONE) {
326-
std::cout << "[WARN] Database: Failed to send email: " << sqlite3_errmsg(db) << std::endl;
327-
sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL);
328-
sqlite3_finalize(stmt);
329-
return false;
332+
// very likely the UNIQUE constraint failing due to
333+
// orphaned attachments from an old email.
334+
// try deleting them first
335+
_deleteEmailAttachments(data->PlayerId, data->MsgIndex, -1);
336+
337+
// try again
338+
sqlite3_reset(stmt);
339+
if (sqlite3_step(stmt) != SQLITE_DONE) {
340+
// different error, give up
341+
std::cout << "[WARN] Database: Failed to send email: " << sqlite3_errmsg(db) << std::endl;
342+
sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL);
343+
sqlite3_finalize(stmt);
344+
return false;
345+
}
330346
}
331347
sqlite3_reset(stmt);
348+
sqlite3_clear_bindings(stmt);
332349
}
333350
sqlite3_finalize(stmt);
334351

0 commit comments

Comments
 (0)