Wednesday 17 January 2007

Copying folder contents with BCOPY through WebDAV


I'm working on an Exchange project at the moment, and have chosen to use WebDAV for the operations required. One of the subsidiary requirements is to copy contacts from one folder on a mailbox to another, then synchronise those contacts with a public folder on the Exchange server too. I discovered the WebDAV BCOPY method, which allows you to copy a whole load of items from one folder to another. Perfect! It works like this.

I make a WebDAV SEARCH request to the exchange server like so


<?xml version="1.0" ?>
<D:searchrequest xmlns:D="DAV:">
  <D:sql>
    select "DAV:href","DAV:contentclass"
    FROM SCOPE ('SHALLOW TRAVERSAL OF "/exchange/<mailbox>/Contacts"')
    WHERE "DAV:ishidden" = false
  </D:sql>
</D:searchrequest>


it returns a result set like this:


<?xml version="1.0" encoding="utf-16"?>
<a:multistatus xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" xmlns:c="xml:" xmlns:a="DAV:">
  <a:response>
    <a:href>http://<exchsrvr>/exchange/<mailbox>/Contacts/BobLog.EML</a:href>
        <a:propstat>
          <a:status>HTTP/1.1 200 OK</a:status>
          <a:prop>
            <a:href>http://<exchsrvr>/exchange/<mailbox>/Contacts/BobLog.EML</a:href>
            <a:contentclass>urn:content-classes:person</a:contentclass>
          </a:prop>
        </a:propstat>
      </a:response>
      <a:response>
        <a:href>...


and so on.

then you iterate through your <a:response>s, extract the hrefs and build this request


<?xml version="1.0" ?>
<D:copy xmlns:D="DAV:">
  <D:target>
    <D:href>http://<exchsrvr>/exchange/<mailbox>/Contacts/BobLog.EML</D:href>
    <D:href>http://<exchsrvr>/exchange/<mailbox>/Contacts/JudahBauer.EML</D:href>
    ... etc
  </D:target>
</D:copy>


add an Http header called Destination, with the value of the destination folder, then fire it off as a BCOPY command. Bingo, all your specified contacts have been copied, with changes from the source overwriting the destination object.

It's a bit long winded though. Not to mention the hassle of removing old entries. Anyway, it worked. So I kept experimenting, and tried adding a subfolder to the items collection to see what would happen if I tried to copy it. And whaddyaknow, it only bloomin created the destination folder, and all the contacts in it!

!!BRAIN WAVE!!

That means the entire operation can be condensed into this:


<?xml version="1.0" ?>
<D:copy xmlns:D="DAV:">
  <D:target>
    <D:href>http://<exchsrvr>/exchange/<mailbox>/Contacts</D:href>
    <D:dest>http://<exchsrvr>/exchange/<mailbox>/ContactsCopy</D:dest>
  </D:target>
</D:copy>


fired off at the mailbox root. And it cascades item deletes and everything!

Laaaaahvley!

No comments: