File Coverage

blib/lib/Kolab/DirServ.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Kolab::DirServ;
2              
3             ##
4             ## Copyright (c) 2003 Code Fusion cc
5             ## Writen by Stephan Buys
6             ##
7             ## This program is free software; you can redistribute it and/or
8             ## modify it under the terms of the GNU General Public License as
9             ## published by the Free Software Foundation; either version 2, or
10             ## (at your option) any later version.
11             ##
12             ## This program is distributed in the hope that it will be useful,
13             ## but WITHOUT ANY WARRANTY; without even the implied warranty of
14             ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15             ## General Public License for more details.
16             ##
17             ## You can view the GNU General Public License, online, at the GNU
18             ## Project's homepage; see .
19             ##
20              
21 1     1   22657 use 5.008;
  1         4  
  1         37  
22 1     1   5 use strict;
  1         2  
  1         31  
23 1     1   5 use warnings;
  1         7  
  1         40  
24 1     1   394 use Kolab;
  0            
  0            
25             use Kolab::Util;
26             #use Kolab::LDAP;
27             use Kolab::Mailer;
28             use MIME::Entity;
29             use MIME::Parser;
30             use MIME::Body;
31             use Net::LDAP;
32             use Net::LDAP::LDIF;
33             use Net::LDAP::Entry;
34             use Mail::IMAPClient;
35             use URI;
36             use IO::File;
37             use POSIX qw(tmpnam);
38             use vars qw(@peers);
39              
40             require Exporter;
41              
42             our @ISA = qw(Exporter);
43              
44             our %EXPORT_TAGS = (
45             'all' => [ qw(
46             @peers
47             &reloadPeers
48             &genericRequest
49             ¬ifyNew
50             ¬ifyModify
51             ¬ifyRemove
52             &handleNotifications
53             )
54             ] );
55              
56             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
57              
58             our @EXPORT = qw(
59             );
60              
61             our $VERSION = sprintf('%d.%02d', q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
62              
63             sub reloadPeers
64             {
65             @peers = readList($Kolab::config{'prefix'} . "/etc/kolab/addressbook.peers");
66              
67             foreach my $peer (@peers) {
68             Kolab::log('DS', "Using peer $peer", KOLAB_DEBUG);
69             }
70             }
71              
72             reloadPeers();
73              
74             sub genericRequest
75             {
76             #print "Sending generic request: Type:\n";
77             return 0 if length(@peers) == 0;
78              
79             my $notify = shift;
80             my $entry = $notify->clone;
81             my $request = shift;
82              
83             $entry->delete('userpassword');
84             $entry->delete('uid');
85             $entry->delete($Kolab::config{'user_field_guid'});
86             $entry->delete($Kolab::config{'user_field_modified'});
87              
88             $entry->add(
89             'objectClass' => 'kolabPerson',
90             'homeServer' => $Kolab::config{'dirserv_home_server'},
91             );
92              
93             Kolab::log('DS', "About to send $request", KOLAB_DEBUG);
94              
95             my $fh = IO::File->new_tmpfile;
96             return 0 if !defined $fh;
97              
98             #foreach my $a ($entry->attributes) {
99             # print "$a : ";
100             # my $vals = $entry->get_value($a, 'asref' => 1);
101             # foreach my $val (@$vals) {
102             # print "$val,"
103             # }
104             # print "\n";
105             #}
106              
107             my $ldif = Net::LDAP::LDIF->new($fh);#, "w+", onerror => 'undef');
108             if (!$ldif) { die "unable to create ldif obj" ; }
109             $ldif->write_entry($entry);
110             #$ldif->dump;
111              
112             my (@stats, $data);
113             @stats = stat($fh);
114             seek($fh, 0, 0);
115             read($fh, $data, $stats[7]);
116             #print "Read " . $stats[7] . " bytes, data = $data";
117              
118             foreach my $peer (@peers) {
119             Kolab::Mailer::sendMultipart(
120             $Kolab::config{'dirserv_notify_from'},
121             $peer,
122             $request,
123             $fh
124             );
125             }
126             $fh->close();
127              
128             return 1;
129             }
130              
131             sub notifyNew
132             {
133             return genericRequest($_[0], "new alias");
134             }
135              
136             sub notifyModify
137             {
138             return genericRequest($_[0], "modify alias");
139             }
140              
141             sub notifyRemove
142             {
143             return genericRequest($_[0], "remove alias");
144             }
145              
146             sub printEntry {
147             my $entry = shift;
148             foreach my $a ($entry->attributes) {
149             print "$a : ";
150             my $vals = $entry->get_value($a, 'asref' => 1);
151             foreach my $val (@$vals) {
152             print "$val,"
153             }
154             print "\n";
155             }
156             }
157              
158             sub scrubEntry {
159             my $entry = shift;
160             foreach my $attr ($$entry->attributes) {
161             #print $attr,"\n";
162             my $value = $$entry->get_value($attr, 'asref' => 1);
163             my @newvalues;
164             foreach my $element (@$value) {
165             $element = trim($element);
166             push(@newvalues, ($element));
167             }
168             $$entry->replace($attr, \@newvalues);
169             }
170             }
171              
172             sub handleNotifications
173             {
174             my $server = shift;
175             my $user = shift;
176             my $password = shift;
177              
178             my ($imap, $ldap);
179              
180             if (!($imap = Mail::IMAPClient->new(
181             Server => $server,
182             User => $user,
183             Port => 143,
184             Password => $password,
185             Peek => 1
186             ))) {
187             Kolab::log('DS', "Unable to open IMAP connection to `$server'", KOLAB_ERROR);
188             return 0;
189             }
190              
191             if (!$imap->Status) {
192             Kolab::log('DS', "Unable to connect to IMAP server", KOLAB_ERROR);
193             return 0;
194             }
195              
196             #if (!($ldap = Kolab::LDAP::create(
197             # $Kolab::config{'ldap_ip'},
198             # $Kolab::config{'ldap_port'},
199             # $Kolab::config{'bind_dn'},
200             # $Kolab::config{'bind_pw'}
201             #))) {
202             # return 1;
203             #}
204              
205             $ldap = Net::LDAP->new(
206             $Kolab::config{'ldap_ip'},
207             port => $Kolab::config{'ldap_port'},
208             );
209             if (!$ldap) {
210             Kolab::log('DS', "Unable to connect to LDAP server", KOLAB_ERROR);
211             return 0;
212             }
213              
214             my $ldapmesg = $ldap->bind(
215             $Kolab::config{'bind_dn'},
216             password => $Kolab::config{'bind_pw'}
217             );
218             if ($ldapmesg->code) {
219             Kolab::log('DS', "Unable to bind to LDAP server, Error = `" . $ldapmesg->error . "'", KOLAB_ERROR);
220             return 0;
221             }
222              
223             my $parser = new MIME::Parser;
224              
225             # Use IDLE instead of polling
226             my @folders = $imap->folders;
227              
228             foreach my $folder (@folders){
229             next if $folder =~ /^\./;
230             $imap->select($folder);
231              
232             my @messagelist = $imap->search('UNDELETED');
233             foreach my $message (@messagelist) {
234             my $data = $imap->message_string($message);
235             warn "Empty message data for $folder/$message" unless defined $data && length $data;
236              
237             $parser->output_under("/tmp");
238             my $entity = $parser->parse_data($data);
239             my $subject = $entity->head->get('Subject',0);
240             $subject = trim($subject);
241              
242             #Sanity check
243             if ($subject =~ /new alias/ && $entity->is_multipart) {
244             #print $entity->parts;
245             my ($name,$fh);
246             my $part = $entity->parts(0);
247             my $bodyh = $part->bodyhandle;
248              
249             $fh = IO::File->new_tmpfile;
250             return 0 if !defined $fh;
251              
252             $bodyh->print(\*$fh);
253             seek($fh,0,0);
254              
255             my $ldif = Net::LDAP::LDIF->new( $fh, "r", onerror => 'undef' );
256             while ( not $ldif->eof() ) {
257             my $entry = $ldif->read_entry();
258             my $cn = $entry->get_value('cn'); #,".$Kolab::config{'bind_dn'});
259             $cn = trim($cn);
260             $cn = "cn=$cn".",cn=external,".$Kolab::config{'base_dn'};
261             $entry->dn($cn);
262              
263             if ( !$ldif->error() ) {
264             scrubEntry(\$entry);
265              
266             my $result = $entry->update($ldap);
267             $result->code && warn "failed to add entry: ", $result->error ;
268             }
269             #print "$subject ",$entry->dn(),"\n";
270             }
271             $fh->close();
272             } elsif ($subject =~ /modify alias/ && $entity->is_multipart) {
273             # #print $entity->parts;
274             # my ($name,$fh);
275             # my $part = $entity->parts(0);
276             # my $bodyh = $part->bodyhandle;
277             #
278             # $fh = IO::File->new_tmpfile;
279             # return 0 if !defined $fh;
280             #
281             # $bodyh->print(\*$fh);
282             # seek($fh,0,0);
283             #
284             # my $ldif = Net::LDAP::LDIF->new( $fh, "r", onerror => 'undef' );
285             # while ( not $ldif->eof() ) {
286             # my $entry = $ldif->read_entry();
287             # my $cn = $entry->get_value('cn'); #,".$Kolab::config{'bind_dn'});
288             # $cn = trim($cn);
289             # $cn = "cn=$cn".",cn=external,".$Kolab::config{'base_dn'};
290             # $entry->dn($cn);
291             # $entry->changetype('modify');
292             #
293             # if ( !$ldif->error() ) {
294             # foreach my $attr ($entry->attributes) {
295             # #print $attr,"\n";
296             # my $value = $entry->get_value($attr);
297             # $value = trim($value);
298             # $entry->replace($attr,$value);
299             # #print join("\n ",$attr, $entry->get_value($attr)),"\n";
300             # }
301             # my $result = $entry->update($ldap);
302             # if ($result->code) {
303             # warn "failed to add entry: ", $result->error ;
304             # $entry->changetype('add');
305             # $result = $entry->update($ldap);
306             # $result->code && warn "failed to add entry: ", $result->error ;
307             # }
308             # }
309             # #print "$subject ",$entry->dn(),"\n";
310             # }
311             # $fh->close();
312             #print $entity->parts;
313             my ($name,$fh);
314             my $part = $entity->parts(0);
315             my $bodyh = $part->bodyhandle;
316              
317             $fh = IO::File->new_tmpfile;
318             return 0 if !defined $fh;
319              
320             $bodyh->print(\*$fh);
321             seek($fh,0,0);
322              
323             my $ldif = Net::LDAP::LDIF->new( $fh, "r", onerror => 'undef' );
324             while ( not $ldif->eof() ) {
325             my $entry = $ldif->read_entry();
326             my $cn = $entry->get_value('cn'); #,".$Kolab::config{'bind_dn'});
327             $cn = trim($cn);
328             $cn = "cn=$cn".",cn=external,".$Kolab::config{'base_dn'};
329             $entry->dn($cn);
330             $entry->changetype('modify');
331              
332             if ( !$ldif->error() ) {
333             scrubEntry(\$entry);
334              
335             my $result = $entry->update($ldap);
336             if ($result->code) {
337             warn "failed to modify entry, trying to add : ", $result->error ;
338             $entry->changetype('add');
339             $result = $entry->update($ldap);
340             $result->code && warn "failed to add entry: ", $result->error ;
341             }
342             }
343             #print "$subject ",$entry->dn(),"\n";
344             }
345             $fh->close();
346             } elsif ($subject =~ /remove alias/ && $entity->is_multipart) {
347             #print $entity->parts;
348             # my ($name,$fh);
349             # my $part = $entity->parts(0);
350             # my $bodyh = $part->bodyhandle;
351             # #trim($bodyh);
352             # #print $bodyh;
353             # my $IO = $bodyh->open("r") || die "open body: $!";
354             # while (defined($_ = $IO->getline)) {
355             # my $line = $_;
356             # $line = trim($line);
357             # if (/(.*) : (.*)/) {
358             # if ($1 eq "cn") {
359             # my $cn = trim($2);
360             # #print "cn=$cn,cn=external,".$Kolab::config{'base_dn'},"\n";
361             # my $result = $ldap->delete("cn=$cn,cn=external,".$Kolab::config{'base_dn'});
362             # $result->code && warn "failed to delete entry: ", $result->error ;
363             # }
364             # }
365             # }
366             # $IO->close || die "close I/O handle: $!";
367             # #print $subject,"\n";
368              
369             my ($name,$fh);
370             my $part = $entity->parts(0);
371             my $bodyh = $part->bodyhandle;
372              
373             $fh = IO::File->new_tmpfile;
374             return 0 if !defined $fh;
375              
376             $bodyh->print(\*$fh);
377             seek($fh,0,0);
378              
379             my $ldif = Net::LDAP::LDIF->new( $fh, "r", onerror => 'undef' );
380             while ( not $ldif->eof() ) {
381             my $entry = $ldif->read_entry();
382             my $cn = $entry->get_value('cn'); #,".$Kolab::config{'bind_dn'});
383             $cn = trim($cn);
384             $cn = "cn=$cn".",cn=external,".$Kolab::config{'base_dn'};
385             $entry->dn($cn);
386             $entry->changetype('delete');
387              
388             if ( !$ldif->error() ) {
389             scrubEntry(\$entry);
390             my $result = $entry->update($ldap);
391             $result->code && warn "failed to delete entry: ", $result->error ;
392             }
393             }
394             $fh->close();
395              
396             }
397              
398              
399             }
400             $imap->set_flag("Deleted",@messagelist);
401             $imap->close or die "Could not close :$folder\n";
402             }
403              
404             if (defined($ldap) && $ldap->isa('Net::LDAP')) {
405             $ldap->abandon;
406             $ldap->unbind;
407             $ldap->disconnect;
408             }
409              
410             return 1;
411             }
412              
413             1;
414             __END__