#!/usr/bin/perl -w # mutt_ldap_query.pl version 3.0 # Written by Marc de Courville # The latest version of the code can be retrieved at # ftp://ftp.mutt.org/pub/mutt/contrib # This code is distributed under the GNU General Public License (GPL). See # http://www.opensource.org/gpl-license.html and http://www.opensource.org/. # mutt_ldap_query performs ldap queries using either ldapsearch command # or the perl-ldap module and it outputs the required formatted data for # feeding mutt when using its "External Address Query" feature. # This perl script can be interfaced with mutt by defining in your .muttrc: # set query_command = "mutt_ldap_query.pl '%s'" # Multiple requests are supported: the "Q" command of mutt accepts as argument # a list of queries (e.g. "Gosse de\ Courville"). # References: # - ldapsearch is a ldap server query tool present in ldap-3.3 distribution # http://www.umich.edu/~rsug/ldap) # - perl-ldap module # http://www.perl.com/CPAN-local/authors/id/GBARR # - mutt is the ultimate email client # http://www.mutt.org # - historical Brandon Blong's "External Address Query" feature patch for mutt # http://www.fiction.net/blong/programs/mutt/#query # Version History (major changes only) # 3.0 (12/29/1999): # implemented another query method using perl-ldap module enabled by # the -p boolean flag # 2.3 (12/28/1999): # added better parsing of the options, a shortcut for avoiding # -s and -b options by using the script builtin table of common # servers and associated search bases performing a # lookup (changes inspired from a patch sent by Adrian Likins # ), performed some Y2K cleanups ;-) # 2.2 (11/02/1999): # merged perl style fixes proposed by Warren Jones # 2.1 (4/14/1998): # first public release use strict; use constant DEBUG => 0; use constant ONLY_PERL => 0; use Getopt::Std; use vars qw($opt_p $opt_h $opt_s $opt_b $opt_n); getopts('hpn:s:b:'); if ($opt_p) { use Net::LDAP; } #----8<------8<------8<------8<---CONFIG AREA--->8------>8------>8------>8---- # Please change the following lines to match your site configuration # These are my defaults... my $ldap_server = "ldap.crm.mot.com"; my $search_base = "o=Motorola, c=US"; my $LDAPSEARCH="/usr/bin/ldapsearch"; my @fields = qw(cn mail sn fn uid); # list of the fields that will be used for composing the answer my $expected_answers = "cn fn sn mail business_group telephonenumber"; #8<------8<------8<------8<------8<--------->8------>8------>8------>8------>8 my $ldap_server_nick; my @results; # database of the common server with default search starting points # the format is: 'server nickname', 'full address of the server', 'search base' my %server_db = ( bigfoot => ['ldap.bigfoot.com', ''], novell => ['ldap.novell.com', ''], netscape => ['memberdir.netscape.com', 'ou=member_directory,o=netcenter.com'], infospace => ['ldap.infospace.com', 'c=US'], verisign => ['directory.verisign.com', ''], local => ['127.0.0.1', ''], four11 => ['ldap.four11.com', ''], redhat => ['slag.support.redhat.com', 'dc=redhat,dc=com'], motorola => ['ldap.mot.com', 'o=Motorola,c=US'], crm => ['ldap.crm.mot.com', 'o=Motorola,c=US'] ); sub usage { < -b -n [[] ...] -p use perl-ldap module instead of ldapsearch (which is the default) -s query ldap server -b use as the starting point for the search instead of the default -n shortcut for avoiding -s and -b options by using the script builtin table of common servers and associated search bases performing a lookup examples of queries: classical query: mutt_ldap_query.pl -s ldap.crm.mot.com -b 'o=Motorola,c=US' Gosse and its shortcut version using a nickname mutt_ldap_query.pl -n crm Gosse de\ Courville EOF } # print usage error die usage if (! $ARGV[0] || $opt_h); # define default $ldap_server $ldap_server = $opt_s if $opt_s; $search_base = $opt_b if $opt_b; if ($opt_n) { $ldap_server_nick = $opt_n; my $option_array = $server_db{$ldap_server_nick}; die print "$0 unknown server nickname:\n\t no server associated to the nickname $ldap_server_nick, please modify the internal database according your needs by editing the script $0\n" if ! $option_array; $ldap_server = $option_array->[0]; $search_base = $option_array->[1]; } print "DEBUG: ldap_server=$ldap_server search_base=$search_base\n" if (DEBUG); $/ = ''; # Paragraph mode for input. foreach my $askfor ( @ARGV ) { # enable this if you want to include wildcard in your search with some huge # ldap databases you might want to avoid it # my $query = join '', map { "($_=$askfor*)" } @fields; my $query = join '', map { "($_=$askfor)" } @fields; $query = "(|" . $query . ")"; my $command = "$LDAPSEARCH -L -h $ldap_server -b '$search_base' '(|$query)' $expected_answers"; print "DEBUG: ldapsearch command is:\nDEBUG: $command\n" if (DEBUG); if ($opt_p) { my $ldap = Net::LDAP->new($ldap_server, DN => "", Password => "", Port => 389, Debug => 3,) or die $@; $ldap->bind; my $mesg = $ldap->search( base => $search_base, filter => $query ) or die $@; $mesg->code && die $mesg->error; my @entries = $mesg->entries; map { $_->dump } $mesg->all_entries if (DEBUG); my $entry; foreach $entry (@entries) { print "DEBUG processing $entry->dn\n" if (DEBUG); # only keep the first email address, telephonenumber and businessgroup my $email = $entry->get('mail')->[0]; my $phone = $entry->get('telephonenumber')->[0]; my $sector = $entry->get('business_group')->[0]; my $cn = $entry->get('cn'); my @name = ($entry->get('fn'), $entry->get('sn')); # for Motorola it is more convenient to have these information as output push @results, "<$email>\t@name\t($phone) $sector\n"; # this one works mostly for everyody # push @results, "<$email>\t@name\n"; } $ldap->unbind; } else { open ( LDAPQUERY , "$command |") || die "LDAP query error: $!\n"; while ( ) { next if ! /^mail: (.*)$/im; my $email = $1; my $phone = /^telephonenumber: (.*)$/im ? $1 : ''; my $sector = /^business_group: (.*)$/im ? $1 : ''; my $cn = /^cn: (.*)/im ? $1 : ' '; my @name = ( /^fn: (.*)$/im, /^sn: (.*)$/im ); # for Motorola it is more convinient to have these information as output push @results, "<$email>\t@name\t($phone) $sector\n"; # this one works mostly for everyody # push @results, "<$email>\t@name\n"; ## for pretty printing... # my $name = join ' ', ( /^fn=(.*)$/im, /^sn=(.*)$/im ); # use one of these two next lines # my $answer = sprintf ("<%s>\t%-17.17s\t(%s) %s\n", $email, $name , $phone, $sector); # my $answer = sprintf ("<%s>\t%-20.20s\n", $email, $cn ); # push(@results, $answer); } close(LDAPQUERY) || die "ldapsearch failed: $!\n"; } } print "LDAP query: found ", scalar(@results), "\n", @results; exit 1 if ! @results;