Welcome, guest | Sign In | My Account | Store | Cart

Webdav is useful to get information on something in exchange. Often you need to know what you can ask for. Here is a simple recipe to get a list of the attributes available for a specific item.

Python, 117 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import win32com,win32com.client
from xml.parsers import expat

def propfind(url,request,logon='',passwd='',depth=1):
    ##pfind='''<?xml version="1.0" ?>
    ##<D:propfind xmlns:D='DAV:' xmlns:m='urn:schemas:httpmail:'>
    ##  <D:prop> <m:from/> <m:to/> <m:subject/> </D:prop>
    ##</D:propfind>'''
    ##dav=propfind(url,pfind)
   dav = win32com.client.Dispatch('Microsoft.XMLHTTP')
   dav.open('PROPFIND',url, 0) #,Logon, passwd)
   dav.setRequestHeader("Content-type:", "text/xml")
   dav.setRequestHeader("depth", depth) #0=immediate,1=w/children,infinity=all 
   dav.setRequestHeader("Translate", "f")
   dav.send(request)
   return dav.responseText  


class xml_process:
    def __init__(self,the_data,fields=[],keep_prefix=0,keep_attr=0):
        self.results=[]
        self.cur_name=None
        self.tmp=[]
        self.the_data=the_data
        self.p=expat.ParserCreate()
        self.p.StartElementHandler=self.start
        self.p.EndElementHandler=self.end
        self.p.CharacterDataHandler=self.data
        self.fields=fields
        self.keep_prefix=keep_prefix
        self.keep_attr=keep_attr
    def clean(self,data):
        tmp=''.join(data)
        return ' '.join(tmp.split())
    def start(self,name,attrs): 
        if not self.cur_name: self.cur_name=name
        tmp_name=self.cur_name
        if not self.keep_prefix:
            if self.cur_name[1]==':': tmp_name=self.cur_name[2:]
        self.attrs=attrs
        if name != self.cur_name:
            if not self.attrs or not self.keep_attr:
                if not self.fields or tmp_name.lower() in self.fields:
                    self.results.append( {tmp_name:self.clean(self.tmp)})
            else:
                if not self.fields or tmp_name.lower() in self.fields:
                 self.results.append( { tmp_name:{self.clean(self.tmp):attrs}})
            self.tmp=[]
            self.cur_name=name
    def data(self,info):  self.tmp.append(info)
    def end(self,name): pass
    def parse(self):
        if 'xml' not in self.the_data[0:50].lower(): return []
        self.p.Parse(self.the_data,1)
        results=self.results
        if self.fields:
            filter_cache={}
            results=[{}]
            
            for i in self.fields: filter_cache[i]=None
            for row in self.results:
                k,v=row.items()[0]
                #check if filter_cache is full
                full=0
                for i in filter_cache:
                    if not filter_cache[i]:
                        filter_cache[i]=1
                        full=0;break
                    full=1
                if full:
                    for i in self.fields: filter_cache[i]=None
                    full=0
                    results.append({})
                if k not in results[-1]:
                    results[-1][k]=v
        return results

#Props={}

def all_props(url,raw=0,namespace=0,logon='',passwd=''):  
    request='''<?xml version="1.0" ?>
    <D:propfind xmlns:D="DAV:">
            <D:allprop/>
    </D:propfind>'''

    text=propfind(url,request,depth=0,logon=logon,passwd=passwd)
    if raw:  return text
    elif namespace:
        xmlns=text[text.find('multistatus'):]
        xmlns=xmlns[:xmlns.find('>')]
        xmlns_ref={}
        for i in xmlns.split('xmlns:'): 
            j=i.split('=')
            if len(j)==2:
                    k,v=j
                    xmlns_ref[k]=v
        result=xml_process(text,keep_prefix=1)
        field_ref={}
        for i in result.parse(): 
            l=i.keys()[0] #l=d:busystatus
            if ':' not in l: continue
            k,v=l.split(':')
            field_ref[v]=xmlns_ref[k]
        return field_ref
    else:    
        result=xml_process(text)
        result2=[]
        for i in result.parse(): 
            field=i.keys()[0]
            result2.append(field)
        return result2


url='http://host/exchange/user/Calendar/'
print all_props(url)
print all_props(url,namespace=1)
print all_props(url,raw=1)

As an example, information about the calendar is acquired.

The function all_props has 3 modes. Without any options it just gives you a list of properties. If you set namespace to be true, you get a list of properties and their corresponding namespace. If you want to look at the raw xml, set raw to true. The xml is parsed rather simply with expat which works well with the xml data the exchange server returns.

2 comments

John Nielsen (author) 19 years, 6 months ago  # | flag

I am pyguy2 on yahoo. You can reach me(the author) at pyguy2 on yahoo

Stuart Turner 18 years, 6 months ago  # | flag

xmlhhtp without win32com. Hi,

This code really helped me get started with webdav. I also wrote a small python class to give the same functionality as the xmlhttp com object. Have tested the code on Windows XP Service Pack 2 and also Red Hat Linux. Both seem to work fine. Let me know if you encounter any issues!

Class File

# Create a class with the same functionality
# as XMLHTTP

import httplib, base64, urlparse

class xmlhttp:

    def __init__ (self):
        self.__headers = {}

    def addHeader (self, name, content):
        self.__headers[name] = content

    def sendRequest (self, verb, url, request, username, password):

        # Encode the username and password as base 64.  Remove the newline
        # which base64 puts at the end of the string
        upB64 = base64.encodestring('%s:%s' % (username, password))[:-1]

        # Add the Authorisation header
        self.__headers['Authorization'] = 'Basic %s' % upB64

        # Parse out the URL in to components
        (scheme, netloc, path, params, query) = \
            urlparse.urlsplit (url)

        con = httplib.HTTPConnection(netloc)
        con.request(verb, path, request, self.__headers)

        response = con.getresponse()

        return (response.status, response.reason, response.read())

Example Usage

import ... xmlhttp ...

...

        dav = xmlhttp.xmlhttp()
        dav.addHeader("Content-type", "text/xml")
        status, statustext, responseText = \
            dav.sendRequest('SEARCH', url, req, user, pwd)