+
+
+
+ `;
+ if (message_list) {
+
+ data += `
+ ${total_message_count} e-mail message${(total_message_count != 1) ? 's' : ''} for
+
+|
+${username}@${minisrv_config.config.service_name}
+ |
+
+
+
+
+
+
+
+|
+From
+ | Subject
+ | Date
+ |
+
+
+`;
+ Object.keys(message_list).forEach(function (k) {
+ var message = message_list[k];
+ console.log(message);
+ data += `
+
+
+
+
+
+${(message.known_sender) ? ' ' : ''}
+ |
+
+${(message.from_name) ? message.from_name : message.from_addr}
+
+ |
+ |
+
+${(message.subject) ? message.subject : "(No Subject)"}
+
+ |
+ |
+
+`;
+ var message_date = new Date(message.date * 1000);
+ data += (message_date.getMonth() + 1) + "/" + message_date.getDate() + "\n";
+ data += `
+
+ |
+ |
+`;
+ });
+ } else {
+ data += `
+ No ${(mailbox_name == "Inbox") ? `new e-mail messages for
+|
+${username}@${minisrv_config.config.service_name}
+ |
+ ` : 'e-mail messages in mailbox '+mailbox_name}
+
+`;
+ }
+data += `
+
+ |
+
+
+`;
+
+
+ }
+} else {
+ mail_end_error("Access Denied");
+}
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/WTVClientSessionData.js b/zefie_wtvp_minisrv/WTVClientSessionData.js
index f3ca63ef..6dea55d8 100644
--- a/zefie_wtvp_minisrv/WTVClientSessionData.js
+++ b/zefie_wtvp_minisrv/WTVClientSessionData.js
@@ -8,6 +8,7 @@ class WTVClientSessionData {
ssid = null;
data_store = null;
session_store = null;
+ mailstore = null;
login_security = null;
capabilities = null;
session_storage = "";
@@ -23,6 +24,7 @@ class WTVClientSessionData {
if (!minisrv_config) throw ("minisrv_config required");
var WTVShared = require('./WTVShared.js')['WTVShared'];
var WTVMime = require('./WTVMime.js');
+ var WTVMail = require('./WTVMail.js');
this.minisrv_config = minisrv_config;
this.wtvshared = new WTVShared(minisrv_config);
this.wtvmime = new WTVMime(minisrv_config);
@@ -39,6 +41,7 @@ class WTVClientSessionData {
"wtv-log:/log"
];
this.lockdownWhitelist.push(minisrv_config.config.unauthorized_url);
+ this.mailstore = new WTVMail(minisrv_config, ssid, this);
}
/**
@@ -61,6 +64,8 @@ class WTVClientSessionData {
storeUserStoreFile(path, data, last_modified = null, overwrite = true) {
var store_dir = this.getUserStoreDirectory();
if (!store_dir) return false; // unregistered
+ // FileStore
+ store_dir += "FileStore" + this.path.sep;
var result = false;
var path_split = path.split('/');
var file_name = path_split.pop();
@@ -89,6 +94,8 @@ class WTVClientSessionData {
getUserStoreFile(path) {
var store_dir = this.getUserStoreDirectory();
if (!store_dir) return false; // unregistered
+ // FileStore
+ store_dir += "FileStore" + this.path.sep;
var store_dir_path = this.wtvshared.makeSafePath(store_dir, path.replace('/', this.path.sep));
if (this.fs.existsSync(store_dir_path)) return this.fs.readFileSync(store_dir_path);
else return false;
@@ -559,6 +566,10 @@ class WTVClientSessionData {
return this.clientAddress;
}
+ setMailstore(mailstore) {
+ this.mailstore = mailstore;
+ }
+
}
module.exports = WTVClientSessionData;
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/WTVMail.js b/zefie_wtvp_minisrv/WTVMail.js
new file mode 100644
index 00000000..ac443779
--- /dev/null
+++ b/zefie_wtvp_minisrv/WTVMail.js
@@ -0,0 +1,217 @@
+class WTVMail {
+
+ fs = require('fs');
+ path = require('path');
+ uuid = require('uuid');
+
+ ssid = null;
+ unread_mail = 0;
+ inbox_store = null;
+ sent_store = null;
+ saved_store = null;
+ minisrv_config = [];
+ wtvshared = null;
+ wtvmime = null;
+ wtvclient = null;
+ mailstore_dir = null;
+ is_guest = null;
+ mailboxes = null;
+
+ constructor(minisrv_config, ssid, WTVClientSessionData) {
+ if (!minisrv_config) throw ("minisrv_config required");
+ var WTVShared = require('./WTVShared.js')['WTVShared'];
+ var WTVMime = require('./WTVMime.js');
+ this.minisrv_config = minisrv_config;
+ this.wtvshared = new WTVShared(minisrv_config);
+ this.wtvmime = new WTVMime(minisrv_config);
+ this.wtvclient = WTVClientSessionData;
+ this.is_guest = !this.wtvclient.isRegistered();
+ this.ssid = ssid;
+ this.unread_mail = this.wtvclient.getSessionData("subscriber_unread_mail") ? this.wtvclient.getSessionData("subscriber_unread_mail") : 0;
+ this.mailboxes = [
+ // referenced by id, so order is important!
+ "Inbox",
+ "Sent",
+ "Saved",
+ "Trash"
+ ];
+ }
+
+ mailstoreExists() {
+ if (!this.isguest) {
+ if (this.mailstore_dir === null) {
+ // set mailstore directory local var so we don't call the function every time
+ var userstore_dir = this.wtvclient.getUserStoreDirectory();
+
+ // MailStore
+ var store_dir = "MailStore" + this.path.sep;
+ this.mailstore_dir = userstore_dir + store_dir;
+ }
+ return this.fs.existsSync(this.mailstore_dir);
+ }
+ return null;
+ }
+
+ mailboxExists(mailboxid) {
+ if (mailboxid > this.mailboxes.length) return null;
+ var mailbox_dir = null;
+ if (this.mailstoreExists()) {
+ var mailbox_name = this.getMailboxById(mailboxid);
+ if (!mailbox_name) return null;
+
+ var mailbox_dir = mailbox_name + this.path.sep;
+ var store_dir = this.mailstore_dir + mailbox_dir;
+ }
+ return (store_dir !== null) ? this.fs.existsSync(store_dir) : false;
+ }
+
+ createMailstore() {
+ if (this.mailstoreExists() === false) {
+ if (!this.fs.existsSync(this.mailstore_dir)) this.fs.mkdirSync(this.mailstore_dir, { recursive: true });
+ return true;
+ }
+ return false;
+ }
+
+ getMailboxById(mailboxid) {
+ return (mailboxid < this.mailboxes.length - 1) ? this.mailboxes[mailboxid] : false;
+ }
+
+ getMailboxStoreDir(mailboxid) {
+ if (this.mailboxExists(mailboxid)) {
+ var mailbox_name = this.getMailboxById(mailboxid);
+ return this.mailstore_dir + mailbox_name + this.path.sep;
+ }
+ return null;
+ }
+
+ createMailbox(mailboxid) {
+ var mailbox_exists = this.mailboxExists(mailboxid);
+ if (mailbox_exists === false) {
+ var mailbox_name = this.getMailboxById(mailboxid);
+ var mailbox_dir = mailbox_name + this.path.sep;
+ var store_dir = this.mailstore_dir + mailbox_dir;
+ if (!this.fs.existsSync(store_dir)) this.fs.mkdirSync(store_dir, { recursive: true });
+ return true;
+ }
+ return mailbox_exists;
+ }
+
+ createMessageID() {
+ return this.uuid.v1();
+ }
+
+
+ createMessage(mailboxid, from_addr, to_addr, msgbody, subject = null, from_name = null, to_name = null, date = null, known_sender = false) {
+ if (this.createMailbox(mailboxid)) {
+ if (!date) date = Math.floor(Date.now() / 1000);
+
+ var mailbox_path = this.getMailboxStoreDir(mailboxid);
+ var message_file = this.createMessageID() + ".zmsg";
+ var message_file_out = mailbox_path + message_file;
+ var message_data = {
+ "from_addr": from_addr,
+ "from_name": from_name,
+ "to_addr": to_addr,
+ "to_name": to_name,
+ "date": date,
+ "subject": subject,
+ "body": msgbody,
+ "known_sender": known_sender
+ }
+ try {
+ if (this.fs.existsSync(message_file_out)) {
+ console.log(" * ERROR: Message with this UUID already exists (should never happen). Message lost.");
+ return false;
+ }
+
+ // encode message into json
+ var result = this.fs.writeFileSync(message_file_out, JSON.stringify(message_data));
+ if (!result) return false;
+
+ // rely on filesystem times for sorting as it is quicker then reading every file
+ var file_timestamp = new Date(date * 1000);
+ fs.utimesSync(message_file, Date.now(), file_timestamp);
+ if (!result) console.error(" WARNING: Setting timestamp on " + message_file + " failed, mail dates will be inaccurate.");
+
+ } catch (e) {
+ console.error(" # MailErr: Mail Store failed\n", e, "\n", message_file_out, "\n", message_data ,"\n");
+ }
+ return false;
+ }
+ }
+
+ createWelcomeMessage() {
+ var from_addr = (this.minisrv_config.config.service_owner_account) ? this.minisrv_config.config.service_owner_account : this.minisrv_config.config.service_owner;
+ from_addr += "@" + this.minisrv_config.config.service_name;
+ var from_name = this.minisrv_config.config.service_owner
+ var to_addr = this.wtvclient.getSessionData("subscriber_username") + "@" + this.minisrv_config.config.service_name;
+ var to_name = this.wtvclient.getSessionData("subscriber_name");
+ var subj = "Welcome to " + this.minisrv_config.config.service_name;
+ var msg = "poop";
+ return this.createMessage(0, from_addr, to_addr, msg, subj, from_name, to_name, null, true);
+ }
+
+ getMessage(mailboxid, messageid) {
+ if (this.createMailbox(mailboxid)) {
+ var mailbox_path = this.getMailboxStoreDir(mailboxid);
+ var message_file = messageid + ".zmsg";
+ var message_file_in = mailbox_path + this.path.sep + message_file;
+ var message_data_raw = null;
+
+ if (this.fs.existsSync(message_file_in)) message_data_raw = this.fs.readFileSync(message_file_in);
+ else console.error(" # MailErr: could not find ", message_file_in);
+
+ if (message_data_raw) {
+ var message_data = JSON.parse(message_data_raw);
+ if (message_data) {
+ message_data.id = messageid;
+ return message_data;
+ }
+ else console.error(" # MailErr: could not parse json in ", message_file_in);
+ }
+ }
+ return false;
+ }
+
+ listMessages(mailboxid, limit, reverse_sort = false, offset = 0) {
+ if (this.createMailbox(mailboxid)) {
+ var mailbox_path = this.getMailboxStoreDir(mailboxid);
+ var self = this;
+ var files = this.fs.readdirSync(mailbox_path)
+ .map(function (v) {
+ return {
+ name: v,
+ time: self.fs.statSync(mailbox_path + self.path.sep + v).mtime.getTime()
+ };
+ })
+ .sort(function (a, b) {
+ if (reverse_sort) return b.time - a.time;
+ else return a.time - b.time;
+ })
+ .map(function (v) {
+ if (v.name.substring((v.name.length - 5)) === ".zmsg") return v.name.substring(0, (v.name.length - 5));
+ });
+
+ if (files.length == 0) return false; // no messages
+ else {
+ // todo filter previous results when offset
+ var messagelist_out = new Array();
+ Object.keys(files).forEach(function (k) {
+ var message = self.getMessage(mailboxid, files[k]);
+ if (message) messagelist_out.push(mailboxid, message);
+ else console.error(" # MailErr: reading message ID: ", files[k]);
+ })
+ return messagelist_out.filter(function (n) { return n; });
+ }
+ }
+ return null; // error
+ }
+
+ countMessages(mailboxid) {
+ var messages = this.listMessages(mailboxid, false);
+ return (messages.length) ? messages.length : 0;
+ }
+}
+
+module.exports = WTVMail;
diff --git a/zefie_wtvp_minisrv/config.json b/zefie_wtvp_minisrv/config.json
index 03540afa..dac0a17a 100644
--- a/zefie_wtvp_minisrv/config.json
+++ b/zefie_wtvp_minisrv/config.json
@@ -7,6 +7,7 @@
],
"SessionStore": "SessionStore",
"service_owner": "a minisrv user",
+ "service_owner_account": "minisrvuser",
"service_name": "WebTV",
"service_logo": "WebTVLogoJewel.gif",
"service_splash_logo": "file://ROM/images/SplashLogo1.gif",
@@ -71,6 +72,10 @@
"flags": "0x00000010",
"connections": 3
},
+ "wtv-music": {
+ "port": 1656,
+ "connections": 3
+ },
"wtv-cookie": {
"port": 1619,
"connections": 1
@@ -83,6 +88,10 @@
"port": 1635,
"connections": 3
},
+ "wtv-mail": {
+ "port": 1608,
+ "connections": 3
+ },
"http": {
"port": 1650,
"connections": 3,
@@ -101,8 +110,8 @@
"external_proxy_port": 1080,
"flags": "0x00000001"
},
- "wtv-music": {
- "port": 1656,
+ "wtv-guide": {
+ "port": 1621,
"connections": 3
}
}
diff --git a/zefie_wtvp_minisrv/package-lock.json b/zefie_wtvp_minisrv/package-lock.json
index ebfbb179..ee27529b 100644
--- a/zefie_wtvp_minisrv/package-lock.json
+++ b/zefie_wtvp_minisrv/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "zefie_wtvp_minisrv",
- "version": "0.9.22",
+ "version": "0.9.24",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "zefie_wtvp_minisrv",
- "version": "0.9.22",
+ "version": "0.9.24",
"license": "GPL3",
"dependencies": {
"crypto-js": "^4.1.1",
@@ -14,7 +14,8 @@
"endianness": "^8.0.2",
"mime-types": "^2.1.33",
"proxy-agent": "^5.0.0",
- "strftime": "^0.10.0"
+ "strftime": "^0.10.0",
+ "uuid": "^8.3.2"
},
"funding": {
"type": "patreon",
@@ -586,6 +587,14 @@
"node": ">= 0.8"
}
},
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/vm2": {
"version": "3.9.5",
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.5.tgz",
@@ -1045,6 +1054,11 @@
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
+ "uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+ },
"vm2": {
"version": "3.9.5",
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.5.tgz",
diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json
index 4aabc910..570935ba 100644
--- a/zefie_wtvp_minisrv/package.json
+++ b/zefie_wtvp_minisrv/package.json
@@ -32,6 +32,7 @@
"endianness": "^8.0.2",
"mime-types": "^2.1.33",
"proxy-agent": "^5.0.0",
- "strftime": "^0.10.0"
+ "strftime": "^0.10.0",
+ "uuid": "^8.3.2"
}
}
diff --git a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
index 7fa8312b..b61ecf89 100644
--- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
+++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
@@ -91,6 +91,10 @@
Code
+
+
+ Code
+
@@ -325,6 +329,9 @@
Code
+
+ Code
+
Code
@@ -345,6 +352,8 @@
+
+
| |