1
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
41 sys.path.insert(0,os.path.abspath(__file__+"/../.."))
42 from contacts import contacts
43 import pisiprogress
44
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
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
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)
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
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
135
136 raise ValueError("LDAP module not (yet) writable!")
137