Added addressbook+LDAP functions.
authorpallo <pallo@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Sat, 25 Mar 2000 17:01:15 +0000 (17:01 +0000)
committerpallo <pallo@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Sat, 25 Mar 2000 17:01:15 +0000 (17:01 +0000)
git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@345 7612ce4b-ef26-0410-bec9-ea0150e637f0

TODO
functions/abook_ldap_server.php [new file with mode: 0644]
functions/abook_local_file.php [new file with mode: 0644]
functions/addressbook.php [new file with mode: 0644]
src/addrbook_popup.php [new file with mode: 0644]
src/addrbook_search.php [new file with mode: 0644]
src/compose.php

diff --git a/TODO b/TODO
index 493809c7d0afc3759a52dd39a9af8426c0206a34..3c6f2f1584e7f58c5712ede3eb5b0c61556d71c4 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,8 +3,7 @@ Ideas to be implemented
 
 initials = taken by that person
 
 
 initials = taken by that person
 
-  -     LDAP support for address books
-  -     Importing of address books
+(pl/gf) Importing of address books
 (lme)   Better email message body parsing
   -     Use PHP4 Session management, get rid of cookies
   -     Make it possible to save preferences in MySQL DB or on Filesystem
 (lme)   Better email message body parsing
   -     Use PHP4 Session management, get rid of cookies
   -     Make it possible to save preferences in MySQL DB or on Filesystem
@@ -23,3 +22,4 @@ Finished:
 (lme) (24.3.00) Saving sent messages  
 (lme) (24.3.00) Fix "Seen" bug with UW IMAP server 
 (lme) (24.3.00) Add "subscribe" to folders section
 (lme) (24.3.00) Saving sent messages  
 (lme) (24.3.00) Fix "Seen" bug with UW IMAP server 
 (lme) (24.3.00) Add "subscribe" to folders section
+(pl)  (25.3.00) LDAP support for address books
diff --git a/functions/abook_ldap_server.php b/functions/abook_ldap_server.php
new file mode 100644 (file)
index 0000000..3ed9e41
--- /dev/null
@@ -0,0 +1,204 @@
+<?php
+
+  /**
+   **  abook_ldap_server.php
+   **
+   **  Address book backend for LDAP server
+   **
+   **  An array with the following elements must be passed to
+   **  the class constructor (elements marked ? are optional):
+   **
+   **     host      => LDAP server hostname/IP-address
+   **     base      => LDAP server root (base dn). Empty string allowed.
+   **   ? port      => LDAP server TCP port number (default: 389)
+   **   ? charset   => LDAP server charset (default: utf-8)
+   **   ? name      => Name for LDAP server (default "LDAP: hostname")
+   **                  Used to tag the result data
+   **   ? maxrows   => Maximum # of rows in search result
+   **
+   **  NOTE. This class should not be used directly. Use the
+   **        "AddressBook" class instead.
+   **/
+
+   class abook_ldap_server extends addressbook_backend {
+     var $btype = "remote";
+     var $bname = "ldap_server";
+
+     // Parameters changed by class
+     var $sname   = "LDAP";       // Service name
+     var $server  = "";           // LDAP server name
+     var $port    = 389;          // LDAP server port
+     var $basedn  = "";           // LDAP base DN 
+     var $charset = "utf-8";      // LDAP server charset
+     var $linkid  = false;        // PHP LDAP link ID
+     var $bound   = false;        // True if LDAP server is bound
+     var $maxrows = 250;          // Max rows in result
+     
+
+     // Constructor. Connects to database
+     function abook_ldap_server($param) {
+       if(is_array($param)) {
+        $this->server = $param["host"];
+        $this->basedn = $param["base"];
+        if(!empty($param["port"]))
+          $this->port = $param["port"];
+        if(!empty($param["charset"]))
+          $this->charset = strtolower($param["charset"]);
+        if(isset($param["maxrows"]))
+          $this->maxrows = $param["maxrows"];
+        if(empty($param["name"]))
+          $this->sname = "LDAP: ".$param["host"];
+        else
+          $this->sname = $param["name"];
+        
+        $this->open(true);
+       } else {
+        $this->set_error(_("Invalid argument to constructor"));
+       }
+     }
+
+
+     // Open the LDAP server. New connection if $new is true
+     function open($new = false) {
+       $this->error = "";
+
+       // Connection is already open
+       if($this->linkid != false && !$new) 
+        return true;
+
+       $this->linkid = @ldap_connect($this->server, $this->port);
+       if(!$this->linkid) 
+        if(function_exists("ldap_error"))
+          return $this->set_error(ldap_error($this->linkid)); 
+        else
+          return $this->set_error("ldap_connect failed");
+       
+       if(!@ldap_bind($this->linkid))
+        if(function_exists("ldap_error"))
+          return $this->set_error(ldap_error($this->linkid)); 
+        else
+          return $this->set_error("ldap_bind failed");
+
+       $this->bound = true;
+       
+       return true;
+     }
+
+
+     // Encode iso8859-1 string to the charset used by this LDAP server
+     function charset_encode($str) {
+       if($this->charset == "utf-8") {
+        if(function_exists("utf8_encode"))
+          return utf8_encode($str);
+        else
+          return $str;
+       } else {
+        return $str;
+       }
+     }
+
+
+     // Decode from charset used by this LDAP server to iso8859-1
+     function charset_decode($str) {
+       if($this->charset == "utf-8") {
+        if(function_exists("utf8_decode"))
+          return utf8_decode($str);
+        else
+          return $str;
+       } else {
+        return $str;
+       }
+     }
+
+     
+     // ========================== Public ========================
+
+     // Search the LDAP server
+     function search($expr) {
+
+       // To be replaced by advanded search expression parsing
+       if(is_array($expr)) return false;
+
+       // Encode the expression
+       $expr = $this->charset_encode($expr);
+       if(!ereg("\*", $expr)) 
+        $expr = "*$expr*";
+       $expression = "cn=$expr";
+
+       // Make sure connection is there
+       if(!$this->open())
+        return false;
+
+       // Do the search
+       $sret = @ldap_search($this->linkid, $this->basedn, $expression,
+                           array("dn", "o", "ou", "sn", "givenname", 
+                                 "cn", "mail", "telephonenumber"));
+
+       // Should get error from server using the ldap_error() function,
+       // but it only exist in the PHP LDAP documentation.
+       if(!$sret)
+        if(function_exists("ldap_error"))
+          return $this->set_error(ldap_error($this->linkid)); 
+        else
+          return $this->set_error("ldap_search failed");       
+
+       if(@ldap_count_entries($this->linkid, $sret) <= 0)
+        return array();
+
+       // Get results
+       $ret = array();
+       $returned_rows = 0;
+       $res = @ldap_get_entries($this->linkid, $sret);
+       for($i = 0 ; $i < $res["count"] ; $i++) {
+        $row = $res[$i];
+
+        // Extract data common for all e-mail addresses
+        // of an object. Use only the first name
+        $nickname = $this->charset_decode($row["dn"]);
+        $fullname = $this->charset_decode($row["cn"][0]);
+
+        if(empty($row["telephonenumber"][0])) $phone = "";
+        else $phone = $this->charset_decode($row["telephonenumber"][0]);
+
+        if(!empty($row["ou"][0]))
+          $label = $this->charset_decode($row["ou"][0]);
+        else if(!empty($row["o"][0]))
+          $label = $this->charset_decode($row["o"][0]);
+        else 
+          $label = "";
+
+        if(empty($row["givenname"][0])) $firstname = "";
+        else $firstname = $this->charset_decode($row["givenname"][0]);
+
+        if(empty($row["sn"][0])) $surname = "";
+        else $surname = $this->charset_decode($row["sn"][0]);
+
+        // Add one row to result for each e-mail address
+        for($j = 0 ; $j < $row["mail"]["count"] ; $j++) {
+          array_push($ret, array("nickname"  => $nickname,
+                                 "name"      => $fullname,
+                                 "firstname" => $firstname,
+                                 "lastname"  => $surname,
+                                 "email"     => $row["mail"][$j],
+                                 "label"     => $label,
+                                 "phone"     => $phone,
+                                 "backend"   => $this->bnum,
+                                 "source"    => &$this->sname));
+
+          // Limit number of hits
+          $returned_rows++;
+          if(($returned_rows >= $this->maxrows) && 
+             ($this->maxrows > 0) ) {
+            ldap_free_result($sret);
+            return $ret;
+          }
+
+        }
+       }
+
+       ldap_free_result($sret);
+       return $ret;
+     } // end search()
+
+   }
+?>
diff --git a/functions/abook_local_file.php b/functions/abook_local_file.php
new file mode 100644 (file)
index 0000000..7e25b11
--- /dev/null
@@ -0,0 +1,220 @@
+<?php
+
+  /**
+   **  abook_local_file.php
+   **
+   **  Backend for addressbook as a pipe separated file
+   **
+   **  An array with the following elements must be passed to
+   **  the class constructor (elements marked ? are optional):
+   **
+   **     filename  => path to addressbook file
+   **   ? create    => if true: file is created if it does not exist.
+   **   ? umask     => umask set before opening file.
+   **
+   **  NOTE. This class should not be used directly. Use the
+   **        "AddressBook" class instead.
+   **/
+
+   class abook_local_file extends addressbook_backend {
+     var $btype = "local";
+     var $bname = "local_file";
+
+     var $filename   = "";
+     var $filehandle = 0;
+     var $create     = false;
+     var $umask;
+
+     // ========================== Private =======================
+
+     // Constructor
+     function abook_local_file($param) {
+       $this->sname = _("Personal address book");
+       $this->umask = Umask();
+
+       if(is_array($param)) {
+        if(empty($param["filename"]))
+          return $this->set_error("Invalid parameters");
+        if(!is_string($param["filename"]))
+          return $this->set_error($param["filename"] . ": ".
+                                  _("Not a file name"));
+
+        $this->filename = $param["filename"];
+
+        if($param["create"])
+          $this->create = true;
+        if(isset($param["umask"])) 
+          $this->umask = $param["umask"];
+
+        $this->open(true);
+       } else {
+        $this->set_error(_("Invalid argument to constructor"));
+       }
+     }
+
+     // Open the addressbook file and store the file pointer.
+     // Use $file as the file to open, or the class' own 
+     // filename property. If $param is empty and file is  
+     // open, do nothing.
+     function open($new = false) {
+       $this->error = "";
+       $file   = $this->filename;
+       $create = $this->create;
+
+       // Return true is file is open and $new is unset
+       if($this->filehandle && !$new)
+        return true;
+
+       // Check that new file exitsts
+       if((!(file_exists($file) && is_readable($file))) && !$create)
+        return $this->set_error("$file: " . 
+                                _("No such file or directory"));
+
+       // Close old file, if any
+       if($this->filehandle) $this->close();
+       
+       // Open file. First try to open for reading and writing,
+       // but fall back to read only.
+       umask($this->umask);
+       $fh = @fopen($file, "a+");
+       if($fh) {
+        $this->filehandle = &$fh;
+        $this->filename   = $file;
+        $this->writeable  = true;
+       } else {
+        $fh = @fopen($file, "r");
+        if($fh) {
+          $this->filehandle = &$fh;
+          $this->filename   = $file;
+          $this->writeable  = false;
+        } else {
+          return $this->set_error("$file: "._("Open failed"));
+        }
+       }
+
+       return true;
+     }
+
+     // Close the file and forget the filehandle
+     function close() {
+       @fclose($this->filehandle);
+       $this->filehandle = 0;
+       $this->filename   = "";
+       $this->writable   = false;
+     }
+     
+     // ========================== Public ========================
+     
+     // Search the file
+     function search($expr) {
+
+       // To be replaced by advanded search expression parsing
+       if(is_array($expr)) return;
+
+       // Make regexp from glob'ed expression 
+       $expr = ereg_replace("\?", ".", $expr);
+       $expr = ereg_replace("\*", ".*", $expr);
+
+       $res = array();
+       if(!$this->open())
+        return false;
+
+       @rewind($this->filehandle);
+       
+       while ($row = @fgetcsv($this->filehandle, 2048, "|")) {
+        $line = join(" ", $row);
+        if(eregi($expr, $line)) {
+          array_push($res, array("nickname"  => $row[0],
+                                 "name"      => $row[1] . " " . $row[2],
+                                 "firstname" => $row[1],
+                                 "lastname"  => $row[2],
+                                 "email"     => $row[3],
+                                 "label"     => $row[4],
+                                 "backend"   => $this->bnum,
+                                 "source"    => &$this->sname));
+        }
+       }
+       
+       return $res;
+     }
+     
+     // Lookup alias
+     function lookup($alias) {
+       if(empty($alias))
+        return array();
+
+       $alias = strtolower($alias);
+       
+       $this->open();
+       @rewind($this->filehandle);
+       
+       while ($row = @fgetcsv($this->filehandle, 2048, "|")) {
+        if(strtolower($row[0]) == $alias) {
+          return array("nickname"  => $row[0],
+                       "name"      => $row[1] . " " . $row[2],
+                       "firstname" => $row[1],
+                       "lastname"  => $row[2],
+                       "email"     => $row[3],
+                       "label"     => $row[4],
+                       "backend"   => $this->bnum,
+                       "source"    => &$this->sname);
+        }
+       }
+       
+       return array();
+     }
+
+     // List all addresses
+     function list_addr() {
+       $res = array();
+       $this->open();
+       @rewind($this->filehandle);
+       
+       while ($row = @fgetcsv($this->filehandle, 2048, "|")) {
+        array_push($res, array("nickname"  => $row[0],
+                               "name"      => $row[1] . " " . $row[2],
+                               "firstname" => $row[1],
+                               "lastname"  => $row[2],
+                               "email"     => $row[3],
+                               "label"     => $row[4],
+                               "backend"   => $this->bnum,
+                               "source"    => &$this->sname));
+       }
+       return $res;
+     }
+
+     // Add address
+     function add($userdata) {
+       if(!$this->writeable) 
+        return $this->set_error(_("Addressbook is read-only"));
+
+       // See if user exist already
+       $ret = $this->lookup($userdata["nickname"]);
+       if(!empty($ret))
+        return $this->set_error(sprintf(_("User '%s' already exist"), 
+                                        $ret["nickname"]));
+
+       // Here is the data to write
+       $data = sprintf("%s|%s|%s|%s|%s", $userdata["nickname"],
+                      $userdata["firstname"], $userdata["lastname"],
+                      $userdata["email"], $userdata["label"]);
+       // Strip linefeeds
+       $data = ereg_replace("[\r\n]", " ", $data);
+       // Add linefeed at end
+       $data = $data."\n";
+
+       // Reopen file, just to be sure
+       $this->open(true);
+       if(!$this->writeable) 
+        return $this->set_error(_("Addressbook is read-only"));
+
+       $r = fwrite($this->filehandle, $data);
+       if($r > 0)
+        return true;
+
+       $this->set_error(_("Write to addressbook failed"));
+       return false;
+     }
+
+   }
+?>
diff --git a/functions/addressbook.php b/functions/addressbook.php
new file mode 100644 (file)
index 0000000..eec06b7
--- /dev/null
@@ -0,0 +1,269 @@
+<?php
+
+  /**
+   **  addressbook.php
+   **
+   **  Functions and classes for the addressbook system.
+   **
+   **/
+    
+   $addressbook_php = true;
+
+   // Include backends here.
+   include("../functions/abook_local_file.php");
+   include("../functions/abook_ldap_server.php");
+
+   // Create and initialize an addressbook object. 
+   // Returns the created object
+   function addressbook_init() {
+      global $data_dir, $username, $ldap_server;
+      
+      // Create a new addressbook object
+      $abook = new AddressBook;
+      
+      // Always add a local backend
+      $filename = sprintf("%s%s.abook", $data_dir, $username);
+      $r = $abook->add_backend("local_file", Array("filename" => $filename,
+                                                  "create"   => true));
+      if(!$r) {
+        print _("Error opening ") ."$filename";
+        exit;
+      }
+     
+
+      // Load configured LDAP servers
+      reset($ldap_server);
+      while(list($key,$param) = each($ldap_server))
+        if(is_array($param))
+           $abook->add_backend("ldap_server", $param);
+
+      // Return the initialized object
+      return $abook;
+   }
+
+
+
+  /**
+   ** This is the main address book class that connect all the
+   ** backends and provide services to the functions above.
+   **
+   **/
+   class AddressBook { 
+      var $backends    = array();
+      var $numbackends = 0;
+      var $error       = "";
+
+      // Constructor function.
+      function AddressBook() {
+      }
+
+      // Return an array of backends of a given type, 
+      // or all backends if no type is specified.
+      function get_backend_list($type = "") {
+        $ret = array();
+        for($i = 1 ; $i <= $this->numbackends ; $i++) {
+           if(empty($type) || $type == $this->backends[$i]->btype) {
+              array_push($ret, &$this->backends[$i]);
+           }
+        }
+        return $ret;
+      }
+
+
+      // ========================== Public ========================
+
+      // Add a new backend. $backend is the name of a backend
+      // (without the abook_ prefix), and $param is an optional
+      // mixed variable that is passed to the backend constructor.
+      // See each of the backend classes for valid parameters.
+      function add_backend($backend, $param = "") {
+        $backend_name = "abook_".$backend;
+        eval("\$newback = new $backend_name(\$param);");
+        if(!empty($newback->error)) {
+           $this->error = $newback->error;
+           return false;
+        }
+
+        $this->numbackends++;
+       
+        $newback->bnum = $this->numbackends;
+        $this->backends[$this->numbackends] = $newback;
+        return $this->numbackends;
+      }
+
+
+      // Return a list of addresses matching expression in
+      // all backends of a given type.
+      function search($expression, $btype = "") {
+        $ret = array();
+
+        $sel = $this->get_backend_list($btype);
+        for($i = 0 ; $i < sizeof($sel) ; $i++) {
+           $backend = &$sel[$i];
+           $backend->error = "";
+           $res = $backend->search($expression);
+           if(is_array($res)) {
+              $ret = array_merge($ret, $res);
+           } else {
+              $this->error = $backend->error;
+              return false;
+           }
+        }
+
+        return $ret;
+      }
+
+
+      // Return a sorted search
+      function s_search($expression, $btype = "") {
+        $ret = $this->search($expression, $btype);
+
+        // Inline function - Not nice, but still.. 
+        function cmp($a,$b) {   
+           if($a["backend"] > $b["backend"]) 
+              return 1;
+           else if($a["backend"] < $b["backend"]) 
+              return -1;
+        
+           return (strtolower($a["name"]) > strtolower($b["name"])) ? 1 : -1;
+        }
+
+        usort($ret, 'cmp');
+        return $ret;
+      }
+
+
+      // Lookup an address by alias. Only possible in
+      // local backends.
+      function lookup($alias) {
+        $ret = array();
+
+        $sel = $this->get_backend_list("local");
+        for($i = 0 ; $i < sizeof($sel) ; $i++) {
+           $backend = &$sel[$i];
+           $backend->error = "";
+           $res = $backend->lookup($alias);
+           if(is_array($res)) {
+              return $res;
+           } else {
+              $this->error = $backend->error;
+              return false;
+           }
+        }
+
+        return $ret;
+      }
+
+
+      // Return all addresses
+      function list_addr() {
+        $ret = array();
+
+        $sel = $this->get_backend_list("local");
+        for($i = 0 ; $i < sizeof($sel) ; $i++) {
+           $backend = &$sel[$i];
+           $backend->error = "";
+           $res = $backend->list_addr();
+           if(is_array($res)) {
+              $ret = array_merge($ret, $res);
+           } else {
+              $this->error = $backend->error;
+              return false;
+           }
+        }
+
+        return $ret;
+      }
+
+
+      // Create a new address from $userdata, in backend $bnum.
+      // Return the backend number that the/ address was added
+      // to, or false if it failed.
+      function add($userdata, $bnum) {
+
+        // Validate data
+        if(!is_array($userdata)) {
+           $this->error = _("Invalid input data");
+           return false;
+        }
+        if(empty($userdata["fullname"]) &&
+           empty($userdata["lastname"])) {
+           $this->error = _("Name is missing");
+           return false;
+        }
+        if(empty($userdata["email"])) {
+           $this->error = _("E-mail address is missing");
+           return false;
+        }
+        if(empty($userdata["nickname"])) {
+           $userdata["nickname"] = $userdata["email"];
+        }
+
+        // Check that specified backend accept new entries
+        if(!$this->backends[$bnum]->writeable) {
+           $this->error = _("Addressbook is not writable");
+           return false;
+        }
+
+        // Add address to backend
+        $res = $this->backends[$bnum]->add($userdata);
+        if($res) {
+           return $bnum;
+        } else {
+           $this->error = $this->backends[$bnum]->error;
+           return false;
+        }
+
+        return false;  // Not reached
+      }
+
+   }
+
+
+  /**
+   ** Generic backend that all other backends extend
+   **/
+   class addressbook_backend {
+
+      // Variables that all backends must provide.
+      var $btype      = "dummy";
+      var $bname      = "dummy";
+      var $sname      = "Dummy backend";
+
+      // Variables common for all backends, but that 
+      // should not be changed by the backends.
+      var $bnum       = -1;
+      var $error      = "";
+      var $writeable  = false;
+
+      function set_error($string) {
+        $this->error = "[" . $this->sname . "] " . $string;
+        return false;
+      }
+
+
+      // ========================== Public ========================
+
+      function search($expression) {
+        $this->set_error("search not implemented");
+        return false;
+      }
+
+      function lookup($alias) {
+        $this->set_error("lookup not implemented");
+        return false;
+      }
+
+      function list_addr() {
+        $this->set_error("list_addr not implemented");
+        return false;
+      }
+
+      function add($userdata) {
+        $this->set_error("add not implemented");
+        return false;
+      }
+
+   }
+
+?>
diff --git a/src/addrbook_popup.php b/src/addrbook_popup.php
new file mode 100644 (file)
index 0000000..11b293e
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+   /**
+    **  addrbook_popup.php
+    **
+    **  Frameset for the JavaScript version of the address book.
+    **
+    **/
+
+   if(!isset($logged_in)) {
+      echo _("You must ");
+      echo _("login");
+      echo _(" first.");
+      exit;
+   }
+   if(!isset($username) || !isset($key)) {
+      echo _("You need a valid user and password to access this page!");
+      exit;
+   }
+
+   if (!isset($config_php))
+      include("../config/config.php");
+   if (!isset($page_header_php))
+      include("../functions/page_header.php");
+   if (!isset($addressbook_php))
+      include("../functions/addressbook.php");
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
+
+<HTML>
+<HEAD>
+<TITLE><?php 
+   printf("%s: %s", $org_title, _("Address Book")); 
+?></TITLE>
+</HEAD>
+
+<FRAMESET ROWS="60,*" BORDER=0>
+ <FRAME NAME="abookmain" MARGINWIDTH=0 SCROLLING=NO
+        SRC="addrbook_search.php?show=form" BORDER=0>
+ <FRAME NAME="abookres" MARGINWIDTH=0 SRC="addrbook_search.php?show=blank"
+        BORDER=0>
+</FRAMESET>
+
+</HTML>
diff --git a/src/addrbook_search.php b/src/addrbook_search.php
new file mode 100644 (file)
index 0000000..9202b13
--- /dev/null
@@ -0,0 +1,168 @@
+<?php
+   /**
+    **  addrbook_search.php
+    **
+    **  Handle addressbook searching in the popup window.
+    **
+    **/
+
+   if(!isset($logged_in)) {
+      echo _("You must ");
+      echo _("login");
+      echo _(" first.");
+      exit;
+   }
+   if(!isset($username) || !isset($key)) {
+      echo _("You need a valid user and password to access this page!");
+      exit;
+   }
+
+   if (!isset($config_php))
+      include("../config/config.php");
+   if (!isset($array_php))
+      include("../functions/array.php");
+   if (!isset($strings_php))
+      include("../functions/strings.php");
+   if (!isset($imap_php))
+      include("../functions/imap.php");
+   if (!isset($page_header_php))
+      include("../functions/page_header.php");
+   if (!isset($addressbook_php))
+      include("../functions/addressbook.php");
+
+   // Authenticate user and load prefs
+   $imapConnection = sqimap_login($username, $key, 
+                                 $imapServerAddress, $imapPort, 10);
+   include("../src/load_prefs.php");
+   sqimap_logout ($imapConnection);
+
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+
+<HTML>
+<HEAD>
+<TITLE><?php 
+   printf("%s: %s", $org_title, _("Address Book")); 
+?></TITLE>
+</HEAD>
+
+<?php
+   // Choose correct colors for top and bottom frame
+   if($show == "form") {
+      echo "<BODY BGCOLOR=\"$color[3]\" TEXT=\"$color[6]\" ";
+      echo "LINK=\"$color[6]\" VLINK=\"$color[6]\" ALINK=\"$color[6]\" ";
+      echo "OnLoad=\"document.sform.query.focus();\">";  
+   } else {
+      echo "<BODY TEXT=\"$color[8]\" BGCOLOR=\"$color[4]\" ";
+      echo "LINK=\"$color[7]\" VLINK=\"$color[7]\" ALINK=\"$color[7]\">\n";
+   }
+
+   // Just make a blank page and exit
+   if(($show == "blank") || (empty($query) && empty($show)))  {
+      printf("<P ALIGN=center><BR>%s</P>\n</BODY></HTML>\n",
+            _("Search results will display here"));
+      exit;
+   }
+
+   // Create search form 
+   if($show == "form") {
+      printf("<FORM NAME=sform TARGET=abookres ACTION=\"%s\" METHOD=GET>\n",
+            $PHP_SELF);
+      printf("<TABLE BORDER=0 WIDTH=\"100%%\" HEIGHT=\"100%%\">");
+      printf("<TR><TD NOWRAP VALIGN=middle>\n");
+      printf("  <STRONG>%s:</STRONG>\n</TD><TD VALIGN=middle>\n",
+            _("Search for"));
+      printf("  <INPUT TYPE=text NAME=query VALUE=\"%s\" SIZE=30>\n",
+            htmlspecialchars($query));
+      printf("</TD><TD VALIGN=middle>\n");
+      printf("  <INPUT TYPE=submit VALUE=\"%s\">",
+            _("Search"));
+      printf("</TD><TD WIDTH=\"50%%\" VALIGN=middle ALIGN=right>\n");
+      printf("<INPUT TYPE=button VALUE=\"%s\" onclick=\"parent.close();\">\n",
+             _("Close window"));
+      printf("</TD></TR></TABLE></FORM>\n");
+   }
+
+   // Include JavaScript code if this is search results
+   if(!empty($query)) {
+?>
+<SCRIPT LANGUAGE="Javascript"><!--
+
+function to_address($addr) {
+  var prefix    = "";
+  var pwintype = typeof parent.opener.document.compose;
+
+  if(pwintype != "undefined" ) {
+    if ( parent.opener.document.compose.send_to.value ) {
+      prefix = ", ";
+      parent.opener.document.compose.send_to.value = 
+        parent.opener.document.compose.send_to.value + ", " + $addr;      
+    } else {
+      parent.opener.document.compose.send_to.value = $addr;
+    }
+  }
+}
+
+function cc_address($addr) {
+  var prefix    = "";
+  var pwintype = typeof parent.opener.document.compose;
+
+  if(pwintype != "undefined" ) {
+    if ( parent.opener.document.compose.send_to_cc.value ) {
+      prefix = ", ";
+      parent.opener.document.compose.send_to_cc.value = 
+        parent.opener.document.compose.send_to_cc.value + ", " + $addr;      
+    } else {
+      parent.opener.document.compose.send_to_cc.value = $addr;
+    }
+  }
+}
+
+function bcc_address($addr) {
+  var prefix    = "";
+  var pwintype = typeof parent.opener.document.compose;
+
+  if(pwintype != "undefined" ) {
+    if ( parent.opener.document.compose.bcc.value ) {
+      prefix = ", ";
+      parent.opener.document.compose.bcc.value = 
+        parent.opener.document.compose.bcc.value + ", " + $addr;      
+    } else {
+      parent.opener.document.compose.bcc.value = $addr;
+    }
+  }
+}
+
+// --></SCRIPT>
+
+<?php 
+   } // End of included JavaScript code
+
+   // Do the search
+   if(!empty($query)) {
+      $abook = addressbook_init();
+      $res = $abook->s_search($query);
+
+      if(!is_array($res)) {
+        printf("<P ALIGN=center><BR>%s.</P>\n</BODY></HTML>\n",
+               _("No persons matching your search was found"));
+        exit;
+      }
+
+      // List search results
+      $line = 0;
+      print "<table border=0 width=100%>";
+      print "<tr bgcolor=\"$color[9]\"><TH align=left>&nbsp;<TH align=left>Name<TH align=left>E-mail<TH align=left>Info<TH align=left>Source</tr>\n";
+
+      while(list($key, $row) = each($res)) {
+        printf("<tr%s nowrap><td nowrap><a href=\"javascript:to_address('%s');\">To</A> | <a href=\"javascript:cc_address('%s');\">Cc</A><td nowrap>%s&nbsp;<td nowrap>%s&nbsp;<td nowrap>%s&nbsp;<td nowrap>%s</tr>\n", 
+               ($line % 2) ? " bgcolor=\"$color[0]\"" : "", $row["email"],
+               $row["email"], $row["name"], $row["email"], $row["label"], 
+               $row["source"]);
+        $line++;
+      }
+      print "</TABLE>";
+   }
+?>
+
+</BODY></HTML>
index 000eb0f09c270369991351eab0a4b2a377c0ce83..c92d1d55bdb55f5bbf342fa75f8f13337538c194 100644 (file)
       $reply_subj = decodeHeader($reply_subj);
       $forward_subj = decodeHeader($forward_subj);
 
       $reply_subj = decodeHeader($reply_subj);
       $forward_subj = decodeHeader($forward_subj);
 
-      echo "\n<FORM action=\"compose.php\" METHOD=POST\n";
+      echo "\n<SCRIPT LANGUAGE=JavaScript><!--\n";
+      echo "function open_abook() { \n";
+      echo "  var nwin = window.open(\"addrbook_popup.php\",\"abookpopup\",";
+      echo "\"width=670,height=300,resizable=yes,scrollbars=yes\");\n";
+      echo "  if((!nwin.opener) && (document.windows != null))\n";
+      echo "    nwin.opener = document.windows;\n";
+      echo "}\n";
+      echo "// --></SCRIPT>\n\n";
+
+      echo "\n<FORM name=compose action=\"compose.php\" METHOD=POST\n";
       echo "ENCTYPE=\"multipart/form-data\">\n";
       echo "<TABLE COLS=2 WIDTH=50 ALIGN=center CELLSPACING=0 BORDER=0>\n";
       echo "   <TR>\n";
       echo "ENCTYPE=\"multipart/form-data\">\n";
       echo "<TABLE COLS=2 WIDTH=50 ALIGN=center CELLSPACING=0 BORDER=0>\n";
       echo "   <TR>\n";
          echo "         <INPUT TYPE=TEXT NAME=send_to_bcc SIZE=60><BR>";
       echo "      </TD>\n";
       echo "   </TR>\n";
          echo "         <INPUT TYPE=TEXT NAME=send_to_bcc SIZE=60><BR>";
       echo "      </TD>\n";
       echo "   </TR>\n";
+
+      echo "<SCRIPT LANGUAGE=JavaScript><!--\n document.write(\"";
+      echo "<TR><TD BGCOLOR=\\\"$color[4]\\\">&nbsp;</TD>";
+      echo "</TD><TD BGCOLOR=\\\"$color[4]\\\" ALIGN=LEFT>";
+      printf("<A HREF=\\\"javascript:open_abook();\\\">%s</A>",
+            _("Lookup recipients in addressbook.<BR>"));
+      echo "</TD></TR>\");\n";
+      echo "// --></SCRIPT>\n";
+
       echo "   <TR>\n";
       echo "      <TD WIDTH=50 BGCOLOR=\"$color[4]\" ALIGN=RIGHT>\n";
       echo _("Subject:");
       echo "   <TR>\n";
       echo "      <TD WIDTH=50 BGCOLOR=\"$color[4]\" ALIGN=RIGHT>\n";
       echo _("Subject:");