﻿// Copyright Michael Anthony Puls II, http://shadow2531.com/
// Distributed under the Boost Software License, Version 1.0.
// http://boost.org/LICENSE_1_0.txt .
// Newest versions:  http://shadow2531.com/opera/testcases/mailto/MailtoURIParserPack.zip

function MailtoURIParser(INURI) {
    eval(INURI);
    
    this.setURI = function(INURI) {
        eval(INURI);
    };
    
    this.getURI = function() {
        return uri;
    };
    
    this.getNormalizedURI = function() {
        return nuri;
    };
    
    this.getEncodedTO = function() {
        return to;
    };
    
    this.getDecodedTO = function() {
        return dto;
    };
    
    this.getEncodedSubject = function() {
        return subject;
    };
    
    this.getDecodedSubject = function() {
        return dsubject;
    };
    
    this.getEncodedBody = function() {
        return body;
    };
    
    this.getDecodedBody = function() {
        return dbody;
    };
    
    this.getEncodedCC = function() {
        return cc;
    };
    
    this.getDecodedCC = function() {
        return dcc;
    };
    
    this.getEncodedBCC = function() {
        return bcc;
    };
    
    this.getDecodedBCC = function() {
        return dbcc;
    };
    
    // %w = original uri
    // %n = normalized uri (mailto URI with just the basic hnames with no duplicate hnames)
    // %t = decoded TO value
    // %T = encoded TO value
    // %s = decoded Subject value
    // %m = deocded Body value
    // %M = encoded Body value
    // %c = decoded CC value
    // %C = encoded CC value
    // %b = decoded BCC value
    // %B = encoded BCC value
    // %% = %
    // An invalid %key or a % at the end of the string is treated literally.

    // By example:
    // resolveCommandFormatString("%T") would return the value of the to string.
    // resolveCommandFormatString("%%") would return %.
    
    this.resolveCommandFormatString = function(S) {
        var ret = "";
        var IDENT = '%';
        var i = 0;
        for (var pos; (pos = S.indexOf(IDENT, i)) != -1; ) {
            ret += S.substring(i, pos);
            ++pos;
            if (pos != S.length) {
                var K = S.charAt(pos);
                switch(K) {
                    case IDENT:
                        ret += IDENT;
                        break;
                    case 'w':
                        ret += uri;
                        break;
                    case 'n':
                        ret += nuri;
                        break;
                    case 'T':
                        ret += to;
                        break;
                    case 't':
                        ret += dto;
                        break;
                    case 'S':
                        ret += subject;
                        break;
                    case 's':
                        ret += dsubject;
                        break;
                    case 'M':
                        ret += body;
                        break;
                    case 'm':
                        ret += dbody;
                        break;
                    case 'C':
                        ret += cc;
                        break;
                    case 'c':
                        ret += dcc;
                        break;
                    case 'B':
                        ret += bcc;
                        break;
                    case 'b':
                        ret += dbcc;
                        break;
                    default:
                        ret += IDENT;
                        ret += K;
                        break;
                }
                ++pos;
            } else if (S.charAt(pos - 1) == IDENT) {
                ret += IDENT;
            }
            i = pos;
        }
        ret += S.substr(i);
        return ret;
    };
    
    var uri;
    var nuri;
    var to;
    var dto;
    var subject;
    var dsubject;
    var body;
    var dbody;
    var cc;
    var dcc;
    var bcc;
    var dbcc;
    
    // Join all non-empty hvalues for the hname SKEY with %2C%20
    
    function getAddresses(HLIST, SKEY) {
        var ret = "";
        for (var i = 0; i < HLIST.length; ++i) {
            var eq = HLIST[i].indexOf('=');
            if (eq == -1) {
                continue;
            }
            if (HLIST[i].substring(0, eq).toLowerCase() != SKEY) {
                continue;
            }
            var HVALUE = HLIST[i].substr(eq + 1);
            if (HVALUE == "") {
                continue;
            }
            if (ret != "") {
                ret += "%2C%20";
            }
            ret += HVALUE;
        }
        try {
            // Decode and then reencode so the string is encoded according to encodeURIComponent rules.
            // Make sure that all newlines are represented as %0D%0A.
            // Fix addresses that are separated with just %2C so they're separated with %2C%20
            return encodeURIComponent(decodeURIComponent(ret).replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n/g, "\r\n")).replace(/\%2C\%20/g, "%2C").replace(/%2C/g, "%2C%20");
        } catch (x) {
            return ret.replace(/\+/g, "%2B");
        }
    }
    
    // Use the last subject hvalue even if it's empty and even if a previous one is not.
    
    function getSubject(HLIST) {
        for (var i = HLIST.length - 1; i > -1; --i) {
            var eq = HLIST[i].indexOf('=');
            if (eq != -1 && HLIST[i].substring(0, eq).match(/subject/i)) {
                try {
                    // Decode and then reencode so the string is encoded according to encodeURIComponent rules.
                    // Make sure that all newlines are represented as %0D%0A.
                    return encodeURIComponent( decodeURIComponent(HLIST[i].substr(eq + 1)).replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n/g, "\r\n"));
                } catch(x) {
                    return HLIST[i].substr(eq + 1).replace(/\+/g, "%2B");
                }
            }
        }
        return "";
    }
    
    // Join the first non-empty body hvalue and all body hvalues (even if they're empty) after that with %0D%0A
    
    function getBody(HLIST) {
        var ret = "";
        for (var i = 0; i < HLIST.length; ++i) {
            var eq = HLIST[i].indexOf('=');
            if (eq == -1) {
                continue;
            }
            if (HLIST[i].substring(0, eq).toLowerCase() != "body") {
                continue;
            }
            var HVALUE = HLIST[i].substr(eq + 1);
            if (ret == "" && HVALUE == "") {
                continue;
            }
            if (ret != "") {
                ret += "%0D%0A";
            }
            ret += HVALUE;
        }
        try {
            // Decode and then reencode so the string is encoded according to encodeURIComponent rules.
            // Make sure that all newlines are represented as %0D%0A.
            return encodeURIComponent(decodeURIComponent(ret).replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n/g, "\r\n"));
        } catch(x) {
            return ret.replace(/\+/g, "%2B");
        }
    }
    

    function decode(S) {
        try {
            // Decode and make sure all newlines are represented as \n.
            // (The second replace isn't needed at the moment.)
            return decodeURIComponent(S).replace(/\r\n/g, '\n').replace(/\r/g, '\n'); 
        } catch(x) {
            return S;
        }
    }
    
    function eval(INURI) {
        if (INURI.search(/mailto:/i) == 0) {
            uri = INURI;
            var PARSEABLE = INURI.substr(4).replace(/:/, '=').replace(/\?/, '&');
            var HLIST = PARSEABLE.split('&');
            to = getAddresses(HLIST, "to");
            dto = decode(to);
            subject = getSubject(HLIST);
            dsubject = decode(subject);
            body = getBody(HLIST);
            dbody = decode(body);
            cc = getAddresses(HLIST, "cc");
            dcc = decode(cc);
            bcc = getAddresses(HLIST, "bcc");
            dbcc = decode(bcc);
            
            // Normalized mailto URI. It contains just the basic hnames and no duplicates.
            // (For old mail clients)
            nuri = "mailto:";
            nuri += to;
            nuri += "?subject=";
            nuri += subject;
            nuri += "&body=";
            nuri += body;
            nuri += "&cc=";
            nuri += cc;
            nuri += "&bcc=";
            nuri += bcc;
        } else {
            uri = nuri = "mailto:";
            to = dto = subject = dsubject = body = dbody = cc = dcc = bcc = dbcc = "";
        }
    }
}