import MimeHeader from "./MimeHeader.js"; const atext = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-/=?^_`{|}~".split(''); const dtext = "!\"#$%^&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~".split(''); class MessageIdMimeHeader extends MimeHeader { constructor(key, value) { super(key, value); this._messageIdValue = ""; } // Message-ID: <0Q27kpOFnz1MK3ASM_vbjI8L_BYN3j5OSxIaGxerST74zBn7VZfqCowbhEWgJ0Yv4mV847u25YGjENqlsM7-15Zdus90qN7t_kj55FyuN_c=@protonmail.com> get messageIdValue() { // ABNF: // message-id = "Message-ID:" msg-id CRLF // msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] // id-left = dot-atom-text / obs-id-left // obs-id-left = local-part // id-right = dot-atom-text / no-fold-literal / obs-id-right // obs-id-right = domain // no-fold-literal = "[" *dtext "]" // dtext = %d33-90 / ; Printable US-ASCII // %d94-126 / ; characters not including // obs-dtext ; "[", "]", or "\" // dot-atom-text = 1*atext *("." 1*atext) // atext = ALPHA / DIGIT / ; Printable US-ASCII // "!" / "#" / ; characters not including // "$" / "%" / ; specials. Used for atoms. // "&" / "'" / // "*" / "+" / // "-" / "/" / // "=" / "?" / // "^" / "_" / // "`" / "{" / // "|" / "}" / // "~" // dtext = %d33-90 / ; Printable US-ASCII // %d94-126 / ; characters not including // obs-dtext ; "[", "]", or "\" // CFWS = (1*([FWS] comment) [FWS]) / FWS // FWS = ([*WSP CRLF] 1*WSP) / obs-FWS // ; Folding white space // comment = "(" *([FWS] ccontent) [FWS] ")" // ccontent = ctext / quoted-pair / comment // WSP = SP / HTAB ; white space // obs-FWS = 1*WSP *(CRLF 1*WSP) // quoted-pair = ("\" (VCHAR / WSP)) / obs-qp // obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR) // obs-NO-WS-CTL = %d1-8 / ; US-ASCII control // %d11 / ; characters that do not // %d12 / ; include the carriage // %d14-31 / ; return, line feed, and // %d127 ; white space characters // TODO: Implement utf-8 encoding and whatever other encodings we have to support. if ( this._messageIdValue !== "" ) { return this._messageIdValue; } // TODO: Implement this state machine properly according to the above ABNF. var state = ""; var inCRLF = false; var commentDepth = 0; 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 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._messageIdValue = `${idLeft}@${idRight}`; return `${idLeft}@${idRight}`; } } export default MessageIdMimeHeader;