mail/back/imap/storeMessage.js
2023-03-13 00:13:17 +01:00

217 lines
7.7 KiB
JavaScript

const { getAddresseId } = require("../sql/mail");
const { DEBUG } = require("../utils/debug");
const { simpleParser } = require("mailparser");
const {
registerMessage,
registerMailbox_message,
saveHeader_fields,
saveAddress_fields,
registerBodypart,
saveBodypart,
} = require("../sql/saveMessage");
const {
createRoom,
registerMessageInRoom,
createThread,
registerMessageInThread,
isRoomGroup
} = require("../sql/saveMessageApp");
const { getFieldId, findRoomByOwner } = require("../sql/mail");
function saveMessage(attrs, mailboxId, imap) {
const envelope = attrs.envelope;
const timestamp = new Date(envelope.date).getTime();
const rfc822size = attrs.size;
registerMessage(timestamp, rfc822size, envelope.messageId).then(
(messageId) => {
const seen = attrs.flags.includes("Seen") ? 1 : 0; // todo verify
const deleted = attrs.flags.includes("Deleted") ? 1 : 0; // todo verify
registerMailbox_message(
mailboxId,
attrs.uid,
messageId,
attrs.modseq,
seen,
deleted
);
const len = attrs.struct.length;
attrs.struct.forEach((part) => {
if (len > 1) part = part[0];
// todo should be recursive to take eveyraçpghyrue
// todo attachments
if (part?.type == "text") {
const registerType = `${part.type}/${part.subtype}`
const hash = "2"; // todo
const text = "1"; // todo
saveBodypart(part.size, hash, text, '').then((bodypartId) => {
registerBodypart(messageId, registerType, bodypartId, part.size, part.lines);
});
}
});
// const fetch = imap.fetch(uid, { bodies: ["HEADER", part.partID] });
// fetch.on("message", (msg) => {
// msg.on("body", (stream, info) => {
// simpleParser(stream, async (err, parsed) => {
// console.log(part.partID, parsed?.subject);
// });
// });
// msg.once("end", () => {
// console.log("Finished fetching message");
// });
// });
// fetch.once("error", (err) => {
// console.log(err);
// });
// fetch.once("end", () => {
// console.log("Done fetching all messages");
// });
// }
// });
// todo when transfered
//The part column records to which MIME part this header field belongs. It's empty for the main header (the one seen above) and nonempty when a multipart message has headers on each part.
const part = ''; // todo ^
const position = 2; // todo
// save envelope (header + from, to, subject, date, cc)
Object.keys(envelope).forEach(key => {
const newKey = keyNormalizer(key);
if (isHeader(newKey)) {
getFieldId(newKey).then((fieldId) => {
saveHeader_fields(messageId, part, position, fieldId, envelope[key]);
});
} else {
getFieldId(newKey).then((fieldId) => {
if (envelope[key]) {
envelope[key].forEach((elt, index) => {
getAddresseId(`${elt.mailbox}@${elt.host}`).then((addressId) => {
saveAddress_fields(messageId, part, position, fieldId, index, addressId);
});
});
}
});
}
});
// todo check for different provider name of inreplyto
registerMessageInApp()
}
);
}
function haveSameReceivers() {
// take cc and to
}
function registerMessageInApp() {
if (envelope.inReplyTo) {
registerReplyMessage();
} else {
findRoomByOwner(ownerId).then((res) => {
if (res.length == 0) {
registerMessageInRoom(messageId, res[0].id);
} else {
createRoom(envelope.subject, ownerId, envelope.flags.includes["seen"]).then((roomId) => {
registerMessageInRoom(messageId, roomId);
});
}
});
}
}
function registerReplyMessage() {
findSpaceFromMessage(messageId).then((spaces) => {
if(spaces.length == 0) { // no space, so is a transfer
// todo test if members of transferred message are included
} else if (spaces[0].room) { // message in room
isRoomGroup(spaces[0].room_id).then((isGroup) => {
if (isGroup) {
if (hasSameMembersAsParent(messageId)) {
registerMessageInRoom(messageId, spaces[0].room_id);
} else {
// group and not the same member as the reply
// some recipient has been removed create a thread
const notSeen = 0; // todo
const isDm = 0; // todo
createThread(space[0].room_id, envelope.subject, notSeen, isDm).then((threadId) => {
registerMessageInThread(messageId, threadId);
});
}
} else { // reply from channel
// todo
// if (messageInRoom == 1) { // was new channel transform to group
// // register new message in group
// } else if (sender == owner) { // correction from the original sender
// // leave in the same channel
// } else { // user response to announcement
// // create new thread
// }
}
});
} else if (spaces[0].thread) { // message in thread
// todo
// if (hasSameMembersAsParent(messageId)) {
// // register new message in thread
// // possibly convert to room only if parent is channel
// } else {
// // create sub thread
// }
}
});
// `SELECT app_room_messages.room, app_room_messages.thread FROM app_room_messages INNER JOIN messages WHERE messages.messageID = '${envelope.inReplyTo}' AND app_room_messages.message = messages.id`;
}
function findTextPart(struct) {
for (var i = 0, len = struct.length, r; i < len; ++i) {
if (Array.isArray(struct[i])) {
if (r = findTextPart(struct[i]))
return r;
} else if (struct[i].type === 'text'
&& (struct[i].subtype === 'plain'
|| struct[i].subtype === 'html'))
return [struct[i].partID, struct[i].type + '/' + struct[i].subtype];
}
}
function isHeader(key) {
switch (key) {
case "date":
case "subject":
case "messageId":
case "inReplyTo": // when transfer or reply to message
return true;
case "from":
case "sender":
case "replyTo":
case "to":
case "cc":
case "bcc":
return false;
default:
DEBUG.log("Unknown header key: " + key);
return true;
}
}
function keyNormalizer(key) {
// todo
return key;
}
module.exports = {
saveMessage,
};