2009/dap/contacts Overview.html,1.9,1.10

Update of /sources/public/2009/dap/contacts
In directory hutz:/tmp/cvs-serv8348

Modified Files:
	Overview.html 
Log Message:
Contacts API now supporting all requirements in DAP-REQ document

- Multiple Address Book Support
- Added AddressBookArray typedef to support multiple address books
- Renamed AddressBook methods to be more intuitive (e.g. 'add()' becomes 'addContact()'
- Added AddressBook name identifier for the ability to identify AddressBook objects
- Review and update of issues

Index: Overview.html
===================================================================
RCS file: /sources/public/2009/dap/contacts/Overview.html,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- Overview.html	27 Oct 2009 19:33:24 -0000	1.9
+++ Overview.html	30 Oct 2009 15:44:04 -0000	1.10
@@ -37,16 +37,9 @@
                 The Contacts API defines a high-level interface to Address Book information, such as names, addresses and other contact information. The API itself is agnostic of any underlying address book sources.
             </p>
             <p>
-                Rather than each application having its own address book for its own purposes (email, phone,
-                driving directions) it is more practical for the user to have a single address book which
-                multiple applications share. That is what this specification exposes.
+                Each device MAY have more than one address book for different purposes. The user MUST be able to discover and interact with 
+				these address books via this API.
             </p>
-			<p class='issue'>
-				This spec has not yet covered the requirement for multiple address book support. We need to find a suitable 
-				way to identify address books based on e.g. URI, name, identifier or other value.
-				
-				<br /><br />Use Case: I want to target the SIM Address Book so I need to know which AddressBook object that is.				
-			</p>
             <p>
                 The requirements for this set of interfaces are listed in the Device API Requirements
                 document [[DAP-REQS]].
@@ -58,9 +51,9 @@
                 </p>
                 <div>
                     <p>
-                        Example of a simple Address Book search.
+                        Example of a simple Phone-based Address Book search.
                     </p>
-                    <pre class='example'>		// Create the ContactFilter for the find function
+                    <pre class='example'>		// Create the ContactFilter for the find function.
 		var contactFilter = {givenName: 'Bob', phone: '+440000000001'};	
 		
 		// Create the success callback.
@@ -73,15 +66,25 @@
 				// do something with the ContactError response
 		}
 
-		// Perform the address book search with the given contact filter in the address book.
-		var currentSearch = navigator.device.addressbook.find(mySuccessCallback, myErrorCallback, contactFilter);
 
-		// search operation can be cancelled before returning with the following code (highlighted out)
-		// currentSearch.cancel();</pre>
+		// Get the 'phone' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'phone') addressBook = addressBooks[i];
+		}		
+		
+		// Perform the address book search with the given contact filter on the 'phone' address book.
+		if(addressBook) {
+				var currentSearch = addressBook.findContacts(mySuccessCallback, myErrorCallback, contactFilter);	
+				
+				// search operation can be cancelled before returning with the following code (highlighted out)
+				// currentSearch.cancel();
+		}</pre>
                 </div>
                 <div>
                     <p>
-                        Adding a new contact to the Address Book.
+                        Adding a new contact to MyService-based Address Book.
                     </p>
                     <pre class='example'>		// Create the Contact object for the add function
 		var newContact = {givenNames:    ['Alice'],
@@ -98,18 +101,28 @@
 				// do something with the ContactError response
 		}
 
-		// Add contact to the address book.
-		var currentSearch = navigator.device.addressbook.add(mySuccessCallback, myErrorCallback, newContact);
 
-		// operation can be cancelled before returning with the following code (highlighted out)
-		// currentSearch.cancel();</pre>
+		// Get the 'MyService' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'MyService') addressBook = addressBooks[i];
+		}		
+		
+		// Add the new contact to the 'MyService' address book.
+		if(addressBook) {
+				var currentAdd = addressBook.addContact(mySuccessCallback, myErrorCallback, newContact);	
+				
+				// operation can be cancelled before returning with the following code (highlighted out)
+				// currentAdd.cancel();
+		}</pre>
                     <p class='note'>
                         Should we specify mandatory required attributes when adding a new contact? Should we be throwing errorCallbacks if any attributes are incorrectly formed? It is not yet specified in the spec whether we have processing rules and requirements on individual Contact attributes.
                     </p>
                 </div>
                 <div>
                     <p>
-                        Removing an existing contact from the Address Book.
+                        Removing an existing contact, if found, from the SIM-based Address Book.
                     </p>
                     <pre class='example'>		// Create the ContactFilter for the find function
 		var contactFilter = {givenName: 'Bob', phone: '+440000000001'};	
@@ -120,7 +133,7 @@
 				
 				// delete e.g. contact index #4 from the current address book
 				if(response instanceof Array) && response.length>=4) {
-						var removeContact = navigator.device.addressbook.remove(myRemoveSuccessCallback, myErrorCallback, response[3]);
+						var removeContact = addressBook.removeContact(myRemoveSuccessCallback, myErrorCallback, response[3]);
 
 						// update operation can be cancelled before returning with the following code (highlighted out)
 						// removeContact.cancel();	
@@ -137,8 +150,21 @@
 				// do some generic ContactError handling code
 		}
 
-		// Perform the address book search with the given contact filter in the address book.
-		navigator.device.addressbook.find(mySearchSuccessCallback, myErrorCallback, contactFilter);</pre>
+
+		// Get the 'sim' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'sim') addressBook = addressBooks[i];
+		}		
+		
+		// Perform the address book search with the given contact filter on the 'sim' address book.
+		if(addressBook) {
+				var currentSearch = addressBook.findContacts(mySuccessCallback, myErrorCallback, contactFilter);	
+				
+				// search operation can be cancelled before returning with the following code (highlighted out)
+				// currentSearch.cancel();
+		}</pre>
                 </div>
                 <div>
                     <p>
@@ -158,7 +184,7 @@
 						// e.g. 2, Add a new phone number 		
 						response[2].phones.push('+440000000002');
 						
-						var updateContact = response[2].save(myUpdateSuccessCallback, myErrorCallback);
+						var updateContact = response[2].update(myUpdateSuccessCallback, myErrorCallback);
 										
 						// update operation can be cancelled before returning with the following code (highlighted out)
 						// updateContact.cancel();						
@@ -175,8 +201,21 @@
 				// do some generic ContactError handling code
 		}
 
-		// Perform the address book search with the given contact filter in the address book.
-		navigator.device.addressbook.find(mySearchSuccessCallback, myErrorCallback, contactFilter);</pre>
+
+		// Get the 'phone' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'phone') addressBook = addressBooks[i];
+		}		
+		
+		// Perform the address book search with the given contact filter on the 'phone' address book.
+		if(addressBook) {
+				var currentSearch = addressBook.findContacts(mySuccessCallback, myErrorCallback, contactFilter);	
+				
+				// search operation can be cancelled before returning with the following code (highlighted out)
+				// currentSearch.cancel();
+		}</pre>
                 </div>
 
             </section>
@@ -205,11 +244,21 @@
 				// do something with the ContactError response
 		}
 
-		// Perform the address book search with the given contact filter in the address book.
-		var currentSearch = navigator.device.addressbook.find(mySuccessCallback, myErrorCallback, contactFilter);
 
-		// search operation can be cancelled before returning with the following code (highlighted out)
-		// currentSearch.cancel();</pre>
+		// Get the 'phone' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'phone') addressBook = addressBooks[i];
+		}		
+		
+		// Perform the address book search with the given contact filter on the 'phone' address book.
+		if(addressBook) {
+				var currentSearch = addressBook.findContacts(mySuccessCallback, myErrorCallback, contactFilter);	
+				
+				// search operation can be cancelled before returning with the following code (highlighted out)
+				// currentSearch.cancel();
+		}</pre>
                 	</div>
                 	<div>
 	                    <p>
@@ -230,11 +279,21 @@
 				// do something with the ContactError response
 		}
 
-		// Perform the address book search with the given contact filter in the address book.
-		var currentSearch = navigator.device.addressbook.find(mySuccessCallback, myErrorCallback, contactFilterArray);
 
-		// search operation can be cancelled before returning with the following code (highlighted out)
-		// currentSearch.cancel();</pre>
+		// Get the 'phone' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'phone') addressBook = addressBooks[i];
+		}		
+		
+		// Perform the address book search with the given contact filter on the 'phone' address book.
+		if(addressBook) {
+				var currentSearch = addressBook.findContacts(mySuccessCallback, myErrorCallback, contactFilter);	
+				
+				// search operation can be cancelled before returning with the following code (highlighted out)
+				// currentSearch.cancel();
+		}</pre>
                 	</div>
                 </section>
                 <section>
@@ -254,16 +313,21 @@
 				// do something with the ContactArray response
 		}
 
-		// Create the error callback.
-		function myErrorCallback(response) {
-				// do something with the ContactError response
-		}
 
-		// Perform the address book search with the given contact filter in the address book.
-		var currentSearch = navigator.device.addressbook.find(mySuccessCallback, myErrorCallback, contactFilterArray, contactOptions);
-
-		// search operation can be cancelled before returning with the following code (highlighted out)
-		// currentSearch.cancel();</pre>
+		// Get the 'phone' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'phone') addressBook = addressBooks[i];
+		}		
+		
+		// Perform the address book search with the given contact filter on the 'phone' address book.
+		if(addressBook) {
+				var currentSearch = addressBook.findContacts(mySuccessCallback, myErrorCallback, contactFilter);	
+				
+				// search operation can be cancelled before returning with the following code (highlighted out)
+				// currentSearch.cancel();
+		}</pre>
                 	</div>
                 	<div>
 	                    <p>
@@ -286,11 +350,21 @@
 				// do something with the ContactError response
 		}
 
-		// Perform the address book search with the given contact filter in the address book.
-		var currentSearch = navigator.device.addressbook.find(mySuccessCallback, myErrorCallback, contactFilterArray, contactOptions);
 
-		// search operation can be cancelled before returning with the following code (highlighted out)
-		// currentSearch.cancel();</pre>
+		// Get the 'phone' based address book.
+		var addressBooks = navigator.device.contactmanager.getAddressBooks();
+		var addressBook = null;
+		for(var i=0; i&lt;addressBooks.length; i++) {
+				if(addressBooks[i].name == 'phone') addressBook = addressBooks[i];
+		}		
+		
+		// Perform the address book search with the given contact filter on the 'phone' address book.
+		if(addressBook) {
+				var currentSearch = addressBook.findContacts(mySuccessCallback, myErrorCallback, contactFilter);	
+				
+				// search operation can be cancelled before returning with the following code (highlighted out)
+				// currentSearch.cancel();
+		}</pre>
                 	</div>
                 </section>
             </section>
@@ -303,6 +377,31 @@
         </section>
         <section>
             <h2>API Description</h2>
+           <section>
+                <h2><a>ContactManager</a> interface</h2>
+                <p>
+                    The <a>ContactManager</a>
+                    interface provides an interface to a database collecting address book instances available on the device. 
+					Individual address books are uniquely identifiable with the resulting <a href='#addressbook-interface'><code>AddressBook</code></a> objects. 
+                </p>
+                <dl title='interface ContactManager' class='idl'>
+                    <dt>
+                        AddressBookArray getAddressBooks ()
+                    </dt>
+                    <dd>
+                        <p>Get all address books available on the device.</p>	
+						
+						<p>This method takes no arguments. When called, it MUST return 
+						an <a href='#addressbookarray-typedef'><code>AddressBookArray</code></a> 
+						object containing a sequence of AddressBook objects denoting individual
+						address books available on the device.</p>
+						
+						<p>If no address books are available on the device, this method MUST return a <code>NULL</code> value.</p>
+						
+                    </dd>
+                </dl>
+
+            </section>
             <section>
                 <h2><a>AddressBook</a> interface</h2>
                 <p>
@@ -310,9 +409,26 @@
                     interface exposes an interface to a database collecting addresses,
                     such that they may be created, found, read, updated, and deleted.
                 </p>
-                <dl title='interface AddressBook' class='idl'>
+                <dl title='[NoInterfaceObject] interface AddressBook' class='idl'>
                     <dt>
-                        PendingOperation add ()
+                        attribute DOMString name
+                    </dt>
+                    <dd>
+                        <p>
+                            The name of the address book
+                        </p>
+                        <p class='issue'>
+                        	We may wish to standardise around pre-defined address book names and also allow for extension names.
+							
+							<br /><br />e.g. 'phone' and 'sim' could be pre-defined but other values MAY be provided to identify an address book.
+
+							<br /><br />We MAY want to add better address book targeting around URIs (?)
+							
+							<br /><br />TBD
+                        </p>
+                    </dd>
+                    <dt>
+                        PendingOperation addContact ()
                     </dt>
                     <dd>
                         <p>Add a contact to the address book.</p>	
@@ -353,7 +469,7 @@
                         </dl>
                     </dd>
                     <dt>
-                        PendingOperation remove ()
+                        PendingOperation removeContact ()
                     </dt>
                     <dd>                    	
                         <p>Remove a contact from the address book.</p>	
@@ -394,7 +510,7 @@
                         </dl>
                     </dd>
                     <dt>
-                        PendingOperation find ()
+                        PendingOperation findContacts ()
                     </dt>
                     <dd>
                     	<p>Find contacts in the address book based on a <a href='#contactfilter-interface'><code>ContactFilter</code></a> object</p>
@@ -405,7 +521,7 @@
 						<p>		
 							<ol>
 								<li>Search for contacts in the address book according to the <a href='#contact-search-processing-rules'>contact search processing rules</a>.</li> 
-								<li>If successful, invoke the associated <code>successCallback</code> with a <a href='#contactarray-interface'><code>ContactArray</code></a> argument. 
+								<li>If successful, invoke the associated <code>successCallback</code> with a <a href='#contactarray-typedef'><code>ContactArray</code></a> argument. 
 						If the attempt fails, and the method was invoked with a non-null <code>errorCallback</code> argument, this method must 
 						invoke the <code>errorCallback</code> with a <a href='#contacterror-interface'><code>ContactError</code></a> object as an argument.</li>
 							</ol>
@@ -439,10 +555,10 @@
                         </dl>
                     </dd>
                     <dt>
-                        PendingOperation find ()
+                        PendingOperation findContacts ()
                     </dt>
                     <dd>
-                    	<p>Find contacts in the address book based on a <a href='#contactfilterarray-interface'><code>ContactFilterArray</code></a> object</p>
+                    	<p>Find contacts in the address book based on a <a href='#contactfilterarray-typedef'><code>ContactFilterArray</code></a> object</p>
 						
 						<p>This method takes two, three or four arguments. When called, it must immediately return 
 						a <a href='#pendingoperation-interface'><code>PendingOperation</code></a> object and then asynchronously start a <em>find contacts</em> process defined as follows:</p> 
@@ -450,7 +566,7 @@
 						<p>		
 							<ol>
 								<li>Search for contacts in the address book according to the <a href='#contact-search-processing-rules'>contact search processing rules</a>.</li> 
-								<li>If successful, invoke the associated <code>successCallback</code> with a <a href='#contactarray-interface'><code>ContactArray</code></a> argument. 
+								<li>If successful, invoke the associated <code>successCallback</code> with a <a href='#contactarray-typedef'><code>ContactArray</code></a> argument. 
 						If the attempt fails, and the method was invoked with a non-null <code>errorCallback</code> argument, this method must 
 						invoke the <code>errorCallback</code> with a <a href='#contacterror-interface'><code>ContactError</code></a> object as an argument.</li>
 							</ol>
@@ -559,7 +675,19 @@
 			<section>
                 <h2><a>Contact</a> interface</h2>
                 <p class='issue'>
-                    We need more discussion around the attributes that should be provided by the Contacts interface.
+                    This interface is TBD.
+					
+					<br /><br />We need more discussion around the attributes that should be included in the Contacts interface.
+					
+					<br /><br />Regarding options we have:
+					
+					<br /><br />1. Adding a large superset of Contact attributes, only specifying a suitable subset as mandatory for ALL implementations.
+						<br /><span style='color:#CC0000'>Removes ambiguity of attribute naming between implementations?</span>
+					<br />2. Adding a subset of standard Contact attributes.
+						<br /><span style='color:#CC0000'>What will that subset be?</span>
+					<br />3. Not specifying any attributes in the object and allow for run-time discovery and usage.
+					
+					<br /><br />to be discussed at TPAC
                 </p>
                 <p>
                     The <a>Contact</a>
@@ -679,7 +807,7 @@
                         The contact's phonetic name.
                     </dd>
                     <dt>
-                        PendingOperation save ()
+                        PendingOperation update ()
                     </dt>
                     <dd>						
                     	<p>Save the modified contact to the address book.</p>
@@ -723,14 +851,6 @@
                 </dl>
             </section>
             <section>
-                <h2><a>ContactArray</a> typedef</h2>
-                <p>
-                    The <a>ContactArray</a> typedef represents a <code>sequence</code> of <a href='#contact-interface'><code>Contact</code></a> objects.
-                </p>
-                <dl title='typedef sequence<Contact> ContactArray' class='idl'>
-                </dl>
-            </section>
-            <section>
                 <h2><a>Address</a> interface</h2>
                 <p>
                     The <a>Address</a>
@@ -1010,14 +1130,6 @@
                 </dl>
             </section>
             <section>
-                <h2><a>ContactFilterArray</a> typedef</h2>
-                <p>
-                    The <a>ContactFilterArray</a> typedef represents an Array of <a href='#contactfilter-interface'><code>ContactFilter</code></a> objects.
-                </p>
-                <dl title='typedef sequence<ContactFilter> ContactFilterArray' class='idl'>
-                </dl>
-            </section>
-            <section>
                 <h2><a>ContactFilterOptions</a> interface</h2>
                 <p>
                     The <a>ContactFilterOptions</a>
@@ -1053,8 +1165,7 @@
                 <p class='note'>
                     Should we add a grouping attribute to ContactFilterOptions? i.e. ability to 'GROUP BY category'.
                 </p>
-            </section>
-			
+            </section>	
 			<section>
                 <h2><a>ContactError</a> interface</h2>
                 <p>
@@ -1068,7 +1179,30 @@
                    </dd>
                 </dl>
              </section>			 
-			 
+            <section>
+                <h2><a>AddressBookArray</a> typedef</h2>
+                <p>
+                    The <a>AddressBookArray</a> typedef represents a <code>sequence</code> of <a href='#addressbook-interface'><code>AddressBook</code></a> objects.
+                </p>
+                <dl title='typedef sequence<AddressBook> AddressBookArray' class='idl'>
+                </dl>
+            </section>
+            <section>
+                <h2><a>ContactArray</a> typedef</h2>
+                <p>
+                    The <a>ContactArray</a> typedef represents a <code>sequence</code> of <a href='#contact-interface'><code>Contact</code></a> objects.
+                </p>
+                <dl title='typedef sequence<Contact> ContactArray' class='idl'>
+                </dl>
+            </section>
+            <section>
+                <h2><a>ContactFilterArray</a> typedef</h2>
+                <p>
+                    The <a>ContactFilterArray</a> typedef represents an Array of <a href='#contactfilter-interface'><code>ContactFilter</code></a> objects.
+                </p>
+                <dl title='typedef sequence<ContactFilter> ContactFilterArray' class='idl'>
+                </dl>
+            </section>				 
         </section>
         <!-- api description section -->
         <section>
@@ -1082,7 +1216,7 @@
                 <var title=''>
                     filter
                 </var>
-                overloading to provide a means to <a href='#widl-AddressBook-find'>find()</a>
+                overloading to provide a means to <a href='#widl-AddressBook-findContacts'>findContacts()</a>
                 contacts according to the input of a single 
                 <code>
                     ContactFilter
@@ -1103,7 +1237,7 @@
                                     ContactFilter
                                 </code>
                                 passing and processing.<pre>		// Search for an existing contact in the Address Book
-		navigator.device.addressbook.find( {givenName:    'Bob',
+		navigator.device.addressbook.findContacts( {givenName:    'Bob',
                                                    familyName:   'Smith',
                                                    phone:        '+440000000000'} );</pre>
                                 <p>
@@ -1114,7 +1248,7 @@
 		<p>Multiple <code>ContactFilter</code> passing and processing.
 
 	   <pre>		// Search for an existing contact in the Address Book
-		navigator.device.addressbook.add( [ {givenName:    'Bob',
+		navigator.device.addressbook.findContacts( [ {givenName:    'Bob',
                                                      familyName:   'Smith'},
                                                      {phone:        '+440000000000'} ] );</pre>
 
@@ -1129,7 +1263,7 @@
             Do we need to say something about whether contact search matching is loose or strict? Could this be added as a ContactFilterOptions attribute?
           </p>
 
-	    <p>The <dfn id='rules-for-processing-filter-combinations'>rules for processing filter combinations</dfn> is always provided with one <var title="">input</var> parameter, and its behaviour depends on the type of <var title="">input</var>. The following algorithm demonstrates the conversion of a <a href='#widl-AddressBook-find'>find()</a> filter object to an SQL WHERE query.</p>
+	    <p>The <dfn id='rules-for-processing-filter-combinations'>rules for processing filter combinations</dfn> is always provided with one <var title="">input</var> parameter, and its behaviour depends on the type of <var title="">input</var>. The following algorithm demonstrates the conversion of a <a href='#widl-AddressBook-findContacts'>findContacts()</a> filter object to an SQL WHERE query.</p>
 
 	    <dl class=switch>
 	  
@@ -1173,7 +1307,7 @@
 
 		<p>&nbsp;</p>
 
-		<p>The <a href="#addressbook-interface">AddressBook</a> interface also provides a means to apply predefined options to the resulting contacts that match the given <code>ContactFilter</code>. <code>ContactFilterOptions</code> are an optional <var title''>input</var> to the  <a href="#addressbook-interface">AddressBook</a> <a href='#widl-AddressBook-find'>find()</a> method.</p>
+		<p>The <a href="#addressbook-interface">AddressBook</a> interface also provides a means to apply predefined options to the resulting contacts that match the given <code>ContactFilter</code>. <code>ContactFilterOptions</code> are an optional <var title''>input</var> to the  <a href="#addressbook-interface">AddressBook</a> <a href='#widl-AddressBook-findContacts'>findContacts()</a> method.</p>
 
 		<p>The <dfn id='rules-for-applying-filter-options'>rules for applying filter options</dfn> are as given in the following algorithm. If the <var title=''>output</var> of this algorithm is not null, then the string value of <var title=''>output</var> MUST be concatenated with the <var title=''>output</var> parameter of <a href='#rules-for-processing-filter-combinations'>rules for processing filter combinations</a> and returned as a single string result. The following algorithm demonstrates the conversion of a passed <code>ContactFilterOptions</code> object to an SQL Pagination query.</p>
 
@@ -1211,10 +1345,8 @@
 			<h2>Requirements</h2>
 
 			  <ul>
-				<li><em title="must" class="rfc2119">must</em> enable listing all available address books on the device;
-				<p class="note">Not currently included. See issue raised in '<a href='#introduction'>Introduction</a>' section.</p></li>
+				<li><em title="must" class="rfc2119">must</em> enable listing all available address books on the device;</li>
 				<li><em title="must" class="rfc2119">must</em> enable listing all contacts in the address book(s);</li>
-
 				<li><em title="must" class="rfc2119">must</em> enable reading the details for a contact;</li>
 				<li><em title="should" class="rfc2119">should</em> enable creating a new contact;</li>
 				<li><em title="should" class="rfc2119">should</em> enable updating a contact;</li>

Received on Friday, 30 October 2009 15:44:08 UTC