Compare commits

...

3 commits

Author SHA1 Message Date
ClaraCrazy
7d956f7d89
missed one 2025-12-12 19:42:46 +01:00
ClaraCrazy
0ad3e40fcc
log updates 2025-12-12 19:38:47 +01:00
ClaraCrazy
075940b0d8
QoL updates 2025-12-12 19:33:27 +01:00
6 changed files with 226 additions and 236 deletions

11
app.js
View file

@ -1,4 +1,5 @@
#!/usr/bin/env node
/* eslint unicorn/no-process-exit: 0 */
const config = require('./application/config')
@ -35,25 +36,25 @@ imapService.on(ImapService.EVENT_DELETED_MAIL, mail =>
)
mailProcessingService.on('error', err => {
console.error('error from mailProcessingService, stopping.', err)
console.error('Error from mailProcessingService, stopping.', err)
process.exit(1)
})
imapService.on(ImapService.EVENT_ERROR, error => {
console.error('fatal error from imap service', error)
console.error('Fatal error from IMAP service', error)
process.exit(1)
})
app.set('mailProcessingService', mailProcessingService)
imapService.connectAndLoadMessages().catch(error => {
console.error('fatal error from imap service', error)
console.error('Fatal error from IMAP service', error)
process.exit(1)
})
server.on('error', error => {
if (error.syscall !== 'listen') {
console.error('fatal web server error', error)
console.error('Fatal web server error', error)
return
}
@ -68,7 +69,7 @@ server.on('error', error => {
console.error('Port ' + config.http.port + ' is already in use')
process.exit(1)
default:
console.error('fatal web server error', error)
console.error('Fatal web server error', error)
process.exit(1)
}
})

View file

@ -127,21 +127,18 @@ class ImapService extends EventEmitter {
this.connection.on('error', err => {
// We assume that the app will be restarted after a crash.
console.error(
'got fatal error during imap operation, stop app.',
err
)
console.error('Got fatal error during imap operation, stop app.', err)
this.emit('error', err)
})
await this.connection.openBox('INBOX')
debug('connected to imap')
debug('Connected to imap')
}, {
retries: 5
}
)
} catch (error) {
console.error('can not connect, even with retry, stop app', error)
console.error('Cant connect, even after retrying, stopping app', error)
throw error
}
}
@ -202,13 +199,11 @@ class ImapService extends EventEmitter {
let uids = []
//fetch mails from date +1day (calculated in MS) to avoid wasting resources and to fix imaps missing time-awareness
if (helper.moreThanOneDay(moment(), deleteMailsBefore)) {
console.log("Deleting mails older than one day");
uids = await this._searchWithoutFetch([
['!DELETED'],
['BEFORE', deleteMailsBefore]
])
} else {
console.log("Deleting mails without date filter");
uids = await this._searchWithoutFetch([
['!DELETED'],
])
@ -220,18 +215,15 @@ class ImapService extends EventEmitter {
const DeleteOlderThan = helper.purgeTimeStamp()
const uidsWithHeaders = await this._getMailHeaders(uids)
console.log(`Fetched ${uidsWithHeaders.length} mails for deletion check.`);
uidsWithHeaders.forEach(mail => {
if (mail['attributes'].date > DeleteOlderThan || this.config.email.examples.uids.includes(parseInt(mail['attributes'].uid))) {
uids = uids.filter(uid => uid !== mail['attributes'].uid)
console.log(mail['attributes'].date > DeleteOlderThan ? `Mail UID: ${mail['attributes'].uid} is newer than purge time.` : `Mail UID: ${mail['attributes'].uid} is an example mail.`);
}
})
if (uids.length === 0) {
console.log("Length 0")
debug('no mails to delete.')
debug('No mails to delete.')
return
}
@ -239,9 +231,8 @@ class ImapService extends EventEmitter {
await this.connection.deleteMessage(uids)
uids.forEach(uid => {
this.emit(ImapService.EVENT_DELETED_MAIL, uid)
console.log(`UID deleted: ${uid}`);
})
console.log(`deleted ${uids.length} old messages.`)
console.log(`Deleted ${uids.length} old messages.`)
}
/**
@ -249,10 +240,10 @@ class ImapService extends EventEmitter {
* @param uid delete specific mail per UID
*/
async deleteSpecificEmail(uid) {
debug(`deleting mails ${uid}`)
debug(`Deleting mails ${uid}`)
if (!this.config.email.examples.uids.includes(parseInt(uid))) {
await this.connection.deleteMessage(uid)
console.log(`deleted mail with UID: ${uid}.`)
debug(`Deleted mail with UID: ${uid}.`)
this.emit(ImapService.EVENT_DELETED_MAIL, uid)
}
}
@ -303,10 +294,10 @@ class ImapService extends EventEmitter {
async fetchOneFullMail(to, uid, raw = false) {
if (!this.connection) {
// Here we 'fail fast' instead of waiting for the connection.
throw new Error('imap connection not ready')
throw new Error('IMAP connection not ready')
}
debug(`fetching full message ${uid}`)
debug(`Fetching full message ${uid}`)
// For security we also filter TO, so it is harder to just enumerate all messages.
const searchCriteria = [
@ -350,7 +341,7 @@ class ImapService extends EventEmitter {
}
})
} catch (error) {
debug('can not fetch', error)
debug('Cant fetch', error)
throw error
}
}

View file

@ -1,9 +1,9 @@
const EventEmitter = require('events')
const debug = require('debug')('48hr-email:imap-manager')
const mem = require('mem')
const moment = require('moment')
const ImapService = require('./imap-service')
const Helper = require('./helper')
const config = require('./config')
const helper = new(Helper)
@ -26,9 +26,12 @@ class MailProcessingService extends EventEmitter {
this.imapService.once(ImapService.EVENT_INITIAL_LOAD_DONE, () =>
this._deleteOldMails()
)
console.log(`Fetching and deleting mails every ${this.config.imap.refreshIntervalSeconds} seconds`)
setInterval(() => {
this._deleteOldMails()
}, 60 * 1000)
}, this.config.imap.refreshIntervalSeconds * 1000)
}
getMailSummaries(address) {
@ -51,15 +54,13 @@ class MailProcessingService extends EventEmitter {
onInitialLoadDone() {
this.initialLoadDone = true
console.log(
`initial load done, got ${this.mailRepository.mailCount()} mails`
)
console.log(`Initial load done, got ${this.mailRepository.mailCount()} mails`)
}
onNewMail(mail) {
if (this.initialLoadDone) {
// For now, only log messages if they arrive after the initial load
debug('new mail for', mail.to[0])
debug('New mail for', mail.to[0])
}
mail.to.forEach(to => {
@ -69,7 +70,7 @@ class MailProcessingService extends EventEmitter {
}
onMailDeleted(uid) {
debug('mail deleted with uid', uid)
debug('Mail deleted with uid', uid)
this.mailRepository.removeUid(uid)
}
@ -77,7 +78,7 @@ class MailProcessingService extends EventEmitter {
try {
await this.imapService.deleteOldMails(helper.purgeTimeStamp())
} catch (error) {
console.log('can not delete old messages', error)
console.log('Cant delete old messages', error)
}
}
@ -85,7 +86,7 @@ class MailProcessingService extends EventEmitter {
const fs = require('fs')
fs.writeFile(filename, JSON.stringify(mails), err => {
if (err) {
console.error('can not save mails to file', err)
console.error('Cant save mails to file', err)
}
})
}

View file

@ -15,7 +15,7 @@ class MailRepository {
mails.forEach(mail => {
if (mail.to == this.config.email.examples.account && !this.config.email.examples.uids.includes(parseInt(mail.uid))) {
mails = mails.filter(m => m.uid != mail.uid)
console.log('prevented non-example email from being shown in example inbox', mail.uid)
debug('Prevented non-example email from being shown in example inbox', mail.uid)
}
})
return _.orderBy(mails, mail => Date.parse(mail.date), ['desc'])
@ -43,7 +43,7 @@ class MailRepository {
.filter(mail => mail.uid === parseInt(uid) && (address ? to == address : true))
.forEach(mail => {
this.mailSummaries.remove(to, mail)
debug('removed ', mail.date, to, mail.subject)
debug('Removed ', mail.date, to, mail.subject)
deleted = true
})
})

View file

@ -55,8 +55,7 @@ router.get(
})
} else {
res.render(
'error',
{
'error', {
purgeTime: purgeTime,
address: req.params.address,
message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
@ -66,7 +65,7 @@ router.get(
)
}
} catch (error) {
console.error('error while fetching one email', error)
console.error('Error while fetching email', error)
next(error)
}
}
@ -84,7 +83,7 @@ router.get(
}
res.redirect(`/inbox/${req.params.address}`)
} catch (error) {
console.error('error while deleting email', error)
console.error('Error while deleting email', error)
next(error)
}
}
@ -100,7 +99,7 @@ router.get(
await mailProcessingService.deleteSpecificEmail(req.params.address, req.params.uid)
res.redirect(`/inbox/${req.params.address}`)
} catch (error) {
console.error('error while deleting email', error)
console.error('Error while deleting email', error)
next(error)
}
}
@ -125,13 +124,12 @@ router.get(
res.send(attachment.content);
return;
} catch (error) {
console.error('error while fetching attachment', error);
console.error('Error while fetching attachment', error);
next(error);
}
} else {
res.render(
'error',
{
'error', {
purgeTime: purgeTime,
address: req.params.address,
message: 'This attachment could not be found. It either does not exist or has been deleted from our servers!',
@ -141,7 +139,7 @@ router.get(
}
res.redirect(`/inbox/${req.params.address}`)
} catch (error) {
console.error('error while deleting email', error)
console.error('Error while deleting email', error)
next(error)
}
}
@ -170,8 +168,7 @@ router.get(
})
} else {
res.render(
'error',
{
'error', {
purgeTime: purgeTime,
address: req.params.address,
message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
@ -180,7 +177,7 @@ router.get(
)
}
} catch (error) {
console.error('error while fetching one email', error)
console.error('Error while fetching raw email', error)
next(error)
}
}

View file

@ -52,7 +52,7 @@ app.use('/inbox', inboxRouter)
// Catch 404 and forward to error handler
app.use((req, res, next) => {
next({message: 'page not found', status: 404})
next({ message: 'Page not found', status: 404 })
})
// Error handler