Package modules :: Module contacts_ldap
[hide private]
[frames] | no frames]

Source Code for Module modules.contacts_ldap

  1  #!/usr/bin/env python 
  2   
  3  """  
  4  Synchronize with a LDAP 
  5   
  6  It is assumed, that you are using the "mozillaAbPersonAlpha" schema for your LDAP. Otherwise, the mapping wouldn't work as the attributes are required. 
  7   
  8  The LDAP Python site package python-ldap (http://python-ldap.sourceforge.net/) is required for this module. 
  9  Before installing the site package, the LDAP libraries (http://www.openldap.org/) must be available on the machine. 
 10  I couldn't find any pre-compiled package of either of the two - so I had to compile and install everything myself (what a mess). I found the following sources helpful: 
 11   - http://wiki.openmoko.org/wiki/Toolchain 
 12   - http://www.open-moko.de/die-software-anwendungen-f6/libsdl-und-crosscompiler-t25.html (in German) 
 13  Hopefully, in near future an LDAP as well as a Python-LDAP ipkg will be available. 
 14   
 15  Special characters (such as umlauts) seem to result in an error being thrown. This is due to some unicode encoding problem. 
 16  ToDo: Resolv this issue! 
 17   
 18  Please note, that currently, only read access to LDAP is implemented. 
 19   
 20  This file is part of Pisi. 
 21   
 22  Pisi is free software: you can redistribute it and/or modify 
 23  it under the terms of the GNU General Public License as published by 
 24  the Free Software Foundation, either version 3 of the License, or 
 25  (at your option) any later version. 
 26   
 27  Pisi is distributed in the hope that it will be useful, 
 28  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 29  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 30  GNU General Public License for more details. 
 31   
 32  You should have received a copy of the GNU General Public License 
 33  along with Pisi.  If not, see <http://www.gnu.org/licenses/> 
 34  """ 
 35   
 36  import os.path 
 37  import sys,os,re 
 38  import ldap 
 39   
 40  # Allows us to import contact 
 41  sys.path.insert(0,os.path.abspath(__file__+"/../..")) 
 42  from contacts import contacts 
 43  import pisiprogress 
 44   
45 -class SynchronizationModule(contacts.AbstractContactSynchronizationModule):
46 """ 47 The implementation of the interface L{contacts.AbstractContactSynchronizationModule} for the LDAP backend 48 """
49 - def __init__( self, modulesString, config, configsection, folder, verbose=False, soft=False):
50 """ 51 Constructor 52 53 Super class constructor (L{contacts.AbstractContactSynchronizationModule.__init__}) is called. 54 Local variables are initialized. 55 The settings from the configuration file are loaded. 56 """ 57 contacts.AbstractContactSynchronizationModule.__init__(self, verbose, soft, modulesString, config, configsection, "LDAP") 58 self._ldapHost = config.get(configsection,'ldapHost') 59 self._ldapDomain = config.get(configsection,'ldapDomain') 60 self._ldapFilter = config.get(configsection,'ldapFilter') 61 self._ldapUser = config.get(configsection,'ldapUser') 62 self._ldapPassword = config.get(configsection,'ldapPassword') 63 pisiprogress.getCallback().verbose('contact ldap module loaded using host %s' % (self._ldapHost))
64
65 - def _extractAtt(self, contactEntry, key):
66 """ 67 Supporting method for loading content from the LDAP 68 69 Catches possible exceptions and takes care of proper (unicode) encoding. 70 """ 71 try: 72 r = contactEntry[key][0].decode("utf-8") 73 return r 74 except KeyError: 75 return ""
76
77 - def load(self):
78 """ 79 Loads all attributes for all contact items from LDAP repository 80 81 For each entry a new L{contacts.contacts.Contact} instance is created and stored in the instance dictionary L{contacts.AbstractContactSynchronizationModule._allContacts}. 82 """ 83 pisiprogress.getCallback().verbose("LDAP: Loading") 84 l = ldap.initialize("ldap://" + self._ldapHost) 85 l.simple_bind_s(self._ldapUser,self._ldapPassword) 86 res = l.search_s(self._ldapDomain, ldap.SCOPE_SUBTREE, self._ldapFilter) 87 l.unbind() 88 pisiprogress.getCallback().progress.setProgress(20) # we guess that the actual query took up 20 % of the time - the remaining 80 % are taken by parsing the content ... 89 pisiprogress.getCallback().update('Loading') 90 i=0 91 for cn, contactEntry in res: 92 atts = {} 93 94 atts['firstname'] = self._extractAtt(contactEntry, "givenName") 95 atts['middlename'] = self._extractAtt(contactEntry, "mozillaNickname") 96 atts['lastname'] = self._extractAtt(contactEntry,"sn") 97 atts['title'] = self._extractAtt(contactEntry,"title") 98 99 atts['email'] = self._extractAtt(contactEntry,"mail") 100 atts['mobile'] = self._extractAtt(contactEntry,"mobile") 101 atts['phone'] = self._extractAtt(contactEntry,"homePhone") 102 atts['officePhone'] = self._extractAtt(contactEntry,"telephoneNumber") 103 atts['fax'] = self._extractAtt(contactEntry,"facsimileTelephoneNumber") 104 105 atts['homeStreet'] = self._extractAtt(contactEntry, "mozillaHomeStreet") 106 atts['homePostalCode'] = self._extractAtt(contactEntry, "mozillaHomePostalCode") 107 atts['homeCity'] = self._extractAtt(contactEntry, "mozillaHomeLocalityName") 108 atts['homeCountry'] = self._extractAtt(contactEntry, "mozillaHomeCountryName") 109 atts['homeState'] = self._extractAtt(contactEntry, "mozillaHomeState") 110 111 atts['businessOrganisation'] = self._extractAtt(contactEntry, "o") 112 atts['businessDepartment'] = self._extractAtt(contactEntry, "ou") 113 atts['businessPostalCode'] = self._extractAtt(contactEntry, "postalCode") 114 atts['businessStreet'] = self._extractAtt(contactEntry, "street") 115 atts['businessCity'] = self._extractAtt(contactEntry, "l") 116 atts['businessCountry'] = self._extractAtt(contactEntry, "c") 117 atts['businessState'] = self._extractAtt(contactEntry, "st") 118 119 id = contacts.assembleID(atts) 120 c = contacts.Contact(id, atts) 121 self._allContacts[id] = c 122 i+=1 123 pisiprogress.getCallback().progress.setProgress(20 + ((i*80) / len(res))) 124 pisiprogress.getCallback().update('Loading')
125
126 - def saveModifications( self ):
127 """ 128 Stub: To save all changes that have come by 129 130 Saving for LDAP is not yet implemented. This function only raIses an exception (L{ValueError}), informing about this status of implementation. 131 """ 132 pisiprogress.getCallback().verbose("LDAP module: I would apply %d changes now" %(len(self._history))) 133 if len(self._history) == 0: 134 return # don't touch anything if there haven't been any changes 135 136 raise ValueError("LDAP module not (yet) writable!")
137