Bug 450917 - Create and populate nsIAbCollection. r=Standard8, sr=bienvenu
authorJoshua Cranmer <Pidgeot18@gmail.com>
Mon, 22 Sep 2008 21:30:13 -0400
changeset 397 dbc99e82183ad605e634fa2b8088df308945c10c
parent 396 b611aed3fc13973b44ed49de1a0c8ba79c3d4c13
child 398 5a1b4384c192edadb566de475bb9f8633d9c1f15
push idunknown
push userunknown
push dateunknown
reviewersStandard8, bienvenu
bugs450917
Bug 450917 - Create and populate nsIAbCollection. r=Standard8, sr=bienvenu
mail/base/content/editContactOverlay.js
mail/base/content/msgHdrViewOverlay.js
mail/components/addrbook/content/abCardOverlay.js
mail/components/addrbook/content/abCommon.js
mailnews/addrbook/public/Makefile.in
mailnews/addrbook/public/nsIAbCollection.idl
mailnews/addrbook/public/nsIAbDirectory.idl
mailnews/addrbook/resources/content/abCardOverlay.js
mailnews/addrbook/resources/content/abCommon.js
mailnews/addrbook/resources/content/abDragDrop.js
mailnews/addrbook/resources/content/abMailListDialog.js
mailnews/addrbook/resources/content/abResultsPane.js
mailnews/addrbook/resources/content/addrbookWidgets.xml
mailnews/addrbook/src/nsAbDirProperty.cpp
mailnews/addrbook/src/nsAbDirProperty.h
mailnews/addrbook/src/nsAbLDAPDirectory.cpp
mailnews/addrbook/src/nsAbLDAPDirectory.h
mailnews/addrbook/src/nsAbOSXDirectory.h
mailnews/addrbook/src/nsAbOSXDirectory.mm
mailnews/addrbook/src/nsDirectoryDataSource.cpp
mailnews/addrbook/test/resources/abSetup.js
mailnews/addrbook/test/unit/test_basic_nsIAbDirectory.js
mailnews/addrbook/test/unit/test_ldap1.js
mailnews/compose/src/nsMsgCompose.cpp
--- a/mail/base/content/editContactOverlay.js
+++ b/mail/base/content/editContactOverlay.js
@@ -112,18 +112,17 @@ var editContactInlineUI = {
   },
 
   _doShowEditContactPanel: function (aAnchorElement, aPosition) {
     this._blockCommands(); // un-done in the popuphiding handler.
 
     var bundle = document.getElementById("bundle_editContact");
 
     // Is this address book writeable?
-    this._writeable = this._cardDetails.book.operations &
-                      Components.interfaces.nsIAbDirectory.opWrite;
+    this._writeable = !this._cardDetails.book.readOnly;
     var type = this._writeable ? "edit" : "view";
 
     // Update the labels accordingly.
     document.getElementById("editContactPanelTitle").value =
       bundle.getString(type + "Title");
     document.getElementById("editContactPanelEditDetailsButton").label =
       bundle.getString(type + "DetailsLabel");
     document.getElementById("editContactPanelEditDetailsButton").accessKey =
--- a/mail/base/content/msgHdrViewOverlay.js
+++ b/mail/base/content/msgHdrViewOverlay.js
@@ -1136,18 +1136,17 @@ function setupEmailAddressPopup(emailAdd
 {
   var emailAddressPlaceHolder = document.getElementById('emailAddressPlaceHolder');
   var emailAddress = emailAddressNode.getAttribute('emailAddress');
 
   emailAddressPlaceHolder.setAttribute('label', emailAddress);
 
   if (emailAddressNode.cardDetails.card) {
     document.getElementById('addToAddressBookItem').setAttribute('hidden', true);
-    if (emailAddressNode.cardDetails.book.operations &
-        Components.interfaces.nsIAbDirectory.opWrite) {
+    if (!emailAddressNode.cardDetails.book.readOnly) {
       document.getElementById('editContactItem').removeAttribute('hidden');
       document.getElementById('viewContactItem').setAttribute('hidden', true);
     }
     else {
       document.getElementById('editContactItem').setAttribute('hidden', true);
       document.getElementById('viewContactItem').removeAttribute('hidden');
     }
   }
--- a/mail/components/addrbook/content/abCardOverlay.js
+++ b/mail/components/addrbook/content/abCardOverlay.js
@@ -115,17 +115,17 @@ function OnLoadNewCard()
       var abURI = window.arguments[0].selectedAB;
       
       var directory = GetDirectoryFromURI(abURI);
       if (directory.isMailList) {
         var parentURI = GetParentDirectoryFromMailingListURI(abURI);
         if (parentURI)
           gEditCard.selectedAB = parentURI;
       }
-      else if (directory.operations & directory.opWrite)
+      else if (!directory.readOnly)
         gEditCard.selectedAB = window.arguments[0].selectedAB;
     }
 
     // we may have been given properties to pre-initialize the window with....
     // we'll fill these in here...
     if ("primaryEmail" in window.arguments[0])
       gEditCard.card.primaryEmail = window.arguments[0].primaryEmail;
     if ("displayName" in window.arguments[0]) {
@@ -261,17 +261,17 @@ function OnLoadEditCard()
   // check if selectedAB is a writeable
   // if not disable all the fields
   if ("arguments" in window && window.arguments[0])
   {
     if ("abURI" in window.arguments[0]) {
       var abURI = window.arguments[0].abURI;
       var directory = GetDirectoryFromURI(abURI);
 
-      if (!(directory.operations & directory.opWrite)) 
+      if (directory.readOnly) 
       {
         // Set all the editable vcard fields to read only
         for (var i = kVcardFields.length; i-- > 0; )
           document.getElementById(kVcardFields[i][0]).readOnly = true;
 
         // the birthday fields
         document.getElementById("Birthday").readOnly = true;
         document.getElementById("BirthYear").readOnly = true;
--- a/mail/components/addrbook/content/abCommon.js
+++ b/mail/components/addrbook/content/abCommon.js
@@ -95,18 +95,17 @@ var DirPaneController =
                                   "valueList" : "valueAddressBook");
 
         if (selectedDir &&
 	    (selectedDir != kPersonalAddressbookURI) &&
 	    (selectedDir != kCollectedAddressbookURI)) {
           // If the directory is a mailing list, and it is read-only, return
           // false.
           var abDir = GetDirectoryFromURI(selectedDir);
-          if (abDir.isMailList && 
-              ~abDir.operations & abDir.opWrite)
+          if (abDir.isMailList && abDir.readOnly)
             return false;
 
           // If the selected directory is an ldap directory
           // and if the prefs for this directory are locked
           // disable the delete button.
           if (selectedDir.lastIndexOf(kLdapUrlPrefix, 0) == 0)
           {
             var disable = false;
--- a/mailnews/addrbook/public/Makefile.in
+++ b/mailnews/addrbook/public/Makefile.in
@@ -42,19 +42,20 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= addrbook
 
 XPIDLSRCS	= \
 		nsIAbListener.idl \
+		nsIAbItem.idl \
+		nsIAbCollection.idl \
+		nsIAbCard.idl \
 		nsIAbDirectory.idl \
-		nsIAbItem.idl \
-		nsIAbCard.idl \
 		nsIAbMDBDirectory.idl \
 		nsIAddrDBAnnouncer.idl \
 		nsIAddrDBListener.idl \
 		nsIAddrDatabase.idl \
 		nsIAbManager.idl \
 		nsIAbAddressCollecter.idl \
 		nsIAddbookUrl.idl \
 		nsIAbDirFactory.idl	\
new file mode 100644
--- /dev/null
+++ b/mailnews/addrbook/public/nsIAbCollection.idl
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; 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 mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Messaging Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mark Banner <bugzilla@standard8.plus.com>
+ *   Joshua Cranmer <Pidgeot18@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+ 
+#include "nsISupports.idl"
+#include "nsIAbItem.idl"
+
+interface nsIAbCard;
+
+/**
+ * A collection of address book items.
+ */
+[scriptable, uuid(e6f97fdb-2e3e-46ad-974d-50f1388953c0)]
+interface nsIAbCollection : nsIAbItem {
+  
+  /**
+   * Returns true if this collection is read-only.
+   */
+  readonly attribute boolean readOnly;
+
+  /**
+   * Returns true if this collection is accessed over a network connection.
+   */
+  readonly attribute boolean isRemote;
+
+  /**
+   * Returns true if this collection is accessed over a secure connection.
+   *
+   * If isRemote returns false, then this value MUST be false as well.
+   */
+  readonly attribute boolean isSecure;
+
+  /** 
+   * Returns an address book card for the specified email address if found.
+   *
+   * If there are multiple cards with the given email address, this method will
+   * return one of these cards in an implementation-defined manner.
+   *
+   * This method performs a synchronous operation. If the collection cannot do
+   * the search in such a manner, then it should throw NS_ERROR_NOT_IMPLEMENTED.
+   *
+   * @param  emailAddress The email address to find in any of the email address
+   *                      fields. If emailAddress is empty, the database won't
+   *                      be searched and the function will return as if no card
+   *                      was found.
+   * @return              An nsIAbCard if one was found, else returns NULL.
+   * @exception NS_ERROR_NOT_IMPLEMENTED If the collection cannot do this.
+   */
+  nsIAbCard cardForEmailAddress(in AUTF8String emailAddress);
+
+  /**
+   * Returns an address book card for the specified property if found.
+   *
+   * If there are multiple cards with the given value for the property, this
+   * method will return one of these cards in an implementation-defined manner.
+   *
+   * This method performs a synchronous operation. If the collection cannot do
+   * the search in such a manner, then it should throw NS_ERROR_NOT_IMPLEMENTED.
+   *
+   * If the property is not natively a string, it can still be searched for
+   * using the string-encoded value of the property, e.g. "0". See
+   * nsIAbCard::getPropertyAsAUTF8String for more information. Empty values will
+   * return no match, to prevent spurious results.
+   *
+   * @param  aProperty      The property to look for.
+   * @param  aValue         The value to search for.
+   * @param  aCaseSensitive True if matching should be done case-sensitively.
+   * @result                An nsIAbCard if one was found, else returns NULL.
+   * @exception NS_ERROR_NOT_IMPLEMENTED If the collection cannot do this.
+   */
+  nsIAbCard getCardFromProperty(in string aProperty, in AUTF8String aValue,
+                                in boolean aCaseSensitive);
+};
--- a/mailnews/addrbook/public/nsIAbDirectory.idl
+++ b/mailnews/addrbook/public/nsIAbDirectory.idl
@@ -33,17 +33,17 @@
  * 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 ***** */
  
-#include "nsISupports.idl"
+#include "nsIAbCollection.idl"
 #include "nsIAbCard.idl"
 
 interface nsISimpleEnumerator;
 interface nsIArray;
 interface nsIMutableArray;
 
 %{C++
 /* RDF root for all types of address books */
@@ -55,42 +55,27 @@ interface nsIMutableArray;
 #define kCollectedAddressbook      "history.mab"
 #define kCollectedAddressbookUri   "moz-abmdbdirectory://history.mab"
 
 #define kABFileName_PreviousSuffix ".na2" /* final v2 address book format */
 #define kABFileName_PreviousSuffixLen 4
 #define kABFileName_CurrentSuffix ".mab"  /* v3 address book extension */
 %}
 
-[scriptable, uuid(1b2637fb-194e-442b-992a-17fe7c068fd4)]
-interface nsIAbDirectory : nsISupports {
+[scriptable, uuid(5ee48561-aff9-447c-802d-93384d524f53)]
+interface nsIAbDirectory : nsIAbCollection {
 
   /**
    * The chrome URI to use for bringing up a dialog to edit this directory.
    * When opening the dialog, use a JS argument of
    * {selectedDirectory: thisdir} where thisdir is this directory that you just
    * got the chrome URI from.
    */
   readonly attribute ACString propertiesChromeURI;
 
-  // Types of operation
-  // Perform linear reading of directory card
-  // content
-  const long opRead = 0x1;
-  // Perform modification and deletion on a
-  // directories content
-  const long opWrite = 0x2;
-  // Perform searching on a directory card
-  // content via the uri format:
-  // 	scheme://path?query
-  const long opSearch = 0x4;
-
-  // The supported operations
-  readonly attribute long operations;
-
   /**
    * The description of the directory. If this directory is not a mailing list,
    * then setting this attribute will send round a "DirName" update via
    * nsIAddrBookSession.
    */
   attribute AString dirName;
 
   // XXX This should really be replaced by a QI or something better
@@ -160,26 +145,16 @@ interface nsIAbDirectory : nsISupports {
    *
    * @param  aCards  The cards to delete from the database.
    */
   void deleteCards(in nsIArray aCards);
 
   void dropCard(in nsIAbCard card, in boolean needToCopyCard);
 
   /**
-   * directory is local (example, mork based) or remote (example, LDAP)
-   */
-  readonly attribute boolean isRemote;
-
-  /**
-   * directory is secure (as in LDAP over SSL)
-   */
-  readonly attribute boolean isSecure;
-
-  /**
    * Whether or not the directory should be searched when doing autocomplete,
    * (currently by using GetChildCards); LDAP does not support this in online
    * mode, so that should return false; additionally any other directory types
    * that also do not support GetChildCards should return false.
    *
    * @param aIdentity  An optional parameter detailing the identity key (see
    *                   nsIMsgAccountManager) that this autocomplete is being
    *                   run against.
@@ -303,50 +278,9 @@ interface nsIAbDirectory : nsISupports {
    *                      be obtained (e.g. dirPrefId isn't set).
    */
   //@{
   void setIntValue(in string aName, in long aValue);
   void setBoolValue(in string aName, in boolean aValue);
   void setStringValue(in string aName, in ACString aValue);
   void setLocalizedStringValue(in string aName, in AUTF8String aValue);
   //@}
-
-  /** 
-   * Returns an address book card for the specified email address if found.
-   *
-   * If there are multiple cards with the given email address, this method will
-   * return one of these cards in an implementation-defined manner.
-   *
-   * If the address book type does not know how to find a card, it will throw
-   * NS_ERROR_NOT_IMPLEMENTED. Core address book types do throw this exception,
-   * so beware when calling this method.
-   *
-   * @param  emailAddress The email address to find in either the primary or
-   *                      secondary email address fields. If email address is
-   *                      empty, the database won't be searched and the function
-   *                      will return as if no card was found.
-   * @return              An nsIAbCard if one was found, else returns NULL.
-   */
-  nsIAbCard cardForEmailAddress(in AUTF8String emailAddress);
-
-  /**
-   * Returns an address book card for the specified property if found.
-   *
-   * If there are multiple cards with the given value for the property, this
-   * method will return one of these cards in an implementation-defined manner.
-   *
-   * If the address book type does not know how to do this, it will throw
-   * NS_ERROR_NOT_IMPLEMENTED. Core address book types do throw this exception,
-   * so beware when calling this method.
-   *
-   * If the property is not natively a string, it can still be searched for
-   * using the string-encoded value of the property, e.g. "0". See
-   * nsIAbCard::getPropertyAsAUTF8String for more information. Empty values will
-   * return no match, to prevent spurious results.
-   *
-   * @param  aProperty      The property to look for.
-   * @param  aValue         The value to search for.
-   * @param  aCaseSensitive True if matching should be done case-senstively.
-   * @result                An nsIAbCard if one was found, else returns NULL.
-   */
-  nsIAbCard getCardFromProperty(in string aProperty, in AUTF8String aValue,
-                                in boolean aCaseSensitive);
 };
--- a/mailnews/addrbook/resources/content/abCardOverlay.js
+++ b/mailnews/addrbook/resources/content/abCardOverlay.js
@@ -115,17 +115,17 @@ function OnLoadNewCard()
       var abURI = window.arguments[0].selectedAB;
       
       var directory = GetDirectoryFromURI(abURI);
       if (directory.isMailList) {
         var parentURI = GetParentDirectoryFromMailingListURI(abURI);
         if (parentURI)
           gEditCard.selectedAB = parentURI;
       }
-      else if (directory.operations & directory.opWrite)
+      else if (!directory.readOnly)
         gEditCard.selectedAB = window.arguments[0].selectedAB;
     }
     
     // we may have been given properties to pre-initialize the window with....
     // we'll fill these in here...
     if ("primaryEmail" in window.arguments[0])
       gEditCard.card.primaryEmail = window.arguments[0].primaryEmail;
     if ("displayName" in window.arguments[0]) {
@@ -261,17 +261,17 @@ function OnLoadEditCard()
   // check if selectedAB is a writeable
   // if not disable all the fields
   if ("arguments" in window && window.arguments[0])
   {
     if ("abURI" in window.arguments[0]) {
       var abURI = window.arguments[0].abURI;
       var directory = GetDirectoryFromURI(abURI);
 
-      if (!(directory.operations & directory.opWrite)) 
+      if (directory.readOnly) 
       {
         // Set all the editable vcard fields to read only
         for (var i = kVcardFields.length; i-- > 0; )
           document.getElementById(kVcardFields[i][0]).readOnly = true;
 
         // the birthday fields
         document.getElementById("Birthday").readOnly = true;
         document.getElementById("BirthYear").readOnly = true;
--- a/mailnews/addrbook/resources/content/abCommon.js
+++ b/mailnews/addrbook/resources/content/abCommon.js
@@ -93,18 +93,17 @@ var DirPaneController =
         }
 
         if (selectedDir &&
             (selectedDir != kPersonalAddressbookURI) &&
             (selectedDir != kCollectedAddressbookURI)) {
           // If the directory is a mailing list, and it is read-only, return
           // false.
           var abDir = GetDirectoryFromURI(selectedDir);
-          if (abDir.isMailList && 
-              ~abDir.operations & abDir.opWrite)
+          if (abDir.isMailList && abDir.readOnly)
             return false;
 
           // If the selected directory is an ldap directory
           // and if the prefs for this directory are locked
           // disable the delete button.
           if (selectedDir.lastIndexOf(kLdapUrlPrefix, 0) == 0)
           {
             var disable = false;
--- a/mailnews/addrbook/resources/content/abDragDrop.js
+++ b/mailnews/addrbook/resources/content/abDragDrop.js
@@ -50,17 +50,17 @@ var abResultsPaneObserver = {
       aXferData.data = new TransferData();
       aXferData.data.addDataForFlavour("moz/abcard", selectedRows);
       aXferData.data.addDataForFlavour("text/x-moz-address", selectedAddresses);
       aXferData.data.addDataForFlavour("text/unicode", selectedAddresses);
 
       var srcDirectory = GetDirectoryFromURI(GetSelectedDirectory());
       // The default allowable actions are copy, move and link, so we need
       // to restrict them here.
-      if ((srcDirectory.operations & srcDirectory.opWrite))
+      if (!srcDirectory.readOnly)
         // Only allow copy & move from read-write directories.
         aDragAction.action = Components.interfaces.
                              nsIDragService.DRAGDROP_ACTION_COPY |
                              Components.interfaces.
                              nsIDragService.DRAGDROP_ACTION_MOVE;
       else
         // Only allow copy from read-only directories.
         aDragAction.action = Components.interfaces.
@@ -132,17 +132,17 @@ var abDirTreeObserver = {
     // if so, don't allow the drop
     if (srcURI.substring(0, targetURI.length) == targetURI)
       return false
 
     // check if we can write to the target directory 
     // e.g. LDAP is readonly currently
     var targetDirectory = GetDirectoryFromURI(targetURI);
 
-    if (!(targetDirectory.operations & targetDirectory.opWrite))
+    if (targetDirectory.readOnly)
       return false;
 
     var dragSession = dragService.getCurrentSession();
     if (!dragSession)
       return false;
 
     // XXX Due to bug 373125/bug 349044 we can't specify a default action,
     // so we default to move and this means that the user would have to press
@@ -152,17 +152,17 @@ var abDirTreeObserver = {
     //    if (targetDirectory.isMailList &&
     //   dragSession.dragAction != Components.interfaces.
     //                             nsIDragService.DRAGDROP_ACTION_COPY)
     //return false;
 
     var srcDirectory = GetDirectoryFromURI(srcURI);
 
     // Only allow copy from read-only directories.
-    if (!(srcDirectory.operations & srcDirectory.opWrite) &&
+    if (srcDirectory.readOnly &&
         dragSession.dragAction != Components.interfaces.
                                   nsIDragService.DRAGDROP_ACTION_COPY)
       return false;
 
     // Go through the cards checking to see if one of them is a mailing list
     // (if we are attempting a copy) - we can't copy mailing lists as
     // that would give us duplicate names which isn't allowed at the
     // moment.
--- a/mailnews/addrbook/resources/content/abMailListDialog.js
+++ b/mailnews/addrbook/resources/content/abMailListDialog.js
@@ -215,17 +215,17 @@ function OnLoadNewMailList()
     if (abURI) {
       var directory = GetDirectoryFromURI(abURI);
       if (directory.isMailList) {
         var parentURI = GetParentDirectoryFromMailingListURI(abURI);
         if (parentURI) {
           selectedAB = parentURI;
         }
   }
-      else if (!(directory.operations & directory.opWrite)) {
+      else if (directory.readOnly) {
         selectedAB = kPersonalAddressbookURI;
         
       }      
       else {
         selectedAB = abURI;
       }
     }
   }
@@ -304,17 +304,17 @@ function OnLoadEditList()
       }
       var parent = listbox.parentNode;
       parent.replaceChild(newListBoxNode, listbox);
     }
   }
 
   // Is this directory read-only? If so, we now need to set all the fields to
   // read-only.
-  if (~gEditList.operations & gEditList.opWrite) {
+  if (gEditList.readOnly) {
     const kMailListFields = [ 'ListName', 'ListNickName', 'ListDescription' ];
 
     for (var i = 0; i < kMailListFields.length; ++i)
       document.getElementById(kMailListFields[i]).readOnly = true;
 
     document.documentElement.buttons = "accept";
     document.documentElement.removeAttribute("ondialogaccept");
 
--- a/mailnews/addrbook/resources/content/abResultsPane.js
+++ b/mailnews/addrbook/resources/content/abResultsPane.js
@@ -376,17 +376,17 @@ var ResultsPaneController =
       case "cmd_selectAll":
         return true;
       case "cmd_delete":
       case "button_delete":
         var numSelected;
         var enabled = false;
         if (gAbView && gAbView.selection) {
           if (gAbView.directory)
-            enabled = gAbView.directory.operations & gAbView.directory.opWrite;
+            enabled = !gAbView.directory.readOnly;
           numSelected = gAbView.selection.count;
         }
         else
           numSelected = 0;
 
         // fix me, don't update on isCommandEnabled
         if (command == "cmd_delete") {
           switch (GetSelectedCardTypes()) {
--- a/mailnews/addrbook/resources/content/addrbookWidgets.xml
+++ b/mailnews/addrbook/resources/content/addrbookWidgets.xml
@@ -178,21 +178,20 @@
       </method>
 
       <!-- Private methods -->
       <!-- Tests to see whether this directory should display in the list. -->
       <method name="_matches">
         <parameter name="ab"/>
         <body><![CDATA[
           // This condition is used for instance when creating cards
-          if (this.getAttribute("writable") == "true" &&
-              !(ab.operations & Components.interfaces.nsIAbDirectory.opWrite))
+          if (this.getAttribute("writable") == "true" && ab.readOnly)
             return false;
 
-          // This condition is used for isntance when creating mailing lists
+          // This condition is used for instance when creating mailing lists
           if (this.getAttribute("supportsmaillists") == "true" &&
               !ab.supportsMailingLists)
             return false;
 
           return this.getAttribute(ab.isRemote ? "localonly" : "remoteonly") != "true";
         ]]></body>
       </method>
 
--- a/mailnews/addrbook/src/nsAbDirProperty.cpp
+++ b/mailnews/addrbook/src/nsAbDirProperty.cpp
@@ -72,35 +72,29 @@ nsAbDirProperty::~nsAbDirProperty(void)
     for (i = count - 1; i >= 0; i--)
       m_AddressList->RemoveElementAt(i);
   }
 #endif
 }
 
 NS_IMPL_ISUPPORTS1(nsAbDirProperty,nsIAbDirectory)
 
+NS_IMETHODIMP nsAbDirProperty::GenerateName(PRInt32 aGenerateFormat,
+                                            nsIStringBundle *aBundle,
+                                            nsAString &name)
+{
+  return GetDirName(name);
+}
+
 NS_IMETHODIMP nsAbDirProperty::GetPropertiesChromeURI(nsACString &aResult)
 {
   aResult.AssignLiteral("chrome://messenger/content/addressbook/abAddressBookNameDialog.xul");
   return NS_OK;
 }
 
-NS_IMETHODIMP nsAbDirProperty::GetOperations(PRInt32 *aOperations)
-{
-  // Default is to support all operations.
-  // Inheriting implementations may override
-  // to reduce supported operations
-  NS_ENSURE_ARG_POINTER(aOperations);
-	*aOperations = nsIAbDirectory::opRead |
-		nsIAbDirectory::opWrite |
-		nsIAbDirectory::opSearch;
-
-	return NS_OK;
-}
-
 NS_IMETHODIMP nsAbDirProperty::GetDirName(nsAString &aDirName)
 {
   if (m_DirPrefId.IsEmpty())
   {
     aDirName = m_ListDirName;
     return NS_OK;
   }
 
@@ -325,16 +319,25 @@ NS_IMETHODIMP nsAbDirProperty::GetSuppor
 {
   NS_ENSURE_ARG_POINTER(aSupportsMailingsLists);
   // We don't currently support nested mailing lists, so only return true if
   // we're not a mailing list.
   *aSupportsMailingsLists = !m_IsMailList;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsAbDirProperty::GetReadOnly(PRBool *aReadOnly)
+{
+  NS_ENSURE_ARG_POINTER(aReadOnly);
+  // Default is that we are writable. Any implementation that is read-only must
+  // override this method.
+  *aReadOnly = PR_FALSE;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsAbDirProperty::GetIsRemote(PRBool *aIsRemote)
 {
   NS_ENSURE_ARG_POINTER(aIsRemote);
   *aIsRemote = PR_FALSE;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAbDirProperty::GetIsSecure(PRBool *aIsSecure)
--- a/mailnews/addrbook/src/nsAbDirProperty.h
+++ b/mailnews/addrbook/src/nsAbDirProperty.h
@@ -60,18 +60,20 @@
   */ 
 
 class nsAbDirProperty: public nsIAbDirectory
 {
 public: 
 	nsAbDirProperty(void);
 	virtual ~nsAbDirProperty(void);
 
-	NS_DECL_ISUPPORTS
-	NS_DECL_NSIABDIRECTORY
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIABITEM
+  NS_DECL_NSIABCOLLECTION
+  NS_DECL_NSIABDIRECTORY
 
 protected:
   /**
    * Initialise the directory prefs for this branch
    */
   nsresult InitDirectoryPrefs();
 
 	PRUint32 m_LastModifiedDate;
--- a/mailnews/addrbook/src/nsAbLDAPDirectory.cpp
+++ b/mailnews/addrbook/src/nsAbLDAPDirectory.cpp
@@ -133,44 +133,16 @@ NS_IMETHODIMP nsAbLDAPDirectory::GetURI(
 {
   if (mURI.IsEmpty())
     return NS_ERROR_NOT_INITIALIZED;
 
   aURI = mURI;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsAbLDAPDirectory::GetOperations(PRInt32 *aOperations)
-{
-  *aOperations = nsIAbDirectory::opSearch;
-
-#ifdef MOZ_EXPERIMENTAL_WRITEABLE_LDAP
-  PRBool readOnly;
-  nsresult rv = GetBoolValue("readonly", PR_FALSE, &readOnly);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (readOnly)
-    return NS_OK;
-
-  // when online, we'll allow writing as well
-  PRBool offline;
-  nsCOMPtr <nsIIOService> ioService =
-    do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  rv = ioService->GetOffline(&offline);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  if (!offline)
-    *aOperations |= nsIAbDirectory::opWrite;
-#endif
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP nsAbLDAPDirectory::GetChildNodes(nsISimpleEnumerator* *aResult)
 {
   return NS_NewEmptyEnumerator(aResult);
 }
 
 NS_IMETHODIMP nsAbLDAPDirectory::GetChildCards(nsISimpleEnumerator** result)
 {
     nsresult rv;
@@ -452,16 +424,46 @@ NS_IMETHODIMP nsAbLDAPDirectory::OnSearc
 
 NS_IMETHODIMP nsAbLDAPDirectory::GetSupportsMailingLists(PRBool *aSupportsMailingsLists)
 {
   NS_ENSURE_ARG_POINTER(aSupportsMailingsLists);
   *aSupportsMailingsLists = PR_FALSE;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsAbLDAPDirectory::GetReadOnly(PRBool *aReadOnly)
+{
+  NS_ENSURE_ARG_POINTER(aReadOnly);
+
+  *aReadOnly = PR_TRUE;
+
+#ifdef MOZ_EXPERIMENTAL_WRITEABLE_LDAP
+  PRBool readOnly;
+  nsresult rv = GetBoolValue("readonly", PR_FALSE, &readOnly);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (readOnly)
+    return NS_OK;
+
+  // when online, we'll allow writing as well
+  PRBool offline;
+  nsCOMPtr <nsIIOService> ioService =
+    do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  rv = ioService->GetOffline(&offline);
+  NS_ENSURE_SUCCESS(rv,rv);
+
+  if (!offline)
+    *aReadOnly = PR_FALSE;
+#endif
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsAbLDAPDirectory::GetIsRemote(PRBool *aIsRemote)
 {
   NS_ENSURE_ARG_POINTER(aIsRemote);
   *aIsRemote = PR_TRUE;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAbLDAPDirectory::GetIsSecure(PRBool *aIsSecure)
--- a/mailnews/addrbook/src/nsAbLDAPDirectory.h
+++ b/mailnews/addrbook/src/nsAbLDAPDirectory.h
@@ -64,21 +64,21 @@ public:
   nsAbLDAPDirectory();
   virtual ~nsAbLDAPDirectory();
 
   NS_IMETHOD Init(const char *aUri);
 
   // nsIAbDirectory methods
   NS_IMETHOD GetPropertiesChromeURI(nsACString &aResult);
   NS_IMETHOD GetURI(nsACString &aURI);
-  NS_IMETHOD GetOperations(PRInt32 *aOperations);
   NS_IMETHOD GetChildNodes(nsISimpleEnumerator* *result);
   NS_IMETHOD GetChildCards(nsISimpleEnumerator* *result);
   NS_IMETHOD HasCard(nsIAbCard *cards, PRBool *hasCard);
   NS_IMETHOD GetSupportsMailingLists(PRBool *aSupportsMailingsLists);
+  NS_IMETHOD GetReadOnly(PRBool *aReadOnly);
   NS_IMETHOD GetIsRemote(PRBool *aIsRemote);
   NS_IMETHOD GetIsSecure(PRBool *aIsRemote);
   NS_IMETHOD UseForAutocomplete(const nsACString &aIdentityKey, PRBool *aResult);
   NS_IMETHOD AddCard(nsIAbCard *aChildCard, nsIAbCard **aAddedCard);
   NS_IMETHOD ModifyCard(nsIAbCard *aModifiedCard);
   NS_IMETHOD DeleteCards(nsIArray *aCards);
 
   // nsIAbDirectorySearch methods
--- a/mailnews/addrbook/src/nsAbOSXDirectory.h
+++ b/mailnews/addrbook/src/nsAbOSXDirectory.h
@@ -88,17 +88,17 @@ public:
   
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIABDIRSEARCHLISTENER
     
     // nsAbDirectoryRDFResource method
     NS_IMETHOD Init(const char *aUri);
   
   // nsAbDirProperty methods
-  NS_IMETHOD GetOperations(PRInt32 *aOperations);
+  NS_IMETHOD GetReadOnly(PRBool *aReadOnly);
   NS_IMETHOD GetChildCards(nsISimpleEnumerator **aCards);
   NS_IMETHOD GetChildNodes(nsISimpleEnumerator **aNodes);
   NS_IMETHOD HasCard(nsIAbCard *aCard, PRBool *aHasCard);
   NS_IMETHOD HasDirectory(nsIAbDirectory *aDirectory, PRBool *aHasDirectory);
   NS_IMETHOD GetURI(nsACString &aURI);
   NS_IMETHOD CardForEmailAddress(const nsACString &aEmailAddress,
                                  nsIAbCard **aResult);
 
--- a/mailnews/addrbook/src/nsAbOSXDirectory.mm
+++ b/mailnews/addrbook/src/nsAbOSXDirectory.mm
@@ -517,21 +517,21 @@ nsAbOSXDirectory::GetURI(nsACString &aUR
   if (mURI.IsEmpty())
     return NS_ERROR_NOT_INITIALIZED;
 
   aURI = mURI;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsAbOSXDirectory::GetOperations(PRInt32 *aOperations)
+nsAbOSXDirectory::GetReadOnly(PRBool *aReadOnly)
 {
-  *aOperations = nsIAbDirectory::opRead |
-  nsIAbDirectory::opSearch;
-  
+  NS_ENSURE_ARG_POINTER(aReadOnly);
+
+  *aReadOnly = PR_TRUE;
   return NS_OK;
 }
 
 static PRBool
 CheckRedundantCards(nsIAbManager *aManager, nsIAbDirectory *aDirectory,
                     nsIAbCard *aCard, NSMutableArray *aCardList)
 {
   nsCOMPtr<nsIRDFResource> resource(do_QueryInterface(aCard));
--- a/mailnews/addrbook/src/nsDirectoryDataSource.cpp
+++ b/mailnews/addrbook/src/nsDirectoryDataSource.cpp
@@ -489,21 +489,21 @@ nsAbDirectoryDataSource::createDirectory
   NS_IF_ADDREF(*target = (IsSecure ? kTrueLiteral : kFalseLiteral));
   return NS_OK;
 }
 
 nsresult
 nsAbDirectoryDataSource::createDirectoryIsWriteableNode(nsIAbDirectory* directory,
                                                         nsIRDFNode **target)
 {
-  PRBool isWriteable;
-  nsresult rv = directory->GetOperations(&isWriteable);
+  PRBool isReadOnly;
+  nsresult rv = directory->GetReadOnly(&isReadOnly);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NS_IF_ADDREF(*target = ((isWriteable & nsIAbDirectory::opWrite) ? kTrueLiteral : kFalseLiteral));
+  NS_IF_ADDREF(*target = (isReadOnly ? kFalseLiteral : kTrueLiteral));
   return NS_OK;
 }
 
 nsresult
 nsAbDirectoryDataSource::createDirectoryIsMailListNode(nsIAbDirectory* directory,
                                                        nsIRDFNode **target)
 {
   PRBool isMailList;
--- a/mailnews/addrbook/test/resources/abSetup.js
+++ b/mailnews/addrbook/test/resources/abSetup.js
@@ -14,46 +14,41 @@
 // Personal Address Book configuration items.
 var kPABData =
 {
   URI: "moz-abmdbdirectory://abook.mab",
   fileName: "abook.mab",
   dirName: "Personal Address Book",
   dirType: 2,
   dirPrefID: "ldap_2.servers.pab",
-  operations: Components.interfaces.nsIAbDirectory.opRead |
-              Components.interfaces.nsIAbDirectory.opWrite |
-              Components.interfaces.nsIAbDirectory.opSearch,
+  readOnly: false,
   position: 1
 };
 
 // Collected Address Book configuration items.
 var kCABData =
 {
   URI: "moz-abmdbdirectory://history.mab",
   fileName: "history.mab",
   dirName: "Collected Addresses",
   dirType: 2,
   dirPrefID: "ldap_2.servers.history",
-  operations: Components.interfaces.nsIAbDirectory.opRead |
-              Components.interfaces.nsIAbDirectory.opWrite |
-              Components.interfaces.nsIAbDirectory.opSearch,
+  readOnly: false,
   position: 2
 };
 
 // Mac OSX Address Book configurations items
 var kOSXData =
 {
   URI: "moz-abosxdirectory:///",
   fileName: "",
   dirName: "Mac OS X Address Book",
   dirType: 3,
   dirPrefID: "ldap_2.servers.osx",
-  operations: Components.interfaces.nsIAbDirectory.opRead |
-              Components.interfaces.nsIAbDirectory.opSearch,
+  readOnly: true,
   position: 1
 };
 
 // Windows (Outlook Express) Address Book deactivation. (Bug 448859)
 Components.classes["@mozilla.org/preferences-service;1"]
           .getService(Components.interfaces.nsIPrefBranch)
           .deleteBranch("ldap_2.servers.oe.");
 
--- a/mailnews/addrbook/test/unit/test_basic_nsIAbDirectory.js
+++ b/mailnews/addrbook/test/unit/test_basic_nsIAbDirectory.js
@@ -39,18 +39,19 @@ function check_ab(abConfig) {
 
   // Test - Is it the right type?
 
   if (abConfig.dirType == 2)
     do_check_true(AB instanceof Components.interfaces.nsIAbMDBDirectory);
 
   // Test - Check attributes
 
+  do_check_eq(AB.generateName(0), abConfig.dirName);
   do_check_eq(AB.propertiesChromeURI, kNormalPropertiesURI);
-  do_check_eq(AB.operations, abConfig.operations);
+  do_check_eq(AB.readOnly, abConfig.readOnly);
   do_check_eq(AB.dirName, abConfig.dirName);
   do_check_eq(AB.dirType, abConfig.dirType);
   do_check_eq(AB.fileName, abConfig.fileName);
   do_check_eq(AB.URI, abConfig.URI);
   do_check_eq(AB.position, abConfig.position);
   do_check_eq(AB.isMailList, false);
   do_check_eq(AB.isRemote, false);
   do_check_eq(AB.isSecure, false);
--- a/mailnews/addrbook/test/unit/test_ldap1.js
+++ b/mailnews/addrbook/test/unit/test_ldap1.js
@@ -21,16 +21,17 @@ function run_test() {
 
   // Test - Check we have the directory.
   var abDir = abManager.getDirectory(kLDAPUriPrefix + abUri)
                        .QueryInterface(Components.interfaces.nsIAbLDAPDirectory);
 
   // Test - Check various fields
   do_check_eq(abDir.dirName, "test");
   do_check_eq(abDir.lDAPURL.spec, kLDAPTestSpec);
+  do_check_true(abDir.readOnly);
 
   // Test - Write a UTF-8 Auth DN and check it
   abDir.authDn = "test\u00D0";
 
   do_check_eq(abDir.authDn, "test\u00D0");
 
   // Test - searchDuringLocalAutocomplete
 
--- a/mailnews/compose/src/nsMsgCompose.cpp
+++ b/mailnews/compose/src/nsMsgCompose.cpp
@@ -4647,23 +4647,23 @@ nsMsgCompose::CheckAndPopulateRecipients
             if (NS_SUCCEEDED(rv) && existingCard)
             {
               recipient.mPreferFormat = nsIAbPreferMailFormat::unknown;
               rv = existingCard->GetPropertyAsUint32(kPreferMailFormatProperty,
                                                      &recipient.mPreferFormat);
               if (NS_SUCCEEDED(rv))
                 recipient.mProcessed = PR_TRUE;
 
-              PRInt32 isWriteable;
-              rv = abDirectory->GetOperations(&isWriteable);
+              PRBool readOnly;
+              rv = abDirectory->GetReadOnly(&readOnly);
               NS_ENSURE_SUCCESS(rv,rv);
 
               // bump the popularity index for this card since we are about to send e-mail to it
               PRUint32 popularityIndex = 0;
-              if ((isWriteable & nsIAbDirectory::opWrite) && NS_SUCCEEDED(existingCard->GetPropertyAsUint32(
+              if (!readOnly && NS_SUCCEEDED(existingCard->GetPropertyAsUint32(
                       kPopularityIndexProperty, &popularityIndex)))
               {
 
                 existingCard->SetPropertyAsUint32(kPopularityIndexProperty,
                                                   ++popularityIndex);
                 abDirectory->ModifyCard(existingCard);
               }
             }