var utils = require('./imap.utilities'); exports.convStr = function(str) { if (str[0] === '"') return str.substring(1, str.length-1); else if (str === 'NIL') return null; else if (/^\d+$/.test(str)) { // some IMAP extensions utilize large (64-bit) integers, which JavaScript // can't handle natively, so we'll just keep it as a string if it's too big var val = parseInt(str, 10); return (val.toString() === str ? val : str); } else return str; } exports.parseNamespaces = function(str, namespaces) { var result = exports.parseExpr(str); for (var grp=0; grp<3; ++grp) { if (Array.isArray(result[grp])) { var vals = []; for (var i=0,len=result[grp].length; i 2) { // extension data val.extensions = []; for (var j=2,len2=result[grp][i].length; j next) { if (Array.isArray(cur[next])) { part.params = {}; for (var i=0,len=cur[next].length; i next && Array.isArray(cur[next])) { part.envelope = {}; for (var i=0,field,len=cur[next].length; i= 2 && i <= 7) { var val = cur[next][i]; if (Array.isArray(val)) { var addresses = [], inGroup = false, curGroup; for (var j=0,len2=val.length; j next && Array.isArray(cur[next])) { part.body = exports.parseBodyStructure(cur[next], prefix + (prefix !== '' ? '.' : '') + (partID++).toString(), 1); } else part.body = null; ++next; } if ((part.type === 'text' || (part.type === 'message' && part.subtype === 'rfc822')) && partLen > next) part.lines = cur[next++]; if (typeof cur[1] === 'string' && partLen > next) part.md5 = cur[next++]; } // add any extra fields that may or may not be omitted entirely exports.parseStructExtra(part, partLen, cur, next); ret.unshift(part); } return ret; } exports.parseStructExtra = function(part, partLen, cur, next) { if (partLen > next) { // disposition // null or a special k/v list with these kinds of values: // e.g.: ['Foo', null] // ['Foo', ['Bar', 'Baz']] // ['Foo', ['Bar', 'Baz', 'Bam', 'Pow']] if (Array.isArray(cur[next])) { part.disposition = {}; if (Array.isArray(cur[next][1])) { for (var i=0,len=cur[next][1].length; i next) { // language can be a string or a list of one or more strings, so let's // make this more consistent ... if (cur[next] !== null) part.language = (Array.isArray(cur[next]) ? cur[next] : [cur[next]]); else part.language = null; ++next; } if (partLen > next) part.location = cur[next++]; if (partLen > next) { // extension stuff introduced by later RFCs // this can really be any value: a string, number, or (un)nested list // let's not parse it for now ... part.extensions = cur[next]; } } exports.parseExpr = function(o, result, start) { start = start || 0; var inQuote = false, lastPos = start - 1, isTop = false; if (!result) result = new Array(); if (typeof o === 'string') { var state = new Object(); state.str = o; o = state; isTop = true; } for (var i=start,len=o.str.length; i 0) result.push(exports.convStr(o.str.substring(lastPos+1, i))); if (o.str[i] === ')' || o.str[i] === ']') return i; lastPos = i; } else if (o.str[i] === '(' || o.str[i] === '[') { var innerResult = []; i = exports.parseExpr(o, innerResult, i+1); lastPos = i; result.push(innerResult); } } else if (o.str[i] === '"' && (o.str[i-1] && (o.str[i-1] !== '\\' || (o.str[i-2] && o.str[i-2] === '\\')))) inQuote = false; if (i+1 === len && len - (lastPos+1) > 0) result.push(exports.convStr(o.str.substring(lastPos+1))); } return (isTop ? result : start); }