/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, curly:true, browser:true, devel:true, indent:2, maxerr:50, moz:true, newcap:false, moz:true */ /* global mozContact: false, ContactTelField: false, parseLDIF: false */ (function () { "use strict"; // Shim for the intersection of two Arrays. if (!Array.prototype.intersection) { Array.prototype.intersection = function (anotherArr) { return this.filter(function(n) { if (anotherArr.indexOf(n) === -1) { return false; } return true; }); }; } const phoneFields = [ "mobile", "facsimiletelephonenumber", "homePhone", "telephoneNumber" ]; const emailFields = [ "mail" ]; function ValueError(message) { this.name = "ValueError"; this.message = message || "Unknown Value"; } ValueError.prototype = new Error(); ValueError.prototype.constructor = ValueError; /** * Translate objects created from LDIF files to Contacts * * @param Array of LDIF objects * @return Contact with all fields filled * @throws ValueError for unknown field in the LDIF object * * ContactsAPI: * @see https://wiki.mozilla.org/WebAPI/ContactsAPI * @spec http://www.w3.org/TR/contacts-manager-api/ * * Thunderbid LDAP Schema: * @see https://developer.mozilla.org/docs/Thunderbird/LDAP_Support * @see https://tools.ietf.org/html/rfc4519 */ function translateObjectToContact(inRec) { var contact = {}, pomStr = "", curRec = null; /** * Find the proper record (or create new one) in the multi-value * attribute * * @param idx name of the attribute to which the record belongs * @param subClass Function constructor of the record if there is * none * @param subType String with the type of the record * @return record of the proper class * * Uses global variable contact. */ function findSubElement(idx, subType) { var cAddr = null; console.log("idx = " + idx + ", subType = " + subType); // No contact.adr at all if (!contact.hasOwnProperty(idx)) { cAddr = { 'type': [subType] }; contact[idx] = cAddr; } // Single-element property else if (!Array.isArray(contact[idx])) { if (contact[idx].type.indexOf(subType) === -1) { contact[idx] = [contact[idx]]; cAddr = { 'type': [subType] }; contact[idx].push(cAddr); } else { cAddr = contact[idx]; } } // Array else { cAddr = contact[idx].filter(function (addr) { return addr.type.indexOf(subType) !== -1; }); if (cAddr.length === 0) { cAddr = { 'type': [subType] }; contact[idx].push(cAddr); } else { cAddr = cAddr[0]; } } console.log("contact:\n" + contact.toSource()); console.log("cAddr:\n" + cAddr.toSource()); return cAddr; } for (var key in inRec) { if (key === "birthyear") { pomStr = inRec[key]; contact.bday = new Date(pomStr.slice(0,4), pomStr.slice(4,6), pomStr.slice(6,8)); } else if (key === "c") { curRec = findSubElement("adr", "work"); curRec.countryName = inRec[key]; } else if (key === "cn") { contact.name = [inRec[key]]; } else if (key === "description") { contact.note = [inRec[key]]; } else if (key === "facsimiletelephonenumber") { curRec = findSubElement("tel", "fax"); curRec.value = inRec[key]; } else if (key === "givenName") { contact.givenName = [inRec[key]]; } else if (key === "homePhone") { curRec = findSubElement("tel", "home"); curRec.value = inRec[key]; } else if (key === "l") { curRec = findSubElement("adr", "work"); curRec.locality = inRec[key]; } else if (key === "mail") { curRec = findSubElement("email", "work"); curRec.value = inRec[key]; } else if (key === "mobile") { curRec = findSubElement("tel", "mobile"); curRec.value = inRec[key]; } else if (key === "mozillaHomeCountryName") { curRec = findSubElement("adr", "home"); curRec.countryName = inRec[key]; } else if (key === "mozillaHomeLocalityName") { curRec = findSubElement("adr", "home"); curRec.locality = inRec[key]; } else if (key === "mozillaHomePostalCode") { curRec = findSubElement("adr", "home"); curRec.postalCode = inRec[key]; } else if (key === "mozillaHomeState") { curRec = findSubElement("adr", "home"); curRec.region = inRec[key]; } else if (key === "mozillaHomeStreet") { curRec = findSubElement("adr", "home"); curRec.streetAddress = inRec[key]; } else if (key === "mozillaHomeUrl") { curRec = findSubElement("url", "home"); curRec.value = inRec[key]; } else if (key === "mozillaNickname") { contact.nickname = [inRec[key]]; } else if (key === "o") { contact.org = [inRec[key]]; } else if (key === "sn") { contact.familyName = [inRec[key]]; } else if (key === "st") { curRec = findSubElement("adr", "work"); curRec.region = inRec[key]; } else if (key === "street") { curRec = findSubElement("adr", "work"); curRec.streetAddress = inRec[key]; } else if (key === "telephoneNumber") { curRec = findSubElement("tel", "work"); curRec.value = inRec[key]; } else if (key === "title") { contact.jobTitle = [inRec[key]]; } // Unknown attribute else { throw new ValueError("Unknown attribute " + key + " with value:\n" + inRec[key]); } } console.log("contact:\n" + contact.toSource()); if (Object.keys(contact).length > 0) { var outObj = new mozContact(); outObj.init(contact); return contact; } return null; } /** * Not used presently and not debugged. */ function whenContactAlreadyPresent(rec, cb_not_found, cb_found) { var rec_keys = Object.keys(rec); // Finding whether the contact has email or telephone var email_fields = rec_keys.intersection(emailFields); var phone_fields = rec_keys.intersection(phoneFields); var search_keys = []; if (email_fields.length > 0) { search_keys = email_fields; } else if (phone_fields.length > 0) { search_keys = phone_fields; } if (search_keys.length > 0) { var search_opts = { filterValue : rec(search_keys[0]), filterBy : search_keys, filterOp : "contains", filterLimit : 1 }; var search = navigator.mozContacts.find(search_opts); // Possible duplicate found ... bail out, rather do nothing! search.onsuccess = function() { // search.result is found record (Array of length 1) cb_found(rec, search.result); }; // No duplicates, go ahead and create new record search.onerror = function() { cb_not_found(rec); }; } } function restoreURLForm(url) { document.getElementById("progress-div").style.display = "none"; document.getElementById("URL-form").style.display = "block"; if (url !== undefined) { document.getElementsByName("URL")[0].value = url; } } function insertData(ldifText) { var progressEl = document.querySelector("#progress-div progress"); var records = parseLDIF(ldifText.split("\n")); console.log("records.length = " + records.length); if (records.length > 0) { if (!window.confirm("THIS WILL ERASE ALL CONTACTS ON YOUR PHONE!\n" + "Are you cool with that?")) { return false; } } var cl_req = navigator.mozContacts.clear(); cl_req.onerror = function() { throw new Error("Cannot clear whole Contacts database?"); }; cl_req.onsuccess = function() { progressEl.max = records.length; progressEl.value = 0; records.forEach(function (rec) { console.log("processed contact:\n" + rec.toSource()); var add_contact = translateObjectToContact(rec); var sav_req = navigator.mozContacts.save(add_contact); sav_req.onsuccess = function() { progressEl.value += 1; if (progressEl.value >= records.length) { window.alert("All contacts have been imported!"); restoreURLForm(); } }; sav_req.onerror = function() { console.error("Cannot save record " + add_contact.id + "\n" + rec.toSource()); }; }); }; } window.onload = function() { document.body.addEventListener("submit", function(evt) { var URL = document.getElementsByName("URL")[0].value; var progressForm = document.getElementById("progress-div"); document.getElementById("URL-form").style.display = "none"; progressForm.style.display = "block"; var req = new XMLHttpRequest(); req.open("GET", URL, true); var progressEl = progressForm.getElementsByTagName("progress")[0]; req.onprogress = function(evt) { if (evt.lengthComputable) { progressEl.max = evt.total; progressEl.value = evt.loaded; } }; req.onload = function() { var inText = req.responseText; if (inText.length > 0) { insertData(inText); } }; req.onerror = function() { window.alert("Cannot load " + URL + "!"); restoreURLForm(URL); }; req.send(); evt.stopPropagation(); evt.preventDefault(); }, false); }; }());