/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is edsintegration. * * The Initial Developer of the Original Code is * Mozilla Corp. * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Mike Conley * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ var EXPORTED_SYMBOLS = [ "nsAbEDSMailingList", "kMailListDirScheme", "gMailListCount", "attachAddressListToVCard", ]; const Cu = Components.utils; const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; const kMailListDirType = "moz-abedsmailinglist"; const kMailListDirScheme = kMailListDirType + "://"; const kMailListDirContractID = "@mozilla.org/addressbook/directory;1?type=" + kMailListDirType; const kMailListDirClassID = "71e30b23-9bd0-41a0-8496-a10052698a00"; Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource:///modules/mailServices.js"); Cu.import("resource:///modules/iteratorUtils.jsm"); Cu.import("resource://edsintegration/nsAbEDSCommon.jsm"); Cu.import("resource://edsintegration/LibGLib.jsm"); Cu.import("resource://edsintegration/LibEBookClient.jsm"); Cu.import("resource://edsintegration/LibEClient.jsm"); Cu.import("resource://edsintegration/LibEContact.jsm"); Cu.import("resource://edsintegration/LibEVCard.jsm"); Cu.import("resource://edsintegration/nsAbEDSCommon.jsm"); gMailListCount = 0; function nsAbEDSMailingList() { this._uri = ""; this._dirName = ""; this._initialized = false; this._childCards = Cc["@mozilla.org/array;1"] .createInstance(Ci.nsIMutableArray); this._didInitCards = false; this._open = false; this._uri_ptr = null; this._book_view = null; this._isQuery = false; this._query = ""; this._proxy = null; this._searchCache = []; this._EBookURI = null; this._EDSUid = null; } nsAbEDSMailingList.prototype = { classDescription: "Evolution Data Server Address Book Mailing List Type", QueryInterface: XPCOMUtils.generateQI([Ci.nsIAbDirectory, Ci.nsIAbEDSMailingList, Ci.nsIAbEDSDirectory, Ci.nsIAbDirSearchListener, Ci.nsIAbDirectorySearch]), init: function(aURI) { LOG("Init'ed a Mailing List with URI: " + aURI); this._eContact = gMailListEContactLookup[aURI]; LOG("My EContact is at: " + this._eContact); this._uri = aURI; this._eBook = gMailListEBookLookup[aURI]; this._EClient = ctypes.cast(this._eBook, LibEClient.EClient.ptr); let EDSUid = LibEContact.getStringConstProp(this._eContact, LibEContact.getEnum("E_CONTACT_UID")); LOG("Got UID: " + EDSUid); gEContactLookup[EDSUid] = this; this._EDSUid = EDSUid; }, get EDSUid() { return this._EDSUid; }, get propertiesChromeURI() { return kPropertiesChromeURI; }, get fileName() { return ""; }, get URI() { return this._uri; }, get position() { return ""; }, get childNodes() { return CreateSimpleObjectEnumerator({}); }, get addressLists() { if (!this._didInitCards) this._initCards(); return this._childCards; }, get childCards() { if (!this._didInitCards) this._initCards(); return this._childCards.enumerate(); }, get isQuery() { return false; }, get supportsMailingLists() { return false; }, get lastModifiedDate() { return 0; }, get readOnly() { return LibEClient.isReadOnly(this._EClient); }, get isRemote() { return true; }, get isSecure() { return false; }, get dirPrefId() { return kDirPrefId; }, get uuid() { return this.dirPrefId + "." + this.dirName; }, set dirPrefId(val) { }, set lastModifiedDate(val) { }, get isMailList() { return true; }, set isMailList(val) { }, get dirName() { if (!this._dirName) this._dirName = LibEContact .getStringConstProp(this._eContact, LibEContact .getEnum("E_CONTACT_NAME_OR_ORG")); return this._dirName; }, set dirName(aDirName) { }, set addressLists(val) { this._childCards = Cc["@mozilla.org/array;1"] .createInstance(Ci.nsIMutableArray); for (let i = 0; i < val.length; i++) { let card = val.queryElementAt(i, Ci.nsIAbCard); this._childCards.appendElement(card, false); } }, get listNickName() { return ""; }, set listNickName(val) { }, get description() { return ""; }, set description(val) { }, addMailList: function EDSAb_addMailList(aList) { }, deleteDirectory: function EDSAb_deleteDirectory(aDirectory) { }, hasCard: function EDSAb_hasCard(aCard) { return false; }, hasDirectory: function EDSAb_hasDirectory(aDirectory) { return false; }, addCard: function EDSAb_addCard(aCard) { return null; }, modifyCard: function EDSAb_modifyCard(aModifiedCard) { return null; }, deleteCards: function EDSAb_deleteCards(aCards) { for (let i = 0; i < aCards.length; i++) { let cardToRemove = aCards.queryElementAt(i, Ci.nsIAbCard); let targetIndex = this.addressLists.indexOf(0, cardToRemove); if (targetIndex != -1) this.addressLists.removeElementAt(targetIndex); MailServices.ab.notifyDirectoryItemDeleted(this, cardToRemove); } this.commit(); }, dropCard: function EDSAb_dropCard(aCard, aNeedToCopyCard) { // Create a new card, and just copy over the DisplayName // and PrimaryEmail, since this is all EDS seems to care about. var newCard = Cc["@mozilla.org/addressbook/cardproperty;1"] .createInstance(Ci.nsIAbCard); let address = aCard.getProperty("PrimaryEmail", ""); let name = aCard.getProperty("DisplayName", ""); newCard.setProperty("PrimaryEmail", address); newCard.setProperty("DisplayName", name); this.addressLists.appendElement(newCard, false); this.commit(); }, useForAutoComplete: function EDSAb_useForAutoComplete(aIdentityKey) { return false; }, editMailListToDatabase: function EDSAb_editMailListToDatabase(aListCard) { }, copyMailList: function EDSAb_copyMailList(aSrcList) { }, createNewDirectory: function EDSAb_createNewDirectory(aDirName, aURI, aType, aPrefName) { return ""; }, createDirectoryByURI: function EDSAb_createDirectoryByURI(aDisplayName, aURI) { }, getIntValue: function EDSAb_getIntValue(aName, aDefaultValue){ return aDefaultValue; }, getBoolValue: function EDSAb_getBoolValue(aName, aDefaultValue) { if (aName == "HidesRecipients") { let showAddrs = LibEContact .getProp(this._eContact, LibEContact .getEnum("E_CONTACT_LIST_SHOW_ADDRESSES")); return showAddrs.isNull() } return aDefaultValue; }, getStringValue: function EDSAb_getStringValue(aName, aDefaultValue) { return aDefaultValue; }, getLocalizedStringValue: function EDSAb_getLocalizedStringValue(aName, aDefaultValue) { return aDefaultValue; }, setIntValue: function EDSAb_setIntValue(aName, aValue){ }, setBoolValue: function EDSAb_setBoolValue(aName, aValue) { if (aName == "HidesRecipients") { let showAddrs = !aValue ? LibGLib.TRUE : LibGLib.FALSE; let showAddrsPtr = LibGLib.g_int_to_pointer(showAddrs); LibEContact.setProp(this._eContact, LibEContact .getEnum("E_CONTACT_LIST_SHOW_ADDRESSES"), showAddrsPtr); } }, setStringValue: function EDSAb_setStringValue(aName, aValue) { }, setLocalizedStringValue: function EDSAb_setLocalizedStringValue(aName, aValue) { }, cardForEmailAddress: function EDSAb_cardForEmailAddress(aEmailAddress) { return null; }, getCardFromProperty: function EDSAb_getCardFromProperty(aProperty, aValue, aCaseSensitive) { if (!aCaseSensitive) aValue = aValue.toLowerCase(); for (let i = 0; i < this._childCards.length; i++) { let card = this._childCards[i]; let property = card.getProperty(aProperty) if (!aCaseSensitive) property = property.toLowerCase(); if (property == aValue) return card; } return null; }, getCardsFromProperty: function EDSAb_getCardsFromProperty(aProperty, aValue, aCaseSensitive) { let result = [] if (!aCaseSensitive) aValue = aValue.toLowerCase(); for(let i = 0; i < this._childCards.length; i++) { let card = this._childCards[i]; let property = card.getProperty(aProperty) if (!aCaseSensitive) property = property.toLowerCase(); if (property == aValue) result.push(card); } return CreateSimpleEnumerator(result); }, generateName: function EDSAb_generateName(aGenerateFormat, aBundle) { return this.dirName; }, useForAutocomplete: function EDSAb_useForAutocomplete(aIdentity) { return true; }, startSearch: function EDSAb_startSearch() { if (!this.isQuery) return Cr.NS_ERROR_FAILURE; this._performingSearch = true; let args = Cc["@mozilla.org/addressbook/directory/query-arguments;1"] .createInstance(Ci.nsIAbDirectoryQueryArguments); let utils = Cc["@mozilla.org/addressbook/utils-service;1"] .getService(Ci.nsIAbUtilsService); let expression = utils.convertQueryStringToExpression(this._query); args.expression = expression; args.querySubDirectories = false; let queryProxy = Cc["@mozilla.org/addressbook/directory-query/proxy;1"] .createInstance(Ci.nsIAbDirectoryQueryProxy); queryProxy.initiate(); let context = queryProxy.doQuery(this.proxy, args, this, -1, 0); return; }, stopSearch: function EDSAb_stopSearch() { }, onSearchFinished: function EDSAb_onSearchFinished(aResult, aErrorMsg) { // TODO: if we're a query, free up our resources. }, onSearchFoundCard: function EDSAb_onSearchFoundCard(aCard) { this._searchCache.push(aCard); }, commit: function EDSAbMl_commit() { // First, let's clear out all of the existing addresses in the EContact var vcard = ctypes.cast(this._eContact, LibEVCard.EVCard.ptr); LibEVCard.removeAttributes(vcard, "", LibEVCard.EVC_EMAIL) attachAddressListToVCard(vcard, this.addressLists); let errorPtr = new LibGLib.GError.ptr(); let success = LibEBookClient.modifyContactSync(this._eBook, this._eContact, null, errorPtr.address()); if (!success) { let msg = errPtr.contents.readString(); ERROR("Could not commit mailing list - error message was: " + msg); Services.prompt.alert(null, _("ProblemSavingMailingListTitle"), _("ProblemSavingMailingList", [msg])); LibGLib.g_error_free(errorPtr); errorPtr = null; } }, _initCards: function EDSAb__initCards() { if (this._didInitCards) return; this._childCards = Cc["@mozilla.org/array;1"] .createInstance(Ci.nsIMutableArray); // In an EDS mailing list, we just have email addresses. // Nothing more, nothing less. No need to create a special // nsIAbEDSCard for these - we'll just use vanilla nsIAbCard's. let emails = LibEContact .getPropList(this._eContact, LibEContact.getEnum("E_CONTACT_EMAIL")); for (let ptr = emails.next(); ptr != null; ptr = emails.next()) { let card = Cc["@mozilla.org/addressbook/cardproperty;1"] .createInstance(Ci.nsIAbCard); let email = ctypes.cast(ptr, LibGLib.gchar.ptr).readString(); // EDS stores the addresses like this: // username // // I'll use the headerParser to extract the address and the // name to insert into the nsIAbCard's. let address = MailServices .headerParser .extractHeaderAddressMailboxes(email); let name = MailServices .headerParser .extractHeaderAddressName(email); card.setProperty("PrimaryEmail", address); card.setProperty("DisplayName", name); card.setProperty("NickName", name); // We want the mailing list editor to appear when double-clicking // on this card, so we'll pretend this card is a mailing list, // and pass it our URI. A little hack-y, but it does the job. card.isMailList = true; card.mailListURI = this.URI; this._childCards.appendElement(card, false); MailServices.ab.notifyDirectoryItemAdded(this, card); } this._didInitCards = true; }, update: function EDSAb_update(aEContact) { LOG("Updating a mailing list."); LOG("Removing old cards"); for (let card in fixIterator(this._childCards.enumerate())) { MailServices.ab.notifyDirectoryItemDeleted(this, card); } LibGLib.g_object_unref(this._eContact); let newEContact = LibEContact.duplicate(aEContact); gMailListEContactLookup[this.URI] = newEContact; this._eContact = newEContact; this._didInitCards = false; this._childCards = Cc["@mozilla.org/array;1"] .createInstance(Ci.nsIMutableArray); this._initCards(); let oldDirName = this.dirName; this._dirName = null; let newDirName = this.dirName; if (oldDirName != newDirName) MailServices.ab.notifyItemPropertyChanged("DirName", oldDirName, newDirName); LOG("Done updating mailing list"); }, dispose: function EDSAb_dispose() { delete gMailListEContactLookup[this.URI]; delete gMailListEBookLookup[this.URI]; delete gEContactLookup[this.EDSUid]; LibGLib.g_object_unref(this._eContact); }, } function attachAddressListToVCard(aVCard, aAddressList) { for (let i = 0; i < aAddressList.length; i++) { // Create a new EVCardAttribute var attr = LibEVCard.attributeNew(null, LibEVCard.EVC_EMAIL); // Convert the nsIAbCard primary email and display name to something // we can work with: var card = aAddressList.queryElementAt(i, Ci.nsIAbCard); var name = card.getProperty("DisplayName", ""); var address = card.getProperty("PrimaryEmail", ""); var email = MailServices.headerParser.makeFullAddress(name, address); LibEVCard.attributeAddValue(attr, email); LibEVCard.addAttribute(aVCard, attr); LOG("Added email for mailing list: " + email); } } var nsAbEDSMailingListFactory = { createInstance: function(aOuter, aIID) { if (aOuter != null) throw Cr.NS_ERROR_NO_AGGREGATION; if (!aIID.equals(Ci.nsIAbDirectory)) throw Cr.NS_ERROR_NO_INTERFACE; return new nsAbEDSMailingList(); } } Components.manager.QueryInterface(Ci.nsIComponentRegistrar) .registerFactory(Components.ID("{" + kMailListDirClassID + "}"), "EDS Address Book Mailing List Factory", kMailListDirContractID, nsAbEDSMailingListFactory);