WebDAV Commands


Now that you know about the object model of XMLHTTP and ServerXMLHTTP , which allows you to send WebDAV commands to the Exchange server, you're probably wondering what these commands are. WebDAV supports a number of commands, including MKCOL , PROPPATCH , PROPFIND , DELETE , MOVE , COPY , SEARCH , LOCK , UNLOCK , SUBSCRIBE , and POLL . Each of these commands serves a distinctive purpose in your applications. For example, MKCOL allows you to create a collection (or a folder) on your server. PROPPATCH and PROPFIND allow you to set and get properties on resources, respectively. If you are interested in details about these individual commands, take a look at RFC 2518. For now, let's look at some typical tasks you can perform with WebDAV using each of these commands.

Note  

Some of the commands also support batch methods. These batch methods allow you to perform an action against multiple resources in a single call. For example, if you need to PROPPATCH a property onto 300 items, such as changing a shared value across the 300 items with a new value, you need 300 different PROPPATCH commands unless you use the batch version of PROPPATCH , which allows you to pass multiple URLs with one call. The batch methods are BCOPY , BDELETE , BMOVE , BPROPFIND , and BPROPPATCH . They are similar to their nonbatch counterparts; see the Exchange SDK (included with the book's companion content) for more information on batch methods.

Creating Folders

To create a folder using WebDAV, you issue the MKCOL command and pass the URL of the new folder that you want to create. If the creation is successful, you'll receive a Status of 201 and StatusText of Created . The following JavaScript code uses XMLHTTP to create a new folder (as shown in Figure 16-2):

 <HTML> <BODY>      <SCRIPT LANGUAGE=javascript> <!-     //Remember to escape any special characters in your URLs     var strURL = "http://localhost/public/my%20new%20folder/";     var request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("MKCOL", strURL, false);     request.send();     alert(request.status + " " + request.statustext); //--> </SCRIPT>      </BODY> </HTML> 
click to expand
Figure 16-2: A folder created via WebDAV and XMLHTTP

Creating Items

To create an item, you use the HTTP PUT method and pass to it the URL of the new item you want to create. If you are successful, you'll get a Status of 201 and StatusText of Created . The following JavaScript code creates a new post in the public folder we created earlier (as shown in Figure 16-3):

click to expand
Figure 16-3: Creating an item in a public folder via WebDAV and XMLHTTP
 <HTML> <BODY>      <SCRIPT LANGUAGE=javascript> <!--     var strURL =         "http://localhost/public/my%20new%20folder/my%20new%20 item.eml";     var request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("PUT", strURL, false);     request.setRequestHeader("Translate", "f");     request.send();     alert(request.status + " " + request.statustext); //--> </SCRIPT>      </BODY> </HTML> 

Copying Folders and Items

To copy both items and folders, you use the COPY command. This command takes as a parameter the source URL of the item to be copied. As part of your request headers, you must specify the destination URL for the copied item. If you are copying a folder, all the contents of that folder will be copied as well. The following JavaScript code copies the newly created folder and item from the earlier example into another folder. If you are successful, you should receive a Status value of 201 .

 <HTML> <BODY>      <SCRIPT LANGUAGE=javascript> <!--     var strSourceURL = "http://localhost/public/my%20new%20folder/";     var strDestURL = "http://localhost/public/my%20new%20folder%202/";     var request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("COPY", strSourceURL, false);     request.setRequestHeader("Destination", strDestURL);     request.send();     alert(request.status + " " + request.statustext); //--> </SCRIPT>      </BODY> </HTML> 

Moving Folders and Items

Moving folders is as easy as copying them. All you do is change the command from COPY to MOVE . The following JavaScript code shows how to move a folder:

 <HTML> <BODY>      <SCRIPT LANGUAGE=javascript> <!--     var strSourceURL = "http://localhost/public/my%20new%20folder/";     var strDestURL = "http://localhost/public/my%20new%20folder%203/";     var request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("MOVE", strSourceURL, false);     request.setRequestHeader("Destination", strDestURL);     request.send();     alert(request.status + " " + request.statustext); //--> </SCRIPT>      </BODY> </HTML> 

To rename a folder, you use MOVE but create the Allow-Rename header and set it to t for true , as shown in the following line of code:

 request.setRequestHeader("Allow-Rename", "t"); 

Deleting Items and Folders

To delete items or folders, you use the DELETE command and pass to it the URL of the item to be deleted. If you are successful, you'll receive a Status of 200 and StatusText of OK . The following code deletes a folder:

 <HTML> <BODY>      <SCRIPT LANGUAGE=javascript> <!--     var strURL = "http://localhost/public/my%20new%20folder%203/";     var request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("DELETE", strURL, false);     request.send();     alert(request.status + " " + request.statustext); //--> </SCRIPT>      </BODY> </HTML> 

Setting Properties

To set properties, you use the PROPPATCH command. To use this command, you must create an XML document to send that lists the properties you want updated. You can generate this XML document in a number of ways. The two easiest ways are to use XMLDOM or to simply generate the XML yourself by using JavaScript code. The following JavaScript example generates the XML directly and sends it to the server to update the properties (as shown in Figure 16-4):

 <HTML> <BODY>      <SCRIPT LANGUAGE=javascript> <!--     var strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml";     request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("PROPPATCH", strURL, false);     request.setRequestHeader("Content-Type", "text/xml");          proplist  = "<M:subject>My New Message</M:subject>";     proplist = proplist +                "<M:textdescription>This is my body</M:textdescription>";          body = "<?xml version='1.0'?>";     body += "<D:propertyupdate xmlns:D='DAV:' "     body += "xmlns:M='urn:schemas:httpmail:'>";     body += "<D:set><D:prop>";     body += proplist;     body += "</D:prop></D:set>";     body += "</D:propertyupdate>";          request.send(body);     alert(request.status + " " + request.statustext);      //--> </SCRIPT>      </BODY> </HTML> 
click to expand
Figure 16-4: Updating subject line and message body via WebDAV and XMLHTTP

Working with Multivalue Properties

You might be wondering how you can work with multivalue properties using WebDAV. To set a multivalue property, you wrap your values for the property between XML tags. The following example shows an XML file that can be used to set a multivalue property using WebDAV:

 <?xml version="1.0"?> <a:propertyupdate xmlns:a="DAV:"         xmlns:d="urn:schemas-microsoft-com:exch-data:"         xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"         xmlns:c="xml:">   <a:set>     <a:prop>       <d:expected-content-class b:dt="mv.string">              <c:v>urn:content-classes:message</c:v>              <c:v>urn:content-classes:myclass1</c:v>              <c:v>urn:content-classes:item</c:v>       </d:expected-content-class>     </a:prop>   </a:set> </a:propertyupdate> 

The following code takes this XML data (saved in a file called c:\body.xml) and uses it to perform the actual work using WebDAV. Your security settings might require explicit permissions to instantiate the FileSystemObject . Be sure to click Yes in the corresponding Internet Explorer dialog box. 207 Multi-Status indicates a successful operation.

 <HTML> <BODY>      <script language="JavaScript">          var strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml/";     request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("PROPPATCH", strURL, false);     request.setRequestHeader("Content-Type", "text/xml");          //Use the following lines to read the XML from a file called body.xml     //instead of having to compose a lengthy and error-prone string variable.     var TristateFalse = 0;     var ForReading = 1;     oActiveXObject = new ActiveXObject("Scripting.FileSystemObject");     file = oActiveXObject.GetFile("c:\body.xml");     text = file.OpenAsTextStream(ForReading, TristateFalse);          body = text.ReadAll();     text.Close();     //End of reading XML          request.send(body);     alert(request.status + " " + request.statustext);           //--> </SCRIPT>      </BODY> </HTML> 

When you retrieve a multivalue property, if you are trying to load the XML result set from WebDAV into an XMLDOMDocument object, be sure to set the validateonparse property to false . The XMLDOMDocument object does not see the multivalue properties returned as valid XML; setting this property to false prevents unnecessary trouble.

Retrieving Properties

To retrieve properties, you use the PROPFIND command. PROPFIND can request a single property, all properties with values, or just all the property names . When you work with PROPFIND , you must set the Depth header value to the depth you want the request's scope to be. The depth value can be , which indicates only the entity in the URL specified; 1 , which signifies the target URL and any of its immediate children; or Infinity , which indicates the target URL, its children, and its children's children, all the way down to the leaves of the tree. Also, you must send an XML document that specifies the property list you want to retrieve from the resource. The following code requests some WebDAV properties from a messaging object in a public folder:

 <HTML> <BODY> <TEXTAREA rows=10 style="width:100%" id=textarea1 name=textarea1>      </TEXTAREA> <SCRIPT LANGUAGE=javascript> <!--     var strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml/";          request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("PROPFIND", strURL, false);     request.setRequestHeader("Depth", "1,noroot");     request.setRequestHeader("Content-Type", "text/xml");          proplist = "<D:iscollection/><D:displayname/>"              + "<D:getlastmodified/><D:creationdate/>";          body = "<?xml version='1.0'?>";     body += "<D:propfind xmlns:D='DAV:'>";     body += "<D:prop>";     body += proplist;     body += "</D:prop>";     body += "</D:propfind>";          request.send(body);          alert(request.status + " " + request.statustext);     textarea1.value = request.responseText;      //--> </SCRIPT>      </BODY> </HTML> 

The returned XML stream that is placed into the TEXTAREA is shown in Figure 16-5. Notice that it is a multi-status response.

click to expand
Figure 16-5: An XML stream obtained via WebDAV and XMLHTTP

To retrieve all properties in the DAV namespace, you issue the following WebDAV command:

 <?xml version="1.0" ?> <D:propfind xmlns:D="DAV:">     <D:allprop/> </D:propfind> 

To retrieve all the properties for the DAV namespace and also the Exchange namespace, you send the following command. The DAV and Exchange namespaces contain the DAV and Exchange properties (such as DAV:href or http://schemas.microsoft.com/exchange/contentexpiryagelimit ).

 <?xml version="1.0"?> <a:propfind xmlns:a="DAV:" xmlns:e="http://schemas.microsoft.com/exchange/">   <a:allprop>     <e:allprop>     </e:allprop>   </a:allprop> </a:propfind> 

Sometimes you might want to exclude certain properties from being returned in your PROPFIND . To do this, you can use the exclude and include extensions to WebDAV. You use these extensions to list the properties you want to include or exclude. The following sample shows a PROPFIND request that excludes some Messaging Application Programming Interface (MAPI) properties while including other properties:

 <?xml version="1.0"?> <a:propfind xmlns:a="DAV:"         xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"         xmlns:c="xml:"         xmlns:d="http://schemas.microsoft.com/exchange/"         xmlns:e="urn:schemas:httpmail:"         xmlns:f="http://schemas.microsoft.com/mapi/proptag/"         xmlns:g="urn:schemas-microsoft-com:exch-data:">     <a:allprop>       <a:exclude>         <e:htmldescription/>         <f:x0079001e/>         <f:x66590102/>       </>       <a:include>         <f:x65e00102/>         <e:msgfolderroot/>         <e:inbox/>         <e:outbox/>         <e:deleteditems/>         <e:sentitems/>         <e:sendmsg/>         <e:calendar/>         <e:tasks/>         <e:journal/>         <e:contacts/>         <e:notes/>         <e:drafts/>         <g:schema-uri/>         <e:hasattachment/>       </>     </a:allprop> </a:propfind> 

Deleting Properties

Sometimes you might find it necessary to delete properties from an item. You can do this by passing a propertyupdate command with a remove node and a node that contains the property you want to remove. If you work with XMLHTTP, open the resource as if you want to set a property, and set the Content-Type header as follows :

 request.open("PROPPATCH", strURL, false);     request.setRequestHeader("Content-Type", "text/xml"); 

You can then use the following WebDAV command to remove the DAV:comment property, as in this example:

 <?xml version="1.0"?> <a:propertyupdate xmlns:a="DAV:">    <a:remove>       <a:prop>          <a:comment/>        </>    </> </> 

Locking a Resource

You might want to lock a resource, such as a file or a collection, so that no other process can access it. You can acquire an exclusive or shared lock on a resource. Each lock has a timeout, affording you a precise window of opportunity to make your changes before the lock expires . If a lock does expire, you can always request another lock on the resource from the server. The following code requests an exclusive write lock on a message object in a public folder. The XML body requests exclusive access to the DAV:owner property, and the lock will remain in effect for 3000 seconds. If another application tries to modify the message object, it will receive an XML document that contains a lockdiscovery property, which contains the owner property of the person who currently has a lock on the resource. The application can use this property to request that the current lock owner disable the lock or notify the application when the lock is released.

 <HTML> <BODY> <TEXTAREA rows=10 style="width:100%" id=textarea1 name=textarea1>      </TEXTAREA> <SCRIPT LANGUAGE=javascript> <!--          var strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml/";     request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("LOCK", strURL, false);     request.setRequestHeader("Content-Type", "text/xml");     request.setRequestHeader("Timeout", "Second-3000");          body = "<?xml version='1.0'?>";     body += " <a:lockinfo xmlns:a='DAV:'>"     body += "<a:lockscope><a:exclusive /></a:lockscope>";     body += "<a:locktype><a:write /></a:locktype>";     body += "<a:owner><a:href>mailto:thomriz</a:href>";     body += "</a:owner></a:lockinfo>";          request.send(body);     alert(request.status + " " + request.statustext);     textarea1.value = request.responseText;      //--> </SCRIPT>      </BODY> </HTML> 

After this request is sent to the server, the response shown in Figure 16-6 will be received:

click to expand
Figure 16-6: A WebDAV response containing the locktoken property

If the lock is successful, you'll receive a Status of 200 OK , along with the XML just shown. The most important property to be aware of is the locktoken property. This property uniquely identifies your lock and must be used in future requests. Because HTTP is stateless, you must pass this lock token with your future requests so the server knows who is attempting to write to the resource. You'll also need this property for the PUT , PROPPATCH , and other requests you send, and to unlock the file.

Note  

If the resource is already locked when you try to lock it, you will receive a Status of 423 Locked .

Transactions with Locks

Sometimes you might need to not only lock a resource, but also have a single atomic transaction across that lock token. Once you lock the resource, you can pass the lock token of the resource to subsequent WebDAV commands and have all of those commands constitute a single transaction when you unlock the resource. To use transactions, you pass the transaction XML element as part of your lock, as shown in the following code. Also, on all subsequent WebDAV commands that you want as part of the transaction, you must pass a Transaction header with the lock token included in the header. Note that transactions can only have a depth of 0. Notice in the code that when the WebDAV UNLOCK command is used to unlock the resource, you must tell the server whether to commit or abort the transactions. To show how you can program WebDAV from Visual Basic, the following code is written in Visual Basic. It also shows an example of using early binding in Visual Basic to the MSXML library, which you need to add as a reference in your Visual Basic application.

 Private Sub Command1_Click()     Dim oXMLHTTP As New MSXML2.XMLHTTP30          strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml/"          oXMLHTTP.Open "LOCK", strURL, False          oXMLHTTP.setRequestHeader "Content-Type", "text/xml"     oXMLHTTP.setRequestHeader "Depth", "0"     oXMLHTTP.setRequestHeader "Timeout", "Second-45"          body = "<?xml version='1.0'?>"     body = body & "<a:lockinfo xmlns:a='DAV:'>"     body = body & "<a:lockscope><a:local /></a:lockscope>"     body = body & "<a:locktype><a:transaction><a:groupoperation/>"     body = body & "</a:transaction></a:locktype>"     body = body & "<a:owner><a:href>mailto:thomriz</a:href>"     body = body & "</a:owner></a:lockinfo>"          oXMLHTTP.Send body     MsgBox "Status: " & oXMLHTTP.Status & vbNewLine & oXMLHTTP.ResponseText          'Get the OpaqueLockToken to be used later     'when sending a proppatch in a transaction     Dim xmldom As MSXML2.DOMDocument     Set xmldom = oXMLHTTP.responseXML     Dim oDomElement As MSXML2.IXMLDOMNodeList          Set oDomElement = xmldom.getElementsByTagName("a:locktoken")     Set oDomElementChild = oDomElement.nextNode     strLockToken = oDomElementChild.Text     MsgBox strLockToken          oXMLHTTP.Open "PROPPATCH", strURL, False     oXMLHTTP.setRequestHeader "Content-Type", "text/xml"          'Pass the Transaction header so Exchange knows this is part     'of a transaction     oXMLHTTP.setRequestHeader "Transaction", "<" & strLockToken & ">"          proplist = "<M:textdescription>This is my body</M:textdescription>"          body = "<?xml version='1.0'?>"     body = body & "<D:propertyupdate xmlns:D='DAV:' "     body = body & "xmlns:M='urn:schemas:httpmail:'>"     body = body & "<D:set><D:prop>"     body = body & proplist     body = body & "</D:prop></D:set>"     body = body & "</D:propertyupdate>"          oXMLHTTP.Send body     MsgBox "Status: " & oXMLHTTP.Status & vbNewLine & oXMLHTTP.ResponseText               'Send another proppatch to show atomic transaction          oXMLHTTP.Open "PROPPATCH", strURL, False     oXMLHTTP.setRequestHeader "Content-Type", "text/xml"          'Send the Transaction header     oXMLHTTP.setRequestHeader "Transaction", "<" & strLockToken & ">"          proplist = "<M:subject>My New Message</M:subject>"          body = "<?xml version='1.0'?>"     body = body & "<D:propertyupdate xmlns:D='DAV:' "     body = body & "xmlns:M='urn:schemas:httpmail:'>"     body = body & "<D:set><D:prop>"     body = body & proplist     body = body & "</D:prop></D:set>"     body = body & "</D:propertyupdate>"          oXMLHTTP.Send body     MsgBox "Status: " & oXMLHTTP.Status & vbNewLine & oXMLHTTP.ResponseText          'Unlock the resource by passing a commit element as part of our     'transactionstatus if we want to abort, we should pass abort          oXMLHTTP.Open "UNLOCK", strURL, False          oXMLHTTP.setRequestHeader "Content-Type", "text/xml"     oXMLHTTP.setRequestHeader "Lock-Token", "<" & strLockToken & ">"          'Commit the transaction     body = "<?xml version='1.0'?>"     body = body & "<D:transactioninfo xmlns:D='DAV:'><D:transactionstatus>"     body = body & "<D:commit/></D:transactionstatus></D:transactioninfo>"          'If we wanted to abort, we would use the following     'body = "<?xml version='1.0'?><D:transactioninfo xmlns:D='DAV:'>"     'body = body & "<D:transactionstatus><D:abort/>"     'body = body & "</D:transactionstatus></D:transactioninfo>"          oXMLHTTP.Send body          MsgBox "Status: " & oXMLHTTP.Status & vbNewLine & oXMLHTTP.ResponseText End Sub 

Unlocking a Resource

Unlocking a resource is easy if you have a unique lock token. You simply send the UNLOCK command to the server and add a header that contains your lock token. If you are successful, the server will return a Status of 204 No Content . This means that the command completed successfully but the server had no text to return except the status. The following JavaScript code uses a specific lock token to unlock a resource. You must replace the lock token in the code with a specific lock token from your own application. Otherwise, the code will return error 412 (precondition failed).

 <HTML> <BODY> <SCRIPT LANGUAGE=javascript> <!--          var strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml/";     request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("UNLOCK", strURL, false);     request.setRequestHeader("Lock-Token",           "<opaquelocktoken:9641CB50-729A-4966-B904-"         + "6F55773AA5B7:10582347518064984065>");    request.send();    alert(request.status + " " + request.statustext);      //--> </SCRIPT>      </BODY> </HTML> 

Subscribing to a Resource

You can use WebDAV to subscribe to a resource. As a subscriber, you can receive notification about changes to a resource in one of two ways: you can have the server inform you when the resource changes or you can poll the server for any changes to the resource. To create a subscription, you use the SUBSCRIBE command and pass the URL you want to subscribe to, as in the following example. You can listen for different types of notifications (such as deletes, updates, or moves) by specifying the Notification-Type header. See the Exchange SDK for full documentation on the SUBSCRIBE command. This JavaScript example also sets the timeout for a subscription.

 <HTML> <BODY> <SCRIPT LANGUAGE=javascript> <!--          var strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml/";     request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("SUBSCRIBE", strURL, false);     request.setRequestHeader("Subscription-Lifetime", 1000);  request.SetRequestHeader("Notification-Type","update");          request.send();     alert(request.status + " " + request.statustext);      //--> </SCRIPT>      </BODY> </HTML> 

If your subscription is successful, the server will return a Subscription-id , which you should keep because you'll need to pass it when you later poll the server or unsubscribe from the resource.

Polling the Server

To poll the server to see whether any of the resources you've subscribed to have changed, you use the POLL command. This command requires that you pass the Subscription-id that the SUBSCRIBE command gave you when you subscribed to the resource. The following code checks whether anything has changed on a resource. If not, the server will return a 204 status code. In addition to polling, you can listen on a TCP/IP port for a UDP notification of changes. See the full code in the sample application (in the companion content that accompanies this book) called UDP Notification to learn how to use this technique.

 <HTML> <BODY> <SCRIPT LANGUAGE=javascript> <!--          var strURL =         "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml/";     request = new ActiveXObject("Microsoft.XMLHTTP");     request.open("POLL", strURL, false);     //Replace <SomeID> with a Subscription ID from another request     request.setRequestHeader("Subscription-id", "<SomeID>");          request.send();     alert(request.status + " " + request.statustext);      //--> </SCRIPT>      </BODY> </HTML> 

Querying with WebDAV SEARCH

One neat thing you can do with WebDAV is to perform SQL syntax queries against Exchange Server and have your results formatted as XML. Having your query returned to the client as XML is a powerful capability. Most important is the ability of XML data to represent hierarchical relationships. This is significantly different from ADO and relational data models, which represent relationships with a single flat virtual table. Representing hierarchical relationships with XML saves memory space and reduces the data transmission overhead. Furthermore, XML allows you to perform client-side formatting with XSL, and because the XML is already on the client, you can quickly re- sort the data. The following code is taken from the coursexml.asp file in the Training application. The code sends a SEARCH request to the Exchange server and receives the data from the server as XML.

 request = new ActiveXObject("Microsoft.XMLHTTP");      //Example propfind //request.open("PROPFIND", URLSchedule, true);      request.open("SEARCH", URLSchedule, true);      //For propfind you can select a depth //request.setRequestHeader("Depth", "1,noroot"); request.setRequestHeader("Content-Type", "text/xml");      proplist = "<D:iscollection/><D:displayname/>"; proplist += "<D:getlastmodified/><D:creationdate/>"; proplist += "<C:instructoremail/><CAL:location/><O:"; proplist += "<O:Manager/><O:Title/><H:Subject/>      //You can also do a propfind to find specific properties //body = "<?xml version='1.0'?>"; //body += "<D:propfind xmlns:D='DAV: ' //xmlns:O='urn:schemas-microsoft-com:office:office' //xmlns:C='<%=strSchema%>' xmlns:CAL='urn:schemas:calendar:' //xmlns:H='urn:schemas:httpmail:'>";      body = "<searchrequest xmlns='DAV:'>"; body += "<sql>"; body += "SELECT \"strSchemamaterialshttppath\" as materialshttppath,"; body += "\"<%=strSchema%>overallscore\" as "; body += "overallscore,\"<%=strSchema%>rating\" as rating,"; body += "\"<%=strSchema%>materialsfilepath\" as "; body += "materialsfilepath,\"<%=strSchema%>surveycount\" as surveycount, "; body += "\"<%=strSchema%>discussionurl\" as "; body += "discussionurl,\"<%=strSchema%>prereqs\" as prereqs, "; body += "\"urn:schemas:httpmail:textdescription\" as "; body += "description,\"<%=strSchema%>category\" as category, "; body += "\"urn:schemas:calendar:dtstart\" as "; body += "starttime, \"urn:schemas:calendar:dtend\" as endtime, "; body += "\"DAV:iscollection\" as iscollection,\"DAV:href\" as href,"; body += "\"urn:schemas:httpmail:subject\" as "; body += "subject,\"urn:schemas:calendar:location\" as "; body += "location, \"<%=strSchema%>instructoremail\" as "; body += "instructoremail FROM scope('shallow traversal of "; body += "\"<%=strURLToSchedule%>\"') where "; body += "\"DAV:ishidden\" = false AND \"DAV:isfolder\" = false";      //Add date restriction body += " AND \"urn:schemas:calendar:dtstart\" &gt;&eq;"; body += " CAST(\"<%=dISODateStart%>\" as 'dateTime')"; body += " AND \"urn:schemas:calendar:dtstart\" &lt;&eq;"; body += " CAST(\"<%=dISODateEnd%>\" as 'dateTime')"; body += "</sql>"; body += "</searchrequest>";      body += "</sql>"; body += "</searchrequest>";      //For debugging //alert(body);      //Propfind example //body += "<D:prop>"; //body += proplist; //body += "</D:prop>"; //body += "</D:propfind>";      request.onreadystatechange = dostatechange; msgdiv.innerHTML = "<font face='verdana' size='+1'>Loading...</font>"; request.send(body); 

The SELECT statement in this code uses column aliasing, which makes the data easier to format using XSL. You'll see how to use XSL to format the XML data returned shortly. The following code shows the raw XML data returned from this query, illustrating how custom and built-in schemas can be queried and returned with XML:

 <?xml version="1.0"?><a:multistatus xmlns:b="urn:uuid:c2f41010-65b3-11d1- a29f-00aa00c14882/" xmlns:c="xml:" xmlns:d="urn:schemas-microsoft-com: office:office" xmlns:a="DAV:"><a:response><a:href>http://thomriznt5srv/ public/140/Training/Schedule/{8C35C44B-68EB-4651-AC3E-5C475923A7A1} .EML</a:href><a:propstat><a:status>HTTP/1.1 200 OK</a:status><a:prop> <materialshttppath>http://thomriznt5srv/public/140/Training/Course Materials/Leveraging XML in Exchange 2000/?Cmd=contents&amp;View=Messages </materialshttppath><materialsfilepath>file://THOMRIZNT5SRV/Course Materials140/Leveraging XML in Exchange 2000</materialsfilepath> <discussionurl>http://thomriznt5srv/public/140/Training/Discussions/ Leveraging XML in Exchange 2000/?Cmd=contents&amp;View=By Conversation Topic</discussionurl><prereqs>fejio</prereqs><description>fjeoj </description><category>dev</category><starttime b:dt="dateTime.tz"> 2000-03-08T21:00:00.000Z</starttime><endtime b:dt="dateTime.tz">2000-03-  08T23:00:00.000Z</endtime><iscollection b:dt="boolean">0</iscollection> <href>http://thomriznt5srv/public/140/Training/Schedule/{8C35C44B-68EB- 4651-AC3E-5C475923A7A1}.EML</href><subject>Leveraging XML in Exchange 2000</subject><location>43</location><instructoremail>thomriz@thomriznt 5dom.extest.microsoft.com</instructoremail></a:prop></a:propstat> <a:propstat><a:status>HTTP/1.1 404 Resource Not Found</a:status><a:prop> <overallscore/><rating/><surveycount/></a:prop></a:propstat></a:response> <a:response><a:href>http://thomriznt5srv/public/140/Training/Schedule/ {75BD5A83-09E7-47B7-A9F1-A75DD62F5BA7}.EML</a:href><a:propstat> <a:status>HTTP/1.1 200 OK</a:status><a:prop><prereqs>fjoi</prereqs> <description>fei</description><category>dev</category><starttime b:dt="dateTime.tz">2000-03-08T18:00:00.000Z</starttime><endtime b:dt="dateTime.tz">2000-03-08T19:00:00.000Z</endtime><iscollection b:dt="boolean">0</iscollection><href>http://thomriznt5srv/public/140/ Training/Schedule/{75BD5A83-09E7-47B7-A9F1-A75DD62F5BA7}.EML </href><subject>CDO and You</subject><location>43</location> <instructoremail>thomriz@thomriznt5dom.extest.microsoft.com</ instructoremail></a:prop></a:propstat><a:propstat><a:status>HTTP/ 1.1 404 Resource Not Found</a:status><a:prop><materialshttppath/> <overallscore/><rating/><materialsfilepath/><surveycount/><discussionurl/> </a:prop></a:propstat></a:response></a:multistatus> 

Sending E-Mail Through WebDAV

You can use WebDAV to submit e-mail that is to be sent through Exchange by using a special Uniform Resource Identifier (URI), called the Exchange Mail Submission URI. You can retrieve this URI by getting the property urn:schemas:httpmail:sendmsg off the person's private mailbox folder. Before you can submit mail using this URI, you must be logged on as the user, have the user 's credentials, or have send-on- behalf permissions for the user. You either write an RFC 821 stream to the item's stream using a WebDAV PUT or ADO Stream object, or you write to properties on the item and have Exchange automatically create the stream for you. If you write to the properties, you cannot add attachments or send complex MIME messages. For this reason, you should stick to the first approach.

The following code shows how to submit a message using the mail submission URI using WebDAV. (See Figure 16-7.) Note that if you want the item saved in the user's Sent Items folder, you must pass a header called Saveinsent with a value of t for true .

click to expand
Figure 16-7: Sending a message via WebDAV and HTTPXML
 Private Sub Command1_Click()     Dim strSubURL As String     Dim strAlias As String     Dim strUserName As String     Dim strPassWord As String     Dim strExchSvrName As String     Dim strFrom As String     Dim strTo As String     Dim strSubject As String     Dim strBody As String     Dim bResult As Boolean          ' Exchange Server Name.     strExchSvrName = "Server"     ' Alias of the sender.     strAlias = "alias"          ' User Name of the sender.     strUserName = "DOMAIN\username"     ' Password of the sender.     strPassWord = "password"     ' Email address of the sender.     strFrom = "alias@domain.com"     ' Email address of recipient.     strTo = "alias@domain.com"     ' Subject of the mail.     strSubject = "My Subject"     ' Text body of the mail.     strBody = "Textbody"          strSubURL = FindSubmissionURL(strExchSvrName, strAlias, strUserName, _                                   strPassWord)          If strSubURL <> "" Then         bResult = False         bResult = SendMail(strSubURL, strFrom, strTo, strSubject, strBody, _                            strUserName, strPassWord)         If bResult Then             MsgBox "Mail has been successfully sent via WebDAV!"         End If     End If      End Sub      Function FindSubmissionURL(strExchSvr, strAlias, strUserName, _                            strPassWord) As String          Dim query As String     Dim strURL As String     Dim xmlRoot As IXMLDOMElement     Dim xmlNode As IXMLDOMNode     Dim baseName As String          Dim xmlReq As MSXML2.XMLHTTP     Dim xmldom As MSXML2.DOMDocument     Dim xmlAttr As MSXML2.IXMLDOMAttribute          ' Find the mail submission URI by doing a PROPFIND          Set xmlReq = CreateObject("Microsoft.XMLHTTP")          strURL = "http://" & strExchSvr & "/exchange/" & strAlias     xmlReq.Open "PROPFIND", strURL, False, strUserName, strPassWord     xmlReq.setRequestHeader "Content-Type", "text/xml"     xmlReq.setRequestHeader "Depth", "0"          query = "<?xml version='1.0'?>"     query = query + "<a:propfind xmlns:a='DAV:'>"     query = query + "<a:prop xmlns:m='urn:schemas:httpmail:'>"     query = query + "<m:sendmsg/>"     query = query + "</a:prop>"     query = query + "</a:propfind>"          xmlReq.send (query)          If (xmlReq.Status >= 200 And xmlReq.Status < 300) Then         MsgBox "Found URI! " & " Status = " & xmlReq.Status & ": " _                & xmlReq.statusText              Set xmldom = xmlReq.responseXML              Set xmlRoot = xmldom.documentElement         For Each xmlAttr In xmlRoot.Attributes             If xmlAttr.Text = "urn:schemas:httpmail:" Then                 baseName = xmlAttr.baseName                 Exit For             End If         Next              Set xmlNode = xmlRoot.selectSingleNode("//" & baseName & ":sendmsg")         FindSubmissionURL = xmlNode.Text          Else         MsgBox "Failed to find mail submission URL"         FindSubmissionURL = ""     End If      ErrExit:     Set xmlReq = Nothing     Set xmldom = Nothing     Set xmlRoot = Nothing     Set xmlNode = Nothing     Set xmlAttr = Nothing     Exit Function ErrHandler:     MsgBox Err.Number & ": " & Err.Description     FindSubmissionURL = "" End Function           Function SendMail(strSubURL, strFrom, strTo, strSubject, strBody, _                   strUserName, strPassWord) As Boolean          On Error GoTo ErrHandler          Dim xmlReq As MSXML2.XMLHTTP     Dim strText          ' Construct the text of the PUT request.     strText = "From: " & strFrom & vbNewLine & _               "To: " & strTo & vbNewLine & _               "Subject: " & strSubject & vbNewLine & _               "Date: " & Now & _               "X-Mailer: test mailer" & vbNewLine & _               "MIME-Version: 1.0" & vbNewLine & _               "Content-Type: text/plain;" & vbNewLine & _               "Charset = ""iso-8859-1""" & vbNewLine & _               "Content-Transfer-Encoding: 7bit" & vbNewLine & _               vbNewLine & _               strBody          ' Create the DAV PUT request to create the message body     Set xmlReq = CreateObject("Microsoft.XMLHTTP")     xmlReq.Open "PUT", strSubURL, False, strUserName, strPassWord     If strText <> "" Then         xmlReq.setRequestHeader "Content-Type", "message/rfc822"         xmlReq.send strText     End If          'Process the results.     If (xmlReq.Status >= 200 And xmlReq.Status < 300) Then         MsgBox "Success!   " & "PUT Results = " & xmlReq.Status & _                ": " & xmlReq.statusText         SendMail = True     ElseIf xmlReq.Status = 401 Then         MsgBox "You don't have permission to do the job! " & _                "Please check your permissions on this item."         SendMail = False     Else         MsgBox "Request Failed.  Results = " & xmlReq.Status & _                ": " & objRequest.statusText         SendMail = False     End If ErrExit:     Set xmlReq = Nothing     Exit Function ErrHandler:     MsgBox Err.Number & ": " & Err.Description     SendMail = False End Function 

WebDAV XML Elements

In the Exchange SDK, which is included in the companion content, you should look at the WebDAV XML elements section. We have covered many of these elements in this chapter, such as the response, lock, target, and other elements that can be passed to WebDAV requests and responses, but not all of them. You should browse the elements section of the SDK if you plan to work extensively with WebDAV and Exchange.

Working with Attachments in WebDAV

Exchange supports an extension to the WebDAV commands that allows you to enumerate attachments on a message. This WebDAV command is called X-MS-ENUMATTS . You send it like a normal WebDAV command such as PROPPATCH or PROPFIND . The following code shows how to use this command and shows a typical response from the server. In the response, you will see the filename, size, and the application type. These are the most interesting properties in the response to look at.

 Dim oXMLHTTP As New MSXML2.XMLHTTP30      strURL = "http://localhost/public/my%20new%20folder%202/my%20new%20item.eml" oXMLHTTP.Open "X-MS-ENUMATTS", strURL, False oXMLHTTP.Send "" 

Response from the Server ( oXMLHTTP.responseText ):

 <?xml version="1.0"?><a:multistatus xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f- 00aa00c14882/" xmlns:f="http://schemas.microsoft.com/mapi/ " xmlns:e="urn:schemas:httpmail:" xmlns:c="xml:" xmlns:d="http://sche mas.microsoft.com/mapi/proptag/" xmlns:g="http://schemas.microsoft.com/ exchange/" xmlns:j="urn:schemas-microsoft-com:office:office" xmlns:h="http:// schemas.microsoft.com/repl/ " xmlns:i="urn:schemas:contacts:" xmlns:a="DAV:"><a:response><a:href>http:// thomriznt52/public/folder/message.eml/document%20upload.doc</a:href><a:prop stat><a:status>HTTP/1.1 200 OK</a:status><a:prop><d:x3704001e>docume~1.doc</ d:x3704001e><d:x666c000b b:dt="boolean">0</ d:x666c000b><d:x37050003 b:dt="int">1</ d:x37050003><d:x68100102 b:dt="bin.base64">AAAAAAAAAAAAAAAAAAA=</ d:x68100102><e:attachmentfilename>document upload.doc</ e:attachmentfilename><d:x0e200003 b:dt="int">149056</ d:x0e200003><d:x3703001e>doc</d:x3703001e><d:x370b0003 b:dt="int">-1</ d:x370b0003><d:x3f880014 b:dt="i8">-7903522676918976511</ d:x3f880014><d:x3716001e>attachment</ d:x3716001e><d:x0ff90102 b:dt="bin.base64">ze+uqDfe10ySCYYOCU1KaA==</ d:x0ff90102><d:x0e210003 b:dt="int">0</d:x0e210003><i:cn>document upload.doc</ i:cn><d:x370e001e>application/msword</d:x370e001e></a:prop></a:prop stat><a:propstat><a:status>HTTP/1.1 200 OK</a:status><a:prop><d:x0e12000d/ ><d:x0e13000d/></a:prop></a:propstat></a:response><a:response><a:href>http:// thomriznt52/public/folder/message.eml/extensions.txt</a:href><a:prop stat><a:status>HTTP/1.1 200 OK</a:status><a:prop><d:x3704001e>extens~1.txt</ d:x3704001e><d:x666c000b b:dt="boolean">0</ d:x666c000b><d:x37050003 b:dt="int">1</ d:x37050003><d:x68100102 b:dt="bin.base64">AAAAAAAAAAAAAAAAAAA=</ d:x68100102><e:attachmentfilename>extensions.txt</ e:attachmentfilename><d:x0e200003 b:dt="int">648</ d:x0e200003><d:x3703001e>txt</d:x3703001e><d:x370b0003 b:dt="int">-1</ d:x370b0003><d:x3f880014 b:dt="i8">-7759407488843120639</ d:x3f880014><d:x3716001e>attachment</ d:x3716001e><d:x0ff90102 b:dt="bin.base64">v5Z//lJ3jUi7FoO3muigAg==</ d:x0ff90102><d:x0e210003 b:dt=" int">1</d:x0e210003><i:cn>extensions.txt</i:cn><d:x370e001e>text/plain</ d:x370e001e></a:prop></a:propstat><a:propstat><a:status>HTTP/1.1 200 OK</a:sta tus><a:prop><d:x0e12000d/><d:x0e13000d/></a:prop></a:propstat></a:response></ a:multistatus> 

Other Resources

Additional WebDAV functionality includes the ability to create contacts, appointments, and meeting requests. It is nice that you can do this through WebDAV because WebDAV is remotable, unlike ADO with the EXOLEDB provider. However, you do need to be careful when you create appointments and contacts with WebDAV because of time zone and Outlook interoperability issues. You might want to simply use CDO for Exchange to create your appointments and contacts, if you can. CDO for Exchange includes all the necessary Outlook interoperability and time zone conversion code, but, as ADO, it isn't remotable. If you are still interested in using WebDAV for this purpose, check out the Microsoft Knowledge Base at http://support.microsoft.com , which includes a host of articles about creating Exchange items using WebDAV (such as articles 296126, 309699, and 291171). Also, if you want to remotely create contacts, appointments, or mail messages and want to harness the power of CDO, you can create a XML Web service on your Exchange Server and call that from your mid- tier or client applications.




Programming Microsoft Outlook and Microsoft Exchange 2003
Programming MicrosoftВ® OutlookВ® and Microsoft Exchange 2003, Third Edition (Pro-Developer)
ISBN: 0735614644
EAN: 2147483647
Year: 2003
Pages: 227
Authors: Thomas Rizzo

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net