/[cvs]/nfo/perl/scripts/outlook2ldap/libs/Torus/Driver/ldap.pm
ViewVC logotype

Contents of /nfo/perl/scripts/outlook2ldap/libs/Torus/Driver/ldap.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations)
Mon Jan 20 15:56:57 2003 UTC (21 years, 5 months ago) by joko
Branch: MAIN
CVS Tags: v009, HEAD
Changes since 1.2: +0 -162 lines
- refactored code to Data::Storage::Handler::NetLDAP and Data::Storage::Handler::NetLDAP::Extensions

1 #use Unicode::MapUTF8 qw(to_utf8 from_utf8 utf8_supported_charset);
2 use Data::Transform::Encode qw( var2utf8 var_utf2iso );
3 use Data::Dumper;
4
5 my $hr = "=" x 80 . "\n";
6
7 # debugging?
8 my $DEBUGLEVEL = $config->get("debug_level");
9 my $TRACELEVEL = $config->get("trace_level");
10
11 my $dnCache;
12 my $criticalCache;
13 my $msgCache;
14
15
16 # ==================================================
17 # configure here
18 # ==================================================
19 #my $binddn = 'cn=root, dc=labnet, dc=de';
20 my $binddn = 'cn=admin, o=netfrag.org, c=de';
21 #my $binddn = 'cn=admin';
22
23 # V1: hardcoded target ou
24 #my $basedn = 'ou=Adressen, dc=labnet, dc=de';
25
26 # V2: now passed-in to "addEntry"
27
28 my $cfg_objectclasses = [ qw(
29 Person
30 inetOrgPerson
31 organizationalPerson
32 pilotPerson
33 groupOfNames
34 ) ];
35 # msMapi
36 # outlookPerson
37
38 #
39 # other object classes:
40 # outlookPerson
41 # ==================================================
42
43
44 my $ldap;
45 my $map;
46
47
48 sub getEntry {
49
50 die("getEntry!");
51
52 my $basedn = '';
53
54 connectStore();
55
56 my $mesg = $ldap->search ( # perform a search
57 base => $basedn,
58 filter => "(&(sn=*))"
59 );
60
61 $mesg->code && die $mesg->error;
62
63 foreach my $entry ($mesg->all_entries) {
64 $entry->dump;
65 print "\n";
66 }
67
68 disconnectStore();
69
70 }
71
72 sub _example {
73 print "abcdef", "\n";
74 my $result = $ldap->add (
75 'cn = Barbara Jensen, o=University of Michigan, c=us',
76 attr => [ 'cn' => [ 'Barbara Jensen', 'Barbs Jensen' ],
77 'sn' => 'Jensen',
78 'mail' => 'b.jensen@umich.edu',
79 'objectclass' => ['top', 'person',
80 'organizationalPerson',
81 'inetOrgPerson' ],
82 ]
83 );
84
85 }
86
87 sub changeEntry {
88
89 my $dn = shift;
90 my $
91
92 $ldap->modify( $dn,
93 changes => [
94 add => [ sn => 'Barr' ], # Add sn=Barr
95 delete => [ faxNumber => []], # Delete all fax numbers
96 delete => [ telephoneNumber => ['911']], # delete phone number 911
97 replace => [ email => 'gbarr@pobox.com'] # change email address
98 ]
99 );
100
101 }
102
103
104 sub prepareEntry {
105
106 my $basedn = shift;
107 my $mapiEntry = shift;
108
109 my $ldapEntry;
110
111 my $mapfile = '../etc/' . $config->get("fields_mapfile");
112 readFieldMapping($mapfile);
113
114 # dump mapi-entry - don't do that! this is large!
115 #print Dumper($mapiEntry);
116 #exit;
117
118 # utf8-conversion of unmapped mapi-entry - don't do that! this is large!
119 #var2utf8($mapiEntry);
120
121 # map entry
122 foreach my $mapiKey (keys %{$mapiEntry}) {
123 my $ldapKey = $map->{ldap}{$mapiKey};
124 my $ldapValue = $mapiEntry->{$mapiKey};
125 next if (!$ldapKey);
126
127 # utf8-conversion
128 #$ldapKey = toUTF8($ldapKey);
129 #$ldapValue = toUTF8($ldapValue);
130
131 $ldapEntry->{$ldapKey} = $ldapValue;
132 }
133
134 # utf8-conversion of mapped ldap-entry
135 var2utf8($ldapEntry);
136
137 # dump ldap-entry - this is okay
138 #print "ldap-entry before adding:", "\n";
139 #print STDOUT Dumper($ldapEntry);
140
141 # build dn here
142 my $entryIdentifier = buildSnCn( {
143 #sn => $sn,
144 #givenname => $ldapEntry->{givenname},
145 LastName => $mapiEntry->{LastName},
146 FirstName => $mapiEntry->{FirstName},
147 FileAs => $mapiEntry->{FileAs},
148 CompanyName => $mapiEntry->{CompanyName},
149 EntryID => $mapiEntry->{EntryID},
150 } );
151
152 my $sn = $entryIdentifier->{sn};
153 my $cn = $entryIdentifier->{cn};
154
155 if (!$cn) {
156 rememberCriticalEntry("mapi", $mapiEntry->{EntryID});
157 logError('App', "Couldn't build required ldap-attribute \"cn\". LastName/FirstName/FileAs/CompanyName were empty.");
158 return;
159 }
160
161 # remember all already used "cn"s
162 addDnCache($cn);
163
164 my $must = {
165 cn => $cn,
166 sn => $sn,
167 member => $ldapEntry->{member},
168 objectClass => $cfg_objectclasses,
169 };
170 # utf8-conversion of must-have fields
171 var2utf8($must);
172
173 my $dn = buildDn( { basedn => $basedn, cn => $must->{cn} } );
174 rememberMessage($dn, $entryIdentifier->{info});
175
176 return { identifier => $dn, must => $must, may => $ldapEntry };
177
178 }
179
180 sub addEntry {
181
182 my $entry_raw = shift;
183
184 #print Dumper($entry_raw);
185 #return;
186
187 my $identifier = $entry_raw->{identifier};
188 my $must = $entry_raw->{must};
189 my $may = $entry_raw->{may};
190
191 my $dn = $identifier;
192
193 # delete entry (dn) first
194 if (existsEntry('cn', $dn)) {
195 print "entry exists (dn='$dn') deleting", "\n" if $DEBUGLEVEL > 3;
196 $ldap->delete($dn);
197 }
198
199 #print "dn: $dn", "\n";
200 #exit;
201
202 my $entry = Net::LDAP::Entry->new;
203 $entry->dn($dn);
204
205 $entry->add(
206 cn => $must->{cn},
207 sn => $must->{sn},
208 member => $must->{dn},
209 objectClass => $must->{objectClass},
210 );
211 #sn => 'Nachname',
212 #cn => 'Vorname Nachname',
213 my $result1 = $entry->add(%{$may});
214
215 #print Dumper($result1), "\n";
216 #print Dumper($entry);
217
218 my $result = $entry->update($ldap);
219 #print Dumper($ldap->sync());
220
221 #print "result:", "\n";
222 #print Dumper($result);
223 #exit;
224
225 #print "trace-level > 0: ", ($config->get("trace_level") > 0), "\n";
226 #exit;
227
228 #traceEntry($mapiEntry, $entry, { error => $error, prefix => $result->error }) if $TRACELEVEL >= 2;
229 #return 1 if !$error;
230
231 return $result;
232
233 }
234
235 sub logError {
236 my $type = shift;
237 my $message = shift;
238 my $options = shift;
239 if ($DEBUGLEVEL >= 1) {
240 print STDOUT "\n" if $DEBUGLEVEL <= 1;
241 print STDOUT "ERROR ($type): $message", "\n" ;
242 my $buffer = '';
243 foreach (keys %$options) {
244 $buffer .= " $_: $options->{$_}\n" if $options->{$_};
245 }
246 #print STDOUT Dumper($options), "\n";
247 print STDOUT $buffer;
248 }
249 }
250
251 sub logInfo {
252 my $type = shift;
253 my $message = shift;
254 if ($DEBUGLEVEL >= 1) {
255 print STDOUT "\n" if $DEBUGLEVEL <= 1;
256 print STDOUT "INFO ($type): $message", "\n" ;
257 }
258 }
259
260 sub traceEntry {
261 my $entry_source = shift;
262 my $entry_target = shift;
263 my $options = shift;
264
265 my $logfile = '../log/transfer.log';
266 if ($options->{error}) {
267 $logfile = '../log/errors.log';
268 }
269
270 my $dump_source = Dumper($entry_source);
271
272 #my $dump_target = Dumper($entry_target);
273 my $dump_target = "\n";
274 foreach my $attr ($entry_target->attributes) {
275 my $subentry = $attr . ": ";
276 my @value = $entry_target->get_value($attr);
277 if ($#value > 0) {
278 #push @value, "\n ";
279 $subentry .= "\n ";
280 }
281 $subentry .= join("\n ", @value);
282 $dump_target .= $subentry . "\n";
283 }
284
285 my $dump = <<EOD;
286 $hr
287 MAPI-Object:
288 $dump_source
289 $hr
290 Net::LDAP::Entry:
291 $dump_target
292 $hr
293 EOD
294
295 $dump = $hr . $options->{prefix} . $dump if $options->{prefix};
296
297 a2f($logfile, $dump);
298
299 }
300
301 sub toUTF8 {
302 my $string = shift;
303 #return to_utf8( -string => $string, -charset => 'ISO-8859-1');
304 print "before: $string", "\n";
305 var2utf8(\$string);
306 print "after: $string", "\n";
307 return $string;
308 }
309
310 sub readFieldMapping {
311 my $mapfile = shift;
312 if (! -e $mapfile) {
313 print "mapfile \"$mapfile\" does not exist.", "\n";
314 exit;
315 }
316 open(FH, '<', $mapfile);
317 while(<FH>) {
318 s/\r\n/\n/g;
319 chomp();
320 next if (m/^#/);
321 my @entry = split(';', $_);
322 my $key = $entry[0];
323 my $key_ldap = $entry[1];
324 $key_ldap ||= '';
325 $map->{mapi}{$key} = 1;
326 $map->{ldap}{$key} = $key_ldap;
327 }
328 close(FH);
329 }
330
331 sub checkOu {
332 my $basedn = shift;
333 my $ou = shift;
334
335 my $mesg = $ldap->search ( # perform a search
336 base => $basedn,
337 filter => "(&(ou=$ou))"
338 );
339
340 #print "search-result-code: ", $mesg->code, "\n";
341 #print "search-result-error: ", $mesg->error, "\n";
342
343 #return;
344 #print Dumper($mesg);
345 #exit;
346
347 #$mesg->code && die $mesg->error;
348
349 return 1 if exists $mesg->{entries};
350
351 }
352
353
354 sub buildSnCn {
355 my $parts = shift;
356
357 my $logmsg;
358
359 my $cn;
360
361 if ($parts->{LastName}) {
362 # use pure "sn" first!
363 $cn = $parts->{LastName} ;
364
365 # add "givenname" to "cn" if exists
366 $cn = $parts->{FirstName} . ' ' . $cn if $parts->{FirstName};
367 }
368
369 # check if "cn" is already filled, else provide some fallback-mechanism(s) here
370 # use "FileAs"
371 if (!$cn && $parts->{FileAs}) {
372 $cn = $parts->{FileAs};
373 $logmsg = "using \"FileAs\" for \"cn\": $cn";
374 }
375 # use "FirstName"
376 if (!$cn && $parts->{FirstName}) {
377 $cn = $parts->{FirstName};
378 $logmsg = "using \"FirstName\" for \"cn\": $cn";
379 }
380 # use "CompanyName"
381 if (!$cn && $parts->{CompanyName}) {
382 $cn = $parts->{CompanyName};
383 $logmsg = "using \"CompanyName\" for \"cn\": $cn";
384 }
385
386 # handle "must-have"-field "sn"
387 my $sn = $parts->{LastName};
388
389 # additional (last) rule: use unique identifier (EntryID) as "cn" if it's still empty
390 #$cn = 'ident - ' . $parts->{EntryID} if !$cn;
391 if (!$cn) {
392 $cn = $parts->{EntryID};
393 $logmsg = "\"cn\" was empty, using EntryID.\n - cn: $cn";
394 }
395
396 # fallback to "cn" if "sn" is empty
397 $sn = $cn if !$sn;
398
399 # check for collisions in "cn"s
400 if (dnAlreadyUsed($cn)) {
401 #logError('App', "Couldn't use cn='$cn' - already exists!");
402 #return;
403 $cn .= '-' . $parts->{EntryID};
404 $logmsg .= "\n - modified \"cn\" to prevent name-collision.\n - cn: $cn";
405 }
406
407 #$msgCache->{} = $logmsg;
408 logInfo('App::buildCn', $logmsg) if $logmsg;
409
410 return { sn => $sn, cn => $cn, info => $logmsg };
411
412 }
413
414 sub buildDn {
415 my $parts = shift;
416
417 # build "dn"
418 my $dn = join(', ', "cn=" . $parts->{cn}, $parts->{basedn});
419
420 # patch dn (remove forbidden characters)
421 $dn =~ s/\+/&/g;
422
423 return $dn;
424 }
425
426 sub clearDnCache {
427 $dnCache = {};
428 $msgCache = {};
429 }
430
431 sub addDnCache {
432 my $key = shift;
433 $dnCache->{$key}++;
434 }
435
436 sub dnAlreadyUsed {
437 my $key = shift;
438 return exists $dnCache->{$key};
439 }
440
441 sub rememberCriticalEntry {
442 my $type = shift;
443 my $identifier = shift;
444 push @$criticalCache, { type => $type, identifier => $identifier };
445 }
446
447 sub showCriticalEntries {
448 return if !$criticalCache;
449 my @criticals = @$criticalCache;
450 if ($#criticals != -1) {
451 print "=" x 60, "\n";
452 print "Some errors occoured while processing data, show details? (y|n) ";
453 my $answer = <STDIN>;
454 print "\n";
455 if ($answer =~ m/^y/i) {
456 foreach (@criticals) {
457 #print join("\n", @criticals);
458 #print Dumper($_);
459 print $_->{type}, ": ", $_->{identifier}, "\n";
460 print " ", $msgCache->{$_->{identifier}}, "\n";
461 delete $msgCache->{$_->{identifier}};
462 }
463 }
464 }
465 }
466
467 sub showGoodEntries {
468 print "=" x 60, "\n";
469 print "Show good entries? (y|n) ";
470 my $answer = <STDIN>;
471 print "\n";
472 if ($answer =~ m/^y/i) {
473 foreach (keys %$msgCache) {
474 print $_, ": ", $msgCache->{$_}, "\n" if $msgCache->{$_};
475 }
476 }
477 }
478
479 sub processResult {
480
481 my $dn = shift;
482 my $result = shift;
483
484 #print "dn: $dn", "\n";
485 #print Dumper($result);
486
487 my $error = 0;
488 my $error_code;
489 my $error_message;
490 if ($result) {
491 $error_code = $result->code;
492 $error_message = $result->error;
493 } else {
494 $error_code = 'n/a';
495 $error_message = "NO RESULT FROM LDAP-SERVER";
496 }
497
498 if ($error_code) {
499 rememberCriticalEntry("ldap", $dn);
500 my $errmesg = "(error=$error_message, code=$error_code)";
501 rememberMessage($dn, $errmesg);
502 logError("LDAP", $errmesg, { dn => $dn } );
503 $error = 1;
504 } else {
505 print "SUCCESS for (dn='$dn')", "\n" if $DEBUGLEVEL > 1;
506 }
507
508 undef $result;
509 }
510
511 sub rememberMessage {
512 my $ident = shift;
513 my $mesg = shift;
514 $msgCache->{$ident} = $mesg;
515 }
516
517 1;

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed