167 lines
7.1 KiB
JavaScript
167 lines
7.1 KiB
JavaScript
|
import MimeHeader from "./MimeHeader.js";
|
||
|
|
||
|
const atext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-/=?^_`{|}~".split('');
|
||
|
const dtext = "!\"#$%^&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~".split('');
|
||
|
const qtext = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~".split('');
|
||
|
|
||
|
class FromMimeHeader extends MimeHeader {
|
||
|
constructor(key, value) {
|
||
|
super(key, value);
|
||
|
this._fromValue = [];
|
||
|
}
|
||
|
// From: Andrew Pietila <a.pietila@protonmail.com>
|
||
|
get fromValue() {
|
||
|
// ABNF:
|
||
|
// from = "From:" mailbox-list CRLF
|
||
|
// mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
|
||
|
// mailbox = name-addr / addr-spec
|
||
|
// name-addr = [display-name] angle-addr
|
||
|
// display-name = phrase
|
||
|
// phrase = 1*word / obs-phrase
|
||
|
// word = atom / quoted-string
|
||
|
// atom = [CFWS] 1*atext [CFWS]
|
||
|
// addr-spec = local-part "@" domain
|
||
|
// local-part = dot-atom / quoted-string / obs-local-part
|
||
|
// domain = dot-atom / domain-literal / obs-domain
|
||
|
// domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
|
||
|
// dtext = %d33-90 / ; Printable US-ASCII
|
||
|
// %d94-126 / ; characters not including
|
||
|
// obs-dtext ; "[", "]", or "\"
|
||
|
// dot-atom-text = 1*atext *("." 1*atext)
|
||
|
// dot-atom = [CFWS] dot-atom-text [CFWS]
|
||
|
// quoted-string = [CFWS]
|
||
|
// DQUOTE *([FWS] qcontent) [FWS] DQUOTE
|
||
|
// [CFWS]
|
||
|
// qcontent = qtext / quoted-pair
|
||
|
// qtext = %d33 / ; Printable US-ASCII
|
||
|
// %d35-91 / ; characters not including
|
||
|
// %d93-126 / ; "\" or the quote character
|
||
|
// obs-qtext
|
||
|
// TODO: Implement utf-8 encoding and whatever other encodings we have to support.
|
||
|
if ( this._fromValue.length !== 0 ) {
|
||
|
return this._fromValue;
|
||
|
}
|
||
|
// TODO: Implement this state machine properly according to the above ABNF.
|
||
|
var from = [];
|
||
|
var state = "";
|
||
|
var inCRLF = false;
|
||
|
var commentDepth = 0;
|
||
|
var displayName = "";
|
||
|
var inDquot = false;
|
||
|
var idLeft = "";
|
||
|
var idRight = "";
|
||
|
var idRightDatEmittedRightSquacket = false;
|
||
|
for (var char of this.rawValue) {
|
||
|
if ( inCRLF === true && char !== "\n" ) {
|
||
|
return null; // Error state.
|
||
|
}
|
||
|
if (state === "") {
|
||
|
// CFWS
|
||
|
if ( char === " ") {
|
||
|
continue;
|
||
|
} else if ( char === "\t") {
|
||
|
continue;
|
||
|
} else if ( char === "(" && !inDquot ) {
|
||
|
commentDepth++;
|
||
|
} else if ( char === "\"" ) {
|
||
|
inDquot = !inDquot;
|
||
|
} else if ( char === ")" && !inDquot ) {
|
||
|
commentDepth--;
|
||
|
} else if ( char === "\r" ) {
|
||
|
inCRLF = true;
|
||
|
} else if ( char === "\n" ) {
|
||
|
inCRLF = false;
|
||
|
} else {
|
||
|
state = "display-name";
|
||
|
}
|
||
|
} else if ( state === "display-name") {
|
||
|
if ( char === " " ) {
|
||
|
if ( state.endsWith(" ") ) {
|
||
|
continue;
|
||
|
} else {
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// else if ( char === "<" ) {
|
||
|
// state = "id-left";
|
||
|
// } else {
|
||
|
// return null; // Error state, we couldn't produce a proper message ID from the input.
|
||
|
// }
|
||
|
// } else if ( state === "id-left" ) {
|
||
|
// if ( atext.includes(char) ) {
|
||
|
// idLeft += char;
|
||
|
// } else if ( char === "." ) {
|
||
|
// if ( idLeft.endsWith(".") || idLeft.length === 0 ) {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// idLeft += char;
|
||
|
// } else if ( char === "@" ) {
|
||
|
// if ( idLeft.endsWith(".") || idLeft.length === 0) {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// state = "id-right";
|
||
|
// }
|
||
|
// } else if ( state === "id-right" ) {
|
||
|
// if ( char === "[" ) {
|
||
|
// if ( idRight.length !== 0 ) {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// idRight += char;
|
||
|
// state = "id-right-dat";
|
||
|
// } else if ( char === "." ) {
|
||
|
// if ( idRight.endsWith(".") || idRight.length === 0 ) {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// idRight += char;
|
||
|
// } else if ( char === ">" ) {
|
||
|
// if ( idRight.endsWith(".") || idRight.length === 0) {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// state = "end-cfws"
|
||
|
// }
|
||
|
// } else if ( state === "id-right-dat" ) {
|
||
|
// if ( char === ">" && idRight.endsWith("]") ) {
|
||
|
// state = "end-cfws";
|
||
|
// continue;
|
||
|
// }
|
||
|
// if ( dtext.includes(char) ) {
|
||
|
// if ( idRightDatEmittedRightSquacket ) {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// idRight += char;
|
||
|
// } else if ( char === "]" ) {
|
||
|
// if ( idRightDatEmittedRightSquacket ) {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// idRight += char;
|
||
|
// idRightDatEmittedRightSquacket = true;
|
||
|
// }
|
||
|
// } else if ( state === "end-cfws" ) {
|
||
|
// // CFWS
|
||
|
// if ( char === " ") {
|
||
|
// continue;
|
||
|
// } else if ( char === "\t") {
|
||
|
// continue;
|
||
|
// } else if ( char === "(" && !inDquot ) {
|
||
|
// commentDepth++;
|
||
|
// } else if ( char === "\"" ) {
|
||
|
// inDquot = !inDquot;
|
||
|
// } else if ( char === ")" && !inDquot ) {
|
||
|
// commentDepth--;
|
||
|
// } else if ( char === "\r" ) {
|
||
|
// inCRLF = true;
|
||
|
// } else if ( char === "\n" ) {
|
||
|
// inCRLF = false;
|
||
|
// } else {
|
||
|
// return null; // Error state.
|
||
|
// }
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
this._fromValue = from;
|
||
|
return `${idLeft}@${idRight}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export default FromMimeHeader;
|